"Fossies" - the Fresh Open Source Software Archive 
Member "bacula-13.0.3/src/dird/bdirjson.c" (2 May 2023, 52668 Bytes) of package /linux/misc/bacula-13.0.3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "bdirjson.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
13.0.0_vs_13.0.1.
1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2022 Kern Sibbald
5
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.
8
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.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 *
21 * Bacula Director conf to Json
22 *
23 * Kern Sibbald, September MMXII
24 *
25 */
26
27 #include "bacula.h"
28 #include "dird.h"
29
30 /* Exported subroutines */
31 extern bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code);
32
33 static CONFIG *config;
34
35 /* Globals Exported */
36 DIRRES *director; /* Director resource */
37 int FDConnectTimeout;
38 int SDConnectTimeout;
39 char *configfile = NULL;
40
41 /* Globals Imported */
42 extern RES_ITEM job_items[];
43 extern s_jt jobtypes[];
44 extern s_jl joblevels[];
45 extern s_jt migtypes[];
46 extern s_kw ReplaceOptions[];
47 extern RES_ITEM2 newinc_items[];
48 extern RES_ITEM options_items[];
49 extern s_fs_opt FS_options[];
50 extern s_kw RunFields[];
51 extern s_kw tapelabels[];
52 extern s_kw msg_types[];
53 extern RES_TABLE resources[];
54
55 #if defined(_MSC_VER)
56 extern "C" { // work around visual compiler mangling variables
57 extern URES res_all;
58 }
59 #else
60 extern URES res_all;
61 #endif
62
63
64 #define CONFIG_FILE "bacula-dir.conf" /* default configuration file */
65
66 static void usage()
67 {
68 fprintf(stderr, _(
69 PROG_COPYRIGHT
70 "\n%sVersion: %s (%s)\n\n"
71 "Usage: bdirjson [<options>] [config_file]\n"
72 " -r <res> get resource type <res>\n"
73 " -n <name> get resource <name>\n"
74 " -l <dirs> get only directives matching dirs (use with -r)\n"
75 " -D get only data\n"
76 " -R do not apply JobDefs to Job\n"
77 " -c <file> set configuration file to file\n"
78 " -d <nn> set debug level to <nn>\n"
79 " -dt print timestamp in debug output\n"
80 " -t test - read configuration and exit\n"
81 " -s output in show text format\n"
82 " -v verbose user messages\n"
83 " -? print this message.\n"
84 "\n"), 2012, BDEMO, VERSION, BDATE);
85
86 exit(1);
87 }
88
89 typedef struct
90 {
91 /* default { { "Director": { "Name": aa, ...} }, { "Job": {..} */
92 bool do_list; /* [ {}, {}, ..] or { "aa": {}, "bb": {}, ...} */
93 bool do_one; /* { "Name": "aa", "Description": "test, ... } */
94 bool do_only_data; /* [ {}, {}, {}, ] */
95 char *resource_type;
96 char *resource_name;
97 regex_t directive_reg;
98 } display_filter;
99
100 /* Forward referenced subroutines */
101 void terminate_dird(int sig);
102 static bool check_resources(bool config_test);
103 static void sendit(void *ua, const char *fmt, ...);
104 static void dump_json(display_filter *filter);
105
106 /*********************************************************************
107 *
108 * Bacula Director conf to Json
109 *
110 */
111 int main (int argc, char *argv[])
112 {
113 int ch;
114 bool test_config = false;
115 bool apply_jobdefs = true;
116 bool do_show_format = false;
117 display_filter filter;
118 memset(&filter, 0, sizeof(filter));
119
120 setlocale(LC_ALL, "");
121 bindtextdomain("bacula", LOCALEDIR);
122 textdomain("bacula");
123
124 if (init_crypto() != 0) {
125 Emsg0(M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
126 }
127
128 my_name_is(argc, argv, "bacula-dir");
129 init_msg(NULL, NULL);
130
131 while ((ch = getopt(argc, argv, "RCDc:d:stv?l:r:n:")) != -1) {
132 switch (ch) {
133 case 'R':
134 apply_jobdefs = false;
135 break;
136
137 case 'D':
138 filter.do_only_data = true;
139 break;
140
141 case 'l':
142 /* Might use something like -l '^(Name|Description)$' */
143 filter.do_list = true;
144 if (regcomp(&filter.directive_reg, optarg, REG_EXTENDED|REG_ICASE) != 0) {
145 Jmsg((JCR *)NULL, M_ERROR_TERM, 0,
146 _("Please use valid -l argument: %s\n"), optarg);
147 }
148 break;
149
150 case 'r':
151 filter.resource_type = optarg;
152 break;
153
154 case 'n':
155 filter.resource_name = optarg;
156 break;
157
158 case 'c': /* specify config file */
159 if (configfile != NULL) {
160 free(configfile);
161 }
162 configfile = bstrdup(optarg);
163 break;
164
165 case 'd': /* set debug level */
166 if (*optarg == 't') {
167 dbg_timestamp = true;
168 } else {
169 debug_level = atoi(optarg);
170 if (debug_level <= 0) {
171 debug_level = 1;
172 }
173 }
174 Dmsg1(10, "Debug level = %d\n", debug_level);
175 break;
176
177 case 's': /* Show text format */
178 do_show_format = true;
179 break;
180
181 case 't': /* test config */
182 test_config = true;
183 break;
184
185 case 'v': /* verbose */
186 verbose++;
187 break;
188
189 case '?':
190 default:
191 usage();
192
193 }
194 }
195 argc -= optind;
196 argv += optind;
197
198
199 if (argc) {
200 if (configfile != NULL) {
201 free(configfile);
202 }
203 configfile = bstrdup(*argv);
204 argc--;
205 argv++;
206 }
207 if (argc) {
208 usage();
209 }
210
211 if (filter.do_list && !filter.resource_type) {
212 usage();
213 }
214
215 if (filter.resource_type && filter.resource_name) {
216 filter.do_one = true;
217 }
218
219 if (configfile == NULL || configfile[0] == 0) {
220 configfile = bstrdup(CONFIG_FILE);
221 }
222
223 if (test_config && verbose > 0) {
224 char buf[1024];
225 find_config_file(configfile, buf, sizeof(buf));
226 sendit(NULL, "config_file=%s\n", buf);
227 }
228
229 config = New(CONFIG());
230 config->encode_password(false);
231 parse_dir_config(config, configfile, M_ERROR_TERM);
232
233 /* TODO: If we run check_resources, jobdefs will be copied to Job, and the job resource
234 * will no longer be the real job...
235 */
236 if (!check_resources(apply_jobdefs)) {
237 Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
238 }
239
240 if (test_config) {
241 terminate_dird(0);
242 }
243
244 my_name_is(0, NULL, director->name()); /* set user defined name */
245
246 if (do_show_format) {
247 /* Do show output in text */
248 for (int i=r_first; i<=r_last; i++) {
249 dump_each_resource(i, sendit, NULL);
250 }
251 } else {
252 dump_json(&filter);
253 }
254
255 if (filter.do_list) {
256 regfree(&filter.directive_reg);
257 }
258
259 terminate_dird(0);
260
261 return 0;
262 }
263
264 /* Cleanup and then exit */
265 void terminate_dird(int sig)
266 {
267 static bool already_here = false;
268
269 if (already_here) { /* avoid recursive temination problems */
270 bmicrosleep(2, 0); /* yield */
271 exit(1);
272 }
273 already_here = true;
274 debug_level = 0; /* turn off debug */
275 if (configfile != NULL) {
276 free(configfile);
277 }
278 if (debug_level > 5) {
279 print_memory_pool_stats();
280 }
281 if (config) {
282 delete config;
283 config = NULL;
284 }
285 term_msg();
286 free(res_head);
287 res_head = NULL;
288 close_memory_pool(); /* release free memory in pool */
289 //sm_dump(false);
290 exit(sig);
291 }
292
293
294 static void display_jobtype(HPKT &hpkt)
295 {
296 int i;
297 for (i=0; jobtypes[i].type_name; i++) {
298 if (*(int32_t *)(hpkt.ritem->value) == jobtypes[i].job_type) {
299 hpkt.sendit(hpkt, "\n \"%s\": %s", hpkt.ritem->name,
300 quote_string(hpkt.edbuf, jobtypes[i].type_name));
301 return;
302 }
303 }
304 }
305
306 static void display_label(HPKT &hpkt)
307 {
308 int i;
309 for (i=0; tapelabels[i].name; i++) {
310 if (*(int32_t *)(hpkt.ritem->value) == tapelabels[i].token) {
311 hpkt.sendit(hpkt, "\n \"%s\": %s", hpkt.ritem->name,
312 quote_string(hpkt.edbuf, tapelabels[i].name));
313 return;
314 }
315 }
316 }
317
318 static void display_joblevel(HPKT &hpkt)
319 {
320 int i;
321 for (i=0; joblevels[i].level_name; i++) {
322 if (*(int32_t *)(hpkt.ritem->value) == joblevels[i].level) {
323 hpkt.sendit(hpkt, "\n \"%s\": %s", hpkt.ritem->name,
324 quote_string(hpkt.edbuf, joblevels[i].level_name));
325 return;
326 }
327 }
328 }
329
330 static void display_replace(HPKT &hpkt)
331 {
332 int i;
333 for (i=0; ReplaceOptions[i].name; i++) {
334 if (*(int32_t *)(hpkt.ritem->value) == ReplaceOptions[i].token) {
335 hpkt.sendit(hpkt, "\n \"%s\": %s", hpkt.ritem->name,
336 quote_string(hpkt.edbuf, ReplaceOptions[i].name));
337 return;
338 }
339 }
340 }
341
342 static void display_migtype(HPKT &hpkt)
343 {
344 int i;
345 for (i=0; migtypes[i].type_name; i++) {
346 if (*(int32_t *)(hpkt.ritem->value) == migtypes[i].job_type) {
347 hpkt.sendit(hpkt, "\n \"%s\": %s", hpkt.ritem->name,
348 quote_string(hpkt.edbuf, migtypes[i].type_name));
349 return;
350 }
351 }
352 }
353
354 static void display_actiononpurge(HPKT &hpkt)
355 {
356 hpkt.sendit(hpkt, "\n \"%s\":", hpkt.ritem->name);
357 if (*(uint32_t *)(hpkt.ritem->value) | ON_PURGE_TRUNCATE) {
358 hpkt.sendit(hpkt, "\"Truncate\"");
359 } else {
360 hpkt.sendit(hpkt, "null");
361 }
362 }
363
364 static void display_acl(HPKT &hpkt)
365 {
366 hpkt.sendit(hpkt, "\n \"%s\":", hpkt.ritem->name);
367 hpkt.list = ((alist **)hpkt.ritem->value)[hpkt.ritem->code];
368 display_alist(hpkt);
369 }
370
371
372 static void display_options(HPKT &hpkt, INCEXE *ie)
373 {
374 char *elt;
375 bool first_opt = true;
376 bool first_dir;
377 int i, j, k;
378 alist *list;
379
380 hpkt.sendit(hpkt, " \"Options\": [ \n {\n");
381 for (i=0; i<ie->num_opts; i++) {
382 FOPTS *fo = ie->opts_list[i];
383 if (!first_opt) {
384 hpkt.sendit(hpkt, ",\n {\n");
385 }
386 first_dir = true;
387 for (j=0; options_items[j].name; j++) {
388 if (options_items[j].handler == store_regex) {
389 switch (options_items[j].code) {
390 case 1: /* RegexDir */
391 list = &fo->regexdir;
392 break;
393 case 2: /* RegexFile */
394 list = &fo->regexfile;
395 break;
396 default:
397 list = &fo->regex;
398 break;
399 }
400 if (list->size() > 0) {
401 if (!first_dir) {
402 hpkt.sendit(hpkt, ",\n");
403 }
404 hpkt.sendit(hpkt, " \"%s\":", options_items[j].name);
405 hpkt.list = list;
406 display_alist(hpkt);
407 first_dir = false;
408 first_opt = false;
409 }
410 } else if (options_items[j].handler == store_wild) {
411 switch (options_items[j].code) {
412 case 1: /* WildDir */
413 list = &fo->wilddir;
414 break;
415 case 2: /* WildFile */
416 /*
417 * Note: There used to be an enhanced wild card feature,
418 * which was not documented so it is removed, and
419 * apparently the wildfile patterns are stored in the
420 * wildbase list, so we dump it here.
421 * The old enhanced wild implementation appears to be poorly
422 * done, because either there should be two clearly named
423 * lists, or one with everything.
424 */
425 /* We copy one list to the other, else we may print two
426 * times the WildFile list. I don't know how, but sometime
427 * the two lists contain elements.
428 */
429 list = &fo->wildfile;
430 foreach_alist(elt, list) {
431 fo->wildbase.append(bstrdup(elt));
432 }
433 list = &fo->wildbase;
434 break;
435 default:
436 list = &fo->wild;
437 break;
438 }
439 if (list->size() > 0) {
440 if (!first_dir) {
441 hpkt.sendit(hpkt, ",\n");
442 }
443 hpkt.sendit(hpkt, " \"%s\":", options_items[j].name);
444 hpkt.list = list;
445 display_alist(hpkt);
446 first_dir = false;
447 first_opt = false;
448 }
449 } else if (options_items[j].handler == store_base) {
450 list = &fo->base;
451 if (list->size() > 0) {
452 if (!first_dir) {
453 hpkt.sendit(hpkt, ",\n");
454 }
455 hpkt.sendit(hpkt, " \"%s\":", options_items[j].name);
456 hpkt.list = list;
457 display_alist(hpkt);
458 first_dir = false;
459 first_opt = false;
460 }
461 } else if (options_items[j].handler == store_opts) {
462 bool found = false;
463 if (bit_is_set(options_items[j].flags, ie->opt_present)) {
464 for (k=0; FS_options[k].name; k++) {
465 if (FS_options[k].keyword == (int)options_items[j].flags) {
466 char lopts[100];
467 strip_long_opts(lopts, fo->opts);
468 if (strstr(lopts, FS_options[k].option)) {
469 if (!first_dir) {
470 hpkt.sendit(hpkt, ",\n");
471 }
472 hpkt.sendit(hpkt, " \"%s\": %s", options_items[j].name,
473 quote_string(hpkt.edbuf, FS_options[k].name));
474 found = true;
475 break;
476 }
477 }
478 }
479 if (found) {
480 first_dir = false;
481 first_opt = false;
482 }
483 }
484 } else if (options_items[j].handler == store_lopts) {
485 bool found = false;
486 if (bit_is_set(options_items[j].flags, ie->opt_present)) {
487 char *pos;
488 /* Search long_options for code (V, J, C, P) */
489 if ((pos=strchr(fo->opts, options_items[j].code))) {
490 char lopts[100];
491 char *end, bkp;
492 pos++; /* point to beginning of options */
493 bstrncpy(lopts, pos, sizeof(lopts));
494 /* Now terminate at first : */
495 end = strchr(pos, ':');
496 if (end) {
497 bkp = *end; /* save the original char */
498 *end = 0; /* terminate this string */
499 }
500 if (!first_dir) {
501 hpkt.sendit(hpkt, ",\n");
502 }
503 hpkt.sendit(hpkt, " \"%s\": %s", options_items[j].name,
504 quote_string(hpkt.edbuf, pos));
505 found = true;
506 if (end) { /* Still have other options to parse */
507 *end = bkp;
508 }
509 }
510 if (found) {
511 first_dir = false;
512 first_opt = false;
513 }
514 }
515 } else if (options_items[j].handler == store_plugin) {
516 if (fo->plugin) {
517 if (!first_dir) {
518 hpkt.sendit(hpkt, ",\n");
519 }
520 hpkt.sendit(hpkt, " \"%s\": %s", options_items[j].name,
521 quote_string(hpkt.edbuf, fo->plugin));
522 first_dir = false;
523 first_opt = false;
524 }
525 } else if (options_items[j].handler == store_fstype) {
526 list = &fo->fstype;
527 if (list->size() > 0) {
528 if (!first_dir) {
529 hpkt.sendit(hpkt, ",\n");
530 }
531 hpkt.sendit(hpkt, " \"%s\":", options_items[j].name);
532 hpkt.list = list;
533 display_alist(hpkt);
534 first_dir = false;
535 first_opt = false;
536 }
537 } else if (options_items[j].handler == store_drivetype) {
538 list = &fo->drivetype;
539 if (list->size() > 0) {
540 if (!first_dir) {
541 hpkt.sendit(hpkt, ",\n");
542 }
543 hpkt.sendit(hpkt, " \"%s\":", options_items[j].name);
544 hpkt.list = list;
545 display_alist(hpkt);
546 first_dir = false;
547 first_opt = false;
548 }
549 }
550 }
551 hpkt.sendit(hpkt, "\n }");
552 }
553 hpkt.sendit(hpkt, "\n ]");
554 }
555
556 /*
557 * Include or Exclude in a FileSet
558 * TODO: Not working with multiple Include{}
559 * O M
560 * N
561 * I /tmp/regress/build
562 * N
563 * O Z1
564 * N
565 * I /tmp
566 * N
567 */
568 static void display_include_exclude(HPKT &hpkt)
569 {
570 bool first_dir;
571 int i, j;
572 FILESET *fs = (FILESET *)hpkt.res;
573
574 if (hpkt.ritem->code == 0) { /* Include */
575 INCEXE *ie;
576 hpkt.sendit(hpkt, "\n \"%s\": [{\n", hpkt.ritem->name);
577 for (j=0; j<fs->num_includes; j++) {
578 if (j > 0) {
579 hpkt.sendit(hpkt, ",\n {\n");
580 }
581 first_dir = true;
582 ie = fs->include_items[j];
583 for (i=0; newinc_items[i].name; i++) {
584 if (strcasecmp(newinc_items[i].name, "File") == 0) {
585 if (!first_dir) {
586 hpkt.sendit(hpkt, ",\n");
587 }
588 hpkt.sendit(hpkt, " \"%s\":", newinc_items[i].name);
589 first_dir = false;
590 hpkt.list = &ie->name_list;
591 display_alist(hpkt);
592 } if (strcasecmp(newinc_items[i].name, "Plugin") == 0 &&
593 ie->plugin_list.size() > 0) {
594 if (!first_dir) {
595 hpkt.sendit(hpkt, ",\n");
596 }
597 hpkt.sendit(hpkt, " \"%s\":", newinc_items[i].name);
598 first_dir = false;
599 hpkt.list = &ie->plugin_list;
600 display_alist(hpkt);
601 } if (strcasecmp(newinc_items[i].name, "Options") == 0 &&
602 ie->num_opts > 0) {
603 if (!first_dir) {
604 hpkt.sendit(hpkt, ",\n");
605 }
606 display_options(hpkt, ie);
607 } if (strcasecmp(newinc_items[i].name, "ExcludeDirContaining") == 0 &&
608 ie->ignoredir) {
609 if (!first_dir) {
610 hpkt.sendit(hpkt, ",\n");
611 }
612 hpkt.sendit(hpkt, " \"%s\": %s ", newinc_items[i].name,
613 quote_string(hpkt.edbuf, ie->ignoredir));
614 first_dir = false;
615 }
616 }
617 hpkt.sendit(hpkt, "\n }");
618 }
619 hpkt.sendit(hpkt, "]");
620 } else {
621 /* Exclude */
622 hpkt.sendit(hpkt, "\n \"%s\": {\n", hpkt.ritem->name);
623 first_dir = true;
624 for (int i=0; newinc_items[i].name; i++) {
625 INCEXE *ie;
626 if (strcasecmp(newinc_items[i].name, "File") == 0) {
627 if (!first_dir) {
628 hpkt.sendit(hpkt, ",\n");
629 }
630 hpkt.sendit(hpkt, " \"%s\": ", newinc_items[i].name);
631 first_dir = false;
632 ie = fs->exclude_items[0];
633 hpkt.list = &ie->name_list;
634 display_alist(hpkt);
635 }
636 }
637 hpkt.sendit(hpkt, "\n }");
638 }
639 }
640
641 static bool display_runscript(HPKT &hpkt)
642 {
643 RUNSCRIPT *script;
644 RUNSCRIPT *def = new_runscript();
645 alist **runscripts = (alist **)(hpkt.ritem->value) ;
646 bool first=true;
647
648 if (!*runscripts || (*runscripts)->size() == 0) {
649 return false;
650 }
651
652 hpkt.sendit(hpkt, "\n \"Runscript\": [\n");
653
654 foreach_alist(script, *runscripts) {
655 if (first) {
656 hpkt.sendit(hpkt, " {\n");
657 } else {
658 hpkt.sendit(hpkt, ",\n {\n");
659 }
660 if (script->when == SCRIPT_Any) {
661 hpkt.sendit(hpkt, " \"RunsWhen\": \"Always\",\n");
662
663 } else if (script->when == SCRIPT_After) {
664 hpkt.sendit(hpkt, " \"RunsWhen\": \"After\",\n");
665
666 } else if (script->when == SCRIPT_Before) {
667 hpkt.sendit(hpkt, " \"RunsWhen\": \"Before\",\n");
668
669 } else if (script->when == SCRIPT_AfterVSS) {
670 hpkt.sendit(hpkt, " \"RunsWhen\": \"AfterVSS\",\n");
671 }
672
673 if (script->fail_on_error != def->fail_on_error) {
674 hpkt.sendit(hpkt, " \"FailJobOnError\": %s,\n", script->fail_on_error?"true":"false");
675 }
676
677 if (script->on_success != def->on_success) {
678 hpkt.sendit(hpkt, " \"RunsOnSuccess\": %s,\n", script->on_success?"true":"false");
679 }
680
681 if (script->on_failure != def->on_failure) {
682 hpkt.sendit(hpkt, " \"RunsOnFailure\": %s,\n", script->on_failure?"true":"false");
683 }
684
685 if (script->is_local()) {
686 hpkt.sendit(hpkt, " \"RunsOnClient\": false,\n");
687 }
688
689 if (script->command) {
690 hpkt.sendit(hpkt, " \"%s\": %s\n",
691 (script->cmd_type == SHELL_CMD)?"Command":"Console",
692 quote_string(hpkt.edbuf, script->command));
693 }
694 hpkt.sendit(hpkt, " }");
695 first = false;
696 }
697
698 hpkt.sendit(hpkt, "\n ]\n");
699 free_runscript(def);
700 return true;
701 }
702
703 static void display_run(HPKT &hpkt)
704 {
705 int i, j;
706 RUN **prun = (RUN **)hpkt.ritem->value;
707 RUN *run = *prun;
708 bool first = true;
709 bool first_run = true;
710 RES *res;
711
712 hpkt.sendit(hpkt, "\n \"%s\": [\n", hpkt.ritem->name);
713 for ( ; run; run=run->next) {
714 if (!first_run) hpkt.sendit(hpkt, ",\n");
715 first_run = false;
716 first = true;
717 hpkt.sendit(hpkt, " {\n");
718 /* First do override fields */
719 for (i=0; RunFields[i].name; i++) {
720 switch (RunFields[i].token) {
721 case 'f': /* FullPool */
722 if (run->full_pool) {
723 res = (RES *)run->full_pool;
724 if (!first) hpkt.sendit(hpkt, ",\n");
725 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
726 quote_string(hpkt.edbuf, res->name));
727 first = false;
728 }
729 break;
730 case 'i': /* IncrementalPool */
731 if (run->inc_pool) {
732 res = (RES *)run->inc_pool;
733 if (!first) hpkt.sendit(hpkt, ",\n");
734 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
735 quote_string(hpkt.edbuf, res->name));
736 first = false;
737 }
738 break;
739 case 'd': /* Differential Pool */
740 if (run->diff_pool) {
741 res = (RES *)run->diff_pool;
742 if (!first) hpkt.sendit(hpkt, ",\n");
743 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
744 quote_string(hpkt.edbuf, res->name));
745 first = false;
746 }
747 break;
748 case 'N': /* Next Pool */
749 if (run->next_pool) {
750 res = (RES *)run->next_pool;
751 if (!first) hpkt.sendit(hpkt, ",\n");
752 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
753 quote_string(hpkt.edbuf, res->name));
754 first = false;
755 }
756 break;
757 case 'L': /* Level */
758 /* TODO: It's not always set, only when having Level= in the line */
759 //if (run->level_set) {
760 for (j=0; joblevels[j].level_name; j++) {
761 if ((int)run->level == joblevels[j].level) {
762 if (!first) hpkt.sendit(hpkt, ",\n");
763 hpkt.sendit(hpkt, " \"%s\": \"%s\"", RunFields[i].name,
764 joblevels[j].level_name);
765 first = false;
766 }
767 }
768 //}
769 break;
770 case 'P': /* Pool */
771 if (run->pool) {
772 res = (RES *)run->pool;
773 if (!first) hpkt.sendit(hpkt, ",\n");
774 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
775 quote_string(hpkt.edbuf, res->name));
776 first = false;
777 }
778 break;
779 case 'S': /* Storage */
780 if (run->storage) {
781 res = (RES *)run->storage;
782 if (!first) hpkt.sendit(hpkt, ",\n");
783 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
784 quote_string(hpkt.edbuf, res->name));
785 first = false;
786 }
787 break;
788 case 'M': /* Messages */
789 if (run->msgs) {
790 res = (RES *)run->msgs;
791 if (!first) hpkt.sendit(hpkt, ",\n");
792 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
793 quote_string(hpkt.edbuf, res->name));
794 first = false;
795 }
796 break;
797 case 'p': /* priority */
798 if (run->priority_set) {
799 if (!first) hpkt.sendit(hpkt, ",\n");
800 hpkt.sendit(hpkt, " \"%s\": %d", RunFields[i].name,
801 run->Priority);
802 first = false;
803 }
804 break;
805 case 's': /* Spool Data */
806 if (run->spool_data_set) {
807 if (!first) hpkt.sendit(hpkt, ",\n");
808 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
809 run->spool_data?"true":"false");
810 first = false;
811 }
812 break;
813 case 'W': /* Write Part After Job */
814 if (run->write_part_after_job_set) {
815 if (!first) hpkt.sendit(hpkt, ",\n");
816 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
817 run->write_part_after_job?"true":"false");
818 first = false;
819 }
820 break;
821 case 'm': /* MaxRunScheduledTime */
822 if (run->MaxRunSchedTime_set) {
823 if (!first) hpkt.sendit(hpkt, ",\n");
824 hpkt.sendit(hpkt, " \"%s\": %lld", RunFields[i].name,
825 run->MaxRunSchedTime);
826 first = false;
827 }
828 break;
829 case 'a': /* Accurate */
830 if (run->accurate_set) {
831 if (!first) hpkt.sendit(hpkt, ",\n");
832 hpkt.sendit(hpkt, " \"%s\": %s", RunFields[i].name,
833 run->accurate?"true":"false");
834 first = false;
835 }
836 break;
837 default:
838 break;
839 }
840 } /* End all RunFields (overrides) */
841 /* Now handle timing */
842 if (byte_is_set(run->hour, sizeof(run->hour))) {
843 if (!first) hpkt.sendit(hpkt, ",\n");
844 hpkt.sendit(hpkt, " \"Hour\":");
845 display_bit_array(hpkt, run->hour, 24);
846 hpkt.sendit(hpkt, ",\n \"Minute\": %d", run->minute);
847 first = false;
848 }
849 /* bit 32 is used to store the keyword LastDay, so we look up to 0-31 */
850 if (byte_is_set(run->mday, sizeof(run->mday))) {
851 if (!first) hpkt.sendit(hpkt, ",\n");
852 hpkt.sendit(hpkt, " \"Day\":");
853 display_bit_array(hpkt, run->mday, 31);
854 first = false;
855 }
856 if (run->last_day_set) {
857 if (!first) hpkt.sendit(hpkt, ",\n");
858 hpkt.sendit(hpkt, " \"LastDay\": 1");
859 first = false;
860 }
861 if (byte_is_set(run->month, sizeof(run->month))) {
862 if (!first) hpkt.sendit(hpkt, ",\n");
863 hpkt.sendit(hpkt, " \"Month\":");
864 display_bit_array(hpkt, run->month, 12);
865 first = false;
866 }
867 if (byte_is_set(run->wday, sizeof(run->wday))) {
868 if (!first) hpkt.sendit(hpkt, ",\n");
869 hpkt.sendit(hpkt, " \"DayOfWeek\":");
870 display_bit_array(hpkt, run->wday, 7);
871 first = false;
872 }
873 if (byte_is_set(run->wom, sizeof(run->wom))) {
874 if (!first) hpkt.sendit(hpkt, ",\n");
875 hpkt.sendit(hpkt, " \"WeekOfMonth\":");
876 display_bit_array(hpkt, run->wom, 6);
877 first = false;
878 }
879 if (byte_is_set(run->woy, sizeof(run->woy))) {
880 if (!first) hpkt.sendit(hpkt, ",\n");
881 hpkt.sendit(hpkt, " \"WeekOfYear\":");
882 display_bit_array(hpkt, run->woy, 54);
883 first = false;
884 }
885 hpkt.sendit(hpkt, "\n }");
886
887 } /* End this Run directive */
888 hpkt.sendit(hpkt, "\n ]");
889 }
890
891 /*
892 * Dump out all resources in json format.
893 * Note!!!! This routine must be in this file rather
894 * than in src/lib/parser_conf.c otherwise the pointers
895 * will be all messed up.
896 */
897 static void dump_json(display_filter *filter)
898 {
899 int resinx, item, first_directive, name_pos=0, sz;
900 bool first_res;
901 RES_ITEM *items;
902 RES *res;
903 HPKT hpkt;
904 regmatch_t pmatch[32];
905
906 init_hpkt(hpkt);
907
908 /* List resources and directives */
909 if (filter->do_only_data) {
910 /* Skip the Name */
911 hpkt.sendit(hpkt, "[");
912
913 /*
914 * { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... }
915 * or print a single item
916 */
917 } else if (filter->do_one || filter->do_list) {
918 hpkt.sendit(hpkt, "{");
919
920 } else {
921 /* [ { "Client": { "Name": "aa",.. } }, { "Director": { "Name": "bb", ... } } ]*/
922 hpkt.sendit(hpkt, "[");
923 }
924
925 first_res = true;
926 /* Main loop over all resources */
927 for (resinx=0; resources[resinx].items; resinx++) {
928
929 /* Skip this resource type? */
930 if (filter->resource_type &&
931 strcasecmp(filter->resource_type, resources[resinx].name) != 0) {
932 continue;
933 }
934
935 /* Loop over each resource of this type */
936 foreach_rblist(res, res_head[resinx]->res_list) {
937 hpkt.res = res;
938 items = resources[resinx].items;
939 if (!items) {
940 continue;
941 }
942
943 sz = get_resource_size(resinx + r_first);
944 if (sz < 0) {
945 Dmsg1(0, "Unknown resource type %d\n", resinx);
946 continue;
947 }
948
949 /* Copy the resource into res_all */
950 memcpy(&res_all, res, sz);
951
952 /* If needed, skip this resource type */
953 if (filter->resource_name) {
954 bool skip=true;
955 /* The Name should be at the first place, so this is not a real loop */
956 for (item=0; items[item].name; item++) {
957 if (strcasecmp(items[item].name, "Name") == 0) {
958 if (strcmp(*(items[item].value), filter->resource_name) == 0) {
959 skip = false;
960 }
961 break;
962 }
963 }
964 if (skip) { /* The name doesn't match, so skip it */
965 continue;
966 }
967 }
968
969 if (first_res) {
970 hpkt.sendit(hpkt, "\n");
971 } else {
972 hpkt.sendit(hpkt, ",\n");
973 }
974
975 /* Find where the Name is defined, should always be 0 */
976 for (item=0; items[item].name; item++) {
977 if (strcmp(items[item].name, "Name") == 0) {
978 name_pos = item;
979 break;
980 }
981 }
982
983 if (filter->do_only_data) {
984 hpkt.sendit(hpkt, " {");
985
986 } else if (filter->do_one) {
987 /* Nothing to print */
988
989 /* When sending the list, the form is:
990 * { aa: { Name: aa, Description: aadesc...}, bb: { Name: bb
991 */
992 } else if (filter->do_list) {
993 /* Search and display Name, should be the first item */
994 for (item=0; items[item].name; item++) {
995 if (strcmp(items[item].name, "Name") == 0) {
996 hpkt.sendit(hpkt, "%s: {\n", quote_string(hpkt.edbuf2, *items[item].value));
997 break;
998 }
999 }
1000 } else {
1001 /* Begin new resource */
1002 hpkt.sendit(hpkt, "{\n \"%s\": {", resources[resinx].name);
1003 }
1004
1005 first_res = false;
1006 first_directive = 0;
1007
1008 /*
1009 * Here we walk through a resource displaying all the
1010 * directives and sub-resources in the resource.
1011 */
1012 for (item=0; items[item].name; item++) {
1013 /* Check user argument -l */
1014 if (filter->do_list &&
1015 regexec(&filter->directive_reg,
1016 items[item].name, 32, pmatch, 0) != 0)
1017 {
1018 continue;
1019 }
1020
1021 hpkt.ritem = &items[item];
1022
1023 if (bit_is_set(item, res_all.hdr.item_present)) {
1024
1025 /* Skip Directive in lowercase, but check if the next
1026 * one is pointing to the same location (for example User and dbuser)
1027 */
1028 if (!B_ISUPPER(*(items[item].name))) {
1029 int i=item+1;
1030 while(!B_ISUPPER(*(items[i].name)) && items[i].value == items[item].value) {
1031 i++;
1032 }
1033 if (items[i].value == items[item].value) {
1034 set_bit(i, res_all.hdr.item_present);
1035 }
1036 continue;
1037 }
1038 if (first_directive++ > 0) {
1039 hpkt.sendit(hpkt, ",");
1040 }
1041
1042 /* 1: found, 0: not found, -1 found but empty */
1043 int ret = display_global_item(hpkt);
1044 if (ret == -1) {
1045 /* Do not print a comma after this empty directive */
1046 first_directive = 0;
1047 } else if (ret == 1) {
1048 /* Fall-through wanted */
1049
1050 } else if (items[item].handler == store_jobtype) {
1051 display_jobtype(hpkt);
1052 } else if (items[item].handler == store_label) {
1053 display_label(hpkt);
1054 } else if (items[item].handler == store_level) {
1055 display_joblevel(hpkt);
1056 } else if (items[item].handler == store_replace) {
1057 display_replace(hpkt);
1058 } else if (items[item].handler == store_migtype) {
1059 display_migtype(hpkt);
1060 } else if (items[item].handler == store_actiononpurge) {
1061 display_actiononpurge(hpkt);
1062 /* FileSet Include/Exclude directive */
1063 } else if (items[item].handler == store_inc) {
1064 display_include_exclude(hpkt);
1065 } else if (items[item].handler == store_ac_res) {
1066 display_res(hpkt);
1067 /* A different alist for each item.code */
1068 } else if (items[item].handler == store_acl) {
1069 display_acl(hpkt);
1070 } else if (items[item].handler == store_device) {
1071 display_alist_res(hpkt);
1072 } else if (items[item].handler == store_run) {
1073 display_run(hpkt);
1074 } else if (items[item].handler == store_runscript) {
1075 if (!display_runscript(hpkt)) {
1076 first_directive = 0; /* Do not print a comma after this empty runscript */
1077 }
1078 } else if (items[item].handler == store_coll_type) {
1079 display_collector_types(hpkt);
1080 } else {
1081 hpkt.sendit(hpkt, "\n \"%s\": null", items[item].name);
1082 }
1083 } else { /* end if is present */
1084 /* For some directive, the bitmap is not set (like addresses) */
1085 /* Special trick for the Autochanger directive, it can be yes/no/storage */
1086 if (strcmp(resources[resinx].name, "Storage") == 0) {
1087 if (strcasecmp(items[item].name, "Autochanger") == 0
1088 && items[item].handler == store_bool /* yes or no */
1089 && *(bool *)(items[item].value) == true)
1090 {
1091 if (first_directive++ > 0) hpkt.sendit(hpkt, ",");
1092 if (*(items[item-1].value) == NULL) {
1093 hpkt.sendit(hpkt, "\n \"Autochanger\": %s", quote_string(hpkt.edbuf2, *items[name_pos].value));
1094 } else {
1095 STORE *r = (STORE *)*(items[item-1].value);
1096 hpkt.sendit(hpkt, "\n \"Autochanger\": %s", quote_string(hpkt.edbuf2, r->name()));
1097 }
1098 }
1099 }
1100
1101 if (strcmp(resources[resinx].name, "Director") == 0) {
1102 if (strcmp(items[item].name, "DirPort") == 0) {
1103 if (get_first_port_host_order(director->DIRaddrs) != items[item].default_value) {
1104 if (first_directive++ > 0) hpkt.sendit(hpkt, ",");
1105 hpkt.sendit(hpkt, "\n \"DirPort\": %d",
1106 get_first_port_host_order(director->DIRaddrs));
1107 }
1108
1109 } else if (strcmp(items[item].name, "DirAddress") == 0) {
1110 char buf[500];
1111 get_first_address(director->DIRaddrs, buf, sizeof(buf));
1112 if (strcmp(buf, "0.0.0.0") != 0) {
1113 if (first_directive++ > 0) hpkt.sendit(hpkt, ",");
1114 hpkt.sendit(hpkt, "\n \"DirAddress\": \"%s\"", buf);
1115 }
1116
1117 } else if (strcmp(items[item].name, "DirSourceAddress") == 0 && director->DIRsrc_addr) {
1118 char buf[500];
1119 get_first_address(director->DIRsrc_addr, buf, sizeof(buf));
1120 if (strcmp(buf, "0.0.0.0") != 0) {
1121 if (first_directive++ > 0) hpkt.sendit(hpkt, ",");
1122 hpkt.sendit(hpkt, "\n \"DirSourceAddress\": \"%s\"", buf);
1123 }
1124 }
1125 }
1126 }
1127 if (items[item].flags & ITEM_LAST) {
1128 display_last(hpkt); /* If last bit set always call to cleanup */
1129 }
1130 } /* loop over directive names */
1131
1132 /* { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... } */
1133 if (filter->do_only_data || filter->do_list) {
1134 hpkt.sendit(hpkt, "\n }"); /* Finish the Resource with a single } */
1135
1136 } else {
1137 if (filter->do_one) {
1138 /* don't print anything */
1139
1140 } else if (first_directive > 0) {
1141 hpkt.sendit(hpkt, "\n }\n}"); /* end of resource */
1142
1143 } else {
1144 hpkt.sendit(hpkt, "}\n}");
1145 }
1146 }
1147 } /* End loop over all resources of this type */
1148 } /* End loop all resource types */
1149
1150 if (filter->do_only_data) {
1151 hpkt.sendit(hpkt, "\n]\n");
1152
1153 /* In list context, we are dealing with a hash */
1154 } else if (filter->do_one || filter->do_list) {
1155 hpkt.sendit(hpkt, "\n}\n");
1156
1157 } else {
1158 hpkt.sendit(hpkt, "\n]\n");
1159 }
1160 term_hpkt(hpkt);
1161 }
1162
1163 /*
1164 * Make a quick check to see that we have all the
1165 * resources needed.
1166 *
1167 * **** FIXME **** this routine could be a lot more
1168 * intelligent and comprehensive.
1169 */
1170 static bool check_resources(bool apply_jobdefs)
1171 {
1172 bool OK = true;
1173 JOB *job;
1174 bool need_tls;
1175
1176 LockRes();
1177
1178 job = (JOB *)GetNextRes(R_JOB, NULL);
1179 director = (DIRRES *)GetNextRes(R_DIRECTOR, NULL);
1180 if (!director) {
1181 Jmsg(NULL, M_FATAL, 0, _("No Director resource defined in %s\n"
1182 "Without that I don't know who I am :-(\n"), configfile);
1183 OK = false;
1184 } else {
1185 set_working_directory(director->working_directory);
1186 if (!director->messages) { /* If message resource not specified */
1187 director->messages = (MSGS *)GetNextRes(R_MSGS, NULL);
1188 if (!director->messages) {
1189 Jmsg(NULL, M_FATAL, 0, _("No Messages resource defined in %s\n"), configfile);
1190 OK = false;
1191 }
1192 }
1193 if (!director->catalog) { /* If catalog message resource not specified */
1194 director->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1195 }
1196 if (GetNextRes(R_DIRECTOR, (RES *)director) != NULL) {
1197 Jmsg(NULL, M_FATAL, 0, _("Only one Director resource permitted in %s\n"),
1198 configfile);
1199 OK = false;
1200 }
1201 /* tls_require implies tls_enable */
1202 if (director->tls_require) {
1203 if (have_tls) {
1204 if (director->tls_certfile || director->tls_keyfile) {
1205 director->tls_enable = true;
1206 }
1207 } else {
1208 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
1209 OK = false;
1210 }
1211 }
1212
1213 need_tls = director->tls_enable || director->tls_authenticate;
1214
1215 if (!director->tls_certfile && need_tls) {
1216 Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Director \"%s\" in %s.\n"),
1217 director->name(), configfile);
1218 OK = false;
1219 }
1220
1221 if (!director->tls_keyfile && need_tls) {
1222 Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Director \"%s\" in %s.\n"),
1223 director->name(), configfile);
1224 OK = false;
1225 }
1226
1227 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) &&
1228 need_tls && director->tls_verify_peer) {
1229 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate File\" or \"TLS CA"
1230 " Certificate Dir\" are defined for Director \"%s\" in %s."
1231 " At least one CA certificate store is required"
1232 " when using \"TLS Verify Peer\".\n"),
1233 director->name(), configfile);
1234 OK = false;
1235 }
1236 }
1237
1238 /* Loop over Consoles */
1239 CONRES *cons;
1240 foreach_res(cons, R_CONSOLE) {
1241 /* tls_require implies tls_enable */
1242 if (cons->tls_require) {
1243 if (have_tls) {
1244 if (cons->tls_certfile || cons->tls_keyfile) {
1245 cons->tls_enable = true;
1246 }
1247 } else {
1248 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
1249 OK = false;
1250 continue;
1251 }
1252 }
1253
1254 need_tls = cons->tls_enable || cons->tls_authenticate;
1255
1256 if (!cons->tls_certfile && need_tls) {
1257 Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Console \"%s\" in %s.\n"),
1258 cons->name(), configfile);
1259 OK = false;
1260 }
1261
1262 if (!cons->tls_keyfile && need_tls) {
1263 Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Console \"%s\" in %s.\n"),
1264 cons->name(), configfile);
1265 OK = false;
1266 }
1267
1268 if ((!cons->tls_ca_certfile && !cons->tls_ca_certdir)
1269 && need_tls && cons->tls_verify_peer) {
1270 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate File\" or \"TLS CA"
1271 " Certificate Dir\" are defined for Console \"%s\" in %s."
1272 " At least one CA certificate store is required"
1273 " when using \"TLS Verify Peer\".\n"),
1274 cons->name(), configfile);
1275 OK = false;
1276 }
1277 /* If everything is well, attempt to initialize our per-resource TLS context */
1278 if (OK && need_tls) {
1279 /* Initialize TLS context:
1280 * Args: CA certfile, CA certdir, Certfile, Keyfile,
1281 * Keyfile PEM Callback, Keyfile CB Userdata, DHfile, Verify Peer */
1282 cons->tls_ctx = new_tls_context(cons->tls_ca_certfile,
1283 cons->tls_ca_certdir, cons->tls_certfile,
1284 cons->tls_keyfile, NULL, NULL, cons->tls_dhfile, cons->tls_verify_peer);
1285
1286 if (!cons->tls_ctx) {
1287 Jmsg(NULL, M_FATAL, 0, _("Failed to initialize TLS context for Console \"%s\" in %s.\n"),
1288 cons->name(), configfile);
1289 OK = false;
1290 }
1291 }
1292 }
1293
1294 /* Loop over Clients */
1295 CLIENT *client;
1296 foreach_res(client, R_CLIENT) {
1297 if (!client->client_address && !client->allow_fd_connections) {
1298 Jmsg(NULL, M_FATAL, 0, _("Config error: Address directive is required in Client resource \"%s\", but not found.\n"), client->hdr.name);
1299 OK = false;
1300 continue;
1301 }
1302 /* tls_require implies tls_enable */
1303 if (client->tls_require) {
1304 if (have_tls) {
1305 if (client->tls_ca_certfile || client->tls_ca_certdir) {
1306 client->tls_enable = true;
1307 }
1308 } else {
1309 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
1310 OK = false;
1311 continue;
1312 }
1313 }
1314 need_tls = client->tls_enable || client->tls_authenticate;
1315 if ((!client->tls_ca_certfile && !client->tls_ca_certdir) && need_tls) {
1316 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate File\""
1317 " or \"TLS CA Certificate Dir\" are defined for File daemon \"%s\" in %s.\n"),
1318 client->name(), configfile);
1319 OK = false;
1320 }
1321
1322 }
1323
1324 if (!job) {
1325 Jmsg(NULL, M_FATAL, 0, _("No Job records defined in %s\n"), configfile);
1326 OK = false;
1327 }
1328
1329 /* TODO: We can't really update all job, we need to show only the real configuration
1330 * and not Job+JobDefs
1331 */
1332 if (!apply_jobdefs) {
1333 UnlockRes();
1334 return OK;
1335 }
1336
1337 foreach_res(job, R_JOB) {
1338 int i;
1339
1340 if (job->jobdefs) {
1341 JOB *jobdefs = job->jobdefs;
1342 /* Handle RunScripts alists specifically */
1343 if (jobdefs->RunScripts) {
1344 RUNSCRIPT *rs, *elt;
1345
1346 if (!job->RunScripts) {
1347 job->RunScripts = New(alist(10, not_owned_by_alist));
1348 }
1349
1350 foreach_alist(rs, jobdefs->RunScripts) {
1351 elt = copy_runscript(rs);
1352 job->RunScripts->append(elt); /* we have to free it */
1353 }
1354 }
1355
1356 /* Transfer default items from JobDefs Resource */
1357 for (i=0; job_items[i].name; i++) {
1358 char **def_svalue, **svalue; /* string value */
1359 uint32_t *def_ivalue, *ivalue; /* integer value */
1360 bool *def_bvalue, *bvalue; /* bool value */
1361 int64_t *def_lvalue, *lvalue; /* 64 bit values */
1362 uint32_t offset;
1363 alist **def_avalue, **avalue; /* alist value */
1364
1365 Dmsg4(1400, "Job \"%s\", field \"%s\" bit=%d def=%d\n",
1366 job->name(), job_items[i].name,
1367 bit_is_set(i, job->hdr.item_present),
1368 bit_is_set(i, job->jobdefs->hdr.item_present));
1369
1370 if (!bit_is_set(i, job->hdr.item_present) &&
1371 bit_is_set(i, job->jobdefs->hdr.item_present)) {
1372 Dmsg2(400, "Job \"%s\", field \"%s\": getting default.\n",
1373 job->name(), job_items[i].name);
1374 offset = (char *)(job_items[i].value) - (char *)&res_all;
1375 /*
1376 * Handle strings and directory strings
1377 */
1378 if (job_items[i].handler == store_str ||
1379 job_items[i].handler == store_storage_mngr ||
1380 job_items[i].handler == store_dir) {
1381 def_svalue = (char **)((char *)(job->jobdefs) + offset);
1382 Dmsg5(400, "Job \"%s\", field \"%s\" def_svalue=%s item %d offset=%u\n",
1383 job->name(), job_items[i].name, *def_svalue, i, offset);
1384 svalue = (char **)((char *)job + offset);
1385 if (*svalue) {
1386 Pmsg1(000, _("Hey something is wrong. p=0x%lu\n"), *svalue);
1387 }
1388 *svalue = bstrdup(*def_svalue);
1389 set_bit(i, job->hdr.item_present);
1390 /*
1391 * Handle resources
1392 */
1393 } else if (job_items[i].handler == store_res) {
1394 def_svalue = (char **)((char *)(job->jobdefs) + offset);
1395 Dmsg4(400, "Job \"%s\", field \"%s\" item %d offset=%u\n",
1396 job->name(), job_items[i].name, i, offset);
1397 svalue = (char **)((char *)job + offset);
1398 if (*svalue) {
1399 Pmsg1(000, _("Hey something is wrong. p=0x%lu\n"), *svalue);
1400 }
1401 *svalue = *def_svalue;
1402 set_bit(i, job->hdr.item_present);
1403 /*
1404 * Handle alist resources
1405 */
1406 } else if (job_items[i].handler == store_alist_str) {
1407 char *elt;
1408
1409 def_avalue = (alist **)((char *)(job->jobdefs) + offset);
1410 avalue = (alist **)((char *)job + offset);
1411
1412 *avalue = New(alist(10, owned_by_alist));
1413
1414 foreach_alist(elt, (*def_avalue)) {
1415 (*avalue)->append(bstrdup(elt));
1416 }
1417 set_bit(i, job->hdr.item_present);
1418
1419 } else if (job_items[i].handler == store_alist_res) {
1420 void *elt;
1421
1422 def_avalue = (alist **)((char *)(job->jobdefs) + offset);
1423 avalue = (alist **)((char *)job + offset);
1424
1425 *avalue = New(alist(10, not_owned_by_alist));
1426
1427 foreach_alist(elt, (*def_avalue)) {
1428 (*avalue)->append(elt);
1429 }
1430 set_bit(i, job->hdr.item_present);
1431 /*
1432 * Handle integer fields
1433 * Note, our store_bit does not handle bitmaped fields
1434 */
1435 } else if (job_items[i].handler == store_bit ||
1436 job_items[i].handler == store_pint32 ||
1437 job_items[i].handler == store_jobtype ||
1438 job_items[i].handler == store_level ||
1439 job_items[i].handler == store_int32 ||
1440 job_items[i].handler == store_size32 ||
1441 job_items[i].handler == store_migtype ||
1442 job_items[i].handler == store_replace) {
1443 def_ivalue = (uint32_t *)((char *)(job->jobdefs) + offset);
1444 Dmsg5(400, "Job \"%s\", field \"%s\" def_ivalue=%d item %d offset=%u\n",
1445 job->name(), job_items[i].name, *def_ivalue, i, offset);
1446 ivalue = (uint32_t *)((char *)job + offset);
1447 *ivalue = *def_ivalue;
1448 set_bit(i, job->hdr.item_present);
1449 /*
1450 * Handle 64 bit integer fields
1451 */
1452 } else if (job_items[i].handler == store_time ||
1453 job_items[i].handler == store_size64 ||
1454 job_items[i].handler == store_int64) {
1455 def_lvalue = (int64_t *)((char *)(job->jobdefs) + offset);
1456 Dmsg5(400, "Job \"%s\", field \"%s\" def_lvalue=%" lld " item %d offset=%u\n",
1457 job->name(), job_items[i].name, *def_lvalue, i, offset);
1458 lvalue = (int64_t *)((char *)job + offset);
1459 *lvalue = *def_lvalue;
1460 set_bit(i, job->hdr.item_present);
1461 /*
1462 * Handle bool fields
1463 */
1464 } else if (job_items[i].handler == store_bool) {
1465 def_bvalue = (bool *)((char *)(job->jobdefs) + offset);
1466 Dmsg5(400, "Job \"%s\", field \"%s\" def_bvalue=%d item %d offset=%u\n",
1467 job->name(), job_items[i].name, *def_bvalue, i, offset);
1468 bvalue = (bool *)((char *)job + offset);
1469 *bvalue = *def_bvalue;
1470 set_bit(i, job->hdr.item_present);
1471
1472 } else if (job_items[i].handler == store_runscript) {
1473 /* nothing special to do, already handled */
1474
1475 } else {
1476 Dmsg1(10, "Handler missing for job_items[%d]\n", i);
1477 ASSERTD(0, "JobDefs -> Job handler missing\n");
1478 }
1479 }
1480 }
1481 }
1482 /*
1483 * Ensure that all required items are present
1484 */
1485 for (i=0; job_items[i].name; i++) {
1486 if (job_items[i].flags & ITEM_REQUIRED) {
1487 if (!bit_is_set(i, job->hdr.item_present)) {
1488 Jmsg(NULL, M_ERROR_TERM, 0, _("\"%s\" directive in Job \"%s\" resource is required, but not found.\n"),
1489 job_items[i].name, job->name());
1490 OK = false;
1491 }
1492 }
1493 /* If this triggers, take a look at lib/parse_conf.h */
1494 if (i >= MAX_RES_ITEMS) {
1495 Emsg0(M_ERROR_TERM, 0, _("Too many items in Job resource\n"));
1496 }
1497 }
1498 if (!job->storage && !job->pool->storage) {
1499 Jmsg(NULL, M_FATAL, 0, _("No storage specified in Job \"%s\" nor in Pool.\n"),
1500 job->name());
1501 OK = false;
1502 }
1503 } /* End loop over Job res */
1504
1505 UnlockRes();
1506 return OK;
1507 }
1508
1509 static void sendit(void *sock, const char *fmt, ...)
1510 {
1511 char buf[3000];
1512 va_list arg_ptr;
1513
1514 va_start(arg_ptr, fmt);
1515 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
1516 va_end(arg_ptr);
1517 fputs(buf, stdout);
1518 fflush(stdout);
1519 }