"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 }