"Fossies" - the Fresh Open Source Software Archive

Member "bacula-9.4.4/src/dird/bdirjson.c" (28 May 2019, 50603 Bytes) of package /linux/misc/bacula-9.4.4.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.

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