2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Console .conf to Json program.
23 * Kern Sibbald, September MMXII
29 #include "console_conf.h"
32 /* Imported variables */
34 extern "C" { // work around visual compiler mangling variables
40 extern s_kw msg_types[];
41 extern RES_TABLE resources[];
43 /* Exported functions */
44 void senditf(const char *fmt, ...);
45 void sendit(const char *buf);
47 /* Imported functions */
48 extern bool parse_cons_config(CONFIG *config, const char *configfile, int exit_code);
52 /* default { { "Director": { "Name": aa, ...} }, { "Job": {..} */
53 bool do_list; /* [ {}, {}, ..] or { "aa": {}, "bb": {}, ...} */
54 bool do_one; /* { "Name": "aa", "Description": "test, ... } */
55 bool do_only_data; /* [ {}, {}, {}, ] */
58 regex_t directive_reg;
61 /* Forward referenced functions */
62 static void terminate_console(int sig);
63 static int check_resources();
64 //static void ressendit(void *ua, const char *fmt, ...);
65 //static void dump_resource_types();
66 //static void dump_directives();
67 static void dump_json(display_filter *filter);
69 /* Static variables */
70 static char *configfile = NULL;
71 static FILE *output = stdout;
72 static bool teeout = false; /* output to output and stdout */
75 static CONFIG *config;
78 #define CONFIG_FILE "bconsole.conf" /* default configuration file */
84 "\n%sVersion: " VERSION " (" BDATE ") %s %s %s\n\n"
85 "Usage: bconsjson [options] [config_file]\n"
86 " -r <res> get resource type <res>\n"
87 " -n <name> get resource <name>\n"
88 " -l <dirs> get only directives matching dirs (use with -r)\n"
90 " -c <file> set configuration file to file\n"
91 " -d <nn> set debug level to <nn>\n"
92 " -dt print timestamp in debug output\n"
93 " -t test - read configuration and exit\n"
95 " -? print this message.\n"
96 "\n"), 2012, "", HOST_OS, DISTNAME, DISTVER);
101 /*********************************************************************
103 * Bacula console conf to Json
106 int main(int argc, char *argv[])
109 bool test_config = false;
110 display_filter filter;
111 memset(&filter, 0, sizeof(filter));
114 setlocale(LC_ALL, "");
115 bindtextdomain("bacula", LOCALEDIR);
116 textdomain("bacula");
120 my_name_is(argc, argv, "bconsole");
121 init_msg(NULL, NULL);
122 working_directory = "/tmp";
123 args = get_pool_memory(PM_FNAME);
125 while ((ch = getopt(argc, argv, "n:vDabc:d:jl:r:t?")) != -1) {
128 filter.do_only_data = true;
134 case 'c': /* configuration file */
135 if (configfile != NULL) {
138 configfile = bstrdup(optarg);
144 if (*optarg == 't') {
145 dbg_timestamp = true;
147 debug_level = atoi(optarg);
148 if (debug_level <= 0) {
154 filter.do_list = true;
155 if (regcomp(&filter.directive_reg, optarg, REG_EXTENDED) != 0) {
156 Jmsg((JCR *)NULL, M_ERROR_TERM, 0,
157 _("Please use valid -l argument: %s\n"), optarg);
162 filter.resource_type = optarg;
166 filter.resource_name = optarg;
173 case 'v': /* verbose */
193 if (filter.do_list && !filter.resource_type) {
197 if (filter.resource_type && filter.resource_name) {
198 filter.do_one = true;
201 if (configfile == NULL || configfile[0] == 0) {
202 configfile = bstrdup(CONFIG_FILE);
205 if (test_config && verbose > 0) {
207 find_config_file(configfile, buf, sizeof(buf));
208 printf("config_file=%s\n", buf);
211 config = New(CONFIG());
212 config->encode_password(false);
213 parse_cons_config(config, configfile, M_ERROR_TERM);
215 if (!check_resources()) {
216 Emsg1(M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
220 terminate_console(0);
226 terminate_console(0);
230 /* Cleanup and then exit */
231 static void terminate_console(int sig)
233 static bool already_here = false;
235 if (already_here) { /* avoid recursive temination problems */
244 free_pool_memory(args);
255 * Dump out all resources in json format.
256 * Note!!!! This routine must be in this file rather
257 * than in src/lib/parser_conf.c otherwise the pointers
258 * will be all messed up.
260 static void dump_json(display_filter *filter)
265 bool first_directive;
269 regmatch_t pmatch[32];
273 /* List resources and directives */
274 if (filter->do_only_data) {
277 /* { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... }
278 * or print a single item
280 } else if (filter->do_one || filter->do_list) {
284 /* [ { "Client": { "Name": "aa",.. } }, { "Director": { "Name": "bb", ... } } ]*/
289 /* Loop over all resource types */
290 for (resinx=0; resources[resinx].name; resinx++) {
291 /* Skip this resource type */
292 if (filter->resource_type &&
293 strcasecmp(filter->resource_type, resources[resinx].name) != 0) {
298 /* Loop over all resources of this type */
299 foreach_rblist(res, res_head[resinx]->res_list) {
301 items = resources[resinx].items;
306 /* Copy the resource into res_all */
307 memcpy(&res_all, res, sizeof(res_all));
309 if (filter->resource_name) {
311 /* The Name should be at the first place, so this is not a real loop */
312 for (item=0; items[item].name; item++) {
313 if (strcasecmp(items[item].name, "Name") == 0) {
314 if (strcasecmp(*(items[item].value), filter->resource_name) == 0) {
320 if (skip) { /* The name doesn't match, so skip it */
332 if (filter->do_only_data) {
335 } else if (filter->do_one) {
336 /* Nothing to print */
338 /* When sending the list, the form is:
339 * { aa: { Name: aa, Description: aadesc...}, bb: { Name: bb
341 } else if (filter->do_list) {
342 /* Search and display Name, should be the first item */
343 for (item=0; items[item].name; item++) {
344 if (strcmp(items[item].name, "Name") == 0) {
345 printf("%s: {\n", quote_string(hpkt.edbuf, *items[item].value));
350 /* Begin new resource */
351 printf("{\n \"%s\": {", resources[resinx].name);
355 first_directive = true;
358 for (item=0; items[item].name; item++) {
359 /* Check user argument -l */
360 if (filter->do_list &&
361 regexec(&filter->directive_reg,
362 items[item].name, 32, pmatch, 0) != 0)
367 hpkt.ritem = &items[item];
368 if (bit_is_set(item, res_all.hdr.item_present)) {
369 if (!first_directive) printf(",");
370 if (display_global_item(hpkt)) {
371 /* Fall-through wanted */
373 printf("\n \"%s\": null", items[item].name);
376 first_directive = false;
378 if (items[item].flags & ITEM_LAST) {
379 display_last(hpkt); /* If last bit set always call to cleanup */
382 /* { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... } */
383 if (filter->do_only_data || filter->do_list) {
384 printf("\n }"); /* Finish the Resource with a single } */
387 if (filter->do_one) {
388 /* don't print anything */
389 } else if (directives) {
390 printf("\n }\n}"); /* end of resource */
395 } /* End loop over all resources of this type */
396 } /* End loop all resource types */
398 if (filter->do_only_data) {
401 } else if (filter->do_one || filter->do_list) {
412 * Make a quick check to see that we have all the
415 static int check_resources()
424 foreach_res(director, R_DIRECTOR) {
427 /* tls_require implies tls_enable */
428 if (director->tls_require) {
430 director->tls_enable = true;
432 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
438 tls_needed = director->tls_enable || director->tls_authenticate;
440 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && tls_needed) {
441 Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
442 " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s."
443 " At least one CA certificate store is required.\n"),
444 director->hdr.name, configfile);
450 Emsg1(M_FATAL, 0, _("No Director resource defined in %s\n"
451 "Without that I don't how to speak to the Director :-(\n"), configfile);
456 /* Loop over Consoles */
457 foreach_res(cons, R_CONSOLE) {
458 /* tls_require implies tls_enable */
459 if (cons->tls_require) {
461 cons->tls_enable = true;
463 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
468 tls_needed = cons->tls_enable || cons->tls_authenticate;
469 if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir) && tls_needed) {
470 Emsg2(M_FATAL, 0, _("Neither \"TLS CA Certificate\""
471 " or \"TLS CA Certificate Dir\" are defined for Console \"%s\" in %s.\n"),
472 cons->hdr.name, configfile);
483 static void ressendit(void *sock, const char *fmt, ...)
488 va_start(arg_ptr, fmt);
489 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
494 static void dump_resource_types()
499 /* List resources and their code */
502 for (i=0; resources[i].name; i++) {
506 printf(" \"%s\": %d", resources[i].name, resources[i].rcode);
512 static void dump_directives()
516 bool first_directive;
519 /* List resources and directives */
522 for (i=0; resources[i].name; i++) {
526 printf("{\n \"%s\": {\n", resources[i].name);
528 first_directive = true;
529 items = resources[i].items;
530 for (j=0; items[j].name; j++) {
531 if (!first_directive) {
534 printf(" \"%s\": null", items[j].name);
535 first_directive = false;
537 printf("\n }"); /* end of resource */
544 * Send a line to the output file and or the terminal
546 void senditf(const char *fmt,...)
551 va_start(arg_ptr, fmt);
552 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
557 void sendit(const char *buf)
561 if (output == stdout || teeout) {
564 * Here, we convert every \n into \r\n because the
565 * terminal is in raw mode when we are using
568 for (p=q=buf; (p=strchr(q, '\n')); ) {
571 memcpy(obuf, q, len);
573 memcpy(obuf+len, "\r\n", 3);
574 q = ++p; /* point after \n */
582 if (output != stdout) {