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  */
load_config_file(const char* file)32 static 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 
load_config_file(const char *file, Settings& settings)48 void load_config_file(const char *file, Settings& settings)
49 {
50     settings.reconfigure(load_config_file(file));
51 }
52 
validate_proposed_config_changes(const char* new_cfg, cJSON* errors)53 bool 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 
reload_config_file()77 void 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