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.verify_job) {
1070 sendit(sock, _(" --> "));
1071 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
1073 if (res->res_job.run_cmds) {
1075 foreach_alist(runcmd, res->res_job.run_cmds) {
1076 sendit(sock, _(" --> Run=%s\n"), runcmd);
1079 if (res->res_job.selection_pattern) {
1080 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
1082 if (res->res_job.messages) {
1083 sendit(sock, _(" --> "));
1084 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
1091 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
1094 sendit(sock, _("FileSet: name=%s IgnoreFileSetChanges=%d\n"), res->res_fs.hdr.name, res->res_fs.ignore_fs_changes);
1095 for (i=0; i<res->res_fs.num_includes; i++) {
1096 INCEXE *incexe = res->res_fs.include_items[i];
1097 for (j=0; j<incexe->num_opts; j++) {
1098 FOPTS *fo = incexe->opts_list[j];
1099 sendit(sock, " O %s\n", fo->opts);
1101 bool enhanced_wild = false;
1102 for (k=0; fo->opts[k]!='\0'; k++) {
1103 if (fo->opts[k]=='W') {
1104 enhanced_wild = true;
1109 for (k=0; k<fo->regex.size(); k++) {
1110 sendit(sock, " R %s\n", fo->regex.get(k));
1112 for (k=0; k<fo->regexdir.size(); k++) {
1113 sendit(sock, " RD %s\n", fo->regexdir.get(k));
1115 for (k=0; k<fo->regexfile.size(); k++) {
1116 sendit(sock, " RF %s\n", fo->regexfile.get(k));
1118 for (k=0; k<fo->wild.size(); k++) {
1119 sendit(sock, " W %s\n", fo->wild.get(k));
1121 for (k=0; k<fo->wilddir.size(); k++) {
1122 sendit(sock, " WD %s\n", fo->wilddir.get(k));
1124 for (k=0; k<fo->wildfile.size(); k++) {
1125 sendit(sock, " WF %s\n", fo->wildfile.get(k));
1127 for (k=0; k<fo->wildbase.size(); k++) {
1128 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
1130 for (k=0; k<fo->base.size(); k++) {
1131 sendit(sock, " B %s\n", fo->base.get(k));
1133 for (k=0; k<fo->fstype.size(); k++) {
1134 sendit(sock, " X %s\n", fo->fstype.get(k));
1136 for (k=0; k<fo->drivetype.size(); k++) {
1137 sendit(sock, " XD %s\n", fo->drivetype.get(k));
1140 sendit(sock, " G %s\n", fo->plugin);
1143 sendit(sock, " D %s\n", fo->reader);
1146 sendit(sock, " T %s\n", fo->writer);
1148 sendit(sock, " N\n");
1150 if (incexe->ignoredir) {
1151 sendit(sock, " Z %s\n", incexe->ignoredir);
1153 for (j=0; j<incexe->name_list.size(); j++) {
1154 sendit(sock, " I %s\n", incexe->name_list.get(j));
1156 if (incexe->name_list.size()) {
1157 sendit(sock, " N\n");
1159 for (j=0; j<incexe->plugin_list.size(); j++) {
1160 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
1162 if (incexe->plugin_list.size()) {
1163 sendit(sock, " N\n");
1165 } /* end for over includes */
1167 for (i=0; i<res->res_fs.num_excludes; i++) {
1168 INCEXE *incexe = res->res_fs.exclude_items[i];
1169 for (j=0; j<incexe->name_list.size(); j++) {
1170 sendit(sock, " E %s\n", incexe->name_list.get(j));
1172 if (incexe->name_list.size()) {
1173 sendit(sock, " N\n");
1177 } /* end case R_FILESET */
1180 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
1184 if (res->res_sch.run) {
1186 RUN *run = res->res_sch.run;
1187 char buf[1000], num[30];
1188 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
1189 res->res_sch.hdr.name, res->res_sch.is_enabled());
1194 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
1195 if (run->MaxRunSchedTime) {
1196 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
1198 if (run->Priority) {
1199 sendit(sock, _(" Priority=%u\n"), run->Priority);
1201 bstrncpy(buf, _(" hour="), sizeof(buf));
1202 for (i=0; i<24; i++) {
1203 if (bit_is_set(i, run->hour)) {
1204 bsnprintf(num, sizeof(num), "%d ", i);
1205 bstrncat(buf, num, sizeof(buf));
1208 bstrncat(buf, "\n", sizeof(buf));
1210 bstrncpy(buf, _(" mday="), sizeof(buf));
1211 for (i=0; i<32; i++) {
1212 if (bit_is_set(i, run->mday)) {
1213 bsnprintf(num, sizeof(num), "%d ", i);
1214 bstrncat(buf, num, sizeof(buf));
1217 bstrncat(buf, "\n", sizeof(buf));
1219 bstrncpy(buf, _(" month="), sizeof(buf));
1220 for (i=0; i<12; i++) {
1221 if (bit_is_set(i, run->month)) {
1222 bsnprintf(num, sizeof(num), "%d ", i);
1223 bstrncat(buf, num, sizeof(buf));
1226 bstrncat(buf, "\n", sizeof(buf));
1228 bstrncpy(buf, _(" wday="), sizeof(buf));
1229 for (i=0; i<7; i++) {
1230 if (bit_is_set(i, run->wday)) {
1231 bsnprintf(num, sizeof(num), "%d ", i);
1232 bstrncat(buf, num, sizeof(buf));
1235 bstrncat(buf, "\n", sizeof(buf));
1237 bstrncpy(buf, _(" wom="), sizeof(buf));
1238 for (i=0; i<6; i++) {
1239 if (bit_is_set(i, run->wom)) {
1240 bsnprintf(num, sizeof(num), "%d ", i);
1241 bstrncat(buf, num, sizeof(buf));
1244 bstrncat(buf, "\n", sizeof(buf));
1246 bstrncpy(buf, _(" woy="), sizeof(buf));
1247 for (i=0; i<54; i++) {
1248 if (bit_is_set(i, run->woy)) {
1249 bsnprintf(num, sizeof(num), "%d ", i);
1250 bstrncat(buf, num, sizeof(buf));
1253 bstrncat(buf, "\n", sizeof(buf));
1255 sendit(sock, _(" mins=%d\n"), run->minute);
1257 sendit(sock, _(" --> "));
1258 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
1260 if (run->next_pool) {
1261 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1262 dump_resource(-R_POOL, (RES *)run->next_pool, sendit, sock);
1265 sendit(sock, _(" --> "));
1266 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
1269 sendit(sock, _(" --> "));
1270 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
1272 /* If another Run record is chained in, go print it */
1278 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1283 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1286 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1287 res->res_pool.pool_type);
1288 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1289 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1290 res->res_pool.catalog_files);
1291 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1292 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1293 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1294 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1295 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1296 res->res_pool.Recycle,
1297 NPRT(res->res_pool.label_format));
1298 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1299 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1300 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1301 res->res_pool.recycle_oldest_volume,
1302 res->res_pool.purge_oldest_volume,
1303 res->res_pool.action_on_purge);
1304 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1305 res->res_pool.MaxVolJobs,
1306 res->res_pool.MaxVolFiles,
1307 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1308 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1309 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1310 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1311 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1312 sendit(sock, _(" CacheRetention=%s\n"),
1313 edit_utime(res->res_pool.CacheRetention, ed1, sizeof(ed1)));
1314 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1315 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1316 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1317 if (res->res_pool.NextPool) {
1318 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1320 if (res->res_pool.RecyclePool) {
1321 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1323 if (res->res_pool.ScratchPool) {
1324 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1326 if (res->res_pool.catalog) {
1327 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1329 if (res->res_pool.storage) {
1331 foreach_alist(store, res->res_pool.storage) {
1332 sendit(sock, _(" --> "));
1333 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1336 if (res->res_pool.CopyPool) {
1338 foreach_alist(copy, res->res_pool.CopyPool) {
1339 sendit(sock, _(" --> "));
1340 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1347 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1348 if (res->res_msgs.mail_cmd)
1349 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1350 if (res->res_msgs.operator_cmd)
1351 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1355 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1359 next = GetNextRes(0, (RES *)res);
1361 dump_resource(type, next, sendit, sock);
1367 * Free all the members of an INCEXE structure
1369 static void free_incexe(INCEXE *incexe)
1371 incexe->name_list.destroy();
1372 incexe->plugin_list.destroy();
1373 for (int i=0; i<incexe->num_opts; i++) {
1374 FOPTS *fopt = incexe->opts_list[i];
1375 fopt->regex.destroy();
1376 fopt->regexdir.destroy();
1377 fopt->regexfile.destroy();
1378 fopt->wild.destroy();
1379 fopt->wilddir.destroy();
1380 fopt->wildfile.destroy();
1381 fopt->wildbase.destroy();
1382 fopt->base.destroy();
1383 fopt->fstype.destroy();
1384 fopt->drivetype.destroy();
1396 if (incexe->opts_list) {
1397 free(incexe->opts_list);
1399 if (incexe->ignoredir) {
1400 free(incexe->ignoredir);
1407 * Free memory of resource -- called when daemon terminates.
1408 * NB, we don't need to worry about freeing any references
1409 * to other resources as they will be freed when that
1410 * resource chain is traversed. Mainly we worry about freeing
1411 * allocated strings (names).
1413 void free_resource(RES *rres, int type)
1416 URES *res = (URES *)rres;
1422 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1423 /* common stuff -- free the resource name and description */
1424 if (res->res_dir.hdr.name) {
1425 free(res->res_dir.hdr.name);
1427 if (res->res_dir.hdr.desc) {
1428 free(res->res_dir.hdr.desc);
1433 if (res->res_dir.working_directory) {
1434 free(res->res_dir.working_directory);
1436 if (res->res_dir.scripts_directory) {
1437 free((char *)res->res_dir.scripts_directory);
1439 if (res->res_dir.plugin_directory) {
1440 free((char *)res->res_dir.plugin_directory);
1442 if (res->res_dir.pid_directory) {
1443 free(res->res_dir.pid_directory);
1445 if (res->res_dir.subsys_directory) {
1446 free(res->res_dir.subsys_directory);
1448 if (res->res_dir.password) {
1449 free(res->res_dir.password);
1451 if (res->res_dir.query_file) {
1452 free(res->res_dir.query_file);
1454 if (res->res_dir.DIRaddrs) {
1455 free_addresses(res->res_dir.DIRaddrs);
1457 if (res->res_dir.DIRsrc_addr) {
1458 free_addresses(res->res_dir.DIRsrc_addr);
1460 if (res->res_dir.tls_ctx) {
1461 free_tls_context(res->res_dir.tls_ctx);
1463 if (res->res_dir.tls_ca_certfile) {
1464 free(res->res_dir.tls_ca_certfile);
1466 if (res->res_dir.tls_ca_certdir) {
1467 free(res->res_dir.tls_ca_certdir);
1469 if (res->res_dir.tls_certfile) {
1470 free(res->res_dir.tls_certfile);
1472 if (res->res_dir.tls_keyfile) {
1473 free(res->res_dir.tls_keyfile);
1475 if (res->res_dir.tls_dhfile) {
1476 free(res->res_dir.tls_dhfile);
1478 if (res->res_dir.tls_allowed_cns) {
1479 delete res->res_dir.tls_allowed_cns;
1481 if (res->res_dir.verid) {
1482 free(res->res_dir.verid);
1489 if (res->res_con.password) {
1490 free(res->res_con.password);
1492 if (res->res_con.tls_ctx) {
1493 free_tls_context(res->res_con.tls_ctx);
1495 if (res->res_con.tls_ca_certfile) {
1496 free(res->res_con.tls_ca_certfile);
1498 if (res->res_con.tls_ca_certdir) {
1499 free(res->res_con.tls_ca_certdir);
1501 if (res->res_con.tls_certfile) {
1502 free(res->res_con.tls_certfile);
1504 if (res->res_con.tls_keyfile) {
1505 free(res->res_con.tls_keyfile);
1507 if (res->res_con.tls_dhfile) {
1508 free(res->res_con.tls_dhfile);
1510 if (res->res_con.tls_allowed_cns) {
1511 delete res->res_con.tls_allowed_cns;
1513 for (int i=0; i<Num_ACL; i++) {
1514 if (res->res_con.ACL_lists[i]) {
1515 delete res->res_con.ACL_lists[i];
1516 res->res_con.ACL_lists[i] = NULL;
1521 if (res->res_client.client_address) {
1522 free(res->res_client.client_address);
1524 if (res->res_client.fd_storage_address) {
1525 free(res->res_client.fd_storage_address);
1527 if (res->res_client.password) {
1528 free(res->res_client.password);
1530 if (res->res_client.tls_ctx) {
1531 free_tls_context(res->res_client.tls_ctx);
1533 if (res->res_client.tls_ca_certfile) {
1534 free(res->res_client.tls_ca_certfile);
1536 if (res->res_client.tls_ca_certdir) {
1537 free(res->res_client.tls_ca_certdir);
1539 if (res->res_client.tls_certfile) {
1540 free(res->res_client.tls_certfile);
1542 if (res->res_client.tls_keyfile) {
1543 free(res->res_client.tls_keyfile);
1545 if (res->res_client.tls_allowed_cns) {
1546 delete res->res_client.tls_allowed_cns;
1551 if (res->res_store.address) {
1552 free(res->res_store.address);
1554 if (res->res_store.fd_storage_address) {
1555 free(res->res_store.fd_storage_address);
1557 if (res->res_store.password) {
1558 free(res->res_store.password);
1560 if (res->res_store.media_type) {
1561 free(res->res_store.media_type);
1563 if (res->res_store.ac_group) {
1564 free_pool_memory(res->res_store.ac_group);
1566 if (res->res_store.device) {
1567 delete res->res_store.device;
1569 if (res->res_store.tls_ctx) {
1570 free_tls_context(res->res_store.tls_ctx);
1572 if (res->res_store.tls_ca_certfile) {
1573 free(res->res_store.tls_ca_certfile);
1575 if (res->res_store.tls_ca_certdir) {
1576 free(res->res_store.tls_ca_certdir);
1578 if (res->res_store.tls_certfile) {
1579 free(res->res_store.tls_certfile);
1581 if (res->res_store.tls_keyfile) {
1582 free(res->res_store.tls_keyfile);
1586 if (res->res_cat.db_address) {
1587 free(res->res_cat.db_address);
1589 if (res->res_cat.db_socket) {
1590 free(res->res_cat.db_socket);
1592 if (res->res_cat.db_user) {
1593 free(res->res_cat.db_user);
1595 if (res->res_cat.db_name) {
1596 free(res->res_cat.db_name);
1598 if (res->res_cat.db_driver) {
1599 free(res->res_cat.db_driver);
1601 if (res->res_cat.db_password) {
1602 free(res->res_cat.db_password);
1604 if (res->res_cat.db_ssl_key) {
1605 free(res->res_cat.db_ssl_key);
1607 if (res->res_cat.db_ssl_cert) {
1608 free(res->res_cat.db_ssl_cert);
1610 if (res->res_cat.db_ssl_ca) {
1611 free(res->res_cat.db_ssl_ca);
1613 if (res->res_cat.db_ssl_capath) {
1614 free(res->res_cat.db_ssl_capath);
1616 if (res->res_cat.db_ssl_cipher) {
1617 free(res->res_cat.db_ssl_cipher);
1621 if ((num=res->res_fs.num_includes)) {
1622 while (--num >= 0) {
1623 free_incexe(res->res_fs.include_items[num]);
1625 free(res->res_fs.include_items);
1627 res->res_fs.num_includes = 0;
1628 if ((num=res->res_fs.num_excludes)) {
1629 while (--num >= 0) {
1630 free_incexe(res->res_fs.exclude_items[num]);
1632 free(res->res_fs.exclude_items);
1634 res->res_fs.num_excludes = 0;
1637 if (res->res_pool.pool_type) {
1638 free(res->res_pool.pool_type);
1640 if (res->res_pool.label_format) {
1641 free(res->res_pool.label_format);
1643 if (res->res_pool.cleaning_prefix) {
1644 free(res->res_pool.cleaning_prefix);
1646 if (res->res_pool.storage) {
1647 delete res->res_pool.storage;
1651 if (res->res_sch.run) {
1653 nrun = res->res_sch.run;
1663 if (res->res_job.RestoreWhere) {
1664 free(res->res_job.RestoreWhere);
1666 if (res->res_job.RegexWhere) {
1667 free(res->res_job.RegexWhere);
1669 if (res->res_job.strip_prefix) {
1670 free(res->res_job.strip_prefix);
1672 if (res->res_job.add_prefix) {
1673 free(res->res_job.add_prefix);
1675 if (res->res_job.add_suffix) {
1676 free(res->res_job.add_suffix);
1678 if (res->res_job.RestoreBootstrap) {
1679 free(res->res_job.RestoreBootstrap);
1681 if (res->res_job.WriteBootstrap) {
1682 free(res->res_job.WriteBootstrap);
1684 if (res->res_job.PluginOptions) {
1685 free(res->res_job.PluginOptions);
1687 if (res->res_job.selection_pattern) {
1688 free(res->res_job.selection_pattern);
1690 if (res->res_job.run_cmds) {
1691 delete res->res_job.run_cmds;
1693 if (res->res_job.storage) {
1694 delete res->res_job.storage;
1696 if (res->res_job.base) {
1697 delete res->res_job.base;
1699 if (res->res_job.RunScripts) {
1700 free_runscripts(res->res_job.RunScripts);
1701 delete res->res_job.RunScripts;
1705 if (res->res_msgs.mail_cmd) {
1706 free(res->res_msgs.mail_cmd);
1708 if (res->res_msgs.operator_cmd) {
1709 free(res->res_msgs.operator_cmd);
1711 free_msgs_res((MSGS *)res); /* free message resource */
1715 printf(_("Unknown resource type %d in free_resource.\n"), type);
1717 /* Common stuff again -- free the resource, recurse to next one */
1724 * Save the new resource by chaining it into the head list for
1725 * the resource. If this is pass 2, we update any resource
1726 * pointers because they may not have been defined until
1729 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
1732 int rindex = type - r_first;
1736 /* Check Job requirements after applying JobDefs */
1737 if (type != R_JOB && type != R_JOBDEFS) {
1739 * Ensure that all required items are present
1741 for (i=0; items[i].name; i++) {
1742 if (items[i].flags & ITEM_REQUIRED) {
1743 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1744 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1745 items[i].name, resources[rindex].name);
1749 /* If this triggers, take a look at lib/parse_conf.h */
1750 if (i >= MAX_RES_ITEMS) {
1751 Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
1755 } else if (type == R_JOB) {
1757 * Ensure that the name item is present
1759 if (items[0].flags & ITEM_REQUIRED) {
1760 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1761 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1762 items[0].name, resources[rindex].name);
1769 * During pass 2 in each "store" routine, we looked up pointers
1770 * to all the resources referrenced in the current resource, now we
1771 * must copy their addresses from the static record to the allocated
1776 /* Resources not containing a resource */
1784 * Resources containing another resource or alist. First
1785 * look up the resource which contains another resource. It
1786 * was written during pass 1. Then stuff in the pointers to
1787 * the resources it contains, which were inserted this pass.
1788 * Finally, it will all be stored back.
1791 /* Find resource saved in pass 1 */
1792 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1793 Mmsg(config->m_errmsg, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1796 /* Explicitly copy resource pointers from this pass (res_all) */
1797 res->res_pool.NextPool = res_all.res_pool.NextPool;
1798 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1799 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1800 res->res_pool.storage = res_all.res_pool.storage;
1801 res->res_pool.catalog = res_all.res_pool.catalog;
1804 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1805 Mmsg(config->m_errmsg, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1808 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1811 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1812 Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1815 res->res_dir.messages = res_all.res_dir.messages;
1816 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1818 case R_AUTOCHANGER: /* alias for R_STORAGE */
1820 type = R_STORAGE; /* force Storage type */
1821 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1822 Mmsg(config->m_errmsg, _("Cannot find Storage resource %s\n"),
1823 res_all.res_dir.hdr.name);
1826 /* we must explicitly copy the device alist pointer */
1827 res->res_store.device = res_all.res_store.device;
1828 res->res_store.changer = res_all.res_store.changer;
1829 res->res_store.shared_storage = res_all.res_store.shared_storage;
1830 res->res_store.autochanger = res_all.res_store.autochanger;
1831 if (strcasecmp(resources[rindex].name, "autochanger") == 0) {
1832 res->res_store.changer = &res->res_store;
1833 res->res_store.autochanger = true;
1838 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1839 Mmsg(config->m_errmsg, _("Cannot find Job resource %s\n"),
1840 res_all.res_dir.hdr.name);
1843 res->res_job.messages = res_all.res_job.messages;
1844 res->res_job.schedule = res_all.res_job.schedule;
1845 res->res_job.client = res_all.res_job.client;
1846 res->res_job.fileset = res_all.res_job.fileset;
1847 res->res_job.storage = res_all.res_job.storage;
1848 res->res_job.base = res_all.res_job.base;
1849 res->res_job.pool = res_all.res_job.pool;
1850 res->res_job.next_pool = res_all.res_job.next_pool;
1851 res->res_job.full_pool = res_all.res_job.full_pool;
1852 res->res_job.inc_pool = res_all.res_job.inc_pool;
1853 res->res_job.diff_pool = res_all.res_job.diff_pool;
1854 res->res_job.verify_job = res_all.res_job.verify_job;
1855 res->res_job.jobdefs = res_all.res_job.jobdefs;
1856 res->res_job.run_cmds = res_all.res_job.run_cmds;
1857 res->res_job.RunScripts = res_all.res_job.RunScripts;
1859 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1860 * is not very useful)
1861 * We have to set_bit(index, res_all.hdr.item_present);
1862 * or something like that
1865 /* we take RegexWhere before all other options */
1866 if (!res->res_job.RegexWhere
1868 (res->res_job.strip_prefix ||
1869 res->res_job.add_suffix ||
1870 res->res_job.add_prefix))
1872 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1873 res->res_job.add_prefix,
1874 res->res_job.add_suffix);
1875 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1876 bregexp_build_where(res->res_job.RegexWhere, len,
1877 res->res_job.strip_prefix,
1878 res->res_job.add_prefix,
1879 res->res_job.add_suffix);
1880 /* TODO: test bregexp */
1883 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1884 free(res->res_job.RestoreWhere);
1885 res->res_job.RestoreWhere = NULL;
1890 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1891 Mmsg(config->m_errmsg, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1894 res->res_counter.Catalog = res_all.res_counter.Catalog;
1895 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1899 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.name())) == NULL) {
1900 Mmsg(config->m_errmsg, _("Cannot find Client resource %s\n"), res_all.res_client.name());
1903 res->res_client.catalog = res_all.res_client.catalog;
1904 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1908 * Schedule is a bit different in that it contains a RUN record
1909 * chain which isn't a "named" resource. This chain was linked
1910 * in by run_conf.c during pass 2, so here we jam the pointer
1911 * into the Schedule resource.
1913 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.name())) == NULL) {
1914 Mmsg(config->m_errmsg, _("Cannot find Schedule resource %s\n"), res_all.res_client.name());
1917 res->res_sch.run = res_all.res_sch.run;
1920 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1924 /* Note, the resource name was already saved during pass 1,
1925 * so here, we can just release it.
1927 if (res_all.res_dir.hdr.name) {
1928 free(res_all.res_dir.hdr.name);
1929 res_all.res_dir.hdr.name = NULL;
1931 if (res_all.res_dir.hdr.desc) {
1932 free(res_all.res_dir.hdr.desc);
1933 res_all.res_dir.hdr.desc = NULL;
1938 /* R_AUTOCHANGER is alias so turn it into an R_STORAGE */
1939 if (type == R_AUTOCHANGER) {
1941 rindex = type - r_first;
1945 * The following code is only executed during pass 1
1949 size = sizeof(DIRRES);
1952 size = sizeof(CONRES);
1955 size =sizeof(CLIENT);
1958 size = sizeof(STORE);
1968 size = sizeof(FILESET);
1971 size = sizeof(SCHED);
1974 size = sizeof(POOL);
1977 size = sizeof(MSGS);
1980 size = sizeof(COUNTER);
1986 printf(_("Unknown resource type %d in save_resource.\n"), type);
1992 if (!config->insert_res(rindex, size)) {
1999 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
2001 uint32_t *destination = (uint32_t*)item->value;
2002 lex_get_token(lc, T_NAME);
2003 if (strcasecmp(lc->str, "truncate") == 0) {
2004 *destination = (*destination) | ON_PURGE_TRUNCATE;
2006 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
2010 set_bit(index, res_all.hdr.item_present);
2014 * Store an autochanger resource. Used by Autochanger and
2015 * SharedStorage direcives.
2017 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass)
2020 RES_ITEM *next = item + 1;
2022 lex_get_token(lc, T_NAME);
2023 Dmsg1(100, "Got name=%s\n", lc->str);
2025 * For backward compatibility, if yes/no, set the next item
2027 if (strcasecmp(item->name, "autochanger") == 0) {
2028 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2029 *(bool *)(next->value) = true;
2030 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2033 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2034 *(bool *)(next->value) = false;
2035 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2040 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2043 res = GetResWithName(R_STORAGE, lc->str);
2045 scan_err3(lc, _("Could not find Storage Resource %s referenced on line %d : %s\n"),
2046 lc->str, lc->line_no, lc->line);
2049 if (*(item->value)) {
2050 scan_err3(lc, _("Attempt to redefine Storage resource \"%s\" referenced on line %d : %s\n"),
2051 item->name, lc->line_no, lc->line);
2054 Dmsg2(100, "Store %s value=%p\n", lc->str, res);
2055 *(item->value) = (char *)res;
2056 *(bool *)(next->value) = true;
2059 set_bit(index, res_all.hdr.item_present);
2064 * Store Device. Note, the resource is created upon the
2065 * first reference. The details of the resource are obtained
2066 * later from the SD.
2068 void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
2070 int rindex = R_DEVICE - r_first;
2071 int size = sizeof(DEVICE);
2077 lex_get_token(lc, T_NAME);
2078 rblist *list = res_head[rindex]->res_list;
2079 ures = (URES *)malloc(size);
2080 memset(ures, 0, size);
2081 ures->res_dev.hdr.name = bstrdup(lc->str);
2083 if (list->empty()) {
2084 list->insert(res, res_compare);
2085 res_head[rindex]->first = res;
2086 res_head[rindex]->last = res;
2089 prev = res_head[rindex]->last;
2090 item = (RES *)list->insert(res, res_compare);
2092 prev->res_next = res;
2093 res_head[rindex]->last = res;
2095 /* res not inserted */
2096 free(ures->res_dev.hdr.name);
2101 set_bit(index, res_all.hdr.item_present);
2103 store_alist_res(lc, item, index, pass);
2108 * Store Migration/Copy type
2111 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
2115 lex_get_token(lc, T_NAME);
2116 /* Store the type both pass 1 and pass 2 */
2117 for (i=0; migtypes[i].type_name; i++) {
2118 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
2119 *(uint32_t *)(item->value) = migtypes[i].job_type;
2125 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
2128 set_bit(index, res_all.hdr.item_present);
2134 * Store JobType (backup, verify, restore)
2137 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
2141 lex_get_token(lc, T_NAME);
2142 /* Store the type both pass 1 and pass 2 */
2143 for (i=0; jobtypes[i].type_name; i++) {
2144 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
2145 *(uint32_t *)(item->value) = jobtypes[i].job_type;
2151 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
2154 set_bit(index, res_all.hdr.item_present);
2158 * Store Job Level (Full, Incremental, ...)
2161 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
2165 lex_get_token(lc, T_NAME);
2166 /* Store the level pass 2 so that type is defined */
2167 for (i=0; joblevels[i].level_name; i++) {
2168 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
2169 *(uint32_t *)(item->value) = joblevels[i].level;
2175 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
2178 set_bit(index, res_all.hdr.item_present);
2182 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
2185 lex_get_token(lc, T_NAME);
2186 /* Scan Replacement options */
2187 for (i=0; ReplaceOptions[i].name; i++) {
2188 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
2189 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
2195 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
2198 set_bit(index, res_all.hdr.item_present);
2202 * Store ACL (access control list)
2205 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
2210 lex_get_token(lc, T_STRING);
2212 if (((alist **)item->value)[item->code] == NULL) {
2213 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
2214 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
2216 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
2217 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
2219 token = lex_get_token(lc, T_ALL);
2220 if (token == T_COMMA) {
2221 continue; /* get another ACL */
2225 set_bit(index, res_all.hdr.item_present);
2228 /* We build RunScripts items here */
2229 static RUNSCRIPT res_runscript;
2231 /* Store a runscript->when in a bit field */
2232 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
2234 lex_get_token(lc, T_NAME);
2236 if (strcasecmp(lc->str, "before") == 0) {
2237 *(uint32_t *)(item->value) = SCRIPT_Before ;
2238 } else if (strcasecmp(lc->str, "after") == 0) {
2239 *(uint32_t *)(item->value) = SCRIPT_After;
2240 } else if (strcasecmp(lc->str, "aftervss") == 0) {
2241 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2242 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
2243 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2244 } else if (strcasecmp(lc->str, "always") == 0) {
2245 *(uint32_t *)(item->value) = SCRIPT_Any;
2247 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
2252 /* Store a runscript->target
2255 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
2257 lex_get_token(lc, T_STRING);
2260 if (strcmp(lc->str, "%c") == 0) {
2261 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2262 } else if (strcasecmp(lc->str, "yes") == 0) {
2263 ((RUNSCRIPT*) item->value)->set_target("%c");
2264 } else if (strcasecmp(lc->str, "no") == 0) {
2265 ((RUNSCRIPT*) item->value)->set_target("");
2267 RES *res = GetResWithName(R_CLIENT, lc->str);
2269 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
2270 lc->str, lc->line_no, lc->line);
2273 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2280 * Store a runscript->command as a string and runscript->cmd_type as a pointer
2282 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
2284 lex_get_token(lc, T_STRING);
2287 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
2288 POOLMEM *c = get_pool_memory(PM_FNAME);
2289 /* Each runscript command takes 2 entries in commands list */
2290 pm_strcpy(c, lc->str);
2291 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
2292 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
2297 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2299 lex_get_token(lc, T_STRING);
2300 alist **runscripts = (alist **)(item->value) ;
2303 RUNSCRIPT *script = new_runscript();
2304 script->set_job_code_callback(job_code_callback_director);
2306 script->set_command(lc->str);
2308 /* TODO: remove all script->old_proto with bacula 1.42 */
2310 if (strcasecmp(item->name, "runbeforejob") == 0) {
2311 script->when = SCRIPT_Before;
2312 script->fail_on_error = true;
2313 script->set_target("");
2315 } else if (strcasecmp(item->name, "runafterjob") == 0) {
2316 script->when = SCRIPT_After;
2317 script->on_success = true;
2318 script->on_failure = false;
2319 script->set_target("");
2321 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
2322 script->old_proto = true;
2323 script->when = SCRIPT_Before;
2324 script->set_target("%c");
2325 script->fail_on_error = true;
2327 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
2328 script->old_proto = true;
2329 script->when = SCRIPT_After;
2330 script->set_target("%c");
2331 script->on_success = true;
2332 script->on_failure = false;
2334 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2335 script->when = SCRIPT_Before;
2336 script->set_target("");
2337 script->fail_on_error = true;
2338 script->set_command(NPRT(script->command), CONSOLE_CMD);
2340 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2341 script->when = SCRIPT_After;
2342 script->set_target("");
2343 script->on_success = true;
2344 script->on_failure = false;
2345 script->set_command(NPRT(script->command), CONSOLE_CMD);
2347 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2348 script->when = SCRIPT_After;
2349 script->on_failure = true;
2350 script->on_success = false;
2351 script->set_target("");
2354 if (*runscripts == NULL) {
2355 *runscripts = New(alist(10, not_owned_by_alist));
2358 (*runscripts)->append(script);
2362 set_bit(index, res_all.hdr.item_present);
2365 /* Store a bool in a bit field without modifing res_all.hdr
2366 * We can also add an option to store_bool to skip res_all.hdr
2368 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2370 lex_get_token(lc, T_NAME);
2371 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2372 *(bool *)(item->value) = true;
2373 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2374 *(bool *)(item->value) = false;
2376 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2382 * new RunScript items
2383 * name handler value code flags default_value
2385 static RES_ITEM runscript_items[] = {
2386 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2387 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2388 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2389 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2390 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2391 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2392 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2393 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2394 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2395 {NULL, NULL, {0}, 0, 0, 0}
2399 * Store RunScript info
2401 * Note, when this routine is called, we are inside a Job
2402 * resource. We treat the RunScript like a sort of
2403 * mini-resource within the Job resource.
2405 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2409 alist **runscripts = (alist **)(item->value) ;
2411 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2413 token = lex_get_token(lc, T_SKIP_EOL);
2415 if (token != T_BOB) {
2416 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2418 /* setting on_success, on_failure, fail_on_error */
2419 res_runscript.reset_default();
2422 res_runscript.commands = New(alist(10, not_owned_by_alist));
2425 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2426 if (token == T_EOB) {
2429 if (token != T_IDENTIFIER) {
2430 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2432 for (i=0; runscript_items[i].name; i++) {
2433 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2434 token = lex_get_token(lc, T_SKIP_EOL);
2435 if (token != T_EQUALS) {
2436 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2439 /* Call item handler */
2440 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2447 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2452 /* run on client by default */
2453 if (res_runscript.target == NULL) {
2454 res_runscript.set_target("%c");
2456 if (*runscripts == NULL) {
2457 *runscripts = New(alist(10, not_owned_by_alist));
2460 * commands list contains 2 values per command
2461 * - POOLMEM command string (ex: /bin/true)
2462 * - int command type (ex: SHELL_CMD)
2464 res_runscript.set_job_code_callback(job_code_callback_director);
2465 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2466 t = (intptr_t)res_runscript.commands->pop();
2467 RUNSCRIPT *script = new_runscript();
2468 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2469 script->command = c;
2470 script->cmd_type = t;
2471 /* target is taken from res_runscript, each runscript object have
2474 script->target = NULL;
2475 script->set_target(res_runscript.target);
2477 (*runscripts)->append(script);
2480 delete res_runscript.commands;
2481 /* setting on_success, on_failure... cleanup target field */
2482 res_runscript.reset_default(true);
2486 set_bit(index, res_all.hdr.item_present);
2489 /* callback function for edit_job_codes */
2490 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2491 extern "C" char *job_code_callback_director(JCR *jcr, const char* param, char *buf, int buflen)
2493 static char yes[] = "yes";
2494 static char no[] = "no";
2495 static char nothing[] = "";
2503 return jcr->fileset->name();
2507 if (jcr->client && jcr->client->address()) {
2508 return jcr->client->address();
2513 return jcr->pool->name();
2518 return jcr->wstore->name();
2522 return jcr->spool_data ? yes : no;
2526 return jcr->cloned ? yes : no;
2530 edit_uint64(jcr->wjcr->JobId, buf);
2533 edit_uint64(0, buf);
2541 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2543 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2544 r_first, r_last, resources, &res_head);
2545 return config->parse_config();