2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Main configuration file parser for Bacula Directors,
21 * some parts may be split into separate files such as
22 * the schedule configuration (run_config.c).
24 * Note, the configuration file parser consists of three parts
26 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
28 * 2. The generic config scanner in lib/parse_config.c and
30 * These files contain the parser code, some utility
31 * routines, and the common store routines (name, int,
34 * 3. The daemon specific file, which contains the Resource
35 * definitions as well as any specific store routines
36 * for the resource records.
38 * Kern Sibbald, January MM
45 /* Define the first and last resource ID record
46 * types. Note, these should be unique for each
47 * daemon though not a requirement.
49 int32_t r_first = R_FIRST;
50 int32_t r_last = R_LAST;
53 static pthread_mutex_t globals_mutex = PTHREAD_MUTEX_INITIALIZER;
60 /* Imported subroutines */
61 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
62 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
63 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
66 /* Forward referenced subroutines */
68 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
69 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
70 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
71 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
72 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
73 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
76 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
77 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 /* We build the current resource here as we are
81 * scanning the resource configuration definition,
82 * then move it to allocated memory when the resource
86 extern "C" { // work around visual compiler mangling variables
92 int32_t res_all_size = sizeof(res_all);
94 /* Implementation of certain classes */
96 void CLIENT::create_client_globals()
98 globals = (CLIENT_GLOBALS *)malloc(sizeof(CLIENT_GLOBALS));
99 memset(globals, 0, sizeof(CLIENT_GLOBALS));
100 globals->name = bstrdup(name());
101 globals->enabled = -1; /* Not set */
102 client_globals.append(globals);
105 int32_t CLIENT::getNumConcurrentJobs()
110 return globals->NumConcurrentJobs;
113 void CLIENT::setNumConcurrentJobs(int32_t num)
117 create_client_globals();
119 globals->NumConcurrentJobs = num;
122 Dmsg2(200, "Set NumConcurrentJobs=%ld for Client %s\n",
126 char *CLIENT::address()
129 return client_address;
131 if (!globals->SetIPaddress) {
132 return client_address;
134 /* TODO: Fix concurrency issue between setAddress() and address()
135 * we need to copy the address in an argument, the variable can be
138 return globals->SetIPaddress;
141 void CLIENT::setAddress(char *addr)
145 create_client_globals();
147 if (globals->SetIPaddress) {
148 free(globals->SetIPaddress);
150 globals->SetIPaddress = bstrdup(addr);
154 bool CLIENT::is_enabled()
156 if (!globals || globals->enabled < 0) {
159 return globals->enabled;
162 void CLIENT::setEnabled(bool val)
166 create_client_globals();
168 /* TODO: We probably need to set -1 (not set) when we are back to the default value */
169 globals->enabled = val? 1 : 0;
171 Dmsg2(200, "Set Enabled=%d for Client %s\n",
175 void JOB::create_job_globals()
177 globals = (JOB_GLOBALS *)malloc(sizeof(JOB_GLOBALS));
178 memset(globals, 0, sizeof(JOB_GLOBALS));
179 globals->name = bstrdup(name());
180 globals->enabled = -1; /* Not set */
181 job_globals.append(globals);
184 int32_t JOB::getNumConcurrentJobs()
189 return globals->NumConcurrentJobs;
192 void JOB::setNumConcurrentJobs(int32_t num)
196 create_job_globals();
198 globals->NumConcurrentJobs = num;
201 Dmsg2(200, "Set NumConcurrentJobs=%ld for Job %s\n",
205 bool JOB::is_enabled()
207 if (!globals || globals->enabled < 0) {
210 return globals->enabled;
213 void JOB::setEnabled(bool val)
217 create_job_globals();
219 globals->enabled = val ? 1 : 0;
221 Dmsg2(200, "Set Enabled=%d for Job %s\n",
225 void STORE::create_store_globals()
227 globals = (STORE_GLOBALS *)malloc(sizeof(STORE_GLOBALS));
228 memset(globals, 0, sizeof(STORE_GLOBALS));
229 globals->name = bstrdup(name());
230 globals->enabled = -1; /* Not set */
231 store_globals.append(globals);
234 int32_t STORE::getNumConcurrentReadJobs()
239 return globals->NumConcurrentReadJobs;
242 void STORE::setNumConcurrentReadJobs(int32_t num)
246 create_store_globals();
248 globals->NumConcurrentReadJobs = num;
250 Dmsg2(200, "Set NumConcurrentReadJobs=%ld for Store %s\n",
255 int32_t STORE::getNumConcurrentJobs()
260 return globals->NumConcurrentJobs;
263 void STORE::setNumConcurrentJobs(int32_t num)
267 create_store_globals();
269 globals->NumConcurrentJobs = num;
271 Dmsg2(200, "Set numconcurrentJobs=%ld for Store %s\n",
276 bool STORE::is_enabled()
278 if (!globals || globals->enabled < 0) {
281 return globals->enabled;
284 void STORE::setEnabled(bool val)
288 create_store_globals();
290 globals->enabled = val ? 1 : 0;
292 Dmsg2(200, "Set Enabled=%d for Storage %s\n",
296 void SCHED::create_sched_globals()
298 globals = (SCHED_GLOBALS *)malloc(sizeof(CLIENT_GLOBALS));
299 memset(globals, 0, sizeof(SCHED_GLOBALS));
300 globals->name = bstrdup(name());
301 globals->enabled = -1; /* Not set */
302 sched_globals.append(globals);
305 bool SCHED::is_enabled()
307 if (!globals || globals->enabled < 0) {
310 return globals->enabled;
313 void SCHED::setEnabled(bool val)
317 create_sched_globals();
319 globals->enabled = val ? 1 : 0;
321 Dmsg2(200, "Set Enabled=%d for Schedule %s\n",
326 * Definition of records permitted within each
327 * resource with the routine to process the record
328 * information. NOTE! quoted names must be in lower case.
333 * name handler value code flags default_value
335 static RES_ITEM dir_items[] = {
336 {"Name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
337 {"Description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
338 {"Messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
339 {"DirPort", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
340 {"DirAddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
341 {"DirAddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
342 {"DirSourceAddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
343 {"QueryFile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
344 {"WorkingDirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
345 {"PluginDirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
346 {"ScriptsDirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
347 {"PidDirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
348 {"SubsysDirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
349 {"MaximumConcurrentJobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 20},
350 {"MaximumReloadRequests", store_pint32, ITEM(res_dir.MaxReload), 0, ITEM_DEFAULT, 32},
351 {"MaximumConsoleConnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
352 {"Password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
353 {"FdConnectTimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
354 {"SdConnectTimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
355 {"HeartbeatInterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
356 {"TlsAuthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
357 {"TlsEnable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
358 {"TlsRequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
359 {"TlsVerifyPeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
360 {"TlsCaCertificateFile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
361 {"TlsCaCertificateDir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
362 {"TlsCertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
363 {"TlsKey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
364 {"TlsDhFile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
365 {"TlsAllowedCn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
366 {"StatisticsRetention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
367 {"VerId", store_str, ITEM(res_dir.verid), 0, 0, 0},
368 {"CommCompression", store_bool, ITEM(res_dir.comm_compression), 0, ITEM_DEFAULT, true},
369 {NULL, NULL, {0}, 0, 0, 0}
375 * name handler value code flags default_value
377 static RES_ITEM con_items[] = {
378 {"Name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
379 {"Description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
380 {"Password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
381 {"JobAcl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
382 {"ClientAcl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
383 {"StorageAcl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
384 {"ScheduleAcl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
385 {"RunAcl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
386 {"PoolAcl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
387 {"CommandAcl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
388 {"FilesetAcl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
389 {"CatalogAcl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
390 {"WhereAcl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
391 {"RestoreClientAcl", store_acl, ITEM(res_con.ACL_lists), RestoreClient_ACL, 0, 0},
392 {"BackupClientAcl", store_acl, ITEM(res_con.ACL_lists), BackupClient_ACL, 0, 0},
393 {"PluginOptionsAcl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
394 {"DirectoryAcl", store_acl, ITEM(res_con.ACL_lists), Directory_ACL, 0, 0},
395 {"TlsAuthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
396 {"TlsEnable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
397 {"TlsRequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
398 {"TlsVerifyPeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
399 {"TlsCaCertificateFile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
400 {"TlsCaCertificateDir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
401 {"TlsCertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
402 {"TlsKey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
403 {"TlsDhFile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
404 {"TlsAllowedCn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
405 {NULL, NULL, {0}, 0, 0, 0}
410 * Client or File daemon resource
412 * name handler value code flags default_value
415 static RES_ITEM cli_items[] = {
416 {"Name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
417 {"Description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
418 {"fdaddress", store_str, ITEM(res_client.client_address), 0, 0, 0},
419 {"Address", store_str, ITEM(res_client.client_address), 0, ITEM_REQUIRED, 0},
420 {"FdPort", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
421 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
422 {"Password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
423 {"FdStorageAddress", store_str, ITEM(res_client.fd_storage_address), 0, 0, 0},
424 {"Catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
425 {"FileRetention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
426 {"JobRetention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
427 {"HeartbeatInterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
428 {"AutoPrune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
429 {"SDCallsClient", store_bool, ITEM(res_client.sd_calls_client), 0, ITEM_DEFAULT, false},
430 {"SnapshotRetention", store_time, ITEM(res_client.SnapRetention), 0, ITEM_DEFAULT, 0},
431 {"MaximumConcurrentJobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
432 {"TlsAuthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
433 {"TlsEnable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
434 {"TlsRequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
435 {"TlsCaCertificateFile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
436 {"TlsCaCertificateDir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
437 {"TlsCertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
438 {"TlsKey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
439 {"TlsAllowedCn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
440 {"MaximumBandwidthPerJob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
441 {"Enabled", store_bool, ITEM(res_client.Enabled), 0, ITEM_DEFAULT, true},
442 {NULL, NULL, {0}, 0, 0, 0}
445 /* Storage daemon resource
447 * name handler value code flags default_value
449 static RES_ITEM store_items[] = {
450 {"Name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
451 {"Description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
452 {"SdPort", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
453 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
454 {"Address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
455 {"FdStorageAddress", store_str, ITEM(res_store.fd_storage_address), 0, 0, 0},
456 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
457 {"Password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
458 {"Device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
459 {"MediaType", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
461 * Big kludge, these two autochanger definitions must be in
462 * this order and together.
464 {"Autochanger", store_ac_res, ITEM(res_store.changer), 0, ITEM_DEFAULT, 0},
465 {"Autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, false},
466 {"SharedStorage", store_ac_res, ITEM(res_store.shared_storage), 1, ITEM_DEFAULT, 0},
467 {"Enabled", store_bool, ITEM(res_store.Enabled), 0, ITEM_DEFAULT, true},
468 {"AllowCompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
469 {"HeartbeatInterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
470 {"MaximumConcurrentJobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
471 {"MaximumConcurrentReadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
472 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
473 {"TlsAuthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
474 {"TlsEnable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
475 {"TlsRequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
476 {"TlsCaCertificateFile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
477 {"TlsCaCertificateDir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
478 {"TlsCertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
479 {"TlsKey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
480 {NULL, NULL, {0}, 0, 0, 0}
484 * Catalog Resource Directives
486 * name handler value code flags default_value
488 static RES_ITEM cat_items[] = {
489 {"Name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
490 {"Description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
491 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
492 {"Address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
493 {"DbPort", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
494 /* keep this password as store_str for the moment */
495 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
496 {"Password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
497 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
498 {"User", store_str, ITEM(res_cat.db_user), 0, 0, 0},
499 {"DbName", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
500 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
501 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
502 {"dbsslmode", store_str, ITEM(res_cat.db_ssl_mode), 0, 0, 0},
503 {"dbsslkey", store_str, ITEM(res_cat.db_ssl_key), 0, 0, 0},
504 {"dbsslcert", store_str, ITEM(res_cat.db_ssl_cert), 0, 0, 0},
505 {"dbsslca", store_str, ITEM(res_cat.db_ssl_ca), 0, 0, 0},
506 {"dbsslcapath", store_str, ITEM(res_cat.db_ssl_capath), 0, 0, 0},
507 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
508 /* Turned off for the moment */
509 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
510 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
511 {NULL, NULL, {0}, 0, 0, 0}
515 * Job Resource Directives
517 * name handler value code flags default_value
519 RES_ITEM job_items[] = {
520 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
521 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
522 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
523 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
524 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
525 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
526 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
527 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
528 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
529 {"VirtualFullBackupPool", store_res, ITEM(res_job.vfull_pool), R_POOL, 0, 0},
530 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
531 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
532 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
533 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
534 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
535 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
536 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
537 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
538 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
539 /* Root of where to restore files */
540 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
541 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
542 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
543 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
544 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
545 /* Where to find bootstrap during restore */
546 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
547 /* Where to write bootstrap file during backup */
548 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
549 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
550 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
551 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
552 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
553 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
554 /* xxxMaxWaitTime are deprecated */
555 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
556 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
557 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
558 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
559 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
560 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
561 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
562 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
563 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
564 {"MaxVirtualFullInterval", store_time, ITEM(res_job.MaxVirtualFullInterval), 0, 0, 0},
565 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
566 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
567 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
568 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
569 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
570 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
571 {"Enabled", store_bool, ITEM(res_job.Enabled), 0, ITEM_DEFAULT, true},
572 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
573 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
574 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
575 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
576 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
577 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
579 * JSON tools skip Directive in lowercase. They are deprecated or
580 * are synonym with an other one that follows. Like User and dbuser.
582 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
583 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
584 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
585 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
586 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
587 {"consolerunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
588 {"consolerunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
589 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
590 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
591 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
592 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
593 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
594 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
595 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
596 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
597 {"BackupsToKeep", store_pint32, ITEM(res_job.BackupsToKeep), 0, ITEM_DEFAULT, 0},
598 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
599 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
600 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
601 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
602 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
603 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
604 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
605 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
606 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
607 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
608 {"DeleteConsolidatedJobs", store_bool, ITEM(res_job.DeleteConsolidatedJobs), 0, ITEM_DEFAULT, false},
609 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
610 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
611 {NULL, NULL, {0}, 0, 0, 0}
616 * Name handler value code flags default_value
618 static RES_ITEM fs_items[] = {
619 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
620 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
621 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
622 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
623 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
624 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
625 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
626 {NULL, NULL, {0}, 0, 0, 0}
629 /* Schedule -- see run_conf.c */
632 * name handler value code flags default_value
634 static RES_ITEM sch_items[] = {
635 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
636 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
637 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
638 {"Enabled", store_bool, ITEM(res_sch.Enabled), 0, ITEM_DEFAULT, true},
639 {NULL, NULL, {0}, 0, 0, 0}
644 * name handler value code flags default_value
646 static RES_ITEM pool_items[] = {
647 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
648 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
649 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
650 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
651 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
652 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
653 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
654 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
655 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
656 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
657 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
658 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
659 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
660 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
661 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
662 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
663 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
664 {"CacheRetention", store_time, ITEM(res_pool.CacheRetention), 0, 0, 0},
665 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
666 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
667 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
668 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
669 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
670 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
671 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
672 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
673 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
674 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
675 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
676 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
677 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
678 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
679 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
681 {NULL, NULL, {0}, 0, 0, 0}
686 * name handler value code flags default_value
688 static RES_ITEM counter_items[] = {
689 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
690 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
691 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
692 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
693 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
694 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
695 {NULL, NULL, {0}, 0, 0, 0}
699 /* Message resource */
700 extern RES_ITEM msgs_items[];
703 * This is the master resource definition.
704 * It must have one item for each of the resources.
706 * NOTE!!! keep it in the same order as the R_codes
707 * or eliminate all resources[rindex].name
711 RES_TABLE resources[] = {
712 {"Director", dir_items, R_DIRECTOR},
713 {"Client", cli_items, R_CLIENT},
714 {"Job", job_items, R_JOB},
715 {"Storage", store_items, R_STORAGE},
716 {"Catalog", cat_items, R_CATALOG},
717 {"Schedule", sch_items, R_SCHEDULE},
718 {"Fileset", fs_items, R_FILESET},
719 {"Pool", pool_items, R_POOL},
720 {"Messages", msgs_items, R_MSGS},
721 {"Counter", counter_items, R_COUNTER},
722 {"Console", con_items, R_CONSOLE},
723 {"JobDefs", job_items, R_JOBDEFS},
724 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
725 {"Autochanger", store_items, R_AUTOCHANGER}, /* alias for R_STORAGE */
730 /* Keywords (RHS) permitted in Job Level records
732 * level_name level job_type
734 struct s_jl joblevels[] = {
735 {"Full", L_FULL, JT_BACKUP},
736 {"Base", L_BASE, JT_BACKUP},
737 {"Incremental", L_INCREMENTAL, JT_BACKUP},
738 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
739 {"Since", L_SINCE, JT_BACKUP},
740 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
741 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
742 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
743 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
744 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
745 {"Data", L_VERIFY_DATA, JT_VERIFY},
746 {"Full", L_FULL, JT_COPY},
747 {"Incremental", L_INCREMENTAL, JT_COPY},
748 {"Differential", L_DIFFERENTIAL, JT_COPY},
749 {"Full", L_FULL, JT_MIGRATE},
750 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
751 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
752 {" ", L_NONE, JT_ADMIN},
753 {" ", L_NONE, JT_RESTORE},
758 /* Keywords (RHS) permitted in Job type records
763 {"Backup", JT_BACKUP},
765 {"Verify", JT_VERIFY},
766 {"Restore", JT_RESTORE},
767 {"Migrate", JT_MIGRATE},
773 /* Keywords (RHS) permitted in Selection type records
778 {"SmallestVolume", MT_SMALLEST_VOL},
779 {"OldestVolume", MT_OLDEST_VOL},
780 {"PoolOccupancy", MT_POOL_OCCUPANCY},
781 {"PoolTime", MT_POOL_TIME},
782 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
783 {"Client", MT_CLIENT},
784 {"Volume", MT_VOLUME},
786 {"SqlQuery", MT_SQLQUERY},
792 /* Options permitted in Restore replace= */
793 s_kw ReplaceOptions[] = {
794 {"Always", REPLACE_ALWAYS},
795 {"IfNewer", REPLACE_IFNEWER},
796 {"IfOlder", REPLACE_IFOLDER},
797 {"Never", REPLACE_NEVER},
801 char *CAT::display(POOLMEM *dst) {
802 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
803 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
805 name(), NPRTB(db_name),
806 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
807 NPRTB(db_address), db_port, NPRTB(db_socket));
811 const char *level_to_str(int level)
814 static char level_no[30];
815 const char *str = level_no;
817 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
818 for (i=0; joblevels[i].level_name; i++) {
819 if (level == (int)joblevels[i].level) {
820 str = joblevels[i].level_name;
827 /* Dump contents of resource */
828 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
831 URES *res = (URES *)ares;
833 char ed1[100], ed2[100], ed3[100];
835 UAContext *ua = (UAContext *)sock;
838 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
841 if (type < 0) { /* no recursion */
847 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
848 ares->name, res->res_dir.MaxConcurrentJobs,
849 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
850 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
851 if (res->res_dir.query_file) {
852 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
854 if (res->res_dir.messages) {
855 sendit(sock, _(" --> "));
856 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
860 sendit(sock, _("Console: name=%s SSL=%d\n"),
861 res->res_con.hdr.name, res->res_con.tls_enable);
864 if (res->res_counter.WrapCounter) {
865 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
866 res->res_counter.hdr.name, res->res_counter.MinValue,
867 res->res_counter.MaxValue, res->res_counter.CurrentValue,
868 res->res_counter.WrapCounter->hdr.name);
870 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
871 res->res_counter.hdr.name, res->res_counter.MinValue,
872 res->res_counter.MaxValue);
874 if (res->res_counter.Catalog) {
875 sendit(sock, _(" --> "));
876 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
881 if (!acl_access_ok(ua, Client_ACL, res->res_client.name())) {
884 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u NumJobs=%u\n"),
885 res->res_client.name(), res->res_client.is_enabled(),
886 res->res_client.address(), res->res_client.FDport,
887 res->res_client.MaxConcurrentJobs, res->res_client.getNumConcurrentJobs());
888 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
889 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
890 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
891 res->res_client.AutoPrune);
892 if (res->res_client.fd_storage_address) {
893 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
895 if (res->res_client.max_bandwidth) {
896 sendit(sock, _(" MaximumBandwidth=%lld\n"),
897 res->res_client.max_bandwidth);
899 if (res->res_client.catalog) {
900 sendit(sock, _(" --> "));
901 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
908 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
909 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
910 " poolid=%s volname=%s MediaType=%s\n"),
911 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
912 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
913 dev->offline, dev->autochanger,
914 edit_uint64(dev->PoolId, ed1),
915 dev->VolumeName, dev->MediaType);
920 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
923 sendit(sock, _("%s: name=%s address=%s SDport=%d MaxJobs=%u NumJobs=%u\n"
924 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
925 res->res_store.changer == &res->res_store ? "Autochanger" : "Storage",
926 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
927 res->res_store.MaxConcurrentJobs,
928 res->res_store.getNumConcurrentJobs(),
929 res->res_store.dev_name(),
930 res->res_store.media_type,
931 edit_int64(res->res_store.StorageId, ed1),
932 res->res_store.autochanger);
933 if (res->res_store.fd_storage_address) {
934 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
936 if (res->res_store.ac_group) {
937 STORE *shstore = res->res_store.shared_storage;
938 sendit(sock, " AC group=%s ShareStore=%s\n", res->res_store.ac_group,
939 shstore?shstore->name():"*none*");
941 if (res->res_store.changer && res->res_store.changer != &res->res_store) {
942 sendit(sock, _(" Parent --> "));
943 dump_resource(-R_STORAGE, (RES *)res->res_store.changer, sendit, sock);
948 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
951 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
952 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
953 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
954 res->res_cat.db_port, res->res_cat.db_name,
955 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
956 res->res_cat.mult_db_connections);
961 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
964 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
965 type == R_JOB ? _("Job") : _("JobDefs"),
966 res->res_job.hdr.name, res->res_job.JobType,
967 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
968 res->res_job.is_enabled());
969 sendit(sock, _(" MaxJobs=%u NumJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
970 res->res_job.MaxConcurrentJobs,
971 res->res_job.getNumConcurrentJobs(),
972 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
973 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
974 res->res_job.spool_data, res->res_job.write_part_after_job);
975 if (res->res_job.spool_size) {
976 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
978 if (res->res_job.JobType == JT_BACKUP) {
979 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
981 if (res->res_job.max_bandwidth) {
982 sendit(sock, _(" MaximumBandwidth=%lld\n"),
983 res->res_job.max_bandwidth);
985 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
986 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
988 if (res->res_job.JobType == JT_RESTORE) {
989 sendit(sock, _(" PrefixLinks=%d\n"), res->res_job.PrefixLinks);
991 if (res->res_job.client) {
992 sendit(sock, _(" --> "));
993 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
995 if (res->res_job.fileset) {
996 sendit(sock, _(" --> "));
997 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
999 if (res->res_job.schedule) {
1000 sendit(sock, _(" --> "));
1001 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
1003 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
1004 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
1006 if (res->res_job.RegexWhere) {
1007 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
1009 if (res->res_job.RestoreBootstrap) {
1010 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
1012 if (res->res_job.WriteBootstrap) {
1013 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
1015 if (res->res_job.PluginOptions) {
1016 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
1018 if (res->res_job.MaxRunTime) {
1019 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
1021 if (res->res_job.MaxWaitTime) {
1022 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
1024 if (res->res_job.MaxStartDelay) {
1025 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
1027 if (res->res_job.MaxRunSchedTime) {
1028 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
1030 if (res->res_job.storage) {
1032 foreach_alist(store, res->res_job.storage) {
1033 sendit(sock, _(" --> "));
1034 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1037 if (res->res_job.base) {
1039 foreach_alist(job, res->res_job.base) {
1040 sendit(sock, _(" --> Base %s\n"), job->name());
1043 if (res->res_job.RunScripts) {
1045 foreach_alist(script, res->res_job.RunScripts) {
1046 sendit(sock, _(" --> RunScript\n"));
1047 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
1048 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
1049 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
1050 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
1051 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
1052 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
1055 if (res->res_job.pool) {
1056 sendit(sock, _(" --> "));
1057 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
1059 if (res->res_job.vfull_pool) {
1060 sendit(sock, _(" --> VFullBackup"));
1061 dump_resource(-R_POOL, (RES *)res->res_job.vfull_pool, sendit, sock);
1063 if (res->res_job.full_pool) {
1064 sendit(sock, _(" --> FullBackup"));
1065 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
1067 if (res->res_job.inc_pool) {
1068 sendit(sock, _(" --> IncrementalBackup"));
1069 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
1071 if (res->res_job.diff_pool) {
1072 sendit(sock, _(" --> DifferentialBackup"));
1073 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
1075 if (res->res_job.next_pool) {
1076 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1077 dump_resource(-R_POOL, (RES *)res->res_job.next_pool, sendit, sock);
1079 if (res->res_job.JobType == JT_VERIFY && res->res_job.verify_job) {
1080 sendit(sock, _(" --> JobToVerify %s"), (RES *)res->res_job.verify_job->name());
1082 if (res->res_job.run_cmds) {
1084 foreach_alist(runcmd, res->res_job.run_cmds) {
1085 sendit(sock, _(" --> Run=%s\n"), runcmd);
1088 if (res->res_job.selection_pattern) {
1089 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
1091 if (res->res_job.messages) {
1092 sendit(sock, _(" --> "));
1093 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
1100 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
1103 sendit(sock, _("FileSet: name=%s IgnoreFileSetChanges=%d\n"), res->res_fs.hdr.name, res->res_fs.ignore_fs_changes);
1104 for (i=0; i<res->res_fs.num_includes; i++) {
1105 INCEXE *incexe = res->res_fs.include_items[i];
1106 for (j=0; j<incexe->num_opts; j++) {
1107 FOPTS *fo = incexe->opts_list[j];
1108 sendit(sock, " O %s\n", fo->opts);
1110 bool enhanced_wild = false;
1111 for (k=0; fo->opts[k]!='\0'; k++) {
1112 if (fo->opts[k]=='W') {
1113 enhanced_wild = true;
1118 for (k=0; k<fo->regex.size(); k++) {
1119 sendit(sock, " R %s\n", fo->regex.get(k));
1121 for (k=0; k<fo->regexdir.size(); k++) {
1122 sendit(sock, " RD %s\n", fo->regexdir.get(k));
1124 for (k=0; k<fo->regexfile.size(); k++) {
1125 sendit(sock, " RF %s\n", fo->regexfile.get(k));
1127 for (k=0; k<fo->wild.size(); k++) {
1128 sendit(sock, " W %s\n", fo->wild.get(k));
1130 for (k=0; k<fo->wilddir.size(); k++) {
1131 sendit(sock, " WD %s\n", fo->wilddir.get(k));
1133 for (k=0; k<fo->wildfile.size(); k++) {
1134 sendit(sock, " WF %s\n", fo->wildfile.get(k));
1136 for (k=0; k<fo->wildbase.size(); k++) {
1137 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
1139 for (k=0; k<fo->base.size(); k++) {
1140 sendit(sock, " B %s\n", fo->base.get(k));
1142 for (k=0; k<fo->fstype.size(); k++) {
1143 sendit(sock, " X %s\n", fo->fstype.get(k));
1145 for (k=0; k<fo->drivetype.size(); k++) {
1146 sendit(sock, " XD %s\n", fo->drivetype.get(k));
1149 sendit(sock, " G %s\n", fo->plugin);
1152 sendit(sock, " D %s\n", fo->reader);
1155 sendit(sock, " T %s\n", fo->writer);
1157 sendit(sock, " N\n");
1159 if (incexe->ignoredir) {
1160 sendit(sock, " Z %s\n", incexe->ignoredir);
1162 for (j=0; j<incexe->name_list.size(); j++) {
1163 sendit(sock, " I %s\n", incexe->name_list.get(j));
1165 if (incexe->name_list.size()) {
1166 sendit(sock, " N\n");
1168 for (j=0; j<incexe->plugin_list.size(); j++) {
1169 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
1171 if (incexe->plugin_list.size()) {
1172 sendit(sock, " N\n");
1174 } /* end for over includes */
1176 for (i=0; i<res->res_fs.num_excludes; i++) {
1177 INCEXE *incexe = res->res_fs.exclude_items[i];
1178 for (j=0; j<incexe->name_list.size(); j++) {
1179 sendit(sock, " E %s\n", incexe->name_list.get(j));
1181 if (incexe->name_list.size()) {
1182 sendit(sock, " N\n");
1186 } /* end case R_FILESET */
1189 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
1193 if (res->res_sch.run) {
1195 RUN *run = res->res_sch.run;
1196 char buf[1000], num[30];
1197 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
1198 res->res_sch.hdr.name, res->res_sch.is_enabled());
1203 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
1204 if (run->MaxRunSchedTime) {
1205 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
1207 if (run->Priority) {
1208 sendit(sock, _(" Priority=%u\n"), run->Priority);
1210 bstrncpy(buf, _(" hour="), sizeof(buf));
1211 for (i=0; i<24; i++) {
1212 if (bit_is_set(i, run->hour)) {
1213 bsnprintf(num, sizeof(num), "%d ", i);
1214 bstrncat(buf, num, sizeof(buf));
1217 bstrncat(buf, "\n", sizeof(buf));
1219 bstrncpy(buf, _(" mday="), sizeof(buf));
1220 for (i=0; i<32; i++) {
1221 if (bit_is_set(i, run->mday)) {
1222 bsnprintf(num, sizeof(num), "%d ", i);
1223 bstrncat(buf, num, sizeof(buf));
1226 bstrncat(buf, "\n", sizeof(buf));
1228 bstrncpy(buf, _(" month="), sizeof(buf));
1229 for (i=0; i<12; i++) {
1230 if (bit_is_set(i, run->month)) {
1231 bsnprintf(num, sizeof(num), "%d ", i);
1232 bstrncat(buf, num, sizeof(buf));
1235 bstrncat(buf, "\n", sizeof(buf));
1237 bstrncpy(buf, _(" wday="), sizeof(buf));
1238 for (i=0; i<7; i++) {
1239 if (bit_is_set(i, run->wday)) {
1240 bsnprintf(num, sizeof(num), "%d ", i);
1241 bstrncat(buf, num, sizeof(buf));
1244 bstrncat(buf, "\n", sizeof(buf));
1246 bstrncpy(buf, _(" wom="), sizeof(buf));
1247 for (i=0; i<6; i++) {
1248 if (bit_is_set(i, run->wom)) {
1249 bsnprintf(num, sizeof(num), "%d ", i);
1250 bstrncat(buf, num, sizeof(buf));
1253 bstrncat(buf, "\n", sizeof(buf));
1255 bstrncpy(buf, _(" woy="), sizeof(buf));
1256 for (i=0; i<54; i++) {
1257 if (bit_is_set(i, run->woy)) {
1258 bsnprintf(num, sizeof(num), "%d ", i);
1259 bstrncat(buf, num, sizeof(buf));
1262 bstrncat(buf, "\n", sizeof(buf));
1264 sendit(sock, _(" mins=%d\n"), run->minute);
1266 sendit(sock, _(" --> "));
1267 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
1269 if (run->next_pool) {
1270 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1271 dump_resource(-R_POOL, (RES *)run->next_pool, sendit, sock);
1274 sendit(sock, _(" --> "));
1275 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
1278 sendit(sock, _(" --> "));
1279 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
1281 /* If another Run record is chained in, go print it */
1287 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1292 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1295 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1296 res->res_pool.pool_type);
1297 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1298 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1299 res->res_pool.catalog_files);
1300 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1301 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1302 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1303 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1304 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1305 res->res_pool.Recycle,
1306 NPRT(res->res_pool.label_format));
1307 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1308 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1309 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1310 res->res_pool.recycle_oldest_volume,
1311 res->res_pool.purge_oldest_volume,
1312 res->res_pool.action_on_purge);
1313 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1314 res->res_pool.MaxVolJobs,
1315 res->res_pool.MaxVolFiles,
1316 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1317 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1318 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1319 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1320 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1321 sendit(sock, _(" CacheRetention=%s\n"),
1322 edit_utime(res->res_pool.CacheRetention, ed1, sizeof(ed1)));
1323 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1324 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1325 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1326 if (res->res_pool.NextPool) {
1327 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1329 if (res->res_pool.RecyclePool) {
1330 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1332 if (res->res_pool.ScratchPool) {
1333 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1335 if (res->res_pool.catalog) {
1336 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1338 if (res->res_pool.storage) {
1340 foreach_alist(store, res->res_pool.storage) {
1341 sendit(sock, _(" --> "));
1342 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1345 if (res->res_pool.CopyPool) {
1347 foreach_alist(copy, res->res_pool.CopyPool) {
1348 sendit(sock, _(" --> "));
1349 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1356 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1357 if (res->res_msgs.mail_cmd)
1358 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1359 if (res->res_msgs.operator_cmd)
1360 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1364 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1368 next = GetNextRes(0, (RES *)res);
1370 dump_resource(type, next, sendit, sock);
1376 * Free all the members of an INCEXE structure
1378 static void free_incexe(INCEXE *incexe)
1380 incexe->name_list.destroy();
1381 incexe->plugin_list.destroy();
1382 for (int i=0; i<incexe->num_opts; i++) {
1383 FOPTS *fopt = incexe->opts_list[i];
1384 fopt->regex.destroy();
1385 fopt->regexdir.destroy();
1386 fopt->regexfile.destroy();
1387 fopt->wild.destroy();
1388 fopt->wilddir.destroy();
1389 fopt->wildfile.destroy();
1390 fopt->wildbase.destroy();
1391 fopt->base.destroy();
1392 fopt->fstype.destroy();
1393 fopt->drivetype.destroy();
1405 if (incexe->opts_list) {
1406 free(incexe->opts_list);
1408 if (incexe->ignoredir) {
1409 free(incexe->ignoredir);
1416 * Free memory of resource -- called when daemon terminates.
1417 * NB, we don't need to worry about freeing any references
1418 * to other resources as they will be freed when that
1419 * resource chain is traversed. Mainly we worry about freeing
1420 * allocated strings (names).
1422 void free_resource(RES *rres, int type)
1425 URES *res = (URES *)rres;
1431 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1432 /* common stuff -- free the resource name and description */
1433 if (res->res_dir.hdr.name) {
1434 free(res->res_dir.hdr.name);
1436 if (res->res_dir.hdr.desc) {
1437 free(res->res_dir.hdr.desc);
1442 if (res->res_dir.working_directory) {
1443 free(res->res_dir.working_directory);
1445 if (res->res_dir.scripts_directory) {
1446 free((char *)res->res_dir.scripts_directory);
1448 if (res->res_dir.plugin_directory) {
1449 free((char *)res->res_dir.plugin_directory);
1451 if (res->res_dir.pid_directory) {
1452 free(res->res_dir.pid_directory);
1454 if (res->res_dir.subsys_directory) {
1455 free(res->res_dir.subsys_directory);
1457 if (res->res_dir.password) {
1458 free(res->res_dir.password);
1460 if (res->res_dir.query_file) {
1461 free(res->res_dir.query_file);
1463 if (res->res_dir.DIRaddrs) {
1464 free_addresses(res->res_dir.DIRaddrs);
1466 if (res->res_dir.DIRsrc_addr) {
1467 free_addresses(res->res_dir.DIRsrc_addr);
1469 if (res->res_dir.tls_ctx) {
1470 free_tls_context(res->res_dir.tls_ctx);
1472 if (res->res_dir.tls_ca_certfile) {
1473 free(res->res_dir.tls_ca_certfile);
1475 if (res->res_dir.tls_ca_certdir) {
1476 free(res->res_dir.tls_ca_certdir);
1478 if (res->res_dir.tls_certfile) {
1479 free(res->res_dir.tls_certfile);
1481 if (res->res_dir.tls_keyfile) {
1482 free(res->res_dir.tls_keyfile);
1484 if (res->res_dir.tls_dhfile) {
1485 free(res->res_dir.tls_dhfile);
1487 if (res->res_dir.tls_allowed_cns) {
1488 delete res->res_dir.tls_allowed_cns;
1490 if (res->res_dir.verid) {
1491 free(res->res_dir.verid);
1498 if (res->res_con.password) {
1499 free(res->res_con.password);
1501 if (res->res_con.tls_ctx) {
1502 free_tls_context(res->res_con.tls_ctx);
1504 if (res->res_con.tls_ca_certfile) {
1505 free(res->res_con.tls_ca_certfile);
1507 if (res->res_con.tls_ca_certdir) {
1508 free(res->res_con.tls_ca_certdir);
1510 if (res->res_con.tls_certfile) {
1511 free(res->res_con.tls_certfile);
1513 if (res->res_con.tls_keyfile) {
1514 free(res->res_con.tls_keyfile);
1516 if (res->res_con.tls_dhfile) {
1517 free(res->res_con.tls_dhfile);
1519 if (res->res_con.tls_allowed_cns) {
1520 delete res->res_con.tls_allowed_cns;
1522 for (int i=0; i<Num_ACL; i++) {
1523 if (res->res_con.ACL_lists[i]) {
1524 delete res->res_con.ACL_lists[i];
1525 res->res_con.ACL_lists[i] = NULL;
1530 if (res->res_client.client_address) {
1531 free(res->res_client.client_address);
1533 if (res->res_client.fd_storage_address) {
1534 free(res->res_client.fd_storage_address);
1536 if (res->res_client.password) {
1537 free(res->res_client.password);
1539 if (res->res_client.tls_ctx) {
1540 free_tls_context(res->res_client.tls_ctx);
1542 if (res->res_client.tls_ca_certfile) {
1543 free(res->res_client.tls_ca_certfile);
1545 if (res->res_client.tls_ca_certdir) {
1546 free(res->res_client.tls_ca_certdir);
1548 if (res->res_client.tls_certfile) {
1549 free(res->res_client.tls_certfile);
1551 if (res->res_client.tls_keyfile) {
1552 free(res->res_client.tls_keyfile);
1554 if (res->res_client.tls_allowed_cns) {
1555 delete res->res_client.tls_allowed_cns;
1560 if (res->res_store.address) {
1561 free(res->res_store.address);
1563 if (res->res_store.fd_storage_address) {
1564 free(res->res_store.fd_storage_address);
1566 if (res->res_store.password) {
1567 free(res->res_store.password);
1569 if (res->res_store.media_type) {
1570 free(res->res_store.media_type);
1572 if (res->res_store.ac_group) {
1573 free_pool_memory(res->res_store.ac_group);
1575 if (res->res_store.device) {
1576 delete res->res_store.device;
1578 if (res->res_store.tls_ctx) {
1579 free_tls_context(res->res_store.tls_ctx);
1581 if (res->res_store.tls_ca_certfile) {
1582 free(res->res_store.tls_ca_certfile);
1584 if (res->res_store.tls_ca_certdir) {
1585 free(res->res_store.tls_ca_certdir);
1587 if (res->res_store.tls_certfile) {
1588 free(res->res_store.tls_certfile);
1590 if (res->res_store.tls_keyfile) {
1591 free(res->res_store.tls_keyfile);
1595 if (res->res_cat.db_address) {
1596 free(res->res_cat.db_address);
1598 if (res->res_cat.db_socket) {
1599 free(res->res_cat.db_socket);
1601 if (res->res_cat.db_user) {
1602 free(res->res_cat.db_user);
1604 if (res->res_cat.db_name) {
1605 free(res->res_cat.db_name);
1607 if (res->res_cat.db_driver) {
1608 free(res->res_cat.db_driver);
1610 if (res->res_cat.db_password) {
1611 free(res->res_cat.db_password);
1613 if (res->res_cat.db_ssl_mode) {
1614 free(res->res_cat.db_ssl_mode);
1616 if (res->res_cat.db_ssl_key) {
1617 free(res->res_cat.db_ssl_key);
1619 if (res->res_cat.db_ssl_cert) {
1620 free(res->res_cat.db_ssl_cert);
1622 if (res->res_cat.db_ssl_ca) {
1623 free(res->res_cat.db_ssl_ca);
1625 if (res->res_cat.db_ssl_capath) {
1626 free(res->res_cat.db_ssl_capath);
1628 if (res->res_cat.db_ssl_cipher) {
1629 free(res->res_cat.db_ssl_cipher);
1633 if ((num=res->res_fs.num_includes)) {
1634 while (--num >= 0) {
1635 free_incexe(res->res_fs.include_items[num]);
1637 free(res->res_fs.include_items);
1639 res->res_fs.num_includes = 0;
1640 if ((num=res->res_fs.num_excludes)) {
1641 while (--num >= 0) {
1642 free_incexe(res->res_fs.exclude_items[num]);
1644 free(res->res_fs.exclude_items);
1646 res->res_fs.num_excludes = 0;
1649 if (res->res_pool.pool_type) {
1650 free(res->res_pool.pool_type);
1652 if (res->res_pool.label_format) {
1653 free(res->res_pool.label_format);
1655 if (res->res_pool.cleaning_prefix) {
1656 free(res->res_pool.cleaning_prefix);
1658 if (res->res_pool.storage) {
1659 delete res->res_pool.storage;
1663 if (res->res_sch.run) {
1665 nrun = res->res_sch.run;
1675 if (res->res_job.RestoreWhere) {
1676 free(res->res_job.RestoreWhere);
1678 if (res->res_job.RegexWhere) {
1679 free(res->res_job.RegexWhere);
1681 if (res->res_job.strip_prefix) {
1682 free(res->res_job.strip_prefix);
1684 if (res->res_job.add_prefix) {
1685 free(res->res_job.add_prefix);
1687 if (res->res_job.add_suffix) {
1688 free(res->res_job.add_suffix);
1690 if (res->res_job.RestoreBootstrap) {
1691 free(res->res_job.RestoreBootstrap);
1693 if (res->res_job.WriteBootstrap) {
1694 free(res->res_job.WriteBootstrap);
1696 if (res->res_job.PluginOptions) {
1697 free(res->res_job.PluginOptions);
1699 if (res->res_job.selection_pattern) {
1700 free(res->res_job.selection_pattern);
1702 if (res->res_job.run_cmds) {
1703 delete res->res_job.run_cmds;
1705 if (res->res_job.storage) {
1706 delete res->res_job.storage;
1708 if (res->res_job.base) {
1709 delete res->res_job.base;
1711 if (res->res_job.RunScripts) {
1712 free_runscripts(res->res_job.RunScripts);
1713 delete res->res_job.RunScripts;
1717 if (res->res_msgs.mail_cmd) {
1718 free(res->res_msgs.mail_cmd);
1720 if (res->res_msgs.operator_cmd) {
1721 free(res->res_msgs.operator_cmd);
1723 free_msgs_res((MSGS *)res); /* free message resource */
1727 printf(_("Unknown resource type %d in free_resource.\n"), type);
1729 /* Common stuff again -- free the resource, recurse to next one */
1736 * Save the new resource by chaining it into the head list for
1737 * the resource. If this is pass 2, we update any resource
1738 * pointers because they may not have been defined until
1741 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
1744 int rindex = type - r_first;
1748 /* Check Job requirements after applying JobDefs */
1749 if (type != R_JOB && type != R_JOBDEFS) {
1751 * Ensure that all required items are present
1753 for (i=0; items[i].name; i++) {
1754 if (items[i].flags & ITEM_REQUIRED) {
1755 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1756 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1757 items[i].name, resources[rindex].name);
1761 /* If this triggers, take a look at lib/parse_conf.h */
1762 if (i >= MAX_RES_ITEMS) {
1763 Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
1767 } else if (type == R_JOB) {
1769 * Ensure that the name item is present
1771 if (items[0].flags & ITEM_REQUIRED) {
1772 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1773 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1774 items[0].name, resources[rindex].name);
1781 * During pass 2 in each "store" routine, we looked up pointers
1782 * to all the resources referrenced in the current resource, now we
1783 * must copy their addresses from the static record to the allocated
1788 /* Resources not containing a resource */
1796 * Resources containing another resource or alist. First
1797 * look up the resource which contains another resource. It
1798 * was written during pass 1. Then stuff in the pointers to
1799 * the resources it contains, which were inserted this pass.
1800 * Finally, it will all be stored back.
1803 /* Find resource saved in pass 1 */
1804 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1805 Mmsg(config->m_errmsg, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1808 /* Explicitly copy resource pointers from this pass (res_all) */
1809 res->res_pool.NextPool = res_all.res_pool.NextPool;
1810 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1811 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1812 res->res_pool.storage = res_all.res_pool.storage;
1813 res->res_pool.catalog = res_all.res_pool.catalog;
1816 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1817 Mmsg(config->m_errmsg, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1820 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1823 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1824 Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1827 res->res_dir.messages = res_all.res_dir.messages;
1828 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1830 case R_AUTOCHANGER: /* alias for R_STORAGE */
1832 type = R_STORAGE; /* force Storage type */
1833 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1834 Mmsg(config->m_errmsg, _("Cannot find Storage resource %s\n"),
1835 res_all.res_dir.hdr.name);
1838 /* we must explicitly copy the device alist pointer */
1839 res->res_store.device = res_all.res_store.device;
1840 res->res_store.changer = res_all.res_store.changer;
1841 res->res_store.shared_storage = res_all.res_store.shared_storage;
1842 res->res_store.autochanger = res_all.res_store.autochanger;
1843 if (strcasecmp(resources[rindex].name, "autochanger") == 0) {
1844 res->res_store.changer = &res->res_store;
1845 res->res_store.autochanger = true;
1850 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1851 Mmsg(config->m_errmsg, _("Cannot find Job resource %s\n"),
1852 res_all.res_dir.hdr.name);
1855 res->res_job.messages = res_all.res_job.messages;
1856 res->res_job.schedule = res_all.res_job.schedule;
1857 res->res_job.client = res_all.res_job.client;
1858 res->res_job.fileset = res_all.res_job.fileset;
1859 res->res_job.storage = res_all.res_job.storage;
1860 res->res_job.base = res_all.res_job.base;
1861 res->res_job.pool = res_all.res_job.pool;
1862 res->res_job.next_pool = res_all.res_job.next_pool;
1863 res->res_job.full_pool = res_all.res_job.full_pool;
1864 res->res_job.vfull_pool = res_all.res_job.vfull_pool;
1865 res->res_job.inc_pool = res_all.res_job.inc_pool;
1866 res->res_job.diff_pool = res_all.res_job.diff_pool;
1867 res->res_job.verify_job = res_all.res_job.verify_job;
1868 res->res_job.jobdefs = res_all.res_job.jobdefs;
1869 res->res_job.run_cmds = res_all.res_job.run_cmds;
1870 res->res_job.RunScripts = res_all.res_job.RunScripts;
1872 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1873 * is not very useful)
1874 * We have to set_bit(index, res_all.hdr.item_present);
1875 * or something like that
1878 /* we take RegexWhere before all other options */
1879 if (!res->res_job.RegexWhere
1881 (res->res_job.strip_prefix ||
1882 res->res_job.add_suffix ||
1883 res->res_job.add_prefix))
1885 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1886 res->res_job.add_prefix,
1887 res->res_job.add_suffix);
1888 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1889 bregexp_build_where(res->res_job.RegexWhere, len,
1890 res->res_job.strip_prefix,
1891 res->res_job.add_prefix,
1892 res->res_job.add_suffix);
1893 /* TODO: test bregexp */
1896 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1897 free(res->res_job.RestoreWhere);
1898 res->res_job.RestoreWhere = NULL;
1903 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1904 Mmsg(config->m_errmsg, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1907 res->res_counter.Catalog = res_all.res_counter.Catalog;
1908 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1912 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.name())) == NULL) {
1913 Mmsg(config->m_errmsg, _("Cannot find Client resource %s\n"), res_all.res_client.name());
1916 res->res_client.catalog = res_all.res_client.catalog;
1917 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1921 * Schedule is a bit different in that it contains a RUN record
1922 * chain which isn't a "named" resource. This chain was linked
1923 * in by run_conf.c during pass 2, so here we jam the pointer
1924 * into the Schedule resource.
1926 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.name())) == NULL) {
1927 Mmsg(config->m_errmsg, _("Cannot find Schedule resource %s\n"), res_all.res_client.name());
1930 res->res_sch.run = res_all.res_sch.run;
1933 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1937 /* Note, the resource name was already saved during pass 1,
1938 * so here, we can just release it.
1940 if (res_all.res_dir.hdr.name) {
1941 free(res_all.res_dir.hdr.name);
1942 res_all.res_dir.hdr.name = NULL;
1944 if (res_all.res_dir.hdr.desc) {
1945 free(res_all.res_dir.hdr.desc);
1946 res_all.res_dir.hdr.desc = NULL;
1951 /* R_AUTOCHANGER is alias so turn it into an R_STORAGE */
1952 if (type == R_AUTOCHANGER) {
1954 rindex = type - r_first;
1958 * The following code is only executed during pass 1
1962 size = sizeof(DIRRES);
1965 size = sizeof(CONRES);
1968 size =sizeof(CLIENT);
1971 size = sizeof(STORE);
1981 size = sizeof(FILESET);
1984 size = sizeof(SCHED);
1987 size = sizeof(POOL);
1990 size = sizeof(MSGS);
1993 size = sizeof(COUNTER);
1999 printf(_("Unknown resource type %d in save_resource.\n"), type);
2005 if (!config->insert_res(rindex, size)) {
2012 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
2014 uint32_t *destination = (uint32_t*)item->value;
2015 lex_get_token(lc, T_NAME);
2016 if (strcasecmp(lc->str, "truncate") == 0) {
2017 *destination = (*destination) | ON_PURGE_TRUNCATE;
2019 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
2023 set_bit(index, res_all.hdr.item_present);
2027 * Store an autochanger resource. Used by Autochanger and
2028 * SharedStorage direcives.
2030 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass)
2033 RES_ITEM *next = item + 1;
2035 lex_get_token(lc, T_NAME);
2036 Dmsg1(100, "Got name=%s\n", lc->str);
2038 * For backward compatibility, if yes/no, set the next item
2040 if (strcasecmp(item->name, "autochanger") == 0) {
2041 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2042 *(bool *)(next->value) = true;
2043 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2046 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2047 *(bool *)(next->value) = false;
2048 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2053 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2056 res = GetResWithName(R_STORAGE, lc->str);
2058 scan_err3(lc, _("Could not find Storage Resource %s referenced on line %d : %s\n"),
2059 lc->str, lc->line_no, lc->line);
2062 if (*(item->value)) {
2063 scan_err3(lc, _("Attempt to redefine Storage resource \"%s\" referenced on line %d : %s\n"),
2064 item->name, lc->line_no, lc->line);
2067 Dmsg2(100, "Store %s value=%p\n", lc->str, res);
2068 *(item->value) = (char *)res;
2069 *(bool *)(next->value) = true;
2072 set_bit(index, res_all.hdr.item_present);
2077 * Store Device. Note, the resource is created upon the
2078 * first reference. The details of the resource are obtained
2079 * later from the SD.
2081 void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
2083 int rindex = R_DEVICE - r_first;
2084 int size = sizeof(DEVICE);
2090 lex_get_token(lc, T_NAME);
2091 rblist *list = res_head[rindex]->res_list;
2092 ures = (URES *)malloc(size);
2093 memset(ures, 0, size);
2094 ures->res_dev.hdr.name = bstrdup(lc->str);
2096 if (list->empty()) {
2097 list->insert(res, res_compare);
2098 res_head[rindex]->first = res;
2099 res_head[rindex]->last = res;
2102 prev = res_head[rindex]->last;
2103 item = (RES *)list->insert(res, res_compare);
2105 prev->res_next = res;
2106 res_head[rindex]->last = res;
2108 /* res not inserted */
2109 free(ures->res_dev.hdr.name);
2114 set_bit(index, res_all.hdr.item_present);
2116 store_alist_res(lc, item, index, pass);
2121 * Store Migration/Copy type
2124 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
2128 lex_get_token(lc, T_NAME);
2129 /* Store the type both pass 1 and pass 2 */
2130 for (i=0; migtypes[i].type_name; i++) {
2131 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
2132 *(uint32_t *)(item->value) = migtypes[i].job_type;
2138 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
2141 set_bit(index, res_all.hdr.item_present);
2147 * Store JobType (backup, verify, restore)
2150 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
2154 lex_get_token(lc, T_NAME);
2155 /* Store the type both pass 1 and pass 2 */
2156 for (i=0; jobtypes[i].type_name; i++) {
2157 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
2158 *(uint32_t *)(item->value) = jobtypes[i].job_type;
2164 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
2167 set_bit(index, res_all.hdr.item_present);
2171 * Store Job Level (Full, Incremental, ...)
2174 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
2178 lex_get_token(lc, T_NAME);
2179 /* Store the level pass 2 so that type is defined */
2180 for (i=0; joblevels[i].level_name; i++) {
2181 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
2182 *(uint32_t *)(item->value) = joblevels[i].level;
2188 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
2191 set_bit(index, res_all.hdr.item_present);
2195 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
2198 lex_get_token(lc, T_NAME);
2199 /* Scan Replacement options */
2200 for (i=0; ReplaceOptions[i].name; i++) {
2201 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
2202 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
2208 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
2211 set_bit(index, res_all.hdr.item_present);
2215 * Store ACL (access control list)
2218 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
2223 lex_get_token(lc, T_STRING);
2225 if (((alist **)item->value)[item->code] == NULL) {
2226 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
2227 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
2229 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
2230 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
2232 token = lex_get_token(lc, T_ALL);
2233 if (token == T_COMMA) {
2234 continue; /* get another ACL */
2238 set_bit(index, res_all.hdr.item_present);
2241 /* We build RunScripts items here */
2242 static RUNSCRIPT res_runscript;
2244 /* Store a runscript->when in a bit field */
2245 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
2247 lex_get_token(lc, T_NAME);
2249 if (strcasecmp(lc->str, "before") == 0) {
2250 *(uint32_t *)(item->value) = SCRIPT_Before ;
2251 } else if (strcasecmp(lc->str, "after") == 0) {
2252 *(uint32_t *)(item->value) = SCRIPT_After;
2253 } else if (strcasecmp(lc->str, "aftervss") == 0) {
2254 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2255 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
2256 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2257 } else if (strcasecmp(lc->str, "always") == 0) {
2258 *(uint32_t *)(item->value) = SCRIPT_Any;
2260 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
2265 /* Store a runscript->target
2268 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
2270 lex_get_token(lc, T_STRING);
2273 if (strcmp(lc->str, "%c") == 0) {
2274 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2275 } else if (strcasecmp(lc->str, "yes") == 0) {
2276 ((RUNSCRIPT*) item->value)->set_target("%c");
2277 } else if (strcasecmp(lc->str, "no") == 0) {
2278 ((RUNSCRIPT*) item->value)->set_target("");
2280 RES *res = GetResWithName(R_CLIENT, lc->str);
2282 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
2283 lc->str, lc->line_no, lc->line);
2286 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2293 * Store a runscript->command as a string and runscript->cmd_type as a pointer
2295 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
2297 lex_get_token(lc, T_STRING);
2300 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
2301 POOLMEM *c = get_pool_memory(PM_FNAME);
2302 /* Each runscript command takes 2 entries in commands list */
2303 pm_strcpy(c, lc->str);
2304 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
2305 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
2310 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2312 lex_get_token(lc, T_STRING);
2313 alist **runscripts = (alist **)(item->value) ;
2316 RUNSCRIPT *script = new_runscript();
2317 script->set_job_code_callback(job_code_callback_director);
2319 script->set_command(lc->str);
2321 /* TODO: remove all script->old_proto with bacula 1.42 */
2323 if (strcasecmp(item->name, "runbeforejob") == 0) {
2324 script->when = SCRIPT_Before;
2325 script->fail_on_error = true;
2326 script->set_target("");
2328 } else if (strcasecmp(item->name, "runafterjob") == 0) {
2329 script->when = SCRIPT_After;
2330 script->on_success = true;
2331 script->on_failure = false;
2332 script->set_target("");
2334 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
2335 script->old_proto = true;
2336 script->when = SCRIPT_Before;
2337 script->set_target("%c");
2338 script->fail_on_error = true;
2340 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
2341 script->old_proto = true;
2342 script->when = SCRIPT_After;
2343 script->set_target("%c");
2344 script->on_success = true;
2345 script->on_failure = false;
2347 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2348 script->when = SCRIPT_Before;
2349 script->set_target("");
2350 script->fail_on_error = true;
2351 script->set_command(NPRT(script->command), CONSOLE_CMD);
2353 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2354 script->when = SCRIPT_After;
2355 script->set_target("");
2356 script->on_success = true;
2357 script->on_failure = false;
2358 script->set_command(NPRT(script->command), CONSOLE_CMD);
2360 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2361 script->when = SCRIPT_After;
2362 script->on_failure = true;
2363 script->on_success = false;
2364 script->set_target("");
2367 if (*runscripts == NULL) {
2368 *runscripts = New(alist(10, not_owned_by_alist));
2371 (*runscripts)->append(script);
2375 set_bit(index, res_all.hdr.item_present);
2378 /* Store a bool in a bit field without modifing res_all.hdr
2379 * We can also add an option to store_bool to skip res_all.hdr
2381 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2383 lex_get_token(lc, T_NAME);
2384 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2385 *(bool *)(item->value) = true;
2386 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2387 *(bool *)(item->value) = false;
2389 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2395 * new RunScript items
2396 * name handler value code flags default_value
2398 static RES_ITEM runscript_items[] = {
2399 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2400 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2401 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2402 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2403 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2404 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2405 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2406 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2407 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2408 {NULL, NULL, {0}, 0, 0, 0}
2412 * Store RunScript info
2414 * Note, when this routine is called, we are inside a Job
2415 * resource. We treat the RunScript like a sort of
2416 * mini-resource within the Job resource.
2418 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2422 alist **runscripts = (alist **)(item->value) ;
2424 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2426 token = lex_get_token(lc, T_SKIP_EOL);
2428 if (token != T_BOB) {
2429 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2431 /* setting on_success, on_failure, fail_on_error */
2432 res_runscript.reset_default();
2435 res_runscript.commands = New(alist(10, not_owned_by_alist));
2438 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2439 if (token == T_EOB) {
2442 if (token != T_IDENTIFIER) {
2443 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2445 for (i=0; runscript_items[i].name; i++) {
2446 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2447 token = lex_get_token(lc, T_SKIP_EOL);
2448 if (token != T_EQUALS) {
2449 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2452 /* Call item handler */
2453 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2460 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2465 /* run on client by default */
2466 if (res_runscript.target == NULL) {
2467 res_runscript.set_target("%c");
2469 if (*runscripts == NULL) {
2470 *runscripts = New(alist(10, not_owned_by_alist));
2473 * commands list contains 2 values per command
2474 * - POOLMEM command string (ex: /bin/true)
2475 * - int command type (ex: SHELL_CMD)
2477 res_runscript.set_job_code_callback(job_code_callback_director);
2478 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2479 t = (intptr_t)res_runscript.commands->pop();
2480 RUNSCRIPT *script = new_runscript();
2481 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2482 script->command = c;
2483 script->cmd_type = t;
2484 /* target is taken from res_runscript, each runscript object have
2487 script->target = NULL;
2488 script->set_target(res_runscript.target);
2490 (*runscripts)->append(script);
2493 delete res_runscript.commands;
2494 /* setting on_success, on_failure... cleanup target field */
2495 res_runscript.reset_default(true);
2499 set_bit(index, res_all.hdr.item_present);
2502 /* callback function for edit_job_codes */
2503 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2504 extern "C" char *job_code_callback_director(JCR *jcr, const char* param, char *buf, int buflen)
2506 static char yes[] = "yes";
2507 static char no[] = "no";
2508 static char nothing[] = "";
2516 return jcr->fileset->name();
2520 if (jcr->client && jcr->client->address()) {
2521 return jcr->client->address();
2526 return jcr->pool->name();
2531 return jcr->wstore->name();
2535 return jcr->spool_data ? yes : no;
2539 return jcr->cloned ? yes : no;
2543 edit_uint64(jcr->wjcr->JobId, buf);
2546 edit_uint64(0, buf);
2554 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2556 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2557 r_first, r_last, resources, &res_head);
2558 return config->parse_config();