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