2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 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.
28 /* Imported functions */
29 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
31 /* Imported variables */
33 extern "C" { // work around visual compiler mangling variables
39 extern s_kw msg_types[];
40 extern s_kw dev_types[];
41 extern s_kw tapelabels[];
42 extern s_kw cloud_drivers[];
43 extern s_kw trunc_opts[];
44 extern s_kw upload_opts[];
45 extern s_kw proto_opts[];
46 extern s_kw uri_opts[];
48 extern RES_TABLE resources[];
57 regex_t directive_reg;
60 /* Forward referenced functions */
61 void terminate_stored(int sig);
62 static int check_resources();
63 static void sendit(void *sock, const char *fmt, ...);
64 static void dump_json(display_filter *filter);
66 #define CONFIG_FILE "bacula-sd.conf" /* Default config file */
68 /* Global variables exported */
69 STORES *me = NULL; /* our Global resource */
71 char *configfile = NULL;
73 /* Global static variables */
74 static CONFIG *config;
81 "\n%sVersion: %s (%s)\n\n"
82 "Usage: bsdjson [options] [config_file]\n"
83 " -r <res> get resource type <res>\n"
84 " -n <name> get resource <name>\n"
85 " -l <dirs> get only directives matching dirs (use with -r)\n"
87 " -c <file> use <file> as configuration file\n"
88 " -d <nn> set debug level to <nn>\n"
89 " -dt print timestamp in debug output\n"
90 " -t test - read config and exit\n"
91 " -v verbose user messages\n"
92 " -? print this message.\n"
93 "\n"), 2012, "", VERSION, BDATE);
98 /*********************************************************************
100 * Main Bacula Unix Storage Daemon
103 #if defined(HAVE_WIN32)
104 #define main BaculaMain
107 int main (int argc, char *argv[])
110 bool test_config = false;
111 display_filter filter;
112 memset(&filter, 0, sizeof(filter));
114 setlocale(LC_ALL, "");
115 bindtextdomain("bacula", LOCALEDIR);
116 textdomain("bacula");
118 my_name_is(argc, argv, "bacula-sd");
119 init_msg(NULL, NULL);
121 while ((ch = getopt(argc, argv, "Dc:d:tv?r:n:l:")) != -1) {
124 filter.do_only_data = true;
128 filter.do_list = true;
129 /* Might use something like -l '^(Name|Description)$' */
130 filter.do_list = true;
131 if (regcomp(&filter.directive_reg, optarg, REG_EXTENDED) != 0) {
132 Jmsg((JCR *)NULL, M_ERROR_TERM, 0,
133 _("Please use valid -l argument: %s\n"), optarg);
138 filter.resource_type = optarg;
142 filter.resource_name = optarg;
145 case 'c': /* configuration file */
146 if (configfile != NULL) {
149 configfile = bstrdup(optarg);
152 case 'd': /* debug level */
153 if (*optarg == 't') {
154 dbg_timestamp = true;
156 debug_level = atoi(optarg);
157 if (debug_level <= 0) {
167 case 'v': /* verbose */
181 if (configfile != NULL) {
184 configfile = bstrdup(*argv);
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 sendit(NULL, "config_file=%s\n", buf);
211 config = New(CONFIG());
212 config->encode_password(false);
213 parse_sd_config(config, configfile, M_ERROR_TERM);
215 if (!check_resources()) {
216 Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
223 my_name_is(0, (char **)NULL, me->hdr.name); /* Set our real name */
227 if (filter.do_list) {
228 regfree(&filter.directive_reg);
234 static void display_devtype(HPKT &hpkt)
237 for (i=0; dev_types[i].name; i++) {
238 if (*(int32_t *)(hpkt.ritem->value) == dev_types[i].token) {
239 sendit(NULL, "\n \"%s\": \"%s\"", hpkt.ritem->name,
246 static void display_label(HPKT &hpkt)
249 for (i=0; tapelabels[i].name; i++) {
250 if (*(int32_t *)(hpkt.ritem->value) == tapelabels[i].token) {
251 sendit(NULL, "\n \"%s\": \"%s\"", hpkt.ritem->name,
258 static void display_cloud_driver(HPKT &hpkt)
261 for (i=0; cloud_drivers[i].name; i++) {
262 if (*(int32_t *)(hpkt.ritem->value) == cloud_drivers[i].token) {
263 sendit(NULL, "\n \"%s\": \"%s\"", hpkt.ritem->name,
264 cloud_drivers[i].name);
270 static void display_protocol(HPKT &hpkt)
273 for (i=0; proto_opts[i].name; i++) {
274 if (*(int32_t *)(hpkt.ritem->value) == proto_opts[i].token) {
275 sendit(NULL, "\n \"%s\": \"%s\"", hpkt.ritem->name,
282 static void display_truncate_cache(HPKT &hpkt)
285 for (i=0; trunc_opts[i].name; i++) {
286 if (*(int32_t *)(hpkt.ritem->value) == trunc_opts[i].token) {
287 sendit(NULL, "\n \"%s\": \"%s\"", hpkt.ritem->name,
294 static void display_uri_style(HPKT &hpkt)
297 for (i=0; uri_opts[i].name; i++) {
298 if (*(int32_t *)(hpkt.ritem->value) == uri_opts[i].token) {
299 sendit(NULL, "\n \"%s\": \"%s\"", hpkt.ritem->name,
306 static void display_upload(HPKT &hpkt)
309 for (i=0; upload_opts[i].name; i++) {
310 if (*(int32_t *)(hpkt.ritem->value) == upload_opts[i].token) {
311 sendit(NULL, "\n \"%s\": \"%s\"", hpkt.ritem->name,
312 upload_opts[i].name);
319 * Dump out all resources in json format.
320 * Note!!!! This routine must be in this file rather
321 * than in src/lib/parser_conf.c otherwise the pointers
322 * will be all messed up.
324 static void dump_json(display_filter *filter)
326 int resinx, item, directives, first_directive;
331 regmatch_t pmatch[32];
332 STORES *me = (STORES *)GetNextRes(R_STORAGE, NULL);
336 if (filter->do_only_data) {
339 /* List resources and directives */
340 /* { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... }
341 * or print a single item
343 } else if (filter->do_one || filter->do_list) {
347 /* [ { "Device": { "Name": "aa",.. } }, { "Director": { "Name": "bb", ... } } ]*/
352 /* Loop over all resource types */
353 for (resinx=0; resources[resinx].name; resinx++) {
354 if (!resources[resinx].items) {
355 continue; /* skip dummy entries */
358 /* Skip this resource type */
359 if (filter->resource_type &&
360 strcasecmp(filter->resource_type, resources[resinx].name) != 0) {
365 /* Loop over all resources of this type */
366 foreach_rblist(res, res_head[resinx]->res_list) {
368 items = resources[resinx].items;
373 /* Copy the resource into res_all */
374 memcpy(&res_all, res, sizeof(res_all));
376 if (filter->resource_name) {
378 /* The Name should be at the first place, so this is not a real loop */
379 for (item=0; items[item].name; item++) {
380 if (strcasecmp(items[item].name, "Name") == 0) {
381 if (strcasecmp(*(items[item].value), filter->resource_name) == 0) {
387 if (skip) { /* The name doesn't match, so skip it */
398 if (filter->do_only_data) {
401 } else if (filter->do_one) {
402 /* Nothing to print */
404 /* When sending the list, the form is:
405 * { aa: { Name: aa, Description: aadesc...}, bb: { Name: bb
407 } else if (filter->do_list) {
408 /* Search and display Name, should be the first item */
409 for (item=0; items[item].name; item++) {
410 if (strcmp(items[item].name, "Name") == 0) {
411 sendit(NULL, "%s: {\n", quote_string(hpkt.edbuf2, *items[item].value));
416 /* Begin new resource */
417 sendit(NULL, "{\n \"%s\": {", resources[resinx].name);
423 for (item=0; items[item].name; item++) {
424 /* Check user argument -l */
425 if (filter->do_list &&
426 regexec(&filter->directive_reg,
427 items[item].name, 32, pmatch, 0) != 0)
432 hpkt.ritem = &items[item];
433 if (bit_is_set(item, res_all.hdr.item_present)) {
434 if (first_directive++ > 0) printf(",");
435 if (display_global_item(hpkt)) {
436 /* Fall-through wanted */
437 } else if (items[item].handler == store_maxblocksize) {
438 display_int32_pair(hpkt);
439 } else if (items[item].handler == store_devtype) {
440 display_devtype(hpkt);
441 } else if (items[item].handler == store_label) {
443 } else if (items[item].handler == store_cloud_driver) {
444 display_cloud_driver(hpkt);
445 } else if (items[item].handler == store_protocol) {
446 display_protocol(hpkt);
447 } else if (items[item].handler == store_uri_style) {
448 display_uri_style(hpkt);
449 } else if (items[item].handler == store_truncate) {
450 display_truncate_cache(hpkt);
451 } else if (items[item].handler == store_upload) {
452 display_upload(hpkt);
454 printf("\n \"%s\": \"null\"", items[item].name);
457 } else { /* end if is present */
458 /* For some directive, the bitmap is not set (like addresses) */
459 if (me && strcmp(resources[resinx].name, "Storage") == 0) {
460 if (strcmp(items[item].name, "SdPort") == 0) {
461 if (get_first_port_host_order(me->sdaddrs) != items[item].default_value) {
462 if (first_directive++ > 0) sendit(NULL, ",");
463 sendit(NULL, "\n \"SdPort\": %d",
464 get_first_port_host_order(me->sdaddrs));
466 } else if (me && strcmp(items[item].name, "SdAddress") == 0) {
468 get_first_address(me->sdaddrs, buf, sizeof(buf));
469 if (strcmp(buf, "0.0.0.0") != 0) {
470 if (first_directive++ > 0) sendit(NULL, ",");
471 sendit(NULL, "\n \"SdAddress\": \"%s\"", buf);
476 if (items[item].flags & ITEM_LAST) {
477 display_last(hpkt); /* If last bit set always call to cleanup */
481 /* { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... } */
482 if (filter->do_only_data || filter->do_list) {
483 sendit(NULL, "\n }"); /* Finish the Resource with a single } */
486 if (filter->do_one) {
487 /* don't print anything */
489 } else if (first_directive > 0) {
490 sendit(NULL, "\n }\n}"); /* end of resource */
493 sendit(NULL, "}\n }");
497 } /* End loop over all resources of this type */
498 } /* End loop all resource types */
500 if (filter->do_only_data) {
501 sendit(NULL, "\n]\n");
503 /* In list context, we are dealing with a hash */
504 } else if (filter->do_one || filter->do_list) {
505 sendit(NULL, "\n}\n");
508 sendit(NULL, "\n]\n");
514 /* Check Configuration file for necessary info */
515 static int check_resources()
519 AUTOCHANGER *changer;
522 me = (STORES *)GetNextRes(R_STORAGE, NULL);
524 Jmsg1(NULL, M_ERROR, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
529 if (GetNextRes(R_STORAGE, (RES *)me) != NULL) {
530 Jmsg1(NULL, M_ERROR, 0, _("Only one Storage resource permitted in %s\n"),
534 if (GetNextRes(R_DIRECTOR, NULL) == NULL) {
535 Jmsg1(NULL, M_ERROR, 0, _("No Director resource defined in %s. Cannot continue.\n"),
539 if (GetNextRes(R_DEVICE, NULL) == NULL){
540 Jmsg1(NULL, M_ERROR, 0, _("No Device resource defined in %s. Cannot continue.\n"),
546 me->messages = (MSGS *)GetNextRes(R_MSGS, NULL);
548 Jmsg1(NULL, M_ERROR, 0, _("No Messages resource defined in %s. Cannot continue.\n"),
554 if (!me->working_directory) {
555 Jmsg1(NULL, M_ERROR, 0, _("No Working Directory defined in %s. Cannot continue.\n"),
562 foreach_res(store, R_STORAGE) {
563 /* tls_require implies tls_enable */
564 if (store->tls_require) {
566 store->tls_enable = true;
568 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
574 tls_needed = store->tls_enable || store->tls_authenticate;
576 if (!store->tls_certfile && tls_needed) {
577 Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Storage \"%s\" in %s.\n"),
578 store->hdr.name, configfile);
582 if (!store->tls_keyfile && tls_needed) {
583 Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Storage \"%s\" in %s.\n"),
584 store->hdr.name, configfile);
588 if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && tls_needed && store->tls_verify_peer) {
589 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
590 " or \"TLS CA Certificate Dir\" are defined for Storage \"%s\" in %s."
591 " At least one CA certificate store is required"
592 " when using \"TLS Verify Peer\".\n"),
593 store->hdr.name, configfile);
598 foreach_res(director, R_DIRECTOR) {
599 /* tls_require implies tls_enable */
600 if (director->tls_require) {
601 director->tls_enable = true;
604 tls_needed = director->tls_enable || director->tls_authenticate;
606 if (!director->tls_certfile && tls_needed) {
607 Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Director \"%s\" in %s.\n"),
608 director->hdr.name, configfile);
612 if (!director->tls_keyfile && tls_needed) {
613 Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Director \"%s\" in %s.\n"),
614 director->hdr.name, configfile);
618 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && tls_needed && director->tls_verify_peer) {
619 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
620 " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s."
621 " At least one CA certificate store is required"
622 " when using \"TLS Verify Peer\".\n"),
623 director->hdr.name, configfile);
628 foreach_res(changer, R_AUTOCHANGER) {
629 foreach_alist(device, changer->device) {
630 device->cap_bits |= CAP_AUTOCHANGER;
637 /* Clean up and then exit */
638 void terminate_stored(int sig)
640 static bool in_here = false;
642 if (in_here) { /* prevent loops */
643 bmicrosleep(2, 0); /* yield */
647 debug_level = 0; /* turn off any debug */
658 if (debug_level > 10) {
659 print_memory_pool_stats();
666 //sm_dump(false); /* dump orphaned buffers */
670 static void sendit(void *sock, const char *fmt, ...)
675 va_start(arg_ptr, fmt);
676 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);