ctdb-common: Avoid ENOENT for unknown conf options
[vlendec/samba-autobuild/.git] / ctdb / common / conf_tool.c
1 /*
2    Config options tool
3
4    Copyright (C) Amitay Isaacs  2018
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21
22 #include <talloc.h>
23
24 #include "lib/util/debug.h"
25
26 #include "common/logging.h"
27 #include "common/cmdline.h"
28 #include "common/conf.h"
29 #include "common/path.h"
30
31 #include "common/logging_conf.h"
32 #include "cluster/cluster_conf.h"
33 #include "database/database_conf.h"
34 #include "event/event_conf.h"
35 #include "failover/failover_conf.h"
36 #include "server/legacy_conf.h"
37
38 #include "common/conf_tool.h"
39
40 struct conf_tool_context {
41         struct cmdline_context *cmdline;
42         const char *conf_file;
43         struct conf_context *conf;
44 };
45
46 static int conf_tool_dump(TALLOC_CTX *mem_ctx,
47                           int argc,
48                           const char **argv,
49                           void *private_data)
50 {
51         struct conf_tool_context *ctx = talloc_get_type_abort(
52                 private_data, struct conf_tool_context);
53         int ret;
54
55         if (argc != 0) {
56                 cmdline_usage(ctx->cmdline, "dump");
57                 return EINVAL;
58         }
59
60         ret = conf_load(ctx->conf, ctx->conf_file, true);
61         if (ret != 0 && ret != ENOENT) {
62                 D_ERR("Failed to load config file %s\n", ctx->conf_file);
63                 return ret;
64         }
65
66         conf_dump(ctx->conf, stdout);
67         return 0;
68 }
69
70 static int conf_tool_get(TALLOC_CTX *mem_ctx,
71                          int argc,
72                          const char **argv,
73                          void *private_data)
74 {
75         struct conf_tool_context *ctx = talloc_get_type_abort(
76                 private_data, struct conf_tool_context);
77         const char *section, *option;
78         enum conf_type type;
79         int ret;
80         bool ok;
81         const char *s_val = NULL;
82         int i_val;
83         bool b_val;
84
85         if (argc != 2) {
86                 cmdline_usage(ctx->cmdline, "get");
87                 return EINVAL;
88         }
89
90         section = argv[0];
91         option = argv[1];
92
93         ok = conf_query(ctx->conf, section, option, &type);
94         if (!ok) {
95                 D_ERR("Configuration option [%s] -> \"%s\" not defined\n",
96                       section, option);
97                 return ENOENT;
98         }
99
100         ret = conf_load(ctx->conf, ctx->conf_file, true);
101         if (ret != 0 && ret != ENOENT) {
102                 D_ERR("Failed to load config file %s\n", ctx->conf_file);
103                 return ret;
104         }
105
106         switch (type) {
107         case CONF_STRING:
108                 ret = conf_get_string(ctx->conf,
109                                       section,
110                                       option,
111                                       &s_val,
112                                       NULL);
113                 break;
114
115         case CONF_INTEGER:
116                 ret = conf_get_integer(ctx->conf,
117                                        section,
118                                        option,
119                                        &i_val,
120                                        NULL);
121                 break;
122
123         case CONF_BOOLEAN:
124                 ret = conf_get_boolean(ctx->conf,
125                                        section,
126                                        option,
127                                        &b_val,
128                                        NULL);
129                 break;
130
131         default:
132                 D_ERR("Unknown configuration option type\n");
133                 return EINVAL;
134         }
135
136         if (ret != 0) {
137                 D_ERR("Failed to get configuration option value\n");
138                 return ret;
139         }
140
141         switch (type) {
142         case CONF_STRING:
143                 printf("%s\n", s_val == NULL ? "" : s_val);
144                 break;
145
146         case CONF_INTEGER:
147                 printf("%d\n", i_val);
148                 break;
149
150         case CONF_BOOLEAN:
151                 printf("%s\n", b_val ? "true" : "false");
152                 break;
153         }
154
155         return 0;
156 }
157
158 static int conf_tool_validate(TALLOC_CTX *mem_ctx,
159                               int argc,
160                               const char **argv,
161                               void *private_data)
162 {
163         struct conf_tool_context *ctx = talloc_get_type_abort(
164                 private_data, struct conf_tool_context);
165         int ret;
166
167         if (argc != 0) {
168                 cmdline_usage(ctx->cmdline, "validate");
169                 return EINVAL;
170         }
171
172         ret = conf_load(ctx->conf, ctx->conf_file, false);
173         if (ret != 0) {
174                 D_ERR("Failed to load config file %s\n", ctx->conf_file);
175                 return ret;
176         }
177
178         return 0;
179 }
180
181 struct cmdline_command conf_commands[] = {
182         { "dump", conf_tool_dump,
183                 "Dump configuration", NULL },
184         { "get", conf_tool_get,
185                 "Get a config value", "<section> <key>" },
186         { "validate", conf_tool_validate,
187                 "Validate configuration file", NULL },
188         CMDLINE_TABLEEND
189 };
190
191 int conf_tool_init(TALLOC_CTX *mem_ctx,
192                    const char *prog,
193                    struct poptOption *options,
194                    int argc,
195                    const char **argv,
196                    bool parse_options,
197                    struct conf_tool_context **result)
198 {
199         struct conf_tool_context *ctx;
200         int ret;
201
202         ctx = talloc_zero(mem_ctx, struct conf_tool_context);
203         if (ctx == NULL) {
204                 D_ERR("Memory allocation error\n");
205                 return ENOMEM;
206         }
207
208         ret = cmdline_init(ctx, prog, options, conf_commands, &ctx->cmdline);
209         if (ret != 0) {
210                 D_ERR("Failed to initialize cmdline, ret=%d\n", ret);
211                 talloc_free(ctx);
212                 return ret;
213         }
214
215         ret = cmdline_parse(ctx->cmdline, argc, argv, parse_options);
216         if (ret != 0) {
217                 cmdline_usage(ctx->cmdline, NULL);
218                 talloc_free(ctx);
219                 return ret;
220         }
221
222         *result = ctx;
223         return 0;
224 }
225
226 int conf_tool_run(struct conf_tool_context *ctx, int *result)
227 {
228         int ret;
229
230         ctx->conf_file = path_config(ctx);
231         if (ctx->conf_file == NULL) {
232                 D_ERR("Memory allocation error\n");
233                 return ENOMEM;
234         }
235
236         ret = conf_init(ctx, &ctx->conf);
237         if (ret != 0) {
238                 D_ERR("Failed to initialize config\n");
239                 return ret;
240         }
241
242         /* Call functions to initialize config sections/variables */
243         logging_conf_init(ctx->conf, NULL);
244         cluster_conf_init(ctx->conf);
245         database_conf_init(ctx->conf);
246         event_conf_init(ctx->conf);
247         failover_conf_init(ctx->conf);
248         legacy_conf_init(ctx->conf);
249
250         if (! conf_valid(ctx->conf)) {
251                 D_ERR("Failed to define configuration options\n");
252                 return EINVAL;
253         }
254
255         ret = cmdline_run(ctx->cmdline, ctx, result);
256         return ret;
257 }
258
259 #ifdef CTDB_CONF_TOOL
260
261 static struct {
262         const char *debug;
263 } conf_data = {
264         .debug = "ERROR",
265 };
266
267 struct poptOption conf_options[] = {
268         POPT_AUTOHELP
269         { "debug", 'd', POPT_ARG_STRING, &conf_data.debug, 0,
270                 "debug level", "ERROR|WARNING|NOTICE|INFO|DEBUG" },
271         POPT_TABLEEND
272 };
273
274 int main(int argc, const char **argv)
275 {
276         TALLOC_CTX *mem_ctx;
277         struct conf_tool_context *ctx;
278         int ret, result;
279         bool ok;
280
281         mem_ctx = talloc_new(NULL);
282         if (mem_ctx == NULL) {
283                 fprintf(stderr, "Memory allocation error\n");
284                 exit(1);
285         }
286
287         ret = conf_tool_init(mem_ctx,
288                              "ctdb-config",
289                              conf_options,
290                              argc,
291                              argv,
292                              true,
293                              &ctx);
294         if (ret != 0) {
295                 talloc_free(mem_ctx);
296                 exit(1);
297         }
298
299         setup_logging("ctdb-config", DEBUG_STDERR);
300         ok = debug_level_parse(conf_data.debug, &DEBUGLEVEL);
301         if (!ok) {
302                 DEBUGLEVEL = DEBUG_ERR;
303         }
304
305         ret = conf_tool_run(ctx, &result);
306         if (ret != 0) {
307                 result = 1;
308         }
309
310         talloc_free(mem_ctx);
311         exit(result);
312 }
313
314 #endif /* CTDB_CONF_TOOL */