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 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
500 {"dbsslmode", store_str, ITEM(res_cat.db_ssl_mode), 0, 0, 0},
501 {"dbsslkey", store_str, ITEM(res_cat.db_ssl_key), 0, 0, 0},
502 {"dbsslcert", store_str, ITEM(res_cat.db_ssl_cert), 0, 0, 0},
503 {"dbsslca", store_str, ITEM(res_cat.db_ssl_ca), 0, 0, 0},
504 {"dbsslcapath", store_str, ITEM(res_cat.db_ssl_capath), 0, 0, 0},
505 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
506 /* Turned off for the moment */
507 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
508 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
509 {NULL, NULL, {0}, 0, 0, 0}
513 * Job Resource Directives
515 * name handler value code flags default_value
517 RES_ITEM job_items[] = {
518 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
519 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
520 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
521 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
522 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
523 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
524 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
525 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
526 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
527 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
528 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
529 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
530 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
531 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
532 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
533 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
534 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
535 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
536 /* Root of where to restore files */
537 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
538 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
539 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
540 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
541 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
542 /* Where to find bootstrap during restore */
543 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
544 /* Where to write bootstrap file during backup */
545 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
546 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
547 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
548 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
549 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
550 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
551 /* xxxMaxWaitTime are deprecated */
552 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
553 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
554 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
555 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
556 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
557 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
558 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
559 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
560 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
561 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
562 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
563 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
564 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
565 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
566 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
567 {"Enabled", store_bool, ITEM(res_job.Enabled), 0, ITEM_DEFAULT, true},
568 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
569 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
570 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
571 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
572 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
573 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
575 * JSON tools skip Directive in lowercase. They are deprecated or
576 * are synonym with an other one that follows. Like User and dbuser.
578 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
579 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
580 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
581 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
582 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
583 {"consolerunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
584 {"consolerunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
585 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
586 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
587 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
588 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
589 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
590 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
591 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
592 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
593 {"BackupsToKeep", store_pint32, ITEM(res_job.BackupsToKeep), 0, ITEM_DEFAULT, 0},
594 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
595 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
596 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
597 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
598 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
599 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
600 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
601 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
602 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
603 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
604 {"DeleteConsolidatedJobs", store_bool, ITEM(res_job.DeleteConsolidatedJobs), 0, ITEM_DEFAULT, false},
605 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
606 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
607 {NULL, NULL, {0}, 0, 0, 0}
612 * Name handler value code flags default_value
614 static RES_ITEM fs_items[] = {
615 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
616 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
617 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
618 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
619 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
620 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
621 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
622 {NULL, NULL, {0}, 0, 0, 0}
625 /* Schedule -- see run_conf.c */
628 * name handler value code flags default_value
630 static RES_ITEM sch_items[] = {
631 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
632 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
633 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
634 {"Enabled", store_bool, ITEM(res_sch.Enabled), 0, ITEM_DEFAULT, true},
635 {NULL, NULL, {0}, 0, 0, 0}
640 * name handler value code flags default_value
642 static RES_ITEM pool_items[] = {
643 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
644 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
645 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
646 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
647 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
648 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
649 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
650 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
651 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
652 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
653 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
654 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
655 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
656 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
657 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
658 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
659 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
660 {"CacheRetention", store_time, ITEM(res_pool.CacheRetention), 0, 0, 0},
661 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
662 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
663 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
664 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
665 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
666 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
667 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
668 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
669 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
670 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
671 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
672 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
673 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
674 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
675 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
677 {NULL, NULL, {0}, 0, 0, 0}
682 * name handler value code flags default_value
684 static RES_ITEM counter_items[] = {
685 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
686 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
687 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
688 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
689 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
690 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
691 {NULL, NULL, {0}, 0, 0, 0}
695 /* Message resource */
696 extern RES_ITEM msgs_items[];
699 * This is the master resource definition.
700 * It must have one item for each of the resources.
702 * NOTE!!! keep it in the same order as the R_codes
703 * or eliminate all resources[rindex].name
707 RES_TABLE resources[] = {
708 {"Director", dir_items, R_DIRECTOR},
709 {"Client", cli_items, R_CLIENT},
710 {"Job", job_items, R_JOB},
711 {"Storage", store_items, R_STORAGE},
712 {"Catalog", cat_items, R_CATALOG},
713 {"Schedule", sch_items, R_SCHEDULE},
714 {"Fileset", fs_items, R_FILESET},
715 {"Pool", pool_items, R_POOL},
716 {"Messages", msgs_items, R_MSGS},
717 {"Counter", counter_items, R_COUNTER},
718 {"Console", con_items, R_CONSOLE},
719 {"JobDefs", job_items, R_JOBDEFS},
720 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
721 {"Autochanger", store_items, R_AUTOCHANGER}, /* alias for R_STORAGE */
726 /* Keywords (RHS) permitted in Job Level records
728 * level_name level job_type
730 struct s_jl joblevels[] = {
731 {"Full", L_FULL, JT_BACKUP},
732 {"Base", L_BASE, JT_BACKUP},
733 {"Incremental", L_INCREMENTAL, JT_BACKUP},
734 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
735 {"Since", L_SINCE, JT_BACKUP},
736 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
737 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
738 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
739 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
740 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
741 {"Data", L_VERIFY_DATA, JT_VERIFY},
742 {"Full", L_FULL, JT_COPY},
743 {"Incremental", L_INCREMENTAL, JT_COPY},
744 {"Differential", L_DIFFERENTIAL, JT_COPY},
745 {"Full", L_FULL, JT_MIGRATE},
746 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
747 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
748 {" ", L_NONE, JT_ADMIN},
749 {" ", L_NONE, JT_RESTORE},
754 /* Keywords (RHS) permitted in Job type records
759 {"Backup", JT_BACKUP},
761 {"Verify", JT_VERIFY},
762 {"Restore", JT_RESTORE},
763 {"Migrate", JT_MIGRATE},
769 /* Keywords (RHS) permitted in Selection type records
774 {"SmallestVolume", MT_SMALLEST_VOL},
775 {"OldestVolume", MT_OLDEST_VOL},
776 {"PoolOccupancy", MT_POOL_OCCUPANCY},
777 {"PoolTime", MT_POOL_TIME},
778 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
779 {"Client", MT_CLIENT},
780 {"Volume", MT_VOLUME},
782 {"SqlQuery", MT_SQLQUERY},
788 /* Options permitted in Restore replace= */
789 s_kw ReplaceOptions[] = {
790 {"Always", REPLACE_ALWAYS},
791 {"IfNewer", REPLACE_IFNEWER},
792 {"IfOlder", REPLACE_IFOLDER},
793 {"Never", REPLACE_NEVER},
797 char *CAT::display(POOLMEM *dst) {
798 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
799 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
801 name(), NPRTB(db_name),
802 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
803 NPRTB(db_address), db_port, NPRTB(db_socket));
807 const char *level_to_str(int level)
810 static char level_no[30];
811 const char *str = level_no;
813 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
814 for (i=0; joblevels[i].level_name; i++) {
815 if (level == (int)joblevels[i].level) {
816 str = joblevels[i].level_name;
823 /* Dump contents of resource */
824 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
827 URES *res = (URES *)ares;
829 char ed1[100], ed2[100], ed3[100];
831 UAContext *ua = (UAContext *)sock;
834 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
837 if (type < 0) { /* no recursion */
843 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
844 ares->name, res->res_dir.MaxConcurrentJobs,
845 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
846 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
847 if (res->res_dir.query_file) {
848 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
850 if (res->res_dir.messages) {
851 sendit(sock, _(" --> "));
852 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
856 sendit(sock, _("Console: name=%s SSL=%d\n"),
857 res->res_con.hdr.name, res->res_con.tls_enable);
860 if (res->res_counter.WrapCounter) {
861 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
862 res->res_counter.hdr.name, res->res_counter.MinValue,
863 res->res_counter.MaxValue, res->res_counter.CurrentValue,
864 res->res_counter.WrapCounter->hdr.name);
866 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
867 res->res_counter.hdr.name, res->res_counter.MinValue,
868 res->res_counter.MaxValue);
870 if (res->res_counter.Catalog) {
871 sendit(sock, _(" --> "));
872 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
877 if (!acl_access_ok(ua, Client_ACL, res->res_client.name())) {
880 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u NumJobs=%u\n"),
881 res->res_client.name(), res->res_client.is_enabled(),
882 res->res_client.address(), res->res_client.FDport,
883 res->res_client.MaxConcurrentJobs, res->res_client.getNumConcurrentJobs());
884 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
885 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
886 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
887 res->res_client.AutoPrune);
888 if (res->res_client.fd_storage_address) {
889 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
891 if (res->res_client.max_bandwidth) {
892 sendit(sock, _(" MaximumBandwidth=%lld\n"),
893 res->res_client.max_bandwidth);
895 if (res->res_client.catalog) {
896 sendit(sock, _(" --> "));
897 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
904 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
905 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
906 " poolid=%s volname=%s MediaType=%s\n"),
907 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
908 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
909 dev->offline, dev->autochanger,
910 edit_uint64(dev->PoolId, ed1),
911 dev->VolumeName, dev->MediaType);
916 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
919 sendit(sock, _("%s: name=%s address=%s SDport=%d MaxJobs=%u NumJobs=%u\n"
920 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
921 res->res_store.changer == &res->res_store ? "Autochanger" : "Storage",
922 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
923 res->res_store.MaxConcurrentJobs,
924 res->res_store.getNumConcurrentJobs(),
925 res->res_store.dev_name(),
926 res->res_store.media_type,
927 edit_int64(res->res_store.StorageId, ed1),
928 res->res_store.autochanger);
929 if (res->res_store.fd_storage_address) {
930 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
932 if (res->res_store.ac_group) {
933 STORE *shstore = res->res_store.shared_storage;
934 sendit(sock, " AC group=%s ShareStore=%s\n", res->res_store.ac_group,
935 shstore?shstore->name():"*none*");
937 if (res->res_store.changer && res->res_store.changer != &res->res_store) {
938 sendit(sock, _(" Parent --> "));
939 dump_resource(-R_STORAGE, (RES *)res->res_store.changer, sendit, sock);
944 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
947 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
948 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
949 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
950 res->res_cat.db_port, res->res_cat.db_name,
951 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
952 res->res_cat.mult_db_connections);
957 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
960 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
961 type == R_JOB ? _("Job") : _("JobDefs"),
962 res->res_job.hdr.name, res->res_job.JobType,
963 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
964 res->res_job.is_enabled());
965 sendit(sock, _(" MaxJobs=%u NumJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
966 res->res_job.MaxConcurrentJobs,
967 res->res_job.getNumConcurrentJobs(),
968 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
969 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
970 res->res_job.spool_data, res->res_job.write_part_after_job);
971 if (res->res_job.spool_size) {
972 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
974 if (res->res_job.JobType == JT_BACKUP) {
975 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
977 if (res->res_job.max_bandwidth) {
978 sendit(sock, _(" MaximumBandwidth=%lld\n"),
979 res->res_job.max_bandwidth);
981 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
982 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
984 if (res->res_job.JobType == JT_RESTORE) {
985 sendit(sock, _(" PrefixLinks=%d\n"), res->res_job.PrefixLinks);
987 if (res->res_job.client) {
988 sendit(sock, _(" --> "));
989 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
991 if (res->res_job.fileset) {
992 sendit(sock, _(" --> "));
993 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
995 if (res->res_job.schedule) {
996 sendit(sock, _(" --> "));
997 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
999 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
1000 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
1002 if (res->res_job.RegexWhere) {
1003 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
1005 if (res->res_job.RestoreBootstrap) {
1006 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
1008 if (res->res_job.WriteBootstrap) {
1009 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
1011 if (res->res_job.PluginOptions) {
1012 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
1014 if (res->res_job.MaxRunTime) {
1015 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
1017 if (res->res_job.MaxWaitTime) {
1018 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
1020 if (res->res_job.MaxStartDelay) {
1021 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
1023 if (res->res_job.MaxRunSchedTime) {
1024 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
1026 if (res->res_job.storage) {
1028 foreach_alist(store, res->res_job.storage) {
1029 sendit(sock, _(" --> "));
1030 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1033 if (res->res_job.base) {
1035 foreach_alist(job, res->res_job.base) {
1036 sendit(sock, _(" --> Base %s\n"), job->name());
1039 if (res->res_job.RunScripts) {
1041 foreach_alist(script, res->res_job.RunScripts) {
1042 sendit(sock, _(" --> RunScript\n"));
1043 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
1044 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
1045 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
1046 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
1047 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
1048 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
1051 if (res->res_job.pool) {
1052 sendit(sock, _(" --> "));
1053 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
1055 if (res->res_job.full_pool) {
1056 sendit(sock, _(" --> FullBackup"));
1057 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
1059 if (res->res_job.inc_pool) {
1060 sendit(sock, _(" --> IncrementalBackup"));
1061 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
1063 if (res->res_job.diff_pool) {
1064 sendit(sock, _(" --> DifferentialBackup"));
1065 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
1067 if (res->res_job.next_pool) {
1068 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1069 dump_resource(-R_POOL, (RES *)res->res_job.next_pool, sendit, sock);
1071 if (res->res_job.JobType == JT_VERIFY && res->res_job.verify_job) {
1072 sendit(sock, _(" --> JobToVerify %s"), (RES *)res->res_job.verify_job->name());
1074 if (res->res_job.run_cmds) {
1076 foreach_alist(runcmd, res->res_job.run_cmds) {
1077 sendit(sock, _(" --> Run=%s\n"), runcmd);
1080 if (res->res_job.selection_pattern) {
1081 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
1083 if (res->res_job.messages) {
1084 sendit(sock, _(" --> "));
1085 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
1092 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
1095 sendit(sock, _("FileSet: name=%s IgnoreFileSetChanges=%d\n"), res->res_fs.hdr.name, res->res_fs.ignore_fs_changes);
1096 for (i=0; i<res->res_fs.num_includes; i++) {
1097 INCEXE *incexe = res->res_fs.include_items[i];
1098 for (j=0; j<incexe->num_opts; j++) {
1099 FOPTS *fo = incexe->opts_list[j];
1100 sendit(sock, " O %s\n", fo->opts);
1102 bool enhanced_wild = false;
1103 for (k=0; fo->opts[k]!='\0'; k++) {
1104 if (fo->opts[k]=='W') {
1105 enhanced_wild = true;
1110 for (k=0; k<fo->regex.size(); k++) {
1111 sendit(sock, " R %s\n", fo->regex.get(k));
1113 for (k=0; k<fo->regexdir.size(); k++) {
1114 sendit(sock, " RD %s\n", fo->regexdir.get(k));
1116 for (k=0; k<fo->regexfile.size(); k++) {
1117 sendit(sock, " RF %s\n", fo->regexfile.get(k));
1119 for (k=0; k<fo->wild.size(); k++) {
1120 sendit(sock, " W %s\n", fo->wild.get(k));
1122 for (k=0; k<fo->wilddir.size(); k++) {
1123 sendit(sock, " WD %s\n", fo->wilddir.get(k));
1125 for (k=0; k<fo->wildfile.size(); k++) {
1126 sendit(sock, " WF %s\n", fo->wildfile.get(k));
1128 for (k=0; k<fo->wildbase.size(); k++) {
1129 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
1131 for (k=0; k<fo->base.size(); k++) {
1132 sendit(sock, " B %s\n", fo->base.get(k));
1134 for (k=0; k<fo->fstype.size(); k++) {
1135 sendit(sock, " X %s\n", fo->fstype.get(k));
1137 for (k=0; k<fo->drivetype.size(); k++) {
1138 sendit(sock, " XD %s\n", fo->drivetype.get(k));
1141 sendit(sock, " G %s\n", fo->plugin);
1144 sendit(sock, " D %s\n", fo->reader);
1147 sendit(sock, " T %s\n", fo->writer);
1149 sendit(sock, " N\n");
1151 if (incexe->ignoredir) {
1152 sendit(sock, " Z %s\n", incexe->ignoredir);
1154 for (j=0; j<incexe->name_list.size(); j++) {
1155 sendit(sock, " I %s\n", incexe->name_list.get(j));
1157 if (incexe->name_list.size()) {
1158 sendit(sock, " N\n");
1160 for (j=0; j<incexe->plugin_list.size(); j++) {
1161 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
1163 if (incexe->plugin_list.size()) {
1164 sendit(sock, " N\n");
1166 } /* end for over includes */
1168 for (i=0; i<res->res_fs.num_excludes; i++) {
1169 INCEXE *incexe = res->res_fs.exclude_items[i];
1170 for (j=0; j<incexe->name_list.size(); j++) {
1171 sendit(sock, " E %s\n", incexe->name_list.get(j));
1173 if (incexe->name_list.size()) {
1174 sendit(sock, " N\n");
1178 } /* end case R_FILESET */
1181 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
1185 if (res->res_sch.run) {
1187 RUN *run = res->res_sch.run;
1188 char buf[1000], num[30];
1189 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
1190 res->res_sch.hdr.name, res->res_sch.is_enabled());
1195 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
1196 if (run->MaxRunSchedTime) {
1197 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
1199 if (run->Priority) {
1200 sendit(sock, _(" Priority=%u\n"), run->Priority);
1202 bstrncpy(buf, _(" hour="), sizeof(buf));
1203 for (i=0; i<24; i++) {
1204 if (bit_is_set(i, run->hour)) {
1205 bsnprintf(num, sizeof(num), "%d ", i);
1206 bstrncat(buf, num, sizeof(buf));
1209 bstrncat(buf, "\n", sizeof(buf));
1211 bstrncpy(buf, _(" mday="), sizeof(buf));
1212 for (i=0; i<32; i++) {
1213 if (bit_is_set(i, run->mday)) {
1214 bsnprintf(num, sizeof(num), "%d ", i);
1215 bstrncat(buf, num, sizeof(buf));
1218 bstrncat(buf, "\n", sizeof(buf));
1220 bstrncpy(buf, _(" month="), sizeof(buf));
1221 for (i=0; i<12; i++) {
1222 if (bit_is_set(i, run->month)) {
1223 bsnprintf(num, sizeof(num), "%d ", i);
1224 bstrncat(buf, num, sizeof(buf));
1227 bstrncat(buf, "\n", sizeof(buf));
1229 bstrncpy(buf, _(" wday="), sizeof(buf));
1230 for (i=0; i<7; i++) {
1231 if (bit_is_set(i, run->wday)) {
1232 bsnprintf(num, sizeof(num), "%d ", i);
1233 bstrncat(buf, num, sizeof(buf));
1236 bstrncat(buf, "\n", sizeof(buf));
1238 bstrncpy(buf, _(" wom="), sizeof(buf));
1239 for (i=0; i<6; i++) {
1240 if (bit_is_set(i, run->wom)) {
1241 bsnprintf(num, sizeof(num), "%d ", i);
1242 bstrncat(buf, num, sizeof(buf));
1245 bstrncat(buf, "\n", sizeof(buf));
1247 bstrncpy(buf, _(" woy="), sizeof(buf));
1248 for (i=0; i<54; i++) {
1249 if (bit_is_set(i, run->woy)) {
1250 bsnprintf(num, sizeof(num), "%d ", i);
1251 bstrncat(buf, num, sizeof(buf));
1254 bstrncat(buf, "\n", sizeof(buf));
1256 sendit(sock, _(" mins=%d\n"), run->minute);
1258 sendit(sock, _(" --> "));
1259 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
1261 if (run->next_pool) {
1262 sendit(sock, _(" --> Next")); /* Pool will be added by dump_resource */
1263 dump_resource(-R_POOL, (RES *)run->next_pool, sendit, sock);
1266 sendit(sock, _(" --> "));
1267 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
1270 sendit(sock, _(" --> "));
1271 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
1273 /* If another Run record is chained in, go print it */
1279 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1284 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1287 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1288 res->res_pool.pool_type);
1289 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1290 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1291 res->res_pool.catalog_files);
1292 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1293 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1294 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1295 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1296 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1297 res->res_pool.Recycle,
1298 NPRT(res->res_pool.label_format));
1299 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1300 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1301 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1302 res->res_pool.recycle_oldest_volume,
1303 res->res_pool.purge_oldest_volume,
1304 res->res_pool.action_on_purge);
1305 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1306 res->res_pool.MaxVolJobs,
1307 res->res_pool.MaxVolFiles,
1308 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1309 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1310 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1311 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1312 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1313 sendit(sock, _(" CacheRetention=%s\n"),
1314 edit_utime(res->res_pool.CacheRetention, ed1, sizeof(ed1)));
1315 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1316 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1317 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1318 if (res->res_pool.NextPool) {
1319 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1321 if (res->res_pool.RecyclePool) {
1322 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1324 if (res->res_pool.ScratchPool) {
1325 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1327 if (res->res_pool.catalog) {
1328 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1330 if (res->res_pool.storage) {
1332 foreach_alist(store, res->res_pool.storage) {
1333 sendit(sock, _(" --> "));
1334 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1337 if (res->res_pool.CopyPool) {
1339 foreach_alist(copy, res->res_pool.CopyPool) {
1340 sendit(sock, _(" --> "));
1341 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1348 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1349 if (res->res_msgs.mail_cmd)
1350 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1351 if (res->res_msgs.operator_cmd)
1352 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1356 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1360 next = GetNextRes(0, (RES *)res);
1362 dump_resource(type, next, sendit, sock);
1368 * Free all the members of an INCEXE structure
1370 static void free_incexe(INCEXE *incexe)
1372 incexe->name_list.destroy();
1373 incexe->plugin_list.destroy();
1374 for (int i=0; i<incexe->num_opts; i++) {
1375 FOPTS *fopt = incexe->opts_list[i];
1376 fopt->regex.destroy();
1377 fopt->regexdir.destroy();
1378 fopt->regexfile.destroy();
1379 fopt->wild.destroy();
1380 fopt->wilddir.destroy();
1381 fopt->wildfile.destroy();
1382 fopt->wildbase.destroy();
1383 fopt->base.destroy();
1384 fopt->fstype.destroy();
1385 fopt->drivetype.destroy();
1397 if (incexe->opts_list) {
1398 free(incexe->opts_list);
1400 if (incexe->ignoredir) {
1401 free(incexe->ignoredir);
1408 * Free memory of resource -- called when daemon terminates.
1409 * NB, we don't need to worry about freeing any references
1410 * to other resources as they will be freed when that
1411 * resource chain is traversed. Mainly we worry about freeing
1412 * allocated strings (names).
1414 void free_resource(RES *rres, int type)
1417 URES *res = (URES *)rres;
1423 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1424 /* common stuff -- free the resource name and description */
1425 if (res->res_dir.hdr.name) {
1426 free(res->res_dir.hdr.name);
1428 if (res->res_dir.hdr.desc) {
1429 free(res->res_dir.hdr.desc);
1434 if (res->res_dir.working_directory) {
1435 free(res->res_dir.working_directory);
1437 if (res->res_dir.scripts_directory) {
1438 free((char *)res->res_dir.scripts_directory);
1440 if (res->res_dir.plugin_directory) {
1441 free((char *)res->res_dir.plugin_directory);
1443 if (res->res_dir.pid_directory) {
1444 free(res->res_dir.pid_directory);
1446 if (res->res_dir.subsys_directory) {
1447 free(res->res_dir.subsys_directory);
1449 if (res->res_dir.password) {
1450 free(res->res_dir.password);
1452 if (res->res_dir.query_file) {
1453 free(res->res_dir.query_file);
1455 if (res->res_dir.DIRaddrs) {
1456 free_addresses(res->res_dir.DIRaddrs);
1458 if (res->res_dir.DIRsrc_addr) {
1459 free_addresses(res->res_dir.DIRsrc_addr);
1461 if (res->res_dir.tls_ctx) {
1462 free_tls_context(res->res_dir.tls_ctx);
1464 if (res->res_dir.tls_ca_certfile) {
1465 free(res->res_dir.tls_ca_certfile);
1467 if (res->res_dir.tls_ca_certdir) {
1468 free(res->res_dir.tls_ca_certdir);
1470 if (res->res_dir.tls_certfile) {
1471 free(res->res_dir.tls_certfile);
1473 if (res->res_dir.tls_keyfile) {
1474 free(res->res_dir.tls_keyfile);
1476 if (res->res_dir.tls_dhfile) {
1477 free(res->res_dir.tls_dhfile);
1479 if (res->res_dir.tls_allowed_cns) {
1480 delete res->res_dir.tls_allowed_cns;
1482 if (res->res_dir.verid) {
1483 free(res->res_dir.verid);
1490 if (res->res_con.password) {
1491 free(res->res_con.password);
1493 if (res->res_con.tls_ctx) {
1494 free_tls_context(res->res_con.tls_ctx);
1496 if (res->res_con.tls_ca_certfile) {
1497 free(res->res_con.tls_ca_certfile);
1499 if (res->res_con.tls_ca_certdir) {
1500 free(res->res_con.tls_ca_certdir);
1502 if (res->res_con.tls_certfile) {
1503 free(res->res_con.tls_certfile);
1505 if (res->res_con.tls_keyfile) {
1506 free(res->res_con.tls_keyfile);
1508 if (res->res_con.tls_dhfile) {
1509 free(res->res_con.tls_dhfile);
1511 if (res->res_con.tls_allowed_cns) {
1512 delete res->res_con.tls_allowed_cns;
1514 for (int i=0; i<Num_ACL; i++) {
1515 if (res->res_con.ACL_lists[i]) {
1516 delete res->res_con.ACL_lists[i];
1517 res->res_con.ACL_lists[i] = NULL;
1522 if (res->res_client.client_address) {
1523 free(res->res_client.client_address);
1525 if (res->res_client.fd_storage_address) {
1526 free(res->res_client.fd_storage_address);
1528 if (res->res_client.password) {
1529 free(res->res_client.password);
1531 if (res->res_client.tls_ctx) {
1532 free_tls_context(res->res_client.tls_ctx);
1534 if (res->res_client.tls_ca_certfile) {
1535 free(res->res_client.tls_ca_certfile);
1537 if (res->res_client.tls_ca_certdir) {
1538 free(res->res_client.tls_ca_certdir);
1540 if (res->res_client.tls_certfile) {
1541 free(res->res_client.tls_certfile);
1543 if (res->res_client.tls_keyfile) {
1544 free(res->res_client.tls_keyfile);
1546 if (res->res_client.tls_allowed_cns) {
1547 delete res->res_client.tls_allowed_cns;
1552 if (res->res_store.address) {
1553 free(res->res_store.address);
1555 if (res->res_store.fd_storage_address) {
1556 free(res->res_store.fd_storage_address);
1558 if (res->res_store.password) {
1559 free(res->res_store.password);
1561 if (res->res_store.media_type) {
1562 free(res->res_store.media_type);
1564 if (res->res_store.ac_group) {
1565 free_pool_memory(res->res_store.ac_group);
1567 if (res->res_store.device) {
1568 delete res->res_store.device;
1570 if (res->res_store.tls_ctx) {
1571 free_tls_context(res->res_store.tls_ctx);
1573 if (res->res_store.tls_ca_certfile) {
1574 free(res->res_store.tls_ca_certfile);
1576 if (res->res_store.tls_ca_certdir) {
1577 free(res->res_store.tls_ca_certdir);
1579 if (res->res_store.tls_certfile) {
1580 free(res->res_store.tls_certfile);
1582 if (res->res_store.tls_keyfile) {
1583 free(res->res_store.tls_keyfile);
1587 if (res->res_cat.db_address) {
1588 free(res->res_cat.db_address);
1590 if (res->res_cat.db_socket) {
1591 free(res->res_cat.db_socket);
1593 if (res->res_cat.db_user) {
1594 free(res->res_cat.db_user);
1596 if (res->res_cat.db_name) {
1597 free(res->res_cat.db_name);
1599 if (res->res_cat.db_driver) {
1600 free(res->res_cat.db_driver);
1602 if (res->res_cat.db_password) {
1603 free(res->res_cat.db_password);
1605 if (res->res_cat.db_ssl_mode) {
1606 free(res->res_cat.db_ssl_mode);
1608 if (res->res_cat.db_ssl_key) {
1609 free(res->res_cat.db_ssl_key);
1611 if (res->res_cat.db_ssl_cert) {
1612 free(res->res_cat.db_ssl_cert);
1614 if (res->res_cat.db_ssl_ca) {
1615 free(res->res_cat.db_ssl_ca);
1617 if (res->res_cat.db_ssl_capath) {
1618 free(res->res_cat.db_ssl_capath);
1620 if (res->res_cat.db_ssl_cipher) {
1621 free(res->res_cat.db_ssl_cipher);
1625 if ((num=res->res_fs.num_includes)) {
1626 while (--num >= 0) {
1627 free_incexe(res->res_fs.include_items[num]);
1629 free(res->res_fs.include_items);
1631 res->res_fs.num_includes = 0;
1632 if ((num=res->res_fs.num_excludes)) {
1633 while (--num >= 0) {
1634 free_incexe(res->res_fs.exclude_items[num]);
1636 free(res->res_fs.exclude_items);
1638 res->res_fs.num_excludes = 0;
1641 if (res->res_pool.pool_type) {
1642 free(res->res_pool.pool_type);
1644 if (res->res_pool.label_format) {
1645 free(res->res_pool.label_format);
1647 if (res->res_pool.cleaning_prefix) {
1648 free(res->res_pool.cleaning_prefix);
1650 if (res->res_pool.storage) {
1651 delete res->res_pool.storage;
1655 if (res->res_sch.run) {
1657 nrun = res->res_sch.run;
1667 if (res->res_job.RestoreWhere) {
1668 free(res->res_job.RestoreWhere);
1670 if (res->res_job.RegexWhere) {
1671 free(res->res_job.RegexWhere);
1673 if (res->res_job.strip_prefix) {
1674 free(res->res_job.strip_prefix);
1676 if (res->res_job.add_prefix) {
1677 free(res->res_job.add_prefix);
1679 if (res->res_job.add_suffix) {
1680 free(res->res_job.add_suffix);
1682 if (res->res_job.RestoreBootstrap) {
1683 free(res->res_job.RestoreBootstrap);
1685 if (res->res_job.WriteBootstrap) {
1686 free(res->res_job.WriteBootstrap);
1688 if (res->res_job.PluginOptions) {
1689 free(res->res_job.PluginOptions);
1691 if (res->res_job.selection_pattern) {
1692 free(res->res_job.selection_pattern);
1694 if (res->res_job.run_cmds) {
1695 delete res->res_job.run_cmds;
1697 if (res->res_job.storage) {
1698 delete res->res_job.storage;
1700 if (res->res_job.base) {
1701 delete res->res_job.base;
1703 if (res->res_job.RunScripts) {
1704 free_runscripts(res->res_job.RunScripts);
1705 delete res->res_job.RunScripts;
1709 if (res->res_msgs.mail_cmd) {
1710 free(res->res_msgs.mail_cmd);
1712 if (res->res_msgs.operator_cmd) {
1713 free(res->res_msgs.operator_cmd);
1715 free_msgs_res((MSGS *)res); /* free message resource */
1719 printf(_("Unknown resource type %d in free_resource.\n"), type);
1721 /* Common stuff again -- free the resource, recurse to next one */
1728 * Save the new resource by chaining it into the head list for
1729 * the resource. If this is pass 2, we update any resource
1730 * pointers because they may not have been defined until
1733 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
1736 int rindex = type - r_first;
1740 /* Check Job requirements after applying JobDefs */
1741 if (type != R_JOB && type != R_JOBDEFS) {
1743 * Ensure that all required items are present
1745 for (i=0; items[i].name; i++) {
1746 if (items[i].flags & ITEM_REQUIRED) {
1747 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1748 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1749 items[i].name, resources[rindex].name);
1753 /* If this triggers, take a look at lib/parse_conf.h */
1754 if (i >= MAX_RES_ITEMS) {
1755 Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
1759 } else if (type == R_JOB) {
1761 * Ensure that the name item is present
1763 if (items[0].flags & ITEM_REQUIRED) {
1764 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1765 Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
1766 items[0].name, resources[rindex].name);
1773 * During pass 2 in each "store" routine, we looked up pointers
1774 * to all the resources referrenced in the current resource, now we
1775 * must copy their addresses from the static record to the allocated
1780 /* Resources not containing a resource */
1788 * Resources containing another resource or alist. First
1789 * look up the resource which contains another resource. It
1790 * was written during pass 1. Then stuff in the pointers to
1791 * the resources it contains, which were inserted this pass.
1792 * Finally, it will all be stored back.
1795 /* Find resource saved in pass 1 */
1796 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1797 Mmsg(config->m_errmsg, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1800 /* Explicitly copy resource pointers from this pass (res_all) */
1801 res->res_pool.NextPool = res_all.res_pool.NextPool;
1802 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1803 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1804 res->res_pool.storage = res_all.res_pool.storage;
1805 res->res_pool.catalog = res_all.res_pool.catalog;
1808 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1809 Mmsg(config->m_errmsg, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1812 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1815 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1816 Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1819 res->res_dir.messages = res_all.res_dir.messages;
1820 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1822 case R_AUTOCHANGER: /* alias for R_STORAGE */
1824 type = R_STORAGE; /* force Storage type */
1825 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1826 Mmsg(config->m_errmsg, _("Cannot find Storage resource %s\n"),
1827 res_all.res_dir.hdr.name);
1830 /* we must explicitly copy the device alist pointer */
1831 res->res_store.device = res_all.res_store.device;
1832 res->res_store.changer = res_all.res_store.changer;
1833 res->res_store.shared_storage = res_all.res_store.shared_storage;
1834 res->res_store.autochanger = res_all.res_store.autochanger;
1835 if (strcasecmp(resources[rindex].name, "autochanger") == 0) {
1836 res->res_store.changer = &res->res_store;
1837 res->res_store.autochanger = true;
1842 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1843 Mmsg(config->m_errmsg, _("Cannot find Job resource %s\n"),
1844 res_all.res_dir.hdr.name);
1847 res->res_job.messages = res_all.res_job.messages;
1848 res->res_job.schedule = res_all.res_job.schedule;
1849 res->res_job.client = res_all.res_job.client;
1850 res->res_job.fileset = res_all.res_job.fileset;
1851 res->res_job.storage = res_all.res_job.storage;
1852 res->res_job.base = res_all.res_job.base;
1853 res->res_job.pool = res_all.res_job.pool;
1854 res->res_job.next_pool = res_all.res_job.next_pool;
1855 res->res_job.full_pool = res_all.res_job.full_pool;
1856 res->res_job.inc_pool = res_all.res_job.inc_pool;
1857 res->res_job.diff_pool = res_all.res_job.diff_pool;
1858 res->res_job.verify_job = res_all.res_job.verify_job;
1859 res->res_job.jobdefs = res_all.res_job.jobdefs;
1860 res->res_job.run_cmds = res_all.res_job.run_cmds;
1861 res->res_job.RunScripts = res_all.res_job.RunScripts;
1863 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1864 * is not very useful)
1865 * We have to set_bit(index, res_all.hdr.item_present);
1866 * or something like that
1869 /* we take RegexWhere before all other options */
1870 if (!res->res_job.RegexWhere
1872 (res->res_job.strip_prefix ||
1873 res->res_job.add_suffix ||
1874 res->res_job.add_prefix))
1876 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1877 res->res_job.add_prefix,
1878 res->res_job.add_suffix);
1879 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1880 bregexp_build_where(res->res_job.RegexWhere, len,
1881 res->res_job.strip_prefix,
1882 res->res_job.add_prefix,
1883 res->res_job.add_suffix);
1884 /* TODO: test bregexp */
1887 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1888 free(res->res_job.RestoreWhere);
1889 res->res_job.RestoreWhere = NULL;
1894 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1895 Mmsg(config->m_errmsg, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1898 res->res_counter.Catalog = res_all.res_counter.Catalog;
1899 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1903 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.name())) == NULL) {
1904 Mmsg(config->m_errmsg, _("Cannot find Client resource %s\n"), res_all.res_client.name());
1907 res->res_client.catalog = res_all.res_client.catalog;
1908 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1912 * Schedule is a bit different in that it contains a RUN record
1913 * chain which isn't a "named" resource. This chain was linked
1914 * in by run_conf.c during pass 2, so here we jam the pointer
1915 * into the Schedule resource.
1917 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.name())) == NULL) {
1918 Mmsg(config->m_errmsg, _("Cannot find Schedule resource %s\n"), res_all.res_client.name());
1921 res->res_sch.run = res_all.res_sch.run;
1924 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1928 /* Note, the resource name was already saved during pass 1,
1929 * so here, we can just release it.
1931 if (res_all.res_dir.hdr.name) {
1932 free(res_all.res_dir.hdr.name);
1933 res_all.res_dir.hdr.name = NULL;
1935 if (res_all.res_dir.hdr.desc) {
1936 free(res_all.res_dir.hdr.desc);
1937 res_all.res_dir.hdr.desc = NULL;
1942 /* R_AUTOCHANGER is alias so turn it into an R_STORAGE */
1943 if (type == R_AUTOCHANGER) {
1945 rindex = type - r_first;
1949 * The following code is only executed during pass 1
1953 size = sizeof(DIRRES);
1956 size = sizeof(CONRES);
1959 size =sizeof(CLIENT);
1962 size = sizeof(STORE);
1972 size = sizeof(FILESET);
1975 size = sizeof(SCHED);
1978 size = sizeof(POOL);
1981 size = sizeof(MSGS);
1984 size = sizeof(COUNTER);
1990 printf(_("Unknown resource type %d in save_resource.\n"), type);
1996 if (!config->insert_res(rindex, size)) {
2003 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
2005 uint32_t *destination = (uint32_t*)item->value;
2006 lex_get_token(lc, T_NAME);
2007 if (strcasecmp(lc->str, "truncate") == 0) {
2008 *destination = (*destination) | ON_PURGE_TRUNCATE;
2010 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
2014 set_bit(index, res_all.hdr.item_present);
2018 * Store an autochanger resource. Used by Autochanger and
2019 * SharedStorage direcives.
2021 void store_ac_res(LEX *lc, RES_ITEM *item, int index, int pass)
2024 RES_ITEM *next = item + 1;
2026 lex_get_token(lc, T_NAME);
2027 Dmsg1(100, "Got name=%s\n", lc->str);
2029 * For backward compatibility, if yes/no, set the next item
2031 if (strcasecmp(item->name, "autochanger") == 0) {
2032 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2033 *(bool *)(next->value) = true;
2034 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2037 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2038 *(bool *)(next->value) = false;
2039 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2044 Dmsg2(100, "Item=%s got value=%s\n", item->name, lc->str);
2047 res = GetResWithName(R_STORAGE, lc->str);
2049 scan_err3(lc, _("Could not find Storage Resource %s referenced on line %d : %s\n"),
2050 lc->str, lc->line_no, lc->line);
2053 if (*(item->value)) {
2054 scan_err3(lc, _("Attempt to redefine Storage resource \"%s\" referenced on line %d : %s\n"),
2055 item->name, lc->line_no, lc->line);
2058 Dmsg2(100, "Store %s value=%p\n", lc->str, res);
2059 *(item->value) = (char *)res;
2060 *(bool *)(next->value) = true;
2063 set_bit(index, res_all.hdr.item_present);
2068 * Store Device. Note, the resource is created upon the
2069 * first reference. The details of the resource are obtained
2070 * later from the SD.
2072 void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
2074 int rindex = R_DEVICE - r_first;
2075 int size = sizeof(DEVICE);
2081 lex_get_token(lc, T_NAME);
2082 rblist *list = res_head[rindex]->res_list;
2083 ures = (URES *)malloc(size);
2084 memset(ures, 0, size);
2085 ures->res_dev.hdr.name = bstrdup(lc->str);
2087 if (list->empty()) {
2088 list->insert(res, res_compare);
2089 res_head[rindex]->first = res;
2090 res_head[rindex]->last = res;
2093 prev = res_head[rindex]->last;
2094 item = (RES *)list->insert(res, res_compare);
2096 prev->res_next = res;
2097 res_head[rindex]->last = res;
2099 /* res not inserted */
2100 free(ures->res_dev.hdr.name);
2105 set_bit(index, res_all.hdr.item_present);
2107 store_alist_res(lc, item, index, pass);
2112 * Store Migration/Copy type
2115 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
2119 lex_get_token(lc, T_NAME);
2120 /* Store the type both pass 1 and pass 2 */
2121 for (i=0; migtypes[i].type_name; i++) {
2122 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
2123 *(uint32_t *)(item->value) = migtypes[i].job_type;
2129 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
2132 set_bit(index, res_all.hdr.item_present);
2138 * Store JobType (backup, verify, restore)
2141 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
2145 lex_get_token(lc, T_NAME);
2146 /* Store the type both pass 1 and pass 2 */
2147 for (i=0; jobtypes[i].type_name; i++) {
2148 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
2149 *(uint32_t *)(item->value) = jobtypes[i].job_type;
2155 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
2158 set_bit(index, res_all.hdr.item_present);
2162 * Store Job Level (Full, Incremental, ...)
2165 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
2169 lex_get_token(lc, T_NAME);
2170 /* Store the level pass 2 so that type is defined */
2171 for (i=0; joblevels[i].level_name; i++) {
2172 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
2173 *(uint32_t *)(item->value) = joblevels[i].level;
2179 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
2182 set_bit(index, res_all.hdr.item_present);
2186 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
2189 lex_get_token(lc, T_NAME);
2190 /* Scan Replacement options */
2191 for (i=0; ReplaceOptions[i].name; i++) {
2192 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
2193 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
2199 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
2202 set_bit(index, res_all.hdr.item_present);
2206 * Store ACL (access control list)
2209 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
2214 lex_get_token(lc, T_STRING);
2216 if (((alist **)item->value)[item->code] == NULL) {
2217 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
2218 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
2220 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
2221 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
2223 token = lex_get_token(lc, T_ALL);
2224 if (token == T_COMMA) {
2225 continue; /* get another ACL */
2229 set_bit(index, res_all.hdr.item_present);
2232 /* We build RunScripts items here */
2233 static RUNSCRIPT res_runscript;
2235 /* Store a runscript->when in a bit field */
2236 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
2238 lex_get_token(lc, T_NAME);
2240 if (strcasecmp(lc->str, "before") == 0) {
2241 *(uint32_t *)(item->value) = SCRIPT_Before ;
2242 } else if (strcasecmp(lc->str, "after") == 0) {
2243 *(uint32_t *)(item->value) = SCRIPT_After;
2244 } else if (strcasecmp(lc->str, "aftervss") == 0) {
2245 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2246 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
2247 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
2248 } else if (strcasecmp(lc->str, "always") == 0) {
2249 *(uint32_t *)(item->value) = SCRIPT_Any;
2251 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
2256 /* Store a runscript->target
2259 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
2261 lex_get_token(lc, T_STRING);
2264 if (strcmp(lc->str, "%c") == 0) {
2265 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2266 } else if (strcasecmp(lc->str, "yes") == 0) {
2267 ((RUNSCRIPT*) item->value)->set_target("%c");
2268 } else if (strcasecmp(lc->str, "no") == 0) {
2269 ((RUNSCRIPT*) item->value)->set_target("");
2271 RES *res = GetResWithName(R_CLIENT, lc->str);
2273 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
2274 lc->str, lc->line_no, lc->line);
2277 ((RUNSCRIPT*) item->value)->set_target(lc->str);
2284 * Store a runscript->command as a string and runscript->cmd_type as a pointer
2286 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
2288 lex_get_token(lc, T_STRING);
2291 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
2292 POOLMEM *c = get_pool_memory(PM_FNAME);
2293 /* Each runscript command takes 2 entries in commands list */
2294 pm_strcpy(c, lc->str);
2295 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
2296 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
2301 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2303 lex_get_token(lc, T_STRING);
2304 alist **runscripts = (alist **)(item->value) ;
2307 RUNSCRIPT *script = new_runscript();
2308 script->set_job_code_callback(job_code_callback_director);
2310 script->set_command(lc->str);
2312 /* TODO: remove all script->old_proto with bacula 1.42 */
2314 if (strcasecmp(item->name, "runbeforejob") == 0) {
2315 script->when = SCRIPT_Before;
2316 script->fail_on_error = true;
2317 script->set_target("");
2319 } else if (strcasecmp(item->name, "runafterjob") == 0) {
2320 script->when = SCRIPT_After;
2321 script->on_success = true;
2322 script->on_failure = false;
2323 script->set_target("");
2325 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
2326 script->old_proto = true;
2327 script->when = SCRIPT_Before;
2328 script->set_target("%c");
2329 script->fail_on_error = true;
2331 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
2332 script->old_proto = true;
2333 script->when = SCRIPT_After;
2334 script->set_target("%c");
2335 script->on_success = true;
2336 script->on_failure = false;
2338 } else if (strcasecmp(item->name, "consolerunbeforejob") == 0) {
2339 script->when = SCRIPT_Before;
2340 script->set_target("");
2341 script->fail_on_error = true;
2342 script->set_command(NPRT(script->command), CONSOLE_CMD);
2344 } else if (strcasecmp(item->name, "consolerunafterjob") == 0) {
2345 script->when = SCRIPT_After;
2346 script->set_target("");
2347 script->on_success = true;
2348 script->on_failure = false;
2349 script->set_command(NPRT(script->command), CONSOLE_CMD);
2351 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
2352 script->when = SCRIPT_After;
2353 script->on_failure = true;
2354 script->on_success = false;
2355 script->set_target("");
2358 if (*runscripts == NULL) {
2359 *runscripts = New(alist(10, not_owned_by_alist));
2362 (*runscripts)->append(script);
2366 set_bit(index, res_all.hdr.item_present);
2369 /* Store a bool in a bit field without modifing res_all.hdr
2370 * We can also add an option to store_bool to skip res_all.hdr
2372 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2374 lex_get_token(lc, T_NAME);
2375 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2376 *(bool *)(item->value) = true;
2377 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2378 *(bool *)(item->value) = false;
2380 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2386 * new RunScript items
2387 * name handler value code flags default_value
2389 static RES_ITEM runscript_items[] = {
2390 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2391 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2392 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2393 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2394 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2395 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2396 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2397 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2398 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2399 {NULL, NULL, {0}, 0, 0, 0}
2403 * Store RunScript info
2405 * Note, when this routine is called, we are inside a Job
2406 * resource. We treat the RunScript like a sort of
2407 * mini-resource within the Job resource.
2409 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2413 alist **runscripts = (alist **)(item->value) ;
2415 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2417 token = lex_get_token(lc, T_SKIP_EOL);
2419 if (token != T_BOB) {
2420 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2422 /* setting on_success, on_failure, fail_on_error */
2423 res_runscript.reset_default();
2426 res_runscript.commands = New(alist(10, not_owned_by_alist));
2429 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2430 if (token == T_EOB) {
2433 if (token != T_IDENTIFIER) {
2434 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2436 for (i=0; runscript_items[i].name; i++) {
2437 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2438 token = lex_get_token(lc, T_SKIP_EOL);
2439 if (token != T_EQUALS) {
2440 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2443 /* Call item handler */
2444 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2451 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2456 /* run on client by default */
2457 if (res_runscript.target == NULL) {
2458 res_runscript.set_target("%c");
2460 if (*runscripts == NULL) {
2461 *runscripts = New(alist(10, not_owned_by_alist));
2464 * commands list contains 2 values per command
2465 * - POOLMEM command string (ex: /bin/true)
2466 * - int command type (ex: SHELL_CMD)
2468 res_runscript.set_job_code_callback(job_code_callback_director);
2469 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2470 t = (intptr_t)res_runscript.commands->pop();
2471 RUNSCRIPT *script = new_runscript();
2472 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2473 script->command = c;
2474 script->cmd_type = t;
2475 /* target is taken from res_runscript, each runscript object have
2478 script->target = NULL;
2479 script->set_target(res_runscript.target);
2481 (*runscripts)->append(script);
2484 delete res_runscript.commands;
2485 /* setting on_success, on_failure... cleanup target field */
2486 res_runscript.reset_default(true);
2490 set_bit(index, res_all.hdr.item_present);
2493 /* callback function for edit_job_codes */
2494 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2495 extern "C" char *job_code_callback_director(JCR *jcr, const char* param, char *buf, int buflen)
2497 static char yes[] = "yes";
2498 static char no[] = "no";
2499 static char nothing[] = "";
2507 return jcr->fileset->name();
2511 if (jcr->client && jcr->client->address()) {
2512 return jcr->client->address();
2517 return jcr->pool->name();
2522 return jcr->wstore->name();
2526 return jcr->spool_data ? yes : no;
2530 return jcr->cloned ? yes : no;
2534 edit_uint64(jcr->wjcr->JobId, buf);
2537 edit_uint64(0, buf);
2545 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2547 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2548 r_first, r_last, resources, &res_head);
2549 return config->parse_config();