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 {"DirectoryAcl", store_acl, ITEM(res_con.ACL_lists), Directory_ACL, 0, 0},
394 {"TlsAuthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
395 {"TlsEnable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
396 {"TlsRequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
397 {"TlsVerifyPeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
398 {"TlsCaCertificateFile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
399 {"TlsCaCertificateDir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
400 {"TlsCertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
401 {"TlsKey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
402 {"TlsDhFile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
403 {"TlsAllowedCn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
404 {NULL, NULL, {0}, 0, 0, 0}
409 * Client or File daemon resource
411 * name handler value code flags default_value
414 static RES_ITEM cli_items[] = {
415 {"Name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
416 {"Description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
417 {"fdaddress", store_str, ITEM(res_client.client_address), 0, 0, 0},
418 {"Address", store_str, ITEM(res_client.client_address), 0, ITEM_REQUIRED, 0},
419 {"FdPort", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
420 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
421 {"Password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
422 {"FdStorageAddress", store_str, ITEM(res_client.fd_storage_address), 0, 0, 0},
423 {"Catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
424 {"FileRetention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
425 {"JobRetention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
426 {"HeartbeatInterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
427 {"AutoPrune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
428 {"SDCallsClient", store_bool, ITEM(res_client.sd_calls_client), 0, ITEM_DEFAULT, false},
429 {"SnapshotRetention", store_time, ITEM(res_client.SnapRetention), 0, ITEM_DEFAULT, 0},
430 {"MaximumConcurrentJobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
431 {"TlsAuthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
432 {"TlsEnable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
433 {"TlsRequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
434 {"TlsCaCertificateFile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
435 {"TlsCaCertificateDir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
436 {"TlsCertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
437 {"TlsKey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
438 {"TlsAllowedCn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
439 {"MaximumBandwidthPerJob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
440 {"Enabled", store_bool, ITEM(res_client.Enabled), 0, ITEM_DEFAULT, true},
441 {NULL, NULL, {0}, 0, 0, 0}
444 /* Storage daemon resource
446 * name handler value code flags default_value
448 static RES_ITEM store_items[] = {
449 {"Name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
450 {"Description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
451 {"SdPort", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
452 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
453 {"Address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
454 {"FdStorageAddress", store_str, ITEM(res_store.fd_storage_address), 0, 0, 0},
455 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
456 {"Password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
457 {"Device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
458 {"MediaType", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
460 * Big kludge, these two autochanger definitions must be in
461 * this order and together.
463 {"Autochanger", store_ac_res, ITEM(res_store.changer), 0, ITEM_DEFAULT, 0},
464 {"Autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, false},
465 {"SharedStorage", store_ac_res, ITEM(res_store.shared_storage), 1, ITEM_DEFAULT, 0},
466 {"Enabled", store_bool, ITEM(res_store.Enabled), 0, ITEM_DEFAULT, true},
467 {"AllowCompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
468 {"HeartbeatInterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
469 {"MaximumConcurrentJobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
470 {"MaximumConcurrentReadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
471 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
472 {"TlsAuthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
473 {"TlsEnable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
474 {"TlsRequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
475 {"TlsCaCertificateFile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
476 {"TlsCaCertificateDir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
477 {"TlsCertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
478 {"TlsKey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
479 {NULL, NULL, {0}, 0, 0, 0}
483 * Catalog Resource Directives
485 * name handler value code flags default_value
487 static RES_ITEM cat_items[] = {
488 {"Name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
489 {"Description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
490 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
491 {"Address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
492 {"DbPort", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
493 /* keep this password as store_str for the moment */
494 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
495 {"Password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
496 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
497 {"User", store_str, ITEM(res_cat.db_user), 0, 0, 0},
498 {"DbName", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
499 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
500 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
501 {"dbsslmode", store_str, ITEM(res_cat.db_ssl_mode), 0, 0, 0},
502 {"dbsslkey", store_str, ITEM(res_cat.db_ssl_key), 0, 0, 0},
503 {"dbsslcert", store_str, ITEM(res_cat.db_ssl_cert), 0, 0, 0},
504 {"dbsslca", store_str, ITEM(res_cat.db_ssl_ca), 0, 0, 0},
505 {"dbsslcapath", store_str, ITEM(res_cat.db_ssl_capath), 0, 0, 0},
506 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
507 /* Turned off for the moment */
508 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
509 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
510 {NULL, NULL, {0}, 0, 0, 0}
514 * Job Resource Directives
516 * name handler value code flags default_value
518 RES_ITEM job_items[] = {
519 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
520 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
521 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
522 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
523 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
524 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
525 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
526 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
527 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
528 {"VirtualFullBackupPool", store_res, ITEM(res_job.vfull_pool), R_POOL, 0, 0},
529 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
530 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
531 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
532 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
533 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
534 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
535 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
536 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
537 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
538 /* Root of where to restore files */
539 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
540 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
541 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
542 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
543 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
544 /* Where to find bootstrap during restore */
545 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
546 /* Where to write bootstrap file during backup */
547 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
548 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
549 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
550 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
551 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
552 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
553 /* xxxMaxWaitTime are deprecated */
554 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
555 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
556 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
557 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
558 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
559 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
560 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
561 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
562 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
563 {"MaxVirtualFullInterval", store_time, ITEM(res_job.MaxVirtualFullInterval), 0, 0, 0},
564 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
565 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
566 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
567 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
568 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
569 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
570 {"Enabled", store_bool, ITEM(res_job.Enabled), 0, ITEM_DEFAULT, true},
571 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
572 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
573 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
574 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
575 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
576 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
578 * JSON tools skip Directive in lowercase. They are deprecated or
579 * are synonym with an other one that follows. Like User and dbuser.
581 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
582 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
583 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
584 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
585 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
586 {"consolerunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
587 {"consolerunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
588 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
589 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
590 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
591 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
592 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
593 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
594 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
595 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
596 {"BackupsToKeep", store_pint32, ITEM(res_job.BackupsToKeep), 0, ITEM_DEFAULT, 0},
597 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
598 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
599 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
600 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
601 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
602 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
603 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
604 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
605 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
606 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
607 {"DeleteConsolidatedJobs", store_bool, ITEM(res_job.DeleteConsolidatedJobs), 0, ITEM_DEFAULT, false},
608 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
609 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
610 {NULL, NULL, {0}, 0, 0, 0}
615 * Name handler value code flags default_value
617 static RES_ITEM fs_items[] = {
618 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
619 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
620 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
621 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
622 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
623 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
624 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
625 {NULL, NULL, {0}, 0, 0, 0}
628 /* Schedule -- see run_conf.c */
631 * name handler value code flags default_value
633 static RES_ITEM sch_items[] = {
634 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
635 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
636 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
637 {"Enabled", store_bool, ITEM(res_sch.Enabled), 0, ITEM_DEFAULT, true},
638 {NULL, NULL, {0}, 0, 0, 0}
643 * name handler value code flags default_value
645 static RES_ITEM pool_items[] = {
646 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
647 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
648 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
649 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
650 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
651 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
652 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
653 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
654 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
655 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
656 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
657 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
658 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
659 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
660 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
661 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
662 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
663 {"CacheRetention", store_time, ITEM(res_pool.CacheRetention), 0, 0, 0},
664 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
665 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
666 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
667 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
668 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
669 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
670 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
671 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
672 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
673 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
674 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
675 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
676 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
677 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
678 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
680 {NULL, NULL, {0}, 0, 0, 0}
685 * name handler value code flags default_value
687 static RES_ITEM counter_items[] = {
688 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
689 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
690 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
691 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
692 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
693 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
694 {NULL, NULL, {0}, 0, 0, 0}
698 /* Message resource */
699 extern RES_ITEM msgs_items[];
702 * This is the master resource definition.
703 * It must have one item for each of the resources.
705 * NOTE!!! keep it in the same order as the R_codes
706 * or eliminate all resources[rindex].name
710 RES_TABLE resources[] = {
711 {"Director", dir_items, R_DIRECTOR},
712 {"Client", cli_items, R_CLIENT},
713 {"Job", job_items, R_JOB},
714 {"Storage", store_items, R_STORAGE},
715 {"Catalog", cat_items, R_CATALOG},
716 {"Schedule", sch_items, R_SCHEDULE},
717 {"Fileset", fs_items, R_FILESET},
718 {"Pool", pool_items, R_POOL},
719 {"Messages", msgs_items, R_MSGS},
720 {"Counter", counter_items, R_COUNTER},
721 {"Console", con_items, R_CONSOLE},
722 {"JobDefs", job_items, R_JOBDEFS},
723 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
724 {"Autochanger", store_items, R_AUTOCHANGER}, /* alias for R_STORAGE */
729 /* Keywords (RHS) permitted in Job Level records
731 * level_name level job_type
733 struct s_jl joblevels[] = {
734 {"Full", L_FULL, JT_BACKUP},
735 {"Base", L_BASE, JT_BACKUP},
736 {"Incremental", L_INCREMENTAL, JT_BACKUP},
737 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
738 {"Since", L_SINCE, JT_BACKUP},
739 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
740 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
741 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
742 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
743 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
744 {"Data", L_VERIFY_DATA, JT_VERIFY},
745 {"Full", L_FULL, JT_COPY},
746 {"Incremental", L_INCREMENTAL, JT_COPY},
747 {"Differential", L_DIFFERENTIAL, JT_COPY},
748 {"Full", L_FULL, JT_MIGRATE},
749 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
750 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
751 {" ", L_NONE, JT_ADMIN},
752 {" ", L_NONE, JT_RESTORE},
757 /* Keywords (RHS) permitted in Job type records
762 {"Backup", JT_BACKUP},
764 {"Verify", JT_VERIFY},
765 {"Restore", JT_RESTORE},
766 {"Migrate", JT_MIGRATE},
772 /* Keywords (RHS) permitted in Selection type records
777 {"SmallestVolume", MT_SMALLEST_VOL},
778 {"OldestVolume", MT_OLDEST_VOL},
779 {"PoolOccupancy", MT_POOL_OCCUPANCY},
780 {"PoolTime", MT_POOL_TIME},
781 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
782 {"Client", MT_CLIENT},
783 {"Volume", MT_VOLUME},
785 {"SqlQuery", MT_SQLQUERY},
791 /* Options permitted in Restore replace= */
792 s_kw ReplaceOptions[] = {
793 {"Always", REPLACE_ALWAYS},
794 {"IfNewer", REPLACE_IFNEWER},
795 {"IfOlder", REPLACE_IFOLDER},
796 {"Never", REPLACE_NEVER},
800 char *CAT::display(POOLMEM *dst) {
801 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
802 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
804 name(), NPRTB(db_name),
805 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
806 NPRTB(db_address), db_port, NPRTB(db_socket));
810 const char *level_to_str(int level)
813 static char level_no[30];
814 const char *str = level_no;
816 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
817 for (i=0; joblevels[i].level_name; i++) {
818 if (level == (int)joblevels[i].level) {
819 str = joblevels[i].level_name;
826 /* Dump contents of resource */
827 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
830 URES *res = (URES *)ares;
832 char ed1[100], ed2[100], ed3[100];
834 UAContext *ua = (UAContext *)sock;
837 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
840 if (type < 0) { /* no recursion */
846 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
847 ares->name, res->res_dir.MaxConcurrentJobs,
848 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
849 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
850 if (res->res_dir.query_file) {
851 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
853 if (res->res_dir.messages) {
854 sendit(sock, _(" --> "));
855 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
859 sendit(sock, _("Console: name=%s SSL=%d\n"),
860 res->res_con.hdr.name, res->res_con.tls_enable);
863 if (res->res_counter.WrapCounter) {
864 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
865 res->res_counter.hdr.name, res->res_counter.MinValue,
866 res->res_counter.MaxValue, res->res_counter.CurrentValue,
867 res->res_counter.WrapCounter->hdr.name);
869 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
870 res->res_counter.hdr.name, res->res_counter.MinValue,
871 res->res_counter.MaxValue);
873 if (res->res_counter.Catalog) {
874 sendit(sock, _(" --> "));
875 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
880 if (!acl_access_ok(ua, Client_ACL, res->res_client.name())) {
883 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u NumJobs=%u\n"),
884 res->res_client.name(), res->res_client.is_enabled(),
885 res->res_client.address(), res->res_client.FDport,
886 res->res_client.MaxConcurrentJobs, res->res_client.getNumConcurrentJobs());
887 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
888 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
889 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
890 res->res_client.AutoPrune);
891 if (res->res_client.fd_storage_address) {
892 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
894 if (res->res_client.max_bandwidth) {
895 sendit(sock, _(" MaximumBandwidth=%lld\n"),
896 res->res_client.max_bandwidth);
898 if (res->res_client.catalog) {
899 sendit(sock, _(" --> "));
900 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
907 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
908 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
909 " poolid=%s volname=%s MediaType=%s\n"),
910 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
911 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
912 dev->offline, dev->autochanger,
913 edit_uint64(dev->PoolId, ed1),
914 dev->VolumeName, dev->MediaType);
919 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
922 sendit(sock, _("%s: name=%s address=%s SDport=%d MaxJobs=%u NumJobs=%u\n"
923 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
924 res->res_store.changer == &res->res_store ? "Autochanger" : "Storage",
925 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
926 res->res_store.MaxConcurrentJobs,
927 res->res_store.getNumConcurrentJobs(),
928 res->res_store.dev_name(),
929 res->res_store.media_type,
930 edit_int64(res->res_store.StorageId, ed1),
931 res->res_store.autochanger);
932 if (res->res_store.fd_storage_address) {
933 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
935 if (res->res_store.ac_group) {
936 STORE *shstore = res->res_store.shared_storage;
937 sendit(sock, " AC group=%s ShareStore=%s\n", res->res_store.ac_group,
938 shstore?shstore->name():"*none*");
940 if (res->res_store.changer && res->res_store.changer != &res->res_store) {
941 sendit(sock, _(" Parent --> "));
942 dump_resource(-R_STORAGE, (RES *)res->res_store.changer, sendit, sock);
947 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
950 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
951 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
952 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
953 res->res_cat.db_port, res->res_cat.db_name,
954 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
955 res->res_cat.mult_db_connections);
960 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
963 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
964 type == R_JOB ? _("Job") : _("JobDefs"),
965 res->res_job.hdr.name, res->res_job.JobType,
966 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
967 res->res_job.is_enabled());
968 sendit(sock, _(" MaxJobs=%u NumJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
969 res->res_job.MaxConcurrentJobs,
970 res->res_job.getNumConcurrentJobs(),
971 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
972 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
973 res->res_job.spool_data, res->res_job.write_part_after_job);
974 if (res->res_job.spool_size) {
975 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
977 if (res->res_job.JobType == JT_BACKUP) {
978 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
980 if (res->res_job.max_bandwidth) {
981 sendit(sock, _(" MaximumBandwidth=%lld\n"),
982 res->res_job.max_bandwidth);
984 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
985 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
987 if (res->res_job.JobType == JT_RESTORE) {
988 sendit(sock, _(" PrefixLinks=%d\n"), res->res_job.PrefixLinks);
990 if (res->res_job.client) {
991 sendit(sock, _(" --> "));
992 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
994 if (res->res_job.fileset) {
995 sendit(sock, _(" --> "));
996 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
998 if (res->res_job.schedule) {
999 sendit(sock, _(" --> "));
1000 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
1002 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
1003 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
1005 if (res->res_job.RegexWhere) {
1006 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
1008 if (res->res_job.RestoreBootstrap) {
1009 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
1011 if (res->res_job.WriteBootstrap) {
1012 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
1014 if (res->res_job.PluginOptions) {
1015 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
1017 if (res->res_job.MaxRunTime) {
1018 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
1020 if (res->res_job.MaxWaitTime) {
1021 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
1023 if (res->res_job.MaxStartDelay) {
1024 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
1026 if (res->res_job.MaxRunSchedTime) {
1027 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
1029 if (res->res_job.storage) {
1031 foreach_alist(store, res->res_job.storage) {
1032 sendit(sock, _(" --> "));
1033 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1036 if (res->res_job.base) {
1038 foreach_alist(job, res->res_job.base) {
1039 sendit(sock, _(" --> Base %s\n"), job->name());
1042 if (res->res_job.RunScripts) {
1044 foreach_alist(script, res->res_job.RunScripts) {
1045 sendit(sock, _(" --> RunScript\n"));
1046 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
1047 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
1048 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
1049 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
1050 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
1051 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
1054 if (res->res_job.pool) {
1055 sendit(sock, _(" --> "));
1056 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
1058 if (res->res_job.vfull_pool) {
1059 sendit(sock, _(" --> VFullBackup"));
1060 dump_resource(-R_POOL, (RES *)res->res_job.vfull_pool, sendit, sock);
1062 if (res->res_job.full_pool) {
1063 sendit(sock, _(" --> FullBackup"));
1064 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
1066 if (res->res_job.inc_pool) {
1067 sendit(sock, _(" --> IncrementalBackup"));
1068 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
1070 if (res->res_job.diff_pool) {
1071 sendit(sock, _(" --> DifferentialBackup"));
1072 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
1074 if (res->res_job.next_pool) {
1075 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1076 dump_resource(-R_POOL, (RES *)res->res_job.next_pool, sendit, sock);
1078 if (res->res_job.JobType == JT_VERIFY && res->res_job.verify_job) {
1079 sendit(sock, _(" --> JobToVerify %s"), (RES *)res->res_job.verify_job->name());
1081 if (res->res_job.run_cmds) {
1083 foreach_alist(runcmd, res->res_job.run_cmds) {
1084 sendit(sock, _(" --> Run=%s\n"), runcmd);
1087 if (res->res_job.selection_pattern) {
1088 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
1090 if (res->res_job.messages) {
1091 sendit(sock, _(" --> "));
1092 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
1099 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
1102 sendit(sock, _("FileSet: name=%s IgnoreFileSetChanges=%d\n"), res->res_fs.hdr.name, res->res_fs.ignore_fs_changes);
1103 for (i=0; i<res->res_fs.num_includes; i++) {
1104 INCEXE *incexe = res->res_fs.include_items[i];
1105 for (j=0; j<incexe->num_opts; j++) {
1106 FOPTS *fo = incexe->opts_list[j];
1107 sendit(sock, " O %s\n", fo->opts);
1109 bool enhanced_wild = false;
1110 for (k=0; fo->opts[k]!='\0'; k++) {
1111 if (fo->opts[k]=='W') {
1112 enhanced_wild = true;
1117 for (k=0; k<fo->regex.size(); k++) {
1118 sendit(sock, " R %s\n", fo->regex.get(k));
1120 for (k=0; k<fo->regexdir.size(); k++) {
1121 sendit(sock, " RD %s\n", fo->regexdir.get(k));
1123 for (k=0; k<fo->regexfile.size(); k++) {
1124 sendit(sock, " RF %s\n", fo->regexfile.get(k));
1126 for (k=0; k<fo->wild.size(); k++) {
1127 sendit(sock, " W %s\n", fo->wild.get(k));
1129 for (k=0; k<fo->wilddir.size(); k++) {
1130 sendit(sock, " WD %s\n", fo->wilddir.get(k));
1132 for (k=0; k<fo->wildfile.size(); k++) {
1133 sendit(sock, " WF %s\n", fo->wildfile.get(k));
1135 for (k=0; k<fo->wildbase.size(); k++) {
1136 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
1138 for (k=0; k<fo->base.size(); k++) {
1139 sendit(sock, " B %s\n", fo->base.get(k));
1141 for (k=0; k<fo->fstype.size(); k++) {
1142 sendit(sock, " X %s\n", fo->fstype.get(k));
1144 for (k=0; k<fo->drivetype.size(); k++) {
1145 sendit(sock, " XD %s\n", fo->drivetype.get(k));
1148 sendit(sock, " G %s\n", fo->plugin);
1151 sendit(sock, " D %s\n", fo->reader);
1154 sendit(sock, " T %s\n", fo->writer);
1156 sendit(sock, " N\n");
1158 if (incexe->ignoredir) {
1159 sendit(sock, " Z %s\n", incexe->ignoredir);
1161 for (j=0; j<incexe->name_list.size(); j++) {
1162 sendit(sock, " I %s\n", incexe->name_list.get(j));
1164 if (incexe->name_list.size()) {
1165 sendit(sock, " N\n");
1167 for (j=0; j<incexe->plugin_list.size(); j++) {
1168 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
1170 if (incexe->plugin_list.size()) {
1171 sendit(sock, " N\n");
1173 } /* end for over includes */
1175 for (i=0; i<res->res_fs.num_excludes; i++) {
1176 INCEXE *incexe = res->res_fs.exclude_items[i];
1177 for (j=0; j<incexe->name_list.size(); j++) {
1178 sendit(sock, " E %s\n", incexe->name_list.get(j));
1180 if (incexe->name_list.size()) {
1181 sendit(sock, " N\n");
1185 } /* end case R_FILESET */
1188 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
1192 if (res->res_sch.run) {
1194 RUN *run = res->res_sch.run;
1195 char buf[1000], num[30];
1196 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
1197 res->res_sch.hdr.name, res->res_sch.is_enabled());
1202 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
1203 if (run->MaxRunSchedTime) {
1204 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
1206 if (run->Priority) {
1207 sendit(sock, _(" Priority=%u\n"), run->Priority);
1209 bstrncpy(buf, _(" hour="), sizeof(buf));
1210 for (i=0; i<24; i++) {
1211 if (bit_is_set(i, run->hour)) {
1212 bsnprintf(num, sizeof(num), "%d ", i);
1213 bstrncat(buf, num, sizeof(buf));
1216 bstrncat(buf, "\n", sizeof(buf));
1218 bstrncpy(buf, _(" mday="), sizeof(buf));
1219 for (i=0; i<32; i++) {
1220 if (bit_is_set(i, run->mday)) {
1221 bsnprintf(num, sizeof(num), "%d ", i);
1222 bstrncat(buf, num, sizeof(buf));
1225 bstrncat(buf, "\n", sizeof(buf));
1227 bstrncpy(buf, _(" month="), sizeof(buf));
1228 for (i=0; i<12; i++) {
1229 if (bit_is_set(i, run->month)) {
1230 bsnprintf(num, sizeof(num), "%d ", i);
1231 bstrncat(buf, num, sizeof(buf));
1234 bstrncat(buf, "\n", sizeof(buf));
1236 bstrncpy(buf, _(" wday="), sizeof(buf));
1237 for (i=0; i<7; i++) {
1238 if (bit_is_set(i, run->wday)) {
1239 bsnprintf(num, sizeof(num), "%d ", i);
1240 bstrncat(buf, num, sizeof(buf));
1243 bstrncat(buf, "\n", sizeof(buf));
1245 bstrncpy(buf, _(" wom="), sizeof(buf));
1246 for (i=0; i<6; i++) {
1247 if (bit_is_set(i, run->wom)) {
1248 bsnprintf(num, sizeof(num), "%d ", i);
1249 bstrncat(buf, num, sizeof(buf));
1252 bstrncat(buf, "\n", sizeof(buf));
1254 bstrncpy(buf, _(" woy="), sizeof(buf));
1255 for (i=0; i<54; i++) {
1256 if (bit_is_set(i, run->woy)) {
1257 bsnprintf(num, sizeof(num), "%d ", i);
1258 bstrncat(buf, num, sizeof(buf));
1261 bstrncat(buf, "\n", sizeof(buf));
1263 sendit(sock, _(" mins=%d\n"), run->minute);
1265 sendit(sock, _(" --> "));
1266 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
1268 if (run->next_pool) {
1269 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1270 dump_resource(-R_POOL, (RES *)run->next_pool, sendit, sock);
1273 sendit(sock, _(" --> "));
1274 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
1277 sendit(sock, _(" --> "));
1278 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
1280 /* If another Run record is chained in, go print it */
1286 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1291 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1294 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1295 res->res_pool.pool_type);
1296 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1297 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1298 res->res_pool.catalog_files);
1299 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1300 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1301 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1302 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1303 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1304 res->res_pool.Recycle,
1305 NPRT(res->res_pool.label_format));
1306 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1307 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1308 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1309 res->res_pool.recycle_oldest_volume,
1310 res->res_pool.purge_oldest_volume,
1311 res->res_pool.action_on_purge);
1312 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1313 res->res_pool.MaxVolJobs,
1314 res->res_pool.MaxVolFiles,
1315 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1316 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1317 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1318 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1319 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1320 sendit(sock, _(" CacheRetention=%s\n"),
1321 edit_utime(res->res_pool.CacheRetention, ed1, sizeof(ed1)));
1322 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1323 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1324 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1325 if (res->res_pool.NextPool) {
1326 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1328 if (res->res_pool.RecyclePool) {
1329 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1331 if (res->res_pool.ScratchPool) {
1332 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1334 if (res->res_pool.catalog) {
1335 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1337 if (res->res_pool.storage) {
1339 foreach_alist(store, res->res_pool.storage) {
1340 sendit(sock, _(" --> "));
1341 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1344 if (res->res_pool.CopyPool) {
1346 foreach_alist(copy, res->res_pool.CopyPool) {
1347 sendit(sock, _(" --> "));
1348 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1355 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1356 if (res->res_msgs.mail_cmd)
1357 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1358 if (res->res_msgs.operator_cmd)
1359 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1363 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1367 next = GetNextRes(0, (RES *)res);
1369 dump_resource(type, next, sendit, sock);
1375 * Free all the members of an INCEXE structure
1377 static void free_incexe(INCEXE *incexe)
1379 incexe->name_list.destroy();
1380 incexe->plugin_list.destroy();
1381 for (int i=0; i<incexe->num_opts; i++) {
1382 FOPTS *fopt = incexe->opts_list[i];
1383 fopt->regex.destroy();
1384 fopt->regexdir.destroy();
1385 fopt->regexfile.destroy();
1386 fopt->wild.destroy();
1387 fopt->wilddir.destroy();
1388 fopt->wildfile.destroy();
1389 fopt->wildbase.destroy();
1390 fopt->base.destroy();
1391 fopt->fstype.destroy();
1392 fopt->drivetype.destroy();
1404 if (incexe->opts_list) {
1405 free(incexe->opts_list);
1407 if (incexe->ignoredir) {
1408 free(incexe->ignoredir);
1415 * Free memory of resource -- called when daemon terminates.
1416 * NB, we don't need to worry about freeing any references
1417 * to other resources as they will be freed when that
1418 * resource chain is traversed. Mainly we worry about freeing
1419 * allocated strings (names).
1421 void free_resource(RES *rres, int type)
1424 URES *res = (URES *)rres;
1430 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1431 /* common stuff -- free the resource name and description */
1432 if (res->res_dir.hdr.name) {
1433 free(res->res_dir.hdr.name);
1435 if (res->res_dir.hdr.desc) {
1436 free(res->res_dir.hdr.desc);
1441 if (res->res_dir.working_directory) {
1442 free(res->res_dir.working_directory);
1444 if (res->res_dir.scripts_directory) {
1445 free((char *)res->res_dir.scripts_directory);
1447 if (res->res_dir.plugin_directory) {
1448 free((char *)res->res_dir.plugin_directory);
1450 if (res->res_dir.pid_directory) {
1451 free(res->res_dir.pid_directory);
1453 if (res->res_dir.subsys_directory) {
1454 free(res->res_dir.subsys_directory);
1456 if (res->res_dir.password) {
1457 free(res->res_dir.password);
1459 if (res->res_dir.query_file) {
1460 free(res->res_dir.query_file);
1462 if (res->res_dir.DIRaddrs) {
1463 free_addresses(res->res_dir.DIRaddrs);
1465 if (res->res_dir.DIRsrc_addr) {
1466 free_addresses(res->res_dir.DIRsrc_addr);
1468 if (res->res_dir.tls_ctx) {
1469 free_tls_context(res->res_dir.tls_ctx);
1471 if (res->res_dir.tls_ca_certfile) {
1472 free(res->res_dir.tls_ca_certfile);
1474 if (res->res_dir.tls_ca_certdir) {
1475 free(res->res_dir.tls_ca_certdir);
1477 if (res->res_dir.tls_certfile) {
1478 free(res->res_dir.tls_certfile);
1480 if (res->res_dir.tls_keyfile) {
1481 free(res->res_dir.tls_keyfile);
1483 if (res->res_dir.tls_dhfile) {
1484 free(res->res_dir.tls_dhfile);
1486 if (res->res_dir.tls_allowed_cns) {
1487 delete res->res_dir.tls_allowed_cns;
1489 if (res->res_dir.verid) {
1490 free(res->res_dir.verid);
1497 if (res->res_con.password) {
1498 free(res->res_con.password);
1500 if (res->res_con.tls_ctx) {
1501 free_tls_context(res->res_con.tls_ctx);
1503 if (res->res_con.tls_ca_certfile) {
1504 free(res->res_con.tls_ca_certfile);
1506 if (res->res_con.tls_ca_certdir) {
1507 free(res->res_con.tls_ca_certdir);
1509 if (res->res_con.tls_certfile) {
1510 free(res->res_con.tls_certfile);
1512 if (res->res_con.tls_keyfile) {
1513 free(res->res_con.tls_keyfile);
1515 if (res->res_con.tls_dhfile) {
1516 free(res->res_con.tls_dhfile);
1518 if (res->res_con.tls_allowed_cns) {
1519 delete res->res_con.tls_allowed_cns;
1521 for (int i=0; i<Num_ACL; i++) {
1522 if (res->res_con.ACL_lists[i]) {
1523 delete res->res_con.ACL_lists[i];
1524 res->res_con.ACL_lists[i] = NULL;
1529 if (res->res_client.client_address) {
1530 free(res->res_client.client_address);
1532 if (res->res_client.fd_storage_address) {
1533 free(res->res_client.fd_storage_address);
1535 if (res->res_client.password) {
1536 free(res->res_client.password);
1538 if (res->res_client.tls_ctx) {
1539 free_tls_context(res->res_client.tls_ctx);
1541 if (res->res_client.tls_ca_certfile) {
1542 free(res->res_client.tls_ca_certfile);
1544 if (res->res_client.tls_ca_certdir) {
1545 free(res->res_client.tls_ca_certdir);
1547 if (res->res_client.tls_certfile) {
1548 free(res->res_client.tls_certfile);
1550 if (res->res_client.tls_keyfile) {
1551 free(res->res_client.tls_keyfile);
1553 if (res->res_client.tls_allowed_cns) {
1554 delete res->res_client.tls_allowed_cns;
1559 if (res->res_store.address) {
1560 free(res->res_store.address);
1562 if (res->res_store.fd_storage_address) {
1563 free(res->res_store.fd_storage_address);
1565 if (res->res_store.password) {
1566 free(res->res_store.password);
1568 if (res->res_store.media_type) {
1569 free(res->res_store.media_type);
1571 if (res->res_store.ac_group) {
1572 free_pool_memory(res->res_store.ac_group);
1574 if (res->res_store.device) {
1575 delete res->res_store.device;
1577 if (res->res_store.tls_ctx) {
1578 free_tls_context(res->res_store.tls_ctx);
1580 if (res->res_store.tls_ca_certfile) {
1581 free(res->res_store.tls_ca_certfile);
1583 if (res->res_store.tls_ca_certdir) {
1584 free(res->res_store.tls_ca_certdir);
1586 if (res->res_store.tls_certfile) {
1587 free(res->res_store.tls_certfile);
1589 if (res->res_store.tls_keyfile) {
1590 free(res->res_store.tls_keyfile);
1594 if (res->res_cat.db_address) {
1595 free(res->res_cat.db_address);
1597 if (res->res_cat.db_socket) {
1598 free(res->res_cat.db_socket);
1600 if (res->res_cat.db_user) {
1601 free(res->res_cat.db_user);
1603 if (res->res_cat.db_name) {
1604 free(res->res_cat.db_name);
1606 if (res->res_cat.db_driver) {
1607 free(res->res_cat.db_driver);
1609 if (res->res_cat.db_password) {
1610 free(res->res_cat.db_password);
1612 if (res->res_cat.db_ssl_mode) {
1613 free(res->res_cat.db_ssl_mode);
1615 if (res->res_cat.db_ssl_key) {
1616 free(res->res_cat.db_ssl_key);
1618 if (res->res_cat.db_ssl_cert) {
1619 free(res->res_cat.db_ssl_cert);
1621 if (res->res_cat.db_ssl_ca) {
1622 free(res->res_cat.db_ssl_ca);
1624 if (res->res_cat.db_ssl_capath) {
1625 free(res->res_cat.db_ssl_capath);
1627 if (res->res_cat.db_ssl_cipher) {
1628 free(res->res_cat.db_ssl_cipher);
1632 if ((num=res->res_fs.num_includes)) {
1633 while (--num >= 0) {
1634 free_incexe(res->res_fs.include_items[num]);
1636 free(res->res_fs.include_items);
1638 res->res_fs.num_includes = 0;
1639 if ((num=res->res_fs.num_excludes)) {
1640 while (--num >= 0) {
1641 free_incexe(res->res_fs.exclude_items[num]);
1643 free(res->res_fs.exclude_items);
1645 res->res_fs.num_excludes = 0;
1648 if (res->res_pool.pool_type) {
1649 free(res->res_pool.pool_type);
1651 if (res->res_pool.label_format) {
1652 free(res->res_pool.label_format);
1654 if (res->res_pool.cleaning_prefix) {
1655 free(res->res_pool.cleaning_prefix);
1657 if (res->res_pool.storage) {
1658 delete res->res_pool.storage;
1662 if (res->res_sch.run) {
1664 nrun = res->res_sch.run;
1674 if (res->res_job.RestoreWhere) {
1675 free(res->res_job.RestoreWhere);
1677 if (res->res_job.RegexWhere) {
1678 free(res->res_job.RegexWhere);
1680 if (res->res_job.strip_prefix) {
1681 free(res->res_job.strip_prefix);
1683 if (res->res_job.add_prefix) {
1684 free(res->res_job.add_prefix);
1686 if (res->res_job.add_suffix) {
1687 free(res->res_job.add_suffix);
1689 if (res->res_job.RestoreBootstrap) {
1690 free(res->res_job.RestoreBootstrap);
1692 if (res->res_job.WriteBootstrap) {
1693 free(res->res_job.WriteBootstrap);
1695 if (res->res_job.PluginOptions) {
1696 free(res->res_job.PluginOptions);
1698 if (res->res_job.selection_pattern) {
1699 free(res->res_job.selection_pattern);
1701 if (res->res_job.run_cmds) {
1702 delete res->res_job.run_cmds;
1704 if (res->res_job.storage) {
1705 delete res->res_job.storage;
1707 if (res->res_job.base) {
1708 delete res->res_job.base;
1710 if (res->res_job.RunScripts) {
1711 free_runscripts(res->res_job.RunScripts);
1712 delete res->res_job.RunScripts;
1716 if (res->res_msgs.mail_cmd) {
1717 free(res->res_msgs.mail_cmd);
1719 if (res->res_msgs.operator_cmd) {
1720 free(res->res_msgs.operator_cmd);
1722 free_msgs_res((MSGS *)res); /* free message resource */
1726 printf(_("Unknown resource type %d in free_resource.\n"), type);
1728 /* Common stuff again -- free the resource, recurse to next one */
1735 * Save the new resource by chaining it into the head list for
1736 * the resource. If this is pass 2, we update any resource
1737 * pointers because they may not have been defined until
1740 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
1743 int rindex = type - r_first;
1747 /* Check Job requirements after applying JobDefs */
1748 if (type != R_JOB && type != R_JOBDEFS) {
1750 * Ensure that all required items are present
1752 for (i=0; items[i].name; i++) {
1753 if (items[i].flags & ITEM_REQUIRED) {
1754 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1755 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1756 items[i].name, resources[rindex].name);
1760 /* If this triggers, take a look at lib/parse_conf.h */
1761 if (i >= MAX_RES_ITEMS) {
1762 Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
1766 } else if (type == R_JOB) {
1768 * Ensure that the name item is present
1770 if (items[0].flags & ITEM_REQUIRED) {
1771 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1772 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1773 items[0].name, resources[rindex].name);
1780 * During pass 2 in each "store" routine, we looked up pointers
1781 * to all the resources referrenced in the current resource, now we
1782 * must copy their addresses from the static record to the allocated
1787 /* Resources not containing a resource */
1795 * Resources containing another resource or alist. First
1796 * look up the resource which contains another resource. It
1797 * was written during pass 1. Then stuff in the pointers to
1798 * the resources it contains, which were inserted this pass.
1799 * Finally, it will all be stored back.
1802 /* Find resource saved in pass 1 */
1803 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1804 Mmsg(config->m_errmsg, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1807 /* Explicitly copy resource pointers from this pass (res_all) */
1808 res->res_pool.NextPool = res_all.res_pool.NextPool;
1809 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1810 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1811 res->res_pool.storage = res_all.res_pool.storage;
1812 res->res_pool.catalog = res_all.res_pool.catalog;
1815 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1816 Mmsg(config->m_errmsg, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1819 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1822 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1823 Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1826 res->res_dir.messages = res_all.res_dir.messages;
1827 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1829 case R_AUTOCHANGER: /* alias for R_STORAGE */
1831 type = R_STORAGE; /* force Storage type */
1832 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1833 Mmsg(config->m_errmsg, _("Cannot find Storage resource %s\n"),
1834 res_all.res_dir.hdr.name);
1837 /* we must explicitly copy the device alist pointer */
1838 res->res_store.device = res_all.res_store.device;
1839 res->res_store.changer = res_all.res_store.changer;
1840 res->res_store.shared_storage = res_all.res_store.shared_storage;
1841 res->res_store.autochanger = res_all.res_store.autochanger;
1842 if (strcasecmp(resources[rindex].name, "autochanger") == 0) {
1843 res->res_store.changer = &res->res_store;
1844 res->res_store.autochanger = true;
1849 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1850 Mmsg(config->m_errmsg, _("Cannot find Job resource %s\n"),
1851 res_all.res_dir.hdr.name);
1854 res->res_job.messages = res_all.res_job.messages;
1855 res->res_job.schedule = res_all.res_job.schedule;
1856 res->res_job.client = res_all.res_job.client;
1857 res->res_job.fileset = res_all.res_job.fileset;
1858 res->res_job.storage = res_all.res_job.storage;
1859 res->res_job.base = res_all.res_job.base;
1860 res->res_job.pool = res_all.res_job.pool;
1861 res->res_job.next_pool = res_all.res_job.next_pool;
1862 res->res_job.full_pool = res_all.res_job.full_pool;
1863 res->res_job.vfull_pool = res_all.res_job.vfull_pool;
1864 res->res_job.inc_pool = res_all.res_job.inc_pool;
1865 res->res_job.diff_pool = res_all.res_job.diff_pool;
1866 res->res_job.verify_job = res_all.res_job.verify_job;
1867 res->res_job.jobdefs = res_all.res_job.jobdefs;
1868 res->res_job.run_cmds = res_all.res_job.run_cmds;
1869 res->res_job.RunScripts = res_all.res_job.RunScripts;
1871 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1872 * is not very useful)
1873 * We have to set_bit(index, res_all.hdr.item_present);
1874 * or something like that
1877 /* we take RegexWhere before all other options */
1878 if (!res->res_job.RegexWhere
1880 (res->res_job.strip_prefix ||
1881 res->res_job.add_suffix ||
1882 res->res_job.add_prefix))
1884 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1885 res->res_job.add_prefix,
1886 res->res_job.add_suffix);
1887 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1888 bregexp_build_where(res->res_job.RegexWhere, len,
1889 res->res_job.strip_prefix,
1890 res->res_job.add_prefix,
1891 res->res_job.add_suffix);
1892 /* TODO: test bregexp */
1895 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1896 free(res->res_job.RestoreWhere);
1897 res->res_job.RestoreWhere = NULL;
1902 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1903 Mmsg(config->m_errmsg, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1906 res->res_counter.Catalog = res_all.res_counter.Catalog;
1907 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1911 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.name())) == NULL) {
1912 Mmsg(config->m_errmsg, _("Cannot find Client resource %s\n"), res_all.res_client.name());
1915 res->res_client.catalog = res_all.res_client.catalog;
1916 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1920 * Schedule is a bit different in that it contains a RUN record
1921 * chain which isn't a "named" resource. This chain was linked
1922 * in by run_conf.c during pass 2, so here we jam the pointer
1923 * into the Schedule resource.
1925 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.name())) == NULL) {
1926 Mmsg(config->m_errmsg, _("Cannot find Schedule resource %s\n"), res_all.res_client.name());
1929 res->res_sch.run = res_all.res_sch.run;
1932 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1936 /* Note, the resource name was already saved during pass 1,
1937 * so here, we can just release it.
1939 if (res_all.res_dir.hdr.name) {
1940 free(res_all.res_dir.hdr.name);
1941 res_all.res_dir.hdr.name = NULL;
1943 if (res_all.res_dir.hdr.desc) {
1944 free(res_all.res_dir.hdr.desc);
1945 res_all.res_dir.hdr.desc = NULL;
1950 /* R_AUTOCHANGER is alias so turn it into an R_STORAGE */
1951 if (type == R_AUTOCHANGER) {
1953 rindex = type - r_first;
1957 * The following code is only executed during pass 1
1961 size = sizeof(DIRRES);
1964 size = sizeof(CONRES);
1967 size =sizeof(CLIENT);
1970 size = sizeof(STORE);
1980 size = sizeof(FILESET);
1983 size = sizeof(SCHED);
1986 size = sizeof(POOL);
1989 size = sizeof(MSGS);
1992 size = sizeof(COUNTER);
1998 printf(_("Unknown resource type %d in save_resource.\n"), type);
2004 if (!config->insert_res(rindex, size)) {
2011 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
2013 uint32_t *destination = (uint32_t*)item->value;
2014 lex_get_token(lc, T_NAME);
2015 if (strcasecmp(lc->str, "truncate") == 0) {
2016 *destination = (*destination) | ON_PURGE_TRUNCATE;
2018 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
2022 set_bit(index, res_all.hdr.item_present);
2026 * Store an autochanger resource. Used by Autochanger and
2027 * SharedStorage direcives.
2029 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass)
2032 RES_ITEM *next = item + 1;
2034 lex_get_token(lc, T_NAME);
2035 Dmsg1(100, "Got name=%s\n", lc->str);
2037 * For backward compatibility, if yes/no, set the next item
2039 if (strcasecmp(item->name, "autochanger") == 0) {
2040 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2041 *(bool *)(next->value) = true;
2042 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2045 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2046 *(bool *)(next->value) = false;
2047 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2052 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2055 res = GetResWithName(R_STORAGE, lc->str);
2057 scan_err3(lc, _("Could not find Storage Resource %s referenced on line %d : %s\n"),
2058 lc->str, lc->line_no, lc->line);
2061 if (*(item->value)) {
2062 scan_err3(lc, _("Attempt to redefine Storage resource \"%s\" referenced on line %d : %s\n"),
2063 item->name, lc->line_no, lc->line);
2066 Dmsg2(100, "Store %s value=%p\n", lc->str, res);
2067 *(item->value) = (char *)res;
2068 *(bool *)(next->value) = true;
2071 set_bit(index, res_all.hdr.item_present);
2076 * Store Device. Note, the resource is created upon the
2077 * first reference. The details of the resource are obtained
2078 * later from the SD.
2080 void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
2082 int rindex = R_DEVICE - r_first;
2083 int size = sizeof(DEVICE);
2089 lex_get_token(lc, T_NAME);
2090 rblist *list = res_head[rindex]->res_list;
2091 ures = (URES *)malloc(size);
2092 memset(ures, 0, size);
2093 ures->res_dev.hdr.name = bstrdup(lc->str);
2095 if (list->empty()) {
2096 list->insert(res, res_compare);
2097 res_head[rindex]->first = res;
2098 res_head[rindex]->last = res;
2101 prev = res_head[rindex]->last;
2102 item = (RES *)list->insert(res, res_compare);
2104 prev->res_next = res;
2105 res_head[rindex]->last = res;
2107 /* res not inserted */
2108 free(ures->res_dev.hdr.name);
2113 set_bit(index, res_all.hdr.item_present);
2115 store_alist_res(lc, item, index, pass);
2120 * Store Migration/Copy type
2123 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
2127 lex_get_token(lc, T_NAME);
2128 /* Store the type both pass 1 and pass 2 */
2129 for (i=0; migtypes[i].type_name; i++) {
2130 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
2131 *(uint32_t *)(item->value) = migtypes[i].job_type;
2137 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
2140 set_bit(index, res_all.hdr.item_present);
2146 * Store JobType (backup, verify, restore)
2149 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
2153 lex_get_token(lc, T_NAME);
2154 /* Store the type both pass 1 and pass 2 */
2155 for (i=0; jobtypes[i].type_name; i++) {
2156 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
2157 *(uint32_t *)(item->value) = jobtypes[i].job_type;
2163 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
2166 set_bit(index, res_all.hdr.item_present);
2170 * Store Job Level (Full, Incremental, ...)
2173 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
2177 lex_get_token(lc, T_NAME);
2178 /* Store the level pass 2 so that type is defined */
2179 for (i=0; joblevels[i].level_name; i++) {
2180 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
2181 *(uint32_t *)(item->value) = joblevels[i].level;
2187 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
2190 set_bit(index, res_all.hdr.item_present);
2194 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
2197 lex_get_token(lc, T_NAME);
2198 /* Scan Replacement options */
2199 for (i=0; ReplaceOptions[i].name; i++) {
2200 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
2201 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
2207 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
2210 set_bit(index, res_all.hdr.item_present);
2214 * Store ACL (access control list)
2217 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
2222 lex_get_token(lc, T_STRING);
2224 if (((alist **)item->value)[item->code] == NULL) {
2225 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
2226 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
2228 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
2229 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
2231 token = lex_get_token(lc, T_ALL);
2232 if (token == T_COMMA) {
2233 continue; /* get another ACL */
2237 set_bit(index, res_all.hdr.item_present);
2240 /* We build RunScripts items here */
2241 static RUNSCRIPT res_runscript;
2243 /* Store a runscript->when in a bit field */
2244 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
2246 lex_get_token(lc, T_NAME);
2248 if (strcasecmp(lc->str, "before") == 0) {
2249 *(uint32_t *)(item->value) = SCRIPT_Before ;
2250 } else if (strcasecmp(lc->str, "after") == 0) {
2251 *(uint32_t *)(item->value) = SCRIPT_After;
2252 } else if (strcasecmp(lc->str, "aftervss") == 0) {
2253 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2254 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
2255 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2256 } else if (strcasecmp(lc->str, "always") == 0) {
2257 *(uint32_t *)(item->value) = SCRIPT_Any;
2259 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
2264 /* Store a runscript->target
2267 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
2269 lex_get_token(lc, T_STRING);
2272 if (strcmp(lc->str, "%c") == 0) {
2273 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2274 } else if (strcasecmp(lc->str, "yes") == 0) {
2275 ((RUNSCRIPT*) item->value)->set_target("%c");
2276 } else if (strcasecmp(lc->str, "no") == 0) {
2277 ((RUNSCRIPT*) item->value)->set_target("");
2279 RES *res = GetResWithName(R_CLIENT, lc->str);
2281 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
2282 lc->str, lc->line_no, lc->line);
2285 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2292 * Store a runscript->command as a string and runscript->cmd_type as a pointer
2294 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
2296 lex_get_token(lc, T_STRING);
2299 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
2300 POOLMEM *c = get_pool_memory(PM_FNAME);
2301 /* Each runscript command takes 2 entries in commands list */
2302 pm_strcpy(c, lc->str);
2303 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
2304 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
2309 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2311 lex_get_token(lc, T_STRING);
2312 alist **runscripts = (alist **)(item->value) ;
2315 RUNSCRIPT *script = new_runscript();
2316 script->set_job_code_callback(job_code_callback_director);
2318 script->set_command(lc->str);
2320 /* TODO: remove all script->old_proto with bacula 1.42 */
2322 if (strcasecmp(item->name, "runbeforejob") == 0) {
2323 script->when = SCRIPT_Before;
2324 script->fail_on_error = true;
2325 script->set_target("");
2327 } else if (strcasecmp(item->name, "runafterjob") == 0) {
2328 script->when = SCRIPT_After;
2329 script->on_success = true;
2330 script->on_failure = false;
2331 script->set_target("");
2333 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
2334 script->old_proto = true;
2335 script->when = SCRIPT_Before;
2336 script->set_target("%c");
2337 script->fail_on_error = true;
2339 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
2340 script->old_proto = true;
2341 script->when = SCRIPT_After;
2342 script->set_target("%c");
2343 script->on_success = true;
2344 script->on_failure = false;
2346 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2347 script->when = SCRIPT_Before;
2348 script->set_target("");
2349 script->fail_on_error = true;
2350 script->set_command(NPRT(script->command), CONSOLE_CMD);
2352 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2353 script->when = SCRIPT_After;
2354 script->set_target("");
2355 script->on_success = true;
2356 script->on_failure = false;
2357 script->set_command(NPRT(script->command), CONSOLE_CMD);
2359 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2360 script->when = SCRIPT_After;
2361 script->on_failure = true;
2362 script->on_success = false;
2363 script->set_target("");
2366 if (*runscripts == NULL) {
2367 *runscripts = New(alist(10, not_owned_by_alist));
2370 (*runscripts)->append(script);
2374 set_bit(index, res_all.hdr.item_present);
2377 /* Store a bool in a bit field without modifing res_all.hdr
2378 * We can also add an option to store_bool to skip res_all.hdr
2380 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2382 lex_get_token(lc, T_NAME);
2383 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2384 *(bool *)(item->value) = true;
2385 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2386 *(bool *)(item->value) = false;
2388 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2394 * new RunScript items
2395 * name handler value code flags default_value
2397 static RES_ITEM runscript_items[] = {
2398 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2399 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2400 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2401 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2402 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2403 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2404 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2405 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2406 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2407 {NULL, NULL, {0}, 0, 0, 0}
2411 * Store RunScript info
2413 * Note, when this routine is called, we are inside a Job
2414 * resource. We treat the RunScript like a sort of
2415 * mini-resource within the Job resource.
2417 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2421 alist **runscripts = (alist **)(item->value) ;
2423 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2425 token = lex_get_token(lc, T_SKIP_EOL);
2427 if (token != T_BOB) {
2428 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2430 /* setting on_success, on_failure, fail_on_error */
2431 res_runscript.reset_default();
2434 res_runscript.commands = New(alist(10, not_owned_by_alist));
2437 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2438 if (token == T_EOB) {
2441 if (token != T_IDENTIFIER) {
2442 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2444 for (i=0; runscript_items[i].name; i++) {
2445 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2446 token = lex_get_token(lc, T_SKIP_EOL);
2447 if (token != T_EQUALS) {
2448 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2451 /* Call item handler */
2452 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2459 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2464 /* run on client by default */
2465 if (res_runscript.target == NULL) {
2466 res_runscript.set_target("%c");
2468 if (*runscripts == NULL) {
2469 *runscripts = New(alist(10, not_owned_by_alist));
2472 * commands list contains 2 values per command
2473 * - POOLMEM command string (ex: /bin/true)
2474 * - int command type (ex: SHELL_CMD)
2476 res_runscript.set_job_code_callback(job_code_callback_director);
2477 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2478 t = (intptr_t)res_runscript.commands->pop();
2479 RUNSCRIPT *script = new_runscript();
2480 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2481 script->command = c;
2482 script->cmd_type = t;
2483 /* target is taken from res_runscript, each runscript object have
2486 script->target = NULL;
2487 script->set_target(res_runscript.target);
2489 (*runscripts)->append(script);
2492 delete res_runscript.commands;
2493 /* setting on_success, on_failure... cleanup target field */
2494 res_runscript.reset_default(true);
2498 set_bit(index, res_all.hdr.item_present);
2501 /* callback function for edit_job_codes */
2502 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2503 extern "C" char *job_code_callback_director(JCR *jcr, const char* param, char *buf, int buflen)
2505 static char yes[] = "yes";
2506 static char no[] = "no";
2507 static char nothing[] = "";
2515 return jcr->fileset->name();
2519 if (jcr->client && jcr->client->address()) {
2520 return jcr->client->address();
2525 return jcr->pool->name();
2530 return jcr->wstore->name();
2534 return jcr->spool_data ? yes : no;
2538 return jcr->cloned ? yes : no;
2542 edit_uint64(jcr->wjcr->JobId, buf);
2545 edit_uint64(0, buf);
2553 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2555 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2556 r_first, r_last, resources, &res_head);
2557 return config->parse_config();