1 /*------------------------------------------------------------------------------
2 *
3 * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4 * The YADIFA TM software product is provided under the BSD 3-clause license:
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of EURid nor the names of its contributors may be
16 * used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 *------------------------------------------------------------------------------
32 *
33 */
34
35 /** @defgroup yadifa
36 * @ingroup ###
37 * @brief
38 */
39
40 #include <strings.h>
41
42 #include "client-config.h"
43
44 #include "module.h"
45 #include "common.h"
46 #include "ya-conf.h"
47 #include "main.h"
48
49 #if HAS_CTRL
50 #include "module/ctrl.h"
51 #endif
52
53 #if HAS_KEYGEN
54 #include "module/keygen.h"
55 #endif
56
57 #if HAS_ZONESIGN
58 #include "module/zonesign.h"
59 #endif
60
61 #if HAS_YADIG
62 #include "module/yadig.h"
63 #endif
64
65 #if HAS_CRAFT
66 #pragma message("THIS MODULE CANNOT BE PUBLISHED, EVER")
67 #include "module/craft.h"
68 #endif
69
70 #include <dnscore/logger_handle.h>
71 #include <dnscore/config-cmdline.h>
72 #include <dnscore/config_settings.h>
73
74 logger_handle *g_yadifa_logger = LOGGER_HANDLE_SINK;
75
76 extern logger_handle *g_generate_logger;
77
78 static int verbosity_level = 0;
79
module_verbosity_level()80 int module_verbosity_level()
81 {
82 return verbosity_level;
83 }
84
85
86 // each module has a structure --> virtual table
87 // only those that are compiled in the program are taken in
88 static const module_s *module_list[] =
89 {
90 #if HAS_CTRL
91 &ctrl_program,
92 #endif
93
94 #if HAS_KEYGEN
95 &keygen_program,
96 #endif
97
98 #if HAS_ZONESIGN
99 &zonesign_program,
100 #endif
101
102 #if HAS_YADIG
103 &yadig_program,
104 #endif
105
106 #if HAS_CRAFT
107 &craft_program,
108 #endif
109 NULL
110 };
111
112 void
module_print_help(const module_s * module,const char * program_name,int is_executable)113 module_print_help(const module_s *module, const char* program_name, int is_executable)
114 {
115 // formatln("is_executable=%i", is_executable);
116
117 if(is_executable == 0) // if it's not a a module, give the program help (covers 'unspecified')
118 {
119 osformatln(termout, "Usage:\n\n%s %s [command] [options []]\n", program_name, module->parametername);
120 }
121 else
122 {
123 osformatln(termout, "Usage:\n\n%s command [options []]\n", program_name);
124 }
125 module->help_print(module, termout);
126 }
127
128 static void
module_program_print_help(const char * program_name,int help_count,int version_count)129 module_program_print_help(const char *program_name, int help_count, int version_count)
130 {
131 yadifa_show_version(version_count); // level 0 prints nothing
132
133 if(help_count > 0 || version_count == 0)
134 {
135 // give help
136
137 formatln("%s command [parameters]\n", program_name);
138 println("\tCommands:");
139
140 for(int i = 0; module_list[i] != NULL; ++i) // VS false positive: the last item of the array is guaranteed to be NULL
141 {
142 formatln("\t\t%12s : %s", module_list[i]->parametername, module_list[i]->name);
143 }
144
145 formatln("\nTry '%s help command' for more information about a command.\n", program_name);
146 }
147 }
148
149 const module_s *
module_get_from_args(int * argcp,char ** argv,int * is_executable_ptr)150 module_get_from_args(int *argcp, char **argv, int *is_executable_ptr)
151 {
152 // const char *executable_name = filename_from_path(argv[0]); // note: not used
153
154 *is_executable_ptr = -1;
155
156 // no <commandname> found, check for <parametername>
157
158 int argc = *argcp;
159
160 // if <parametername> is used there must be at least 3 parameters.
161 // if not we print an help page
162
163 if(argc >= 2) // if there is at least one parameter after the name
164 {
165 // compares the parameter name with each module "parametername"
166
167 for(int i = 0; module_list[i] != NULL; ++i) // VS false positive: the last item of the array is guaranted to be NULL
168 {
169 if(strcmp(argv[1], module_list[i]->parametername) == 0)
170 {
171 // module has been matched
172
173 *is_executable_ptr = 0;
174
175 // patch the command parameters (shifts out the first parameter)
176
177 for(int i = 2; i < argc; ++i)
178 {
179 argv[i - 1] = argv[i];
180 }
181
182 --argc;
183 *argcp = argc;
184
185 return module_list[i];
186 }
187 }
188
189 // no module has been matched, look if help was requested one way or another
190
191 if(strcasecmp(argv[1], "help") == 0)
192 {
193 // no match.
194 // is it "help" ?
195
196 if(argc >= 3) // if there is a parameter after help ..;
197 {
198 // putting in place the whole settings just to answer help or version would be pointless
199
200 // find the module whose help was requested and print it
201
202 for(int i = 0; module_list[i] != NULL; ++i)
203 {
204 if(strcmp(argv[2], module_list[i]->parametername) == 0)
205 {
206 *is_executable_ptr = 0;
207
208 module_print_help(module_list[i], argv[0], *is_executable_ptr);
209 return NULL;
210 }
211 }
212
213 formatln("'%s' isn't a command.\n", argv[2]);
214
215 module_program_print_help(argv[0], 1, 0);
216
217 return NULL;
218 }
219 else
220 {
221 println("help command requires a parameter.\n");
222
223 module_program_print_help(argv[0], 1, 0);
224 return NULL;
225 }
226 }
227 else if((strcasecmp(argv[1], "--help") == 0) || (strcasecmp(argv[1], "-h") == 0))
228 {
229 // help was asked in a standard way: print the general help listing the modules
230 // used as flag to know, that even if its not a module, the exit can be clean, 'help' of the module
231 // has been asked
232 *is_executable_ptr = 0;
233 }
234 else
235 {
236 // whatever was asked to yadifa is unknown: complain about it then print the general help listing the modules
237 }
238 }
239 else
240 {
241 // nothing was asked to yadifa: print the general help listing the modules
242 }
243
244 int help_count = 0;
245 int version_count = 0;
246 int verbose_level = 0;
247
248 for(int i = 1; i < argc; ++i)
249 {
250 if((strcmp(argv[1], "--help") == 0) || (strcmp(argv[1], "-h") == 0) )
251 {
252 ++help_count;
253 }
254 else if((strcmp(argv[1], "--version") == 0) || (strcmp(argv[1], "-V") == 0))
255 {
256 ++version_count;
257 }
258 else if((strcmp(argv[1], "--verbose") == 0) || (strcmp(argv[1], "-v") == 0))
259 {
260 ++verbose_level;
261 }
262 else
263 {
264 flushout();
265 osformatln(termerr, "%s: invalid option: %s", argv[0], argv[i]);
266 flusherr();
267 }
268 }
269
270 verbosity_level = verbose_level;
271
272 module_program_print_help(argv[0], help_count, version_count);
273
274 return NULL;
275 }
276
277 ya_result
module_run_from_args(int * argcp,char * argv[])278 module_run_from_args(int *argcp, char *argv[])
279 {
280 ya_result ret = ERROR;
281
282 int argc = *argcp;
283 int is_executable = -2;
284
285 const module_s *module = module_get_from_args(&argc, argv, &is_executable);
286
287 module_arg_set(argv, argc);
288
289 *argcp = argc;
290
291 // at this point, the program to execute is known
292
293 if(module != NULL)
294 {
295 if(FAIL(ret = module->init()))
296 {
297 formatln("module %s initialisation failed: %r", module->name, ret);
298 return ret;
299 }
300
301 // if the logger is running (not a guarantee), register the system logger
302
303 if(logger_is_running())
304 {
305 logger_handle_create("yadifa", &g_yadifa_logger);
306 }
307
308 // @TODO 20180611 gve -- this must be uncomment
309 if(ISOK(ret = ya_conf_init()))
310 {
311 int priority = ret;
312
313 if(ISOK(ret = module->config_register(priority)))
314 {
315 ret = ya_conf_read(module->cmdline_table, argc, argv, module->filter, module->filter_arg, module->rcname);
316
317 ya_conf_finalize();
318
319 if(cmdline_help_get() + cmdline_version_get() > 0)
320 {
321 module_print_help(module, argv[0], is_executable);
322 }
323 else
324 {
325 if(ret == 0)
326 {
327 if(ISOK(ret = module->setup()))
328 {
329 ret = module->run();
330 }
331 else // something is wrong with the setup
332 {
333 module_print_help(module, argv[0], is_executable);
334 }
335
336 // THERE IS NO GUARANTEE TO REACH THIS LINE (TCL)
337 }
338
339 if(FAIL(ret))
340 {
341 if((ret == CONFIG_PARSE_UNKNOWN_KEYWORD) || (ret == COMMAND_ARGUMENT_EXPECTED) || (ret == YADIFA_MODULE_HELP_REQUESTED))
342 {
343 module_print_help(module, argv[0], is_executable);
344 }
345 else
346 {
347 /// @todo 20220511 edf -- print the error if it's not YADIFA_MODULE_HELP_REQUESTED ?
348 flushout();
349 flusherr();
350 osformatln(termerr, "error: %r", ret);
351 }
352 }
353 }
354 }
355 else
356 {
357 formatln("module %s configuration registration failed: %r", module->name, ret);
358 }
359 }
360 else
361 {
362 formatln("module %s configuration initialisation failed: %r", module->name, ret);
363 }
364 }
365 else
366 {
367 // no module matched but maybe 'help' was asked instead
368 if (is_executable == 0)
369 {
370 // 'help' was asked instead
371 ret = 0;
372 }
373 }
374
375 *argcp = argc;
376
377 return ret;
378 }
379
380 /*----------------------------------------------------------------------------*/
381 #pragma mark MODULES DEFAULT FUNCTIONS
382
383 // ********************************************************************************
384 // ***** module initializer
385 // ********************************************************************************
386
387 ya_result
module_default_init(const struct module_s * m)388 module_default_init(const struct module_s* m)
389 {
390 (void)m;
391 return SUCCESS;
392 }
393
394 // ********************************************************************************
395 // ***** module finalizer
396 // ********************************************************************************
397
398 ya_result
module_default_finalize()399 module_default_finalize()
400 {
401 return SUCCESS;
402 }
403
404 // ********************************************************************************
405 // ***** module register
406 // ********************************************************************************
407
408 int
module_default_config_register(int argc,char ** argv)409 module_default_config_register(int argc, char **argv)
410 {
411 (void)argc;
412 (void)argv;
413 return 0;
414 }
415
416
417
418 // ********************************************************************************
419 // ***** module setup
420 // ********************************************************************************
421
422 int
module_default_setup()423 module_default_setup()
424 {
425 return SUCCESS; // returns anything else than 0 => program will exit
426 }
427
428 // ********************************************************************************
429 // ***** module run
430 // ********************************************************************************
431
432 ya_result
module_default_run()433 module_default_run()
434 {
435 return SUCCESS;
436 }
437
438 ya_result
module_default_help_print(const struct module_s * m,output_stream * os)439 module_default_help_print(const struct module_s* m, output_stream *os)
440 {
441 if(m->help_text != NULL)
442 {
443 osformatln(os, m->help_text, m->name);
444 }
445 else
446 {
447 osformatln(os, "help callback for module '%s' is not set properly", m->name);
448 }
449 return SUCCESS;
450 }
451
452 ya_result
module_default_cmdline_help_print(const struct module_s * m,output_stream * os)453 module_default_cmdline_help_print(const struct module_s* m, output_stream *os)
454 {
455 cmdline_print_help(m->cmdline_table, 16, 28, " : ", 48, os);
456 return SUCCESS;
457 }
458