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 client_globals.append(globals);
104 int32_t CLIENT::getNumConcurrentJobs()
109 return globals->NumConcurrentJobs;
112 void CLIENT::setNumConcurrentJobs(int32_t num)
116 create_client_globals();
117 /* Copy .conf IP address and Enabled */
118 globals->enabled = Enabled;
119 globals->SetIPaddress = bstrdup(client_address);
121 globals->NumConcurrentJobs = num;
124 Dmsg2(200, "Set NumConcurrentJobs=%ld for Client %s\n",
128 char *CLIENT::address()
131 return client_address;
133 if (!globals->SetIPaddress) {
134 return client_address;
136 return globals->SetIPaddress;
139 void CLIENT::setAddress(char *addr)
143 create_client_globals();
144 globals->enabled = Enabled; /* copy .conf variable */
146 if (globals->SetIPaddress) {
147 free(globals->SetIPaddress);
149 globals->SetIPaddress = bstrdup(addr);
153 bool CLIENT::is_enabled()
158 return globals->enabled;
161 void CLIENT::setEnabled(bool val)
165 create_client_globals();
166 globals->SetIPaddress = bstrdup(client_address); /* copy .conf variable */
168 globals->enabled = val;
170 Dmsg2(200, "Set Enabled=%d for Client %s\n",
174 void JOB::create_job_globals()
176 globals = (JOB_GLOBALS *)malloc(sizeof(JOB_GLOBALS));
177 memset(globals, 0, sizeof(JOB_GLOBALS));
178 globals->name = bstrdup(name());
179 job_globals.append(globals);
182 int32_t JOB::getNumConcurrentJobs()
187 return globals->NumConcurrentJobs;
190 void JOB::setNumConcurrentJobs(int32_t num)
194 create_job_globals();
195 globals->enabled = Enabled; /* copy .conf variable */
197 globals->NumConcurrentJobs = num;
200 Dmsg2(200, "Set NumConcurrentJobs=%ld for Job %s\n",
204 bool JOB::is_enabled()
209 return globals->enabled;
212 void JOB::setEnabled(bool val)
216 create_job_globals();
218 globals->enabled = val;
220 Dmsg2(200, "Set Enabled=%d for Job %s\n",
224 void STORE::create_store_globals()
226 globals = (STORE_GLOBALS *)malloc(sizeof(STORE_GLOBALS));
227 memset(globals, 0, sizeof(STORE_GLOBALS));
228 globals->name = bstrdup(name());
229 store_globals.append(globals);
232 int32_t STORE::getNumConcurrentReadJobs()
237 return globals->NumConcurrentReadJobs;
240 void STORE::setNumConcurrentReadJobs(int32_t num)
244 create_store_globals();
245 globals->enabled = Enabled; /* copy .conf variable */
247 globals->NumConcurrentReadJobs = num;
249 Dmsg2(200, "Set NumConcurrentReadJobs=%ld for Store %s\n",
254 int32_t STORE::getNumConcurrentJobs()
259 return globals->NumConcurrentJobs;
262 void STORE::setNumConcurrentJobs(int32_t num)
266 create_store_globals();
267 globals->enabled = Enabled; /* copy .conf variable */
269 globals->NumConcurrentJobs = num;
271 Dmsg2(200, "Set numconcurrentJobs=%ld for Store %s\n",
276 bool STORE::is_enabled()
281 return globals->enabled;
284 void STORE::setEnabled(bool val)
288 create_store_globals();
290 globals->enabled = val;
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 sched_globals.append(globals);
304 bool SCHED::is_enabled()
309 return globals->enabled;
312 void SCHED::setEnabled(bool val)
316 create_sched_globals();
318 globals->enabled = val;
320 Dmsg2(200, "Set Enabled=%d for Schedule %s\n",
325 * Definition of records permitted within each
326 * resource with the routine to process the record
327 * information. NOTE! quoted names must be in lower case.
332 * name handler value code flags default_value
334 static RES_ITEM dir_items[] = {
335 {"Name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
336 {"Description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
337 {"Messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
338 {"DirPort", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
339 {"DirAddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
340 {"DirAddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
341 {"DirSourceAddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
342 {"QueryFile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
343 {"WorkingDirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
344 {"PluginDirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
345 {"ScriptsDirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
346 {"PidDirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
347 {"SubsysDirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
348 {"MaximumConcurrentJobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 20},
349 {"MaximumReloadRequests", store_pint32, ITEM(res_dir.MaxReload), 0, ITEM_DEFAULT, 32},
350 {"MaximumConsoleConnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
351 {"Password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
352 {"FdConnectTimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
353 {"SdConnectTimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
354 {"HeartbeatInterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
355 {"TlsAuthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
356 {"TlsEnable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
357 {"TlsRequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
358 {"TlsVerifyPeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
359 {"TlsCaCertificateFile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
360 {"TlsCaCertificateDir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
361 {"TlsCertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
362 {"TlsKey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
363 {"TlsDhFile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
364 {"TlsAllowedCn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
365 {"StatisticsRetention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
366 {"VerId", store_str, ITEM(res_dir.verid), 0, 0, 0},
367 {"CommCompression", store_bool, ITEM(res_dir.comm_compression), 0, ITEM_DEFAULT, true},
368 {NULL, NULL, {0}, 0, 0, 0}
374 * name handler value code flags default_value
376 static RES_ITEM con_items[] = {
377 {"Name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
378 {"Description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
379 {"Password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
380 {"JobAcl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
381 {"ClientAcl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
382 {"StorageAcl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
383 {"ScheduleAcl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
384 {"RunAcl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
385 {"PoolAcl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
386 {"CommandAcl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
387 {"FilesetAcl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
388 {"CatalogAcl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
389 {"WhereAcl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
390 {"RestoreClientAcl", store_acl, ITEM(res_con.ACL_lists), RestoreClient_ACL, 0, 0},
391 {"BackupClientAcl", store_acl, ITEM(res_con.ACL_lists), BackupClient_ACL, 0, 0},
392 {"PluginOptionsAcl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
393 {"TlsAuthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
394 {"TlsEnable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
395 {"TlsRequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
396 {"TlsVerifyPeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
397 {"TlsCaCertificateFile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
398 {"TlsCaCertificateDir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
399 {"TlsCertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
400 {"TlsKey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
401 {"TlsDhFile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
402 {"TlsAllowedCn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
403 {NULL, NULL, {0}, 0, 0, 0}
408 * Client or File daemon resource
410 * name handler value code flags default_value
413 static RES_ITEM cli_items[] = {
414 {"Name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
415 {"Description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
416 {"fdaddress", store_str, ITEM(res_client.client_address), 0, 0, 0},
417 {"Address", store_str, ITEM(res_client.client_address), 0, ITEM_REQUIRED, 0},
418 {"FdPort", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
419 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
420 {"Password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
421 {"FdStorageAddress", store_str, ITEM(res_client.fd_storage_address), 0, 0, 0},
422 {"Catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
423 {"FileRetention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
424 {"JobRetention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
425 {"HeartbeatInterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
426 {"AutoPrune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
427 {"SDCallsClient", store_bool, ITEM(res_client.sd_calls_client), 0, ITEM_DEFAULT, false},
428 {"SnapshotRetention", store_time, ITEM(res_client.SnapRetention), 0, ITEM_DEFAULT, 0},
429 {"MaximumConcurrentJobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
430 {"TlsAuthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
431 {"TlsEnable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
432 {"TlsRequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
433 {"TlsCaCertificateFile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
434 {"TlsCaCertificateDir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
435 {"TlsCertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
436 {"TlsKey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
437 {"TlsAllowedCn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
438 {"MaximumBandwidthPerJob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
439 {"Enabled", store_bool, ITEM(res_client.Enabled), 0, ITEM_DEFAULT, true},
440 {NULL, NULL, {0}, 0, 0, 0}
443 /* Storage daemon resource
445 * name handler value code flags default_value
447 static RES_ITEM store_items[] = {
448 {"Name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
449 {"Description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
450 {"SdPort", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
451 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
452 {"Address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
453 {"FdStorageAddress", store_str, ITEM(res_store.fd_storage_address), 0, 0, 0},
454 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
455 {"Password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
456 {"Device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
457 {"MediaType", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
459 * Big kludge, these two autochanger definitions must be in
460 * this order and together.
462 {"Autochanger", store_ac_res, ITEM(res_store.changer), 0, ITEM_DEFAULT, 0},
463 {"Autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, false},
464 {"SharedStorage", store_ac_res, ITEM(res_store.shared_storage), 1, ITEM_DEFAULT, 0},
465 {"Enabled", store_bool, ITEM(res_store.Enabled), 0, ITEM_DEFAULT, true},
466 {"AllowCompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
467 {"HeartbeatInterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
468 {"MaximumConcurrentJobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
469 {"MaximumConcurrentReadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
470 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
471 {"TlsAuthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
472 {"TlsEnable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
473 {"TlsRequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
474 {"TlsCaCertificateFile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
475 {"TlsCaCertificateDir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
476 {"TlsCertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
477 {"TlsKey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
478 {NULL, NULL, {0}, 0, 0, 0}
482 * Catalog Resource Directives
484 * name handler value code flags default_value
486 static RES_ITEM cat_items[] = {
487 {"Name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
488 {"Description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
489 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
490 {"Address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
491 {"DbPort", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
492 /* keep this password as store_str for the moment */
493 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
494 {"Password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
495 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
496 {"User", store_str, ITEM(res_cat.db_user), 0, 0, 0},
497 {"DbName", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
498 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
499 {"dbsslkey", store_str, ITEM(res_cat.db_ssl_key), 0, 0, 0},
500 {"dbsslcert", store_str, ITEM(res_cat.db_ssl_cert), 0, 0, 0},
501 {"dbsslca", store_str, ITEM(res_cat.db_ssl_ca), 0, 0, 0},
502 {"dbsslcapath", store_str, ITEM(res_cat.db_ssl_capath), 0, 0, 0},
503 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
504 /* Turned off for the moment */
505 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
506 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
507 {NULL, NULL, {0}, 0, 0, 0}
511 * Job Resource Directives
513 * name handler value code flags default_value
515 RES_ITEM job_items[] = {
516 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
517 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
518 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
519 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
520 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
521 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
522 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
523 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
524 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
525 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
526 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
527 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
528 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
529 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
530 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
531 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
532 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
533 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
534 /* Root of where to restore files */
535 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
536 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
537 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
538 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
539 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
540 /* Where to find bootstrap during restore */
541 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
542 /* Where to write bootstrap file during backup */
543 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
544 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
545 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
546 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
547 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
548 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
549 /* xxxMaxWaitTime are deprecated */
550 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
551 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
552 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
553 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
554 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
555 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
556 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
557 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
558 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
559 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
560 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
561 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
562 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
563 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
564 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
565 {"Enabled", store_bool, ITEM(res_job.Enabled), 0, ITEM_DEFAULT, true},
566 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
567 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
568 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
569 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
570 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
571 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
573 * JSON tools skip Directive in lowercase. They are deprecated or
574 * are synonym with an other one that follows. Like User and dbuser.
576 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
577 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
578 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
579 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
580 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
581 {"consolerunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
582 {"consolerunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
583 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
584 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
585 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
586 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
587 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
588 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
589 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
590 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
591 {"BackupsToKeep", store_pint32, ITEM(res_job.BackupsToKeep), 0, ITEM_DEFAULT, 0},
592 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
593 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
594 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
595 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
596 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
597 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
598 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
599 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
600 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
601 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
602 {"DeleteConsolidatedJobs", store_bool, ITEM(res_job.DeleteConsolidatedJobs), 0, ITEM_DEFAULT, false},
603 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
604 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
605 {NULL, NULL, {0}, 0, 0, 0}
610 * Name handler value code flags default_value
612 static RES_ITEM fs_items[] = {
613 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
614 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
615 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
616 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
617 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
618 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
619 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
620 {NULL, NULL, {0}, 0, 0, 0}
623 /* Schedule -- see run_conf.c */
626 * name handler value code flags default_value
628 static RES_ITEM sch_items[] = {
629 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
630 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
631 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
632 {"Enabled", store_bool, ITEM(res_sch.Enabled), 0, ITEM_DEFAULT, true},
633 {NULL, NULL, {0}, 0, 0, 0}
638 * name handler value code flags default_value
640 static RES_ITEM pool_items[] = {
641 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
642 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
643 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
644 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
645 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
646 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
647 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
648 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
649 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
650 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
651 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
652 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
653 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
654 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
655 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
656 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
657 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
658 {"CacheRetention", store_time, ITEM(res_pool.CacheRetention), 0, 0, 0},
659 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
660 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
661 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
662 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
663 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
664 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
665 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
666 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
667 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
668 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
669 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
670 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
671 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
672 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
673 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
675 {NULL, NULL, {0}, 0, 0, 0}
680 * name handler value code flags default_value
682 static RES_ITEM counter_items[] = {
683 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
684 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
685 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
686 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
687 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
688 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
689 {NULL, NULL, {0}, 0, 0, 0}
693 /* Message resource */
694 extern RES_ITEM msgs_items[];
697 * This is the master resource definition.
698 * It must have one item for each of the resources.
700 * NOTE!!! keep it in the same order as the R_codes
701 * or eliminate all resources[rindex].name
705 RES_TABLE resources[] = {
706 {"Director", dir_items, R_DIRECTOR},
707 {"Client", cli_items, R_CLIENT},
708 {"Job", job_items, R_JOB},
709 {"Storage", store_items, R_STORAGE},
710 {"Catalog", cat_items, R_CATALOG},
711 {"Schedule", sch_items, R_SCHEDULE},
712 {"Fileset", fs_items, R_FILESET},
713 {"Pool", pool_items, R_POOL},
714 {"Messages", msgs_items, R_MSGS},
715 {"Counter", counter_items, R_COUNTER},
716 {"Console", con_items, R_CONSOLE},
717 {"JobDefs", job_items, R_JOBDEFS},
718 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
719 {"Autochanger", store_items, R_AUTOCHANGER}, /* alias for R_STORAGE */
724 /* Keywords (RHS) permitted in Job Level records
726 * level_name level job_type
728 struct s_jl joblevels[] = {
729 {"Full", L_FULL, JT_BACKUP},
730 {"Base", L_BASE, JT_BACKUP},
731 {"Incremental", L_INCREMENTAL, JT_BACKUP},
732 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
733 {"Since", L_SINCE, JT_BACKUP},
734 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
735 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
736 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
737 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
738 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
739 {"Data", L_VERIFY_DATA, JT_VERIFY},
740 {"Full", L_FULL, JT_COPY},
741 {"Incremental", L_INCREMENTAL, JT_COPY},
742 {"Differential", L_DIFFERENTIAL, JT_COPY},
743 {"Full", L_FULL, JT_MIGRATE},
744 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
745 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
746 {" ", L_NONE, JT_ADMIN},
747 {" ", L_NONE, JT_RESTORE},
752 /* Keywords (RHS) permitted in Job type records
757 {"Backup", JT_BACKUP},
759 {"Verify", JT_VERIFY},
760 {"Restore", JT_RESTORE},
761 {"Migrate", JT_MIGRATE},
767 /* Keywords (RHS) permitted in Selection type records
772 {"SmallestVolume", MT_SMALLEST_VOL},
773 {"OldestVolume", MT_OLDEST_VOL},
774 {"PoolOccupancy", MT_POOL_OCCUPANCY},
775 {"PoolTime", MT_POOL_TIME},
776 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
777 {"Client", MT_CLIENT},
778 {"Volume", MT_VOLUME},
780 {"SqlQuery", MT_SQLQUERY},
786 /* Options permitted in Restore replace= */
787 s_kw ReplaceOptions[] = {
788 {"Always", REPLACE_ALWAYS},
789 {"IfNewer", REPLACE_IFNEWER},
790 {"IfOlder", REPLACE_IFOLDER},
791 {"Never", REPLACE_NEVER},
795 char *CAT::display(POOLMEM *dst) {
796 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
797 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
799 name(), NPRTB(db_name),
800 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
801 NPRTB(db_address), db_port, NPRTB(db_socket));
805 const char *level_to_str(int level)
808 static char level_no[30];
809 const char *str = level_no;
811 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
812 for (i=0; joblevels[i].level_name; i++) {
813 if (level == (int)joblevels[i].level) {
814 str = joblevels[i].level_name;
821 /* Dump contents of resource */
822 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
825 URES *res = (URES *)ares;
827 char ed1[100], ed2[100], ed3[100];
829 UAContext *ua = (UAContext *)sock;
832 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
835 if (type < 0) { /* no recursion */
841 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
842 ares->name, res->res_dir.MaxConcurrentJobs,
843 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
844 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
845 if (res->res_dir.query_file) {
846 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
848 if (res->res_dir.messages) {
849 sendit(sock, _(" --> "));
850 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
854 sendit(sock, _("Console: name=%s SSL=%d\n"),
855 res->res_con.hdr.name, res->res_con.tls_enable);
858 if (res->res_counter.WrapCounter) {
859 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
860 res->res_counter.hdr.name, res->res_counter.MinValue,
861 res->res_counter.MaxValue, res->res_counter.CurrentValue,
862 res->res_counter.WrapCounter->hdr.name);
864 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
865 res->res_counter.hdr.name, res->res_counter.MinValue,
866 res->res_counter.MaxValue);
868 if (res->res_counter.Catalog) {
869 sendit(sock, _(" --> "));
870 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
875 if (!acl_access_ok(ua, Client_ACL, res->res_client.name())) {
878 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u NumJobs=%u\n"),
879 res->res_client.name(), res->res_client.is_enabled(),
880 res->res_client.address(), res->res_client.FDport,
881 res->res_client.MaxConcurrentJobs, res->res_client.getNumConcurrentJobs());
882 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
883 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
884 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
885 res->res_client.AutoPrune);
886 if (res->res_client.fd_storage_address) {
887 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
889 if (res->res_client.max_bandwidth) {
890 sendit(sock, _(" MaximumBandwidth=%lld\n"),
891 res->res_client.max_bandwidth);
893 if (res->res_client.catalog) {
894 sendit(sock, _(" --> "));
895 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
902 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
903 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
904 " poolid=%s volname=%s MediaType=%s\n"),
905 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
906 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
907 dev->offline, dev->autochanger,
908 edit_uint64(dev->PoolId, ed1),
909 dev->VolumeName, dev->MediaType);
914 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
917 sendit(sock, _("%s: name=%s address=%s SDport=%d MaxJobs=%u NumJobs=%u\n"
918 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
919 res->res_store.changer == &res->res_store ? "Autochanger" : "Storage",
920 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
921 res->res_store.MaxConcurrentJobs,
922 res->res_store.getNumConcurrentJobs(),
923 res->res_store.dev_name(),
924 res->res_store.media_type,
925 edit_int64(res->res_store.StorageId, ed1),
926 res->res_store.autochanger);
927 if (res->res_store.fd_storage_address) {
928 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
930 if (res->res_store.ac_group) {
931 STORE *shstore = res->res_store.shared_storage;
932 sendit(sock, " AC group=%s ShareStore=%s\n", res->res_store.ac_group,
933 shstore?shstore->name():"*none*");
935 if (res->res_store.changer && res->res_store.changer != &res->res_store) {
936 sendit(sock, _(" Parent --> "));
937 dump_resource(-R_STORAGE, (RES *)res->res_store.changer, sendit, sock);
942 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
945 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
946 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
947 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
948 res->res_cat.db_port, res->res_cat.db_name,
949 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
950 res->res_cat.mult_db_connections);
955 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
958 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
959 type == R_JOB ? _("Job") : _("JobDefs"),
960 res->res_job.hdr.name, res->res_job.JobType,
961 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
962 res->res_job.is_enabled());
963 sendit(sock, _(" MaxJobs=%u NumJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
964 res->res_job.MaxConcurrentJobs,
965 res->res_job.getNumConcurrentJobs(),
966 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
967 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
968 res->res_job.spool_data, res->res_job.write_part_after_job);
969 if (res->res_job.spool_size) {
970 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
972 if (res->res_job.JobType == JT_BACKUP) {
973 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
975 if (res->res_job.max_bandwidth) {
976 sendit(sock, _(" MaximumBandwidth=%lld\n"),
977 res->res_job.max_bandwidth);
979 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
980 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
982 if (res->res_job.JobType == JT_RESTORE) {
983 sendit(sock, _(" PrefixLinks=%d\n"), res->res_job.PrefixLinks);
985 if (res->res_job.client) {
986 sendit(sock, _(" --> "));
987 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
989 if (res->res_job.fileset) {
990 sendit(sock, _(" --> "));
991 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
993 if (res->res_job.schedule) {
994 sendit(sock, _(" --> "));
995 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
997 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
998 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
1000 if (res->res_job.RegexWhere) {
1001 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
1003 if (res->res_job.RestoreBootstrap) {
1004 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
1006 if (res->res_job.WriteBootstrap) {
1007 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
1009 if (res->res_job.PluginOptions) {
1010 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
1012 if (res->res_job.MaxRunTime) {
1013 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
1015 if (res->res_job.MaxWaitTime) {
1016 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
1018 if (res->res_job.MaxStartDelay) {
1019 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
1021 if (res->res_job.MaxRunSchedTime) {
1022 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
1024 if (res->res_job.storage) {
1026 foreach_alist(store, res->res_job.storage) {
1027 sendit(sock, _(" --> "));
1028 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1031 if (res->res_job.base) {
1033 foreach_alist(job, res->res_job.base) {
1034 sendit(sock, _(" --> Base %s\n"), job->name());
1037 if (res->res_job.RunScripts) {
1039 foreach_alist(script, res->res_job.RunScripts) {
1040 sendit(sock, _(" --> RunScript\n"));
1041 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
1042 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
1043 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
1044 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
1045 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
1046 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
1049 if (res->res_job.pool) {
1050 sendit(sock, _(" --> "));
1051 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
1053 if (res->res_job.full_pool) {
1054 sendit(sock, _(" --> FullBackup"));
1055 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
1057 if (res->res_job.inc_pool) {
1058 sendit(sock, _(" --> IncrementalBackup"));
1059 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
1061 if (res->res_job.diff_pool) {
1062 sendit(sock, _(" --> DifferentialBackup"));
1063 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
1065 if (res->res_job.next_pool) {
1066 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1067 dump_resource(-R_POOL, (RES *)res->res_job.next_pool, sendit, sock);
1069 if (res->res_job.JobType == JT_VERIFY && res->res_job.verify_job) {
1070 sendit(sock, _(" --> JobToVerify %s"), (RES *)res->res_job.verify_job->name());
1072 if (res->res_job.run_cmds) {
1074 foreach_alist(runcmd, res->res_job.run_cmds) {
1075 sendit(sock, _(" --> Run=%s\n"), runcmd);
1078 if (res->res_job.selection_pattern) {
1079 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
1081 if (res->res_job.messages) {
1082 sendit(sock, _(" --> "));
1083 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
1090 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
1093 sendit(sock, _("FileSet: name=%s IgnoreFileSetChanges=%d\n"), res->res_fs.hdr.name, res->res_fs.ignore_fs_changes);
1094 for (i=0; i<res->res_fs.num_includes; i++) {
1095 INCEXE *incexe = res->res_fs.include_items[i];
1096 for (j=0; j<incexe->num_opts; j++) {
1097 FOPTS *fo = incexe->opts_list[j];
1098 sendit(sock, " O %s\n", fo->opts);
1100 bool enhanced_wild = false;
1101 for (k=0; fo->opts[k]!='\0'; k++) {
1102 if (fo->opts[k]=='W') {
1103 enhanced_wild = true;
1108 for (k=0; k<fo->regex.size(); k++) {
1109 sendit(sock, " R %s\n", fo->regex.get(k));
1111 for (k=0; k<fo->regexdir.size(); k++) {
1112 sendit(sock, " RD %s\n", fo->regexdir.get(k));
1114 for (k=0; k<fo->regexfile.size(); k++) {
1115 sendit(sock, " RF %s\n", fo->regexfile.get(k));
1117 for (k=0; k<fo->wild.size(); k++) {
1118 sendit(sock, " W %s\n", fo->wild.get(k));
1120 for (k=0; k<fo->wilddir.size(); k++) {
1121 sendit(sock, " WD %s\n", fo->wilddir.get(k));
1123 for (k=0; k<fo->wildfile.size(); k++) {
1124 sendit(sock, " WF %s\n", fo->wildfile.get(k));
1126 for (k=0; k<fo->wildbase.size(); k++) {
1127 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
1129 for (k=0; k<fo->base.size(); k++) {
1130 sendit(sock, " B %s\n", fo->base.get(k));
1132 for (k=0; k<fo->fstype.size(); k++) {
1133 sendit(sock, " X %s\n", fo->fstype.get(k));
1135 for (k=0; k<fo->drivetype.size(); k++) {
1136 sendit(sock, " XD %s\n", fo->drivetype.get(k));
1139 sendit(sock, " G %s\n", fo->plugin);
1142 sendit(sock, " D %s\n", fo->reader);
1145 sendit(sock, " T %s\n", fo->writer);
1147 sendit(sock, " N\n");
1149 if (incexe->ignoredir) {
1150 sendit(sock, " Z %s\n", incexe->ignoredir);
1152 for (j=0; j<incexe->name_list.size(); j++) {
1153 sendit(sock, " I %s\n", incexe->name_list.get(j));
1155 if (incexe->name_list.size()) {
1156 sendit(sock, " N\n");
1158 for (j=0; j<incexe->plugin_list.size(); j++) {
1159 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
1161 if (incexe->plugin_list.size()) {
1162 sendit(sock, " N\n");
1164 } /* end for over includes */
1166 for (i=0; i<res->res_fs.num_excludes; i++) {
1167 INCEXE *incexe = res->res_fs.exclude_items[i];
1168 for (j=0; j<incexe->name_list.size(); j++) {
1169 sendit(sock, " E %s\n", incexe->name_list.get(j));
1171 if (incexe->name_list.size()) {
1172 sendit(sock, " N\n");
1176 } /* end case R_FILESET */
1179 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
1183 if (res->res_sch.run) {
1185 RUN *run = res->res_sch.run;
1186 char buf[1000], num[30];
1187 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
1188 res->res_sch.hdr.name, res->res_sch.is_enabled());
1193 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
1194 if (run->MaxRunSchedTime) {
1195 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
1197 if (run->Priority) {
1198 sendit(sock, _(" Priority=%u\n"), run->Priority);
1200 bstrncpy(buf, _(" hour="), sizeof(buf));
1201 for (i=0; i<24; i++) {
1202 if (bit_is_set(i, run->hour)) {
1203 bsnprintf(num, sizeof(num), "%d ", i);
1204 bstrncat(buf, num, sizeof(buf));
1207 bstrncat(buf, "\n", sizeof(buf));
1209 bstrncpy(buf, _(" mday="), sizeof(buf));
1210 for (i=0; i<32; i++) {
1211 if (bit_is_set(i, run->mday)) {
1212 bsnprintf(num, sizeof(num), "%d ", i);
1213 bstrncat(buf, num, sizeof(buf));
1216 bstrncat(buf, "\n", sizeof(buf));
1218 bstrncpy(buf, _(" month="), sizeof(buf));
1219 for (i=0; i<12; i++) {
1220 if (bit_is_set(i, run->month)) {
1221 bsnprintf(num, sizeof(num), "%d ", i);
1222 bstrncat(buf, num, sizeof(buf));
1225 bstrncat(buf, "\n", sizeof(buf));
1227 bstrncpy(buf, _(" wday="), sizeof(buf));
1228 for (i=0; i<7; i++) {
1229 if (bit_is_set(i, run->wday)) {
1230 bsnprintf(num, sizeof(num), "%d ", i);
1231 bstrncat(buf, num, sizeof(buf));
1234 bstrncat(buf, "\n", sizeof(buf));
1236 bstrncpy(buf, _(" wom="), sizeof(buf));
1237 for (i=0; i<6; i++) {
1238 if (bit_is_set(i, run->wom)) {
1239 bsnprintf(num, sizeof(num), "%d ", i);
1240 bstrncat(buf, num, sizeof(buf));
1243 bstrncat(buf, "\n", sizeof(buf));
1245 bstrncpy(buf, _(" woy="), sizeof(buf));
1246 for (i=0; i<54; i++) {
1247 if (bit_is_set(i, run->woy)) {
1248 bsnprintf(num, sizeof(num), "%d ", i);
1249 bstrncat(buf, num, sizeof(buf));
1252 bstrncat(buf, "\n", sizeof(buf));
1254 sendit(sock, _(" mins=%d\n"), run->minute);
1256 sendit(sock, _(" --> "));
1257 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
1259 if (run->next_pool) {
1260 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1261 dump_resource(-R_POOL, (RES *)run->next_pool, sendit, sock);
1264 sendit(sock, _(" --> "));
1265 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
1268 sendit(sock, _(" --> "));
1269 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
1271 /* If another Run record is chained in, go print it */
1277 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1282 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1285 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1286 res->res_pool.pool_type);
1287 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1288 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1289 res->res_pool.catalog_files);
1290 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1291 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1292 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1293 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1294 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1295 res->res_pool.Recycle,
1296 NPRT(res->res_pool.label_format));
1297 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1298 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1299 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1300 res->res_pool.recycle_oldest_volume,
1301 res->res_pool.purge_oldest_volume,
1302 res->res_pool.action_on_purge);
1303 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1304 res->res_pool.MaxVolJobs,
1305 res->res_pool.MaxVolFiles,
1306 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1307 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1308 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1309 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1310 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1311 sendit(sock, _(" CacheRetention=%s\n"),
1312 edit_utime(res->res_pool.CacheRetention, ed1, sizeof(ed1)));
1313 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1314 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1315 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1316 if (res->res_pool.NextPool) {
1317 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1319 if (res->res_pool.RecyclePool) {
1320 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1322 if (res->res_pool.ScratchPool) {
1323 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1325 if (res->res_pool.catalog) {
1326 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1328 if (res->res_pool.storage) {
1330 foreach_alist(store, res->res_pool.storage) {
1331 sendit(sock, _(" --> "));
1332 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1335 if (res->res_pool.CopyPool) {
1337 foreach_alist(copy, res->res_pool.CopyPool) {
1338 sendit(sock, _(" --> "));
1339 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1346 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1347 if (res->res_msgs.mail_cmd)
1348 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1349 if (res->res_msgs.operator_cmd)
1350 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1354 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1358 next = GetNextRes(0, (RES *)res);
1360 dump_resource(type, next, sendit, sock);
1366 * Free all the members of an INCEXE structure
1368 static void free_incexe(INCEXE *incexe)
1370 incexe->name_list.destroy();
1371 incexe->plugin_list.destroy();
1372 for (int i=0; i<incexe->num_opts; i++) {
1373 FOPTS *fopt = incexe->opts_list[i];
1374 fopt->regex.destroy();
1375 fopt->regexdir.destroy();
1376 fopt->regexfile.destroy();
1377 fopt->wild.destroy();
1378 fopt->wilddir.destroy();
1379 fopt->wildfile.destroy();
1380 fopt->wildbase.destroy();
1381 fopt->base.destroy();
1382 fopt->fstype.destroy();
1383 fopt->drivetype.destroy();
1395 if (incexe->opts_list) {
1396 free(incexe->opts_list);
1398 if (incexe->ignoredir) {
1399 free(incexe->ignoredir);
1406 * Free memory of resource -- called when daemon terminates.
1407 * NB, we don't need to worry about freeing any references
1408 * to other resources as they will be freed when that
1409 * resource chain is traversed. Mainly we worry about freeing
1410 * allocated strings (names).
1412 void free_resource(RES *rres, int type)
1415 URES *res = (URES *)rres;
1421 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1422 /* common stuff -- free the resource name and description */
1423 if (res->res_dir.hdr.name) {
1424 free(res->res_dir.hdr.name);
1426 if (res->res_dir.hdr.desc) {
1427 free(res->res_dir.hdr.desc);
1432 if (res->res_dir.working_directory) {
1433 free(res->res_dir.working_directory);
1435 if (res->res_dir.scripts_directory) {
1436 free((char *)res->res_dir.scripts_directory);
1438 if (res->res_dir.plugin_directory) {
1439 free((char *)res->res_dir.plugin_directory);
1441 if (res->res_dir.pid_directory) {
1442 free(res->res_dir.pid_directory);
1444 if (res->res_dir.subsys_directory) {
1445 free(res->res_dir.subsys_directory);
1447 if (res->res_dir.password) {
1448 free(res->res_dir.password);
1450 if (res->res_dir.query_file) {
1451 free(res->res_dir.query_file);
1453 if (res->res_dir.DIRaddrs) {
1454 free_addresses(res->res_dir.DIRaddrs);
1456 if (res->res_dir.DIRsrc_addr) {
1457 free_addresses(res->res_dir.DIRsrc_addr);
1459 if (res->res_dir.tls_ctx) {
1460 free_tls_context(res->res_dir.tls_ctx);
1462 if (res->res_dir.tls_ca_certfile) {
1463 free(res->res_dir.tls_ca_certfile);
1465 if (res->res_dir.tls_ca_certdir) {
1466 free(res->res_dir.tls_ca_certdir);
1468 if (res->res_dir.tls_certfile) {
1469 free(res->res_dir.tls_certfile);
1471 if (res->res_dir.tls_keyfile) {
1472 free(res->res_dir.tls_keyfile);
1474 if (res->res_dir.tls_dhfile) {
1475 free(res->res_dir.tls_dhfile);
1477 if (res->res_dir.tls_allowed_cns) {
1478 delete res->res_dir.tls_allowed_cns;
1480 if (res->res_dir.verid) {
1481 free(res->res_dir.verid);
1488 if (res->res_con.password) {
1489 free(res->res_con.password);
1491 if (res->res_con.tls_ctx) {
1492 free_tls_context(res->res_con.tls_ctx);
1494 if (res->res_con.tls_ca_certfile) {
1495 free(res->res_con.tls_ca_certfile);
1497 if (res->res_con.tls_ca_certdir) {
1498 free(res->res_con.tls_ca_certdir);
1500 if (res->res_con.tls_certfile) {
1501 free(res->res_con.tls_certfile);
1503 if (res->res_con.tls_keyfile) {
1504 free(res->res_con.tls_keyfile);
1506 if (res->res_con.tls_dhfile) {
1507 free(res->res_con.tls_dhfile);
1509 if (res->res_con.tls_allowed_cns) {
1510 delete res->res_con.tls_allowed_cns;
1512 for (int i=0; i<Num_ACL; i++) {
1513 if (res->res_con.ACL_lists[i]) {
1514 delete res->res_con.ACL_lists[i];
1515 res->res_con.ACL_lists[i] = NULL;
1520 if (res->res_client.client_address) {
1521 free(res->res_client.client_address);
1523 if (res->res_client.fd_storage_address) {
1524 free(res->res_client.fd_storage_address);
1526 if (res->res_client.password) {
1527 free(res->res_client.password);
1529 if (res->res_client.tls_ctx) {
1530 free_tls_context(res->res_client.tls_ctx);
1532 if (res->res_client.tls_ca_certfile) {
1533 free(res->res_client.tls_ca_certfile);
1535 if (res->res_client.tls_ca_certdir) {
1536 free(res->res_client.tls_ca_certdir);
1538 if (res->res_client.tls_certfile) {
1539 free(res->res_client.tls_certfile);
1541 if (res->res_client.tls_keyfile) {
1542 free(res->res_client.tls_keyfile);
1544 if (res->res_client.tls_allowed_cns) {
1545 delete res->res_client.tls_allowed_cns;
1550 if (res->res_store.address) {
1551 free(res->res_store.address);
1553 if (res->res_store.fd_storage_address) {
1554 free(res->res_store.fd_storage_address);
1556 if (res->res_store.password) {
1557 free(res->res_store.password);
1559 if (res->res_store.media_type) {
1560 free(res->res_store.media_type);
1562 if (res->res_store.ac_group) {
1563 free_pool_memory(res->res_store.ac_group);
1565 if (res->res_store.device) {
1566 delete res->res_store.device;
1568 if (res->res_store.tls_ctx) {
1569 free_tls_context(res->res_store.tls_ctx);
1571 if (res->res_store.tls_ca_certfile) {
1572 free(res->res_store.tls_ca_certfile);
1574 if (res->res_store.tls_ca_certdir) {
1575 free(res->res_store.tls_ca_certdir);
1577 if (res->res_store.tls_certfile) {
1578 free(res->res_store.tls_certfile);
1580 if (res->res_store.tls_keyfile) {
1581 free(res->res_store.tls_keyfile);
1585 if (res->res_cat.db_address) {
1586 free(res->res_cat.db_address);
1588 if (res->res_cat.db_socket) {
1589 free(res->res_cat.db_socket);
1591 if (res->res_cat.db_user) {
1592 free(res->res_cat.db_user);
1594 if (res->res_cat.db_name) {
1595 free(res->res_cat.db_name);
1597 if (res->res_cat.db_driver) {
1598 free(res->res_cat.db_driver);
1600 if (res->res_cat.db_password) {
1601 free(res->res_cat.db_password);
1603 if (res->res_cat.db_ssl_key) {
1604 free(res->res_cat.db_ssl_key);
1606 if (res->res_cat.db_ssl_cert) {
1607 free(res->res_cat.db_ssl_cert);
1609 if (res->res_cat.db_ssl_ca) {
1610 free(res->res_cat.db_ssl_ca);
1612 if (res->res_cat.db_ssl_capath) {
1613 free(res->res_cat.db_ssl_capath);
1615 if (res->res_cat.db_ssl_cipher) {
1616 free(res->res_cat.db_ssl_cipher);
1620 if ((num=res->res_fs.num_includes)) {
1621 while (--num >= 0) {
1622 free_incexe(res->res_fs.include_items[num]);
1624 free(res->res_fs.include_items);
1626 res->res_fs.num_includes = 0;
1627 if ((num=res->res_fs.num_excludes)) {
1628 while (--num >= 0) {
1629 free_incexe(res->res_fs.exclude_items[num]);
1631 free(res->res_fs.exclude_items);
1633 res->res_fs.num_excludes = 0;
1636 if (res->res_pool.pool_type) {
1637 free(res->res_pool.pool_type);
1639 if (res->res_pool.label_format) {
1640 free(res->res_pool.label_format);
1642 if (res->res_pool.cleaning_prefix) {
1643 free(res->res_pool.cleaning_prefix);
1645 if (res->res_pool.storage) {
1646 delete res->res_pool.storage;
1650 if (res->res_sch.run) {
1652 nrun = res->res_sch.run;
1662 if (res->res_job.RestoreWhere) {
1663 free(res->res_job.RestoreWhere);
1665 if (res->res_job.RegexWhere) {
1666 free(res->res_job.RegexWhere);
1668 if (res->res_job.strip_prefix) {
1669 free(res->res_job.strip_prefix);
1671 if (res->res_job.add_prefix) {
1672 free(res->res_job.add_prefix);
1674 if (res->res_job.add_suffix) {
1675 free(res->res_job.add_suffix);
1677 if (res->res_job.RestoreBootstrap) {
1678 free(res->res_job.RestoreBootstrap);
1680 if (res->res_job.WriteBootstrap) {
1681 free(res->res_job.WriteBootstrap);
1683 if (res->res_job.PluginOptions) {
1684 free(res->res_job.PluginOptions);
1686 if (res->res_job.selection_pattern) {
1687 free(res->res_job.selection_pattern);
1689 if (res->res_job.run_cmds) {
1690 delete res->res_job.run_cmds;
1692 if (res->res_job.storage) {
1693 delete res->res_job.storage;
1695 if (res->res_job.base) {
1696 delete res->res_job.base;
1698 if (res->res_job.RunScripts) {
1699 free_runscripts(res->res_job.RunScripts);
1700 delete res->res_job.RunScripts;
1704 if (res->res_msgs.mail_cmd) {
1705 free(res->res_msgs.mail_cmd);
1707 if (res->res_msgs.operator_cmd) {
1708 free(res->res_msgs.operator_cmd);
1710 free_msgs_res((MSGS *)res); /* free message resource */
1714 printf(_("Unknown resource type %d in free_resource.\n"), type);
1716 /* Common stuff again -- free the resource, recurse to next one */
1723 * Save the new resource by chaining it into the head list for
1724 * the resource. If this is pass 2, we update any resource
1725 * pointers because they may not have been defined until
1728 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
1731 int rindex = type - r_first;
1735 /* Check Job requirements after applying JobDefs */
1736 if (type != R_JOB && type != R_JOBDEFS) {
1738 * Ensure that all required items are present
1740 for (i=0; items[i].name; i++) {
1741 if (items[i].flags & ITEM_REQUIRED) {
1742 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1743 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1744 items[i].name, resources[rindex].name);
1748 /* If this triggers, take a look at lib/parse_conf.h */
1749 if (i >= MAX_RES_ITEMS) {
1750 Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
1754 } else if (type == R_JOB) {
1756 * Ensure that the name item is present
1758 if (items[0].flags & ITEM_REQUIRED) {
1759 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1760 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1761 items[0].name, resources[rindex].name);
1768 * During pass 2 in each "store" routine, we looked up pointers
1769 * to all the resources referrenced in the current resource, now we
1770 * must copy their addresses from the static record to the allocated
1775 /* Resources not containing a resource */
1783 * Resources containing another resource or alist. First
1784 * look up the resource which contains another resource. It
1785 * was written during pass 1. Then stuff in the pointers to
1786 * the resources it contains, which were inserted this pass.
1787 * Finally, it will all be stored back.
1790 /* Find resource saved in pass 1 */
1791 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1792 Mmsg(config->m_errmsg, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1795 /* Explicitly copy resource pointers from this pass (res_all) */
1796 res->res_pool.NextPool = res_all.res_pool.NextPool;
1797 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1798 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1799 res->res_pool.storage = res_all.res_pool.storage;
1800 res->res_pool.catalog = res_all.res_pool.catalog;
1803 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1804 Mmsg(config->m_errmsg, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1807 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1810 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1811 Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1814 res->res_dir.messages = res_all.res_dir.messages;
1815 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1817 case R_AUTOCHANGER: /* alias for R_STORAGE */
1819 type = R_STORAGE; /* force Storage type */
1820 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1821 Mmsg(config->m_errmsg, _("Cannot find Storage resource %s\n"),
1822 res_all.res_dir.hdr.name);
1825 /* we must explicitly copy the device alist pointer */
1826 res->res_store.device = res_all.res_store.device;
1827 res->res_store.changer = res_all.res_store.changer;
1828 res->res_store.shared_storage = res_all.res_store.shared_storage;
1829 res->res_store.autochanger = res_all.res_store.autochanger;
1830 if (strcasecmp(resources[rindex].name, "autochanger") == 0) {
1831 res->res_store.changer = &res->res_store;
1832 res->res_store.autochanger = true;
1837 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1838 Mmsg(config->m_errmsg, _("Cannot find Job resource %s\n"),
1839 res_all.res_dir.hdr.name);
1842 res->res_job.messages = res_all.res_job.messages;
1843 res->res_job.schedule = res_all.res_job.schedule;
1844 res->res_job.client = res_all.res_job.client;
1845 res->res_job.fileset = res_all.res_job.fileset;
1846 res->res_job.storage = res_all.res_job.storage;
1847 res->res_job.base = res_all.res_job.base;
1848 res->res_job.pool = res_all.res_job.pool;
1849 res->res_job.next_pool = res_all.res_job.next_pool;
1850 res->res_job.full_pool = res_all.res_job.full_pool;
1851 res->res_job.inc_pool = res_all.res_job.inc_pool;
1852 res->res_job.diff_pool = res_all.res_job.diff_pool;
1853 res->res_job.verify_job = res_all.res_job.verify_job;
1854 res->res_job.jobdefs = res_all.res_job.jobdefs;
1855 res->res_job.run_cmds = res_all.res_job.run_cmds;
1856 res->res_job.RunScripts = res_all.res_job.RunScripts;
1858 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1859 * is not very useful)
1860 * We have to set_bit(index, res_all.hdr.item_present);
1861 * or something like that
1864 /* we take RegexWhere before all other options */
1865 if (!res->res_job.RegexWhere
1867 (res->res_job.strip_prefix ||
1868 res->res_job.add_suffix ||
1869 res->res_job.add_prefix))
1871 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1872 res->res_job.add_prefix,
1873 res->res_job.add_suffix);
1874 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1875 bregexp_build_where(res->res_job.RegexWhere, len,
1876 res->res_job.strip_prefix,
1877 res->res_job.add_prefix,
1878 res->res_job.add_suffix);
1879 /* TODO: test bregexp */
1882 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1883 free(res->res_job.RestoreWhere);
1884 res->res_job.RestoreWhere = NULL;
1889 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1890 Mmsg(config->m_errmsg, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1893 res->res_counter.Catalog = res_all.res_counter.Catalog;
1894 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1898 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.name())) == NULL) {
1899 Mmsg(config->m_errmsg, _("Cannot find Client resource %s\n"), res_all.res_client.name());
1902 res->res_client.catalog = res_all.res_client.catalog;
1903 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1907 * Schedule is a bit different in that it contains a RUN record
1908 * chain which isn't a "named" resource. This chain was linked
1909 * in by run_conf.c during pass 2, so here we jam the pointer
1910 * into the Schedule resource.
1912 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.name())) == NULL) {
1913 Mmsg(config->m_errmsg, _("Cannot find Schedule resource %s\n"), res_all.res_client.name());
1916 res->res_sch.run = res_all.res_sch.run;
1919 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1923 /* Note, the resource name was already saved during pass 1,
1924 * so here, we can just release it.
1926 if (res_all.res_dir.hdr.name) {
1927 free(res_all.res_dir.hdr.name);
1928 res_all.res_dir.hdr.name = NULL;
1930 if (res_all.res_dir.hdr.desc) {
1931 free(res_all.res_dir.hdr.desc);
1932 res_all.res_dir.hdr.desc = NULL;
1937 /* R_AUTOCHANGER is alias so turn it into an R_STORAGE */
1938 if (type == R_AUTOCHANGER) {
1940 rindex = type - r_first;
1944 * The following code is only executed during pass 1
1948 size = sizeof(DIRRES);
1951 size = sizeof(CONRES);
1954 size =sizeof(CLIENT);
1957 size = sizeof(STORE);
1967 size = sizeof(FILESET);
1970 size = sizeof(SCHED);
1973 size = sizeof(POOL);
1976 size = sizeof(MSGS);
1979 size = sizeof(COUNTER);
1985 printf(_("Unknown resource type %d in save_resource.\n"), type);
1991 if (!config->insert_res(rindex, size)) {
1998 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
2000 uint32_t *destination = (uint32_t*)item->value;
2001 lex_get_token(lc, T_NAME);
2002 if (strcasecmp(lc->str, "truncate") == 0) {
2003 *destination = (*destination) | ON_PURGE_TRUNCATE;
2005 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
2009 set_bit(index, res_all.hdr.item_present);
2013 * Store an autochanger resource. Used by Autochanger and
2014 * SharedStorage direcives.
2016 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass)
2019 RES_ITEM *next = item + 1;
2021 lex_get_token(lc, T_NAME);
2022 Dmsg1(100, "Got name=%s\n", lc->str);
2024 * For backward compatibility, if yes/no, set the next item
2026 if (strcasecmp(item->name, "autochanger") == 0) {
2027 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2028 *(bool *)(next->value) = true;
2029 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2032 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2033 *(bool *)(next->value) = false;
2034 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2039 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2042 res = GetResWithName(R_STORAGE, lc->str);
2044 scan_err3(lc, _("Could not find Storage Resource %s referenced on line %d : %s\n"),
2045 lc->str, lc->line_no, lc->line);
2048 if (*(item->value)) {
2049 scan_err3(lc, _("Attempt to redefine Storage resource \"%s\" referenced on line %d : %s\n"),
2050 item->name, lc->line_no, lc->line);
2053 Dmsg2(100, "Store %s value=%p\n", lc->str, res);
2054 *(item->value) = (char *)res;
2055 *(bool *)(next->value) = true;
2058 set_bit(index, res_all.hdr.item_present);
2063 * Store Device. Note, the resource is created upon the
2064 * first reference. The details of the resource are obtained
2065 * later from the SD.
2067 void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
2069 int rindex = R_DEVICE - r_first;
2070 int size = sizeof(DEVICE);
2076 lex_get_token(lc, T_NAME);
2077 rblist *list = res_head[rindex]->res_list;
2078 ures = (URES *)malloc(size);
2079 memset(ures, 0, size);
2080 ures->res_dev.hdr.name = bstrdup(lc->str);
2082 if (list->empty()) {
2083 list->insert(res, res_compare);
2084 res_head[rindex]->first = res;
2085 res_head[rindex]->last = res;
2088 prev = res_head[rindex]->last;
2089 item = (RES *)list->insert(res, res_compare);
2091 prev->res_next = res;
2092 res_head[rindex]->last = res;
2094 /* res not inserted */
2095 free(ures->res_dev.hdr.name);
2100 set_bit(index, res_all.hdr.item_present);
2102 store_alist_res(lc, item, index, pass);
2107 * Store Migration/Copy type
2110 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
2114 lex_get_token(lc, T_NAME);
2115 /* Store the type both pass 1 and pass 2 */
2116 for (i=0; migtypes[i].type_name; i++) {
2117 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
2118 *(uint32_t *)(item->value) = migtypes[i].job_type;
2124 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
2127 set_bit(index, res_all.hdr.item_present);
2133 * Store JobType (backup, verify, restore)
2136 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
2140 lex_get_token(lc, T_NAME);
2141 /* Store the type both pass 1 and pass 2 */
2142 for (i=0; jobtypes[i].type_name; i++) {
2143 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
2144 *(uint32_t *)(item->value) = jobtypes[i].job_type;
2150 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
2153 set_bit(index, res_all.hdr.item_present);
2157 * Store Job Level (Full, Incremental, ...)
2160 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
2164 lex_get_token(lc, T_NAME);
2165 /* Store the level pass 2 so that type is defined */
2166 for (i=0; joblevels[i].level_name; i++) {
2167 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
2168 *(uint32_t *)(item->value) = joblevels[i].level;
2174 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
2177 set_bit(index, res_all.hdr.item_present);
2181 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
2184 lex_get_token(lc, T_NAME);
2185 /* Scan Replacement options */
2186 for (i=0; ReplaceOptions[i].name; i++) {
2187 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
2188 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
2194 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
2197 set_bit(index, res_all.hdr.item_present);
2201 * Store ACL (access control list)
2204 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
2209 lex_get_token(lc, T_STRING);
2211 if (((alist **)item->value)[item->code] == NULL) {
2212 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
2213 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
2215 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
2216 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
2218 token = lex_get_token(lc, T_ALL);
2219 if (token == T_COMMA) {
2220 continue; /* get another ACL */
2224 set_bit(index, res_all.hdr.item_present);
2227 /* We build RunScripts items here */
2228 static RUNSCRIPT res_runscript;
2230 /* Store a runscript->when in a bit field */
2231 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
2233 lex_get_token(lc, T_NAME);
2235 if (strcasecmp(lc->str, "before") == 0) {
2236 *(uint32_t *)(item->value) = SCRIPT_Before ;
2237 } else if (strcasecmp(lc->str, "after") == 0) {
2238 *(uint32_t *)(item->value) = SCRIPT_After;
2239 } else if (strcasecmp(lc->str, "aftervss") == 0) {
2240 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2241 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
2242 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2243 } else if (strcasecmp(lc->str, "always") == 0) {
2244 *(uint32_t *)(item->value) = SCRIPT_Any;
2246 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
2251 /* Store a runscript->target
2254 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
2256 lex_get_token(lc, T_STRING);
2259 if (strcmp(lc->str, "%c") == 0) {
2260 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2261 } else if (strcasecmp(lc->str, "yes") == 0) {
2262 ((RUNSCRIPT*) item->value)->set_target("%c");
2263 } else if (strcasecmp(lc->str, "no") == 0) {
2264 ((RUNSCRIPT*) item->value)->set_target("");
2266 RES *res = GetResWithName(R_CLIENT, lc->str);
2268 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
2269 lc->str, lc->line_no, lc->line);
2272 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2279 * Store a runscript->command as a string and runscript->cmd_type as a pointer
2281 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
2283 lex_get_token(lc, T_STRING);
2286 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
2287 POOLMEM *c = get_pool_memory(PM_FNAME);
2288 /* Each runscript command takes 2 entries in commands list */
2289 pm_strcpy(c, lc->str);
2290 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
2291 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
2296 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2298 lex_get_token(lc, T_STRING);
2299 alist **runscripts = (alist **)(item->value) ;
2302 RUNSCRIPT *script = new_runscript();
2303 script->set_job_code_callback(job_code_callback_director);
2305 script->set_command(lc->str);
2307 /* TODO: remove all script->old_proto with bacula 1.42 */
2309 if (strcasecmp(item->name, "runbeforejob") == 0) {
2310 script->when = SCRIPT_Before;
2311 script->fail_on_error = true;
2312 script->set_target("");
2314 } else if (strcasecmp(item->name, "runafterjob") == 0) {
2315 script->when = SCRIPT_After;
2316 script->on_success = true;
2317 script->on_failure = false;
2318 script->set_target("");
2320 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
2321 script->old_proto = true;
2322 script->when = SCRIPT_Before;
2323 script->set_target("%c");
2324 script->fail_on_error = true;
2326 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
2327 script->old_proto = true;
2328 script->when = SCRIPT_After;
2329 script->set_target("%c");
2330 script->on_success = true;
2331 script->on_failure = false;
2333 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2334 script->when = SCRIPT_Before;
2335 script->set_target("");
2336 script->fail_on_error = true;
2337 script->set_command(NPRT(script->command), CONSOLE_CMD);
2339 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2340 script->when = SCRIPT_After;
2341 script->set_target("");
2342 script->on_success = true;
2343 script->on_failure = false;
2344 script->set_command(NPRT(script->command), CONSOLE_CMD);
2346 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2347 script->when = SCRIPT_After;
2348 script->on_failure = true;
2349 script->on_success = false;
2350 script->set_target("");
2353 if (*runscripts == NULL) {
2354 *runscripts = New(alist(10, not_owned_by_alist));
2357 (*runscripts)->append(script);
2361 set_bit(index, res_all.hdr.item_present);
2364 /* Store a bool in a bit field without modifing res_all.hdr
2365 * We can also add an option to store_bool to skip res_all.hdr
2367 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2369 lex_get_token(lc, T_NAME);
2370 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2371 *(bool *)(item->value) = true;
2372 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2373 *(bool *)(item->value) = false;
2375 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2381 * new RunScript items
2382 * name handler value code flags default_value
2384 static RES_ITEM runscript_items[] = {
2385 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2386 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2387 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2388 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2389 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2390 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2391 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2392 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2393 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2394 {NULL, NULL, {0}, 0, 0, 0}
2398 * Store RunScript info
2400 * Note, when this routine is called, we are inside a Job
2401 * resource. We treat the RunScript like a sort of
2402 * mini-resource within the Job resource.
2404 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2408 alist **runscripts = (alist **)(item->value) ;
2410 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2412 token = lex_get_token(lc, T_SKIP_EOL);
2414 if (token != T_BOB) {
2415 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2417 /* setting on_success, on_failure, fail_on_error */
2418 res_runscript.reset_default();
2421 res_runscript.commands = New(alist(10, not_owned_by_alist));
2424 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2425 if (token == T_EOB) {
2428 if (token != T_IDENTIFIER) {
2429 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2431 for (i=0; runscript_items[i].name; i++) {
2432 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2433 token = lex_get_token(lc, T_SKIP_EOL);
2434 if (token != T_EQUALS) {
2435 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2438 /* Call item handler */
2439 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2446 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2451 /* run on client by default */
2452 if (res_runscript.target == NULL) {
2453 res_runscript.set_target("%c");
2455 if (*runscripts == NULL) {
2456 *runscripts = New(alist(10, not_owned_by_alist));
2459 * commands list contains 2 values per command
2460 * - POOLMEM command string (ex: /bin/true)
2461 * - int command type (ex: SHELL_CMD)
2463 res_runscript.set_job_code_callback(job_code_callback_director);
2464 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2465 t = (intptr_t)res_runscript.commands->pop();
2466 RUNSCRIPT *script = new_runscript();
2467 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2468 script->command = c;
2469 script->cmd_type = t;
2470 /* target is taken from res_runscript, each runscript object have
2473 script->target = NULL;
2474 script->set_target(res_runscript.target);
2476 (*runscripts)->append(script);
2479 delete res_runscript.commands;
2480 /* setting on_success, on_failure... cleanup target field */
2481 res_runscript.reset_default(true);
2485 set_bit(index, res_all.hdr.item_present);
2488 /* callback function for edit_job_codes */
2489 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2490 extern "C" char *job_code_callback_director(JCR *jcr, const char* param, char *buf, int buflen)
2492 static char yes[] = "yes";
2493 static char no[] = "no";
2494 static char nothing[] = "";
2502 return jcr->fileset->name();
2506 if (jcr->client && jcr->client->address()) {
2507 return jcr->client->address();
2512 return jcr->pool->name();
2517 return jcr->wstore->name();
2521 return jcr->spool_data ? yes : no;
2525 return jcr->cloned ? yes : no;
2529 edit_uint64(jcr->wjcr->JobId, buf);
2532 edit_uint64(0, buf);
2540 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2542 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2543 r_first, r_last, resources, &res_head);
2544 return config->parse_config();