1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2016 Couchbase, Inc
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17#include "config.h"
18#include "config_parse.h"
19#include "cmdline.h"
20#include "config_util.h"
21#include "settings.h"
22
23#include <sstream>
24
25/**
26 * Load the configuration file from disk and parse it to JSON
27 *
28 * @param file the name of the file to load
29 * @return A handle to a JSON representing the config file
30 * @throws std::runtime_error if an error occurs
31 */
32static unique_cJSON_ptr load_config_file(const char* file) {
33    cJSON *sys;
34    config_error_t err = config_load_file(file, &sys);
35
36    if (err != CONFIG_SUCCESS) {
37        throw std::runtime_error(config_strerror(file, err));
38    }
39
40    return unique_cJSON_ptr(sys);
41}
42
43
44/******************************************************************************
45 * Public functions
46 *****************************************************************************/
47
48void load_config_file(const char *file, Settings& settings)
49{
50    settings.reconfigure(load_config_file(file));
51}
52
53bool validate_proposed_config_changes(const char* new_cfg, cJSON* errors) {
54
55    unique_cJSON_ptr config(cJSON_Parse(new_cfg));
56    if (config.get() == nullptr) {
57        cJSON_AddItemToArray(errors, cJSON_CreateString("JSON parse error"));
58        return false;
59    }
60
61    // Earlier we returned all of the errors, now I'm terminating on
62    // the first... Ideally all of the errors would be best, but
63    // the code is easier if we can use exceptions to abort the parsing
64    // when we hit an error. Given that this isn't something that the
65    // user would be calling every time I don't think it is a big problem..
66    try {
67        Settings new_settings(config);
68        settings.updateSettings(new_settings, false);
69        return true;
70    } catch (const std::exception& exception) {
71        cJSON_AddItemToArray(errors, cJSON_CreateString(exception.what()));
72    }
73
74    return false;
75}
76
77void reload_config_file() {
78    LOG_INFO("Reloading config file {}", get_config_file());
79
80    try {
81        Settings new_settings(load_config_file(get_config_file()));
82        settings.updateSettings(new_settings, true);
83    } catch (const std::exception& exception) {
84        LOG_WARNING(
85                "Validation failed while reloading config file '{}'. Error: {}",
86                get_config_file(),
87                exception.what());
88    }
89}
90