2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Main configuration file parser for Bacula Directors,
22 * some parts may be split into separate files such as
23 * the schedule configuration (run_config.c).
25 * Note, the configuration file parser consists of three parts
27 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
29 * 2. The generic config scanner in lib/parse_config.c and
31 * These files contain the parser code, some utility
32 * routines, and the common store routines (name, int,
35 * 3. The daemon specific file, which contains the Resource
36 * definitions as well as any specific store routines
37 * for the resource records.
39 * Kern Sibbald, January MM
47 /* Define the first and last resource ID record
48 * types. Note, these should be unique for each
49 * daemon though not a requirement.
51 int32_t r_first = R_FIRST;
52 int32_t r_last = R_LAST;
53 static RES *sres_head[R_LAST - R_FIRST + 1];
54 RES **res_head = sres_head;
56 /* Imported subroutines */
57 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
58 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
59 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
62 /* Forward referenced subroutines */
64 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
65 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
66 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
67 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
68 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
69 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
70 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
71 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
72 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
73 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
75 /* We build the current resource here as we are
76 * scanning the resource configuration definition,
77 * then move it to allocated memory when the resource
81 extern "C" { // work around visual compiler mangling variables
87 int32_t res_all_size = sizeof(res_all);
90 * Definition of records permitted within each
91 * resource with the routine to process the record
97 * name handler value code flags default_value
99 static RES_ITEM dir_items[] = {
100 {"Name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
101 {"Description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
102 {"Messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
103 {"DirPort", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
104 {"DirAddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
105 {"DirAddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
106 {"DirSourceAddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
107 {"QueryFile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
108 {"WorkingDirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
109 {"PluginDirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
110 {"ScriptsDirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
111 {"PidDirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
112 {"SubsysDirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
113 {"MaximumConcurrentJobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
114 {"MaximumReloadRequests", store_pint32, ITEM(res_dir.MaxReload), 0, ITEM_DEFAULT, 32},
115 {"MaximumConsoleConnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
116 {"Password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
117 {"FdConnectTimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
118 {"SdConnectTimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
119 {"HeartbeatInterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
120 {"TlsAuthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
121 {"TlsEnable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
122 {"TlsRequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
123 {"TlsVerifyPeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
124 {"TlsCaCertificateFile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
125 {"TlsCaCertificateDir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
126 {"TlsCertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
127 {"TlsKey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
128 {"TlsDhFile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
129 {"TlsAllowedCn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
130 {"StatisticsRetention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
131 {"VerId", store_str, ITEM(res_dir.verid), 0, 0, 0},
132 {NULL, NULL, {0}, 0, 0, 0}
138 * name handler value code flags default_value
140 static RES_ITEM con_items[] = {
141 {"Name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
142 {"Description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
143 {"Password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
144 {"JobAcl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
145 {"ClientAcl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
146 {"StorageAcl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
147 {"ScheduleAcl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
148 {"RunAcl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
149 {"PoolAcl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
150 {"CommandAcl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
151 {"FilesetAcl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
152 {"CatalogAcl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
153 {"WhereAcl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
154 {"PluginOptionsAcl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
155 {"TlsAuthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
156 {"TlsEnable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
157 {"TlsRequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
158 {"TlsVerifyPeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
159 {"TlsCaCertificateFile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
160 {"TlsCaCertificateDir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
161 {"TlsCertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
162 {"TlsKey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
163 {"TlsDhFile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
164 {"TlsAllowedCn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
165 {NULL, NULL, {0}, 0, 0, 0}
170 * Client or File daemon resource
172 * name handler value code flags default_value
175 static RES_ITEM cli_items[] = {
176 {"Name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
177 {"Description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
178 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
179 {"Address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
180 {"FdPort", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
181 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
182 {"Password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
183 {"FdStorageAddress", store_str, ITEM(res_client.fd_storage_address), 0, 0, 0},
184 {"Catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
185 {"FileRetention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
186 {"JobRetention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
187 {"HeartbeatInterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
188 {"AutoPrune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
189 {"SDCallsClient", store_bool, ITEM(res_client.sd_calls_client), 0, ITEM_DEFAULT, false},
190 {"SnapshotRetention", store_time, ITEM(res_client.SnapRetention), 0, ITEM_DEFAULT, 0},
191 {"MaximumConcurrentJobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
192 {"TlsAuthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
193 {"TlsEnable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
194 {"TlsRequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
195 {"TlsCaCertificateFile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
196 {"TlsCaCertificateDir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
197 {"TlsCertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
198 {"TlsKey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
199 {"TlsAllowedCn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
200 {"MaximumBandwidthPerJob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
201 {"Enabled", store_bool, ITEM(res_client.enabled), 0, ITEM_DEFAULT, true},
202 {NULL, NULL, {0}, 0, 0, 0}
205 /* Storage daemon resource
207 * name handler value code flags default_value
209 static RES_ITEM store_items[] = {
210 {"Name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
211 {"Description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
212 {"SdPort", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
213 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
214 {"Address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
215 {"FdStorageAddress", store_str, ITEM(res_store.fd_storage_address), 0, 0, 0},
216 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
217 {"Password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
218 {"Device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
219 {"MediaType", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
220 {"Autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, false},
221 {"Enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
222 {"AllowCompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
223 {"HeartbeatInterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 5 * 60},
224 {"MaximumConcurrentJobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
225 {"MaximumConcurrentReadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
226 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
227 {"TlsAuthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
228 {"TlsEnable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
229 {"TlsRequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
230 {"TlsCaCertificateFile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
231 {"TlsCaCertificateDir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
232 {"TlsCertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
233 {"TlsKey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
234 {NULL, NULL, {0}, 0, 0, 0}
238 * Catalog Resource Directives
240 * name handler value code flags default_value
242 static RES_ITEM cat_items[] = {
243 {"Name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
244 {"Description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
245 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
246 {"Address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
247 {"DbPort", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
248 /* keep this password as store_str for the moment */
249 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
250 {"Password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
251 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
252 {"User", store_str, ITEM(res_cat.db_user), 0, 0, 0},
253 {"DbName", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
254 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
255 {"DbSocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
256 /* Turned off for the moment */
257 {"MultipleConnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
258 {"DisableBatchInsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
259 {NULL, NULL, {0}, 0, 0, 0}
263 * Job Resource Directives
265 * name handler value code flags default_value
267 RES_ITEM job_items[] = {
268 {"Name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
269 {"Description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
270 {"Type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
271 {"Level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
272 {"Messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
273 {"Storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
274 {"Pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
275 {"NextPool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
276 {"FullBackupPool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
277 {"IncrementalBackupPool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
278 {"DifferentialBackupPool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
279 {"Client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
280 {"Fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
281 {"Schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
282 {"VerifyJob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
283 {"JobToVerify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
284 {"JobDefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
285 {"Run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
286 /* Root of where to restore files */
287 {"Where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
288 {"RegexWhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
289 {"StripPrefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
290 {"AddPrefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
291 {"AddSuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
292 /* Where to find bootstrap during restore */
293 {"Bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
294 /* Where to write bootstrap file during backup */
295 {"WriteBootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
296 {"WriteVerifyList",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
297 {"Replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
298 {"MaximumBandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
299 {"MaxRunSchedTime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
300 {"MaxRunTime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
301 /* xxxMaxWaitTime are deprecated */
302 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
303 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
304 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
305 {"FullMaxRunTime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
306 {"IncrementalMaxRunTime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
307 {"DifferentialMaxRunTime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
308 {"MaxWaitTime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
309 {"MaxStartDelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
310 {"MaxFullInterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
311 {"MaxDiffInterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
312 {"PrefixLinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
313 {"PruneJobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
314 {"PruneFiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
315 {"PruneVolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
316 {"PurgeMigrationJob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
317 {"Enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
318 {"SnapshotRetention", store_time, ITEM(res_job.SnapRetention), 0, ITEM_DEFAULT, 0},
319 {"SpoolAttributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, true},
320 {"SpoolData", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
321 {"SpoolSize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
322 {"ReRunFailedLevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
323 {"PreferMountedVolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
324 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
327 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
328 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
329 {"Runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
330 {"MaximumConcurrentJobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
331 {"MaximumSpawnedJobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
332 {"RescheduleOnError", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
333 {"RescheduleIncompleteJobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
334 {"RescheduleInterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
335 {"RescheduleTimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
336 {"Priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
337 {"AllowMixedPriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
338 {"WritePartAfterJob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
339 {"SelectionPattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
340 {"SelectionType", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
341 {"Accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
342 {"AllowDuplicateJobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
343 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
344 {"CancelLowerLevelDuplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
345 {"CancelQueuedDuplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
346 {"CancelRunningDuplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
347 {"PluginOptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
348 {"Base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
349 {NULL, NULL, {0}, 0, 0, 0}
354 * Name handler value code flags default_value
356 static RES_ITEM fs_items[] = {
357 {"Name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
358 {"Description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
359 {"IgnoreFilesetChanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
360 {"EnableVss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
361 {"EnableSnapshot",store_bool, ITEM(res_fs.enable_snapshot), 0, ITEM_DEFAULT, false},
362 {"Include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
363 {"Exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
364 {NULL, NULL, {0}, 0, 0, 0}
367 /* Schedule -- see run_conf.c */
370 * name handler value code flags default_value
372 static RES_ITEM sch_items[] = {
373 {"Name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
374 {"Description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
375 {"Run", store_run, ITEM(res_sch.run), 0, 0, 0},
376 {"Enabled", store_bool, ITEM(res_sch.enabled), 0, ITEM_DEFAULT, true},
377 {NULL, NULL, {0}, 0, 0, 0}
382 * name handler value code flags default_value
384 static RES_ITEM pool_items[] = {
385 {"Name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
386 {"Description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
387 {"PoolType", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
388 {"LabelFormat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
389 {"LabelType", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
390 {"CleaningPrefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
391 {"UseCatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
392 {"UseVolumeOnce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
393 {"PurgeOldestVolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
394 {"ActionOnPurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
395 {"RecycleOldestVolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
396 {"RecycleCurrentVolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
397 {"MaximumVolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
398 {"MaximumVolumeJobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
399 {"MaximumVolumeFiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
400 {"MaximumVolumeBytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
401 {"CatalogFiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
402 {"VolumeRetention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
403 {"VolumeUseDuration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
404 {"MigrationTime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
405 {"MigrationHighBytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
406 {"MigrationLowBytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
407 {"NextPool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
408 {"Storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
409 {"AutoPrune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
410 {"Recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
411 {"RecyclePool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
412 {"ScratchPool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
413 {"CopyPool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
414 {"Catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
415 {"FileRetention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
416 {"JobRetention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
418 {NULL, NULL, {0}, 0, 0, 0}
423 * name handler value code flags default_value
425 static RES_ITEM counter_items[] = {
426 {"Name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
427 {"Description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
428 {"Minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
429 {"Maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
430 {"WrapCounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
431 {"Catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
432 {NULL, NULL, {0}, 0, 0, 0}
436 /* Message resource */
437 extern RES_ITEM msgs_items[];
440 * This is the master resource definition.
441 * It must have one item for each of the resources.
443 * NOTE!!! keep it in the same order as the R_codes
444 * or eliminate all resources[rindex].name
448 RES_TABLE resources[] = {
449 {"Director", dir_items, R_DIRECTOR},
450 {"Client", cli_items, R_CLIENT},
451 {"Job", job_items, R_JOB},
452 {"Storage", store_items, R_STORAGE},
453 {"Catalog", cat_items, R_CATALOG},
454 {"Schedule", sch_items, R_SCHEDULE},
455 {"Fileset", fs_items, R_FILESET},
456 {"Pool", pool_items, R_POOL},
457 {"Messages", msgs_items, R_MSGS},
458 {"Counter", counter_items, R_COUNTER},
459 {"Console", con_items, R_CONSOLE},
460 {"JobDefs", job_items, R_JOBDEFS},
461 {"Device", NULL, R_DEVICE}, /* info obtained from SD */
466 /* Keywords (RHS) permitted in Job Level records
468 * level_name level job_type
470 struct s_jl joblevels[] = {
471 {"Full", L_FULL, JT_BACKUP},
472 {"Base", L_BASE, JT_BACKUP},
473 {"Incremental", L_INCREMENTAL, JT_BACKUP},
474 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
475 {"Since", L_SINCE, JT_BACKUP},
476 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
477 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
478 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
479 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
480 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
481 {"Data", L_VERIFY_DATA, JT_VERIFY},
482 {"Full", L_FULL, JT_COPY},
483 {"Incremental", L_INCREMENTAL, JT_COPY},
484 {"Differential", L_DIFFERENTIAL, JT_COPY},
485 {"Full", L_FULL, JT_MIGRATE},
486 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
487 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
488 {" ", L_NONE, JT_ADMIN},
489 {" ", L_NONE, JT_RESTORE},
494 /* Keywords (RHS) permitted in Job type records
499 {"Backup", JT_BACKUP},
501 {"Verify", JT_VERIFY},
502 {"Restore", JT_RESTORE},
503 {"Migrate", JT_MIGRATE},
509 /* Keywords (RHS) permitted in Selection type records
514 {"SmallestVolume", MT_SMALLEST_VOL},
515 {"OldestVolume", MT_OLDEST_VOL},
516 {"PoolOccupancy", MT_POOL_OCCUPANCY},
517 {"PoolTime", MT_POOL_TIME},
518 {"PoolUncopiedJobs", MT_POOL_UNCOPIED_JOBS},
519 {"Client", MT_CLIENT},
520 {"Volume", MT_VOLUME},
522 {"SqlQuery", MT_SQLQUERY},
528 /* Options permitted in Restore replace= */
529 struct s_kw ReplaceOptions[] = {
530 {"Always", REPLACE_ALWAYS},
531 {"IfNewer", REPLACE_IFNEWER},
532 {"IfOlder", REPLACE_IFOLDER},
533 {"Never", REPLACE_NEVER},
537 char *CAT::display(POOLMEM *dst) {
538 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
539 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
541 name(), NPRTB(db_name),
542 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
543 NPRTB(db_address), db_port, NPRTB(db_socket));
547 const char *level_to_str(int level)
550 static char level_no[30];
551 const char *str = level_no;
553 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
554 for (i=0; joblevels[i].level_name; i++) {
555 if (level == (int)joblevels[i].level) {
556 str = joblevels[i].level_name;
563 /* Dump contents of resource */
564 void dump_resource(int type, RES *ares, void sendit(void *sock, const char *fmt, ...), void *sock)
566 URES *res = (URES *)ares;
568 char ed1[100], ed2[100], ed3[100];
570 UAContext *ua = (UAContext *)sock;
573 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
576 if (type < 0) { /* no recursion */
582 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
583 ares->name, res->res_dir.MaxConcurrentJobs,
584 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
585 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
586 if (res->res_dir.query_file) {
587 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
589 if (res->res_dir.messages) {
590 sendit(sock, _(" --> "));
591 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
595 sendit(sock, _("Console: name=%s SSL=%d\n"),
596 res->res_con.hdr.name, res->res_con.tls_enable);
599 if (res->res_counter.WrapCounter) {
600 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
601 res->res_counter.hdr.name, res->res_counter.MinValue,
602 res->res_counter.MaxValue, res->res_counter.CurrentValue,
603 res->res_counter.WrapCounter->hdr.name);
605 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
606 res->res_counter.hdr.name, res->res_counter.MinValue,
607 res->res_counter.MaxValue);
609 if (res->res_counter.Catalog) {
610 sendit(sock, _(" --> "));
611 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
616 if (!acl_access_ok(ua, Client_ACL, res->res_client.hdr.name)) {
619 sendit(sock, _("Client: Name=%s Enabled=%d Address=%s FDport=%d MaxJobs=%u\n"),
620 res->res_client.hdr.name, res->res_client.enabled,
621 res->res_client.address, res->res_client.FDport,
622 res->res_client.MaxConcurrentJobs);
623 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
624 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
625 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
626 res->res_client.AutoPrune);
627 if (res->res_client.fd_storage_address) {
628 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
630 if (res->res_client.max_bandwidth) {
631 sendit(sock, _(" MaximumBandwidth=%lld\n"),
632 res->res_client.max_bandwidth);
634 if (res->res_client.catalog) {
635 sendit(sock, _(" --> "));
636 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
643 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
644 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
645 " poolid=%s volname=%s MediaType=%s\n"),
646 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
647 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
648 dev->offline, dev->autochanger,
649 edit_uint64(dev->PoolId, ed1),
650 dev->VolumeName, dev->MediaType);
654 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
657 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
658 " DeviceName=%s MediaType=%s StorageId=%s Autochanger=%d\n"),
659 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
660 res->res_store.MaxConcurrentJobs,
661 res->res_store.dev_name(),
662 res->res_store.media_type,
663 edit_int64(res->res_store.StorageId, ed1),
664 res->res_store.autochanger);
665 if (res->res_store.fd_storage_address) {
666 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
671 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
674 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
675 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
676 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
677 res->res_cat.db_port, res->res_cat.db_name,
678 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
679 res->res_cat.mult_db_connections);
684 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
687 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
688 type == R_JOB ? _("Job") : _("JobDefs"),
689 res->res_job.hdr.name, res->res_job.JobType,
690 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
691 res->res_job.enabled);
692 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
693 res->res_job.MaxConcurrentJobs,
694 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
695 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
696 res->res_job.spool_data, res->res_job.write_part_after_job);
697 if (res->res_job.spool_size) {
698 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
700 if (res->res_job.JobType == JT_BACKUP) {
701 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
703 if (res->res_job.max_bandwidth) {
704 sendit(sock, _(" MaximumBandwidth=%lld\n"),
705 res->res_job.max_bandwidth);
707 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
708 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
710 if (res->res_job.client) {
711 sendit(sock, _(" --> "));
712 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
714 if (res->res_job.fileset) {
715 sendit(sock, _(" --> "));
716 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
718 if (res->res_job.schedule) {
719 sendit(sock, _(" --> "));
720 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
722 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
723 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
725 if (res->res_job.RegexWhere) {
726 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
728 if (res->res_job.RestoreBootstrap) {
729 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
731 if (res->res_job.WriteBootstrap) {
732 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
734 if (res->res_job.PluginOptions) {
735 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
737 if (res->res_job.MaxRunTime) {
738 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
740 if (res->res_job.MaxWaitTime) {
741 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
743 if (res->res_job.MaxStartDelay) {
744 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
746 if (res->res_job.MaxRunSchedTime) {
747 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
749 if (res->res_job.storage) {
751 foreach_alist(store, res->res_job.storage) {
752 sendit(sock, _(" --> "));
753 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
756 if (res->res_job.base) {
758 foreach_alist(job, res->res_job.base) {
759 sendit(sock, _(" --> Base %s\n"), job->name());
762 if (res->res_job.RunScripts) {
764 foreach_alist(script, res->res_job.RunScripts) {
765 sendit(sock, _(" --> RunScript\n"));
766 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
767 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
768 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
769 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
770 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
771 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
774 if (res->res_job.pool) {
775 sendit(sock, _(" --> "));
776 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
778 if (res->res_job.full_pool) {
779 sendit(sock, _(" --> FullBackup"));
780 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
782 if (res->res_job.inc_pool) {
783 sendit(sock, _(" --> IncrementalBackup"));
784 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
786 if (res->res_job.diff_pool) {
787 sendit(sock, _(" --> DifferentialBackup"));
788 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
790 if (res->res_job.verify_job) {
791 sendit(sock, _(" --> "));
792 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
794 if (res->res_job.run_cmds) {
796 foreach_alist(runcmd, res->res_job.run_cmds) {
797 sendit(sock, _(" --> Run=%s\n"), runcmd);
800 if (res->res_job.selection_pattern) {
801 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
803 if (res->res_job.messages) {
804 sendit(sock, _(" --> "));
805 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
812 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
815 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
816 for (i=0; i<res->res_fs.num_includes; i++) {
817 INCEXE *incexe = res->res_fs.include_items[i];
818 for (j=0; j<incexe->num_opts; j++) {
819 FOPTS *fo = incexe->opts_list[j];
820 sendit(sock, " O %s\n", fo->opts);
822 bool enhanced_wild = false;
823 for (k=0; fo->opts[k]!='\0'; k++) {
824 if (fo->opts[k]=='W') {
825 enhanced_wild = true;
830 for (k=0; k<fo->regex.size(); k++) {
831 sendit(sock, " R %s\n", fo->regex.get(k));
833 for (k=0; k<fo->regexdir.size(); k++) {
834 sendit(sock, " RD %s\n", fo->regexdir.get(k));
836 for (k=0; k<fo->regexfile.size(); k++) {
837 sendit(sock, " RF %s\n", fo->regexfile.get(k));
839 for (k=0; k<fo->wild.size(); k++) {
840 sendit(sock, " W %s\n", fo->wild.get(k));
842 for (k=0; k<fo->wilddir.size(); k++) {
843 sendit(sock, " WD %s\n", fo->wilddir.get(k));
845 for (k=0; k<fo->wildfile.size(); k++) {
846 sendit(sock, " WF %s\n", fo->wildfile.get(k));
848 for (k=0; k<fo->wildbase.size(); k++) {
849 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
851 for (k=0; k<fo->base.size(); k++) {
852 sendit(sock, " B %s\n", fo->base.get(k));
854 for (k=0; k<fo->fstype.size(); k++) {
855 sendit(sock, " X %s\n", fo->fstype.get(k));
857 for (k=0; k<fo->drivetype.size(); k++) {
858 sendit(sock, " XD %s\n", fo->drivetype.get(k));
861 sendit(sock, " G %s\n", fo->plugin);
864 sendit(sock, " D %s\n", fo->reader);
867 sendit(sock, " T %s\n", fo->writer);
869 sendit(sock, " N\n");
871 if (incexe->ignoredir) {
872 sendit(sock, " Z %s\n", incexe->ignoredir);
874 for (j=0; j<incexe->name_list.size(); j++) {
875 sendit(sock, " I %s\n", incexe->name_list.get(j));
877 if (incexe->name_list.size()) {
878 sendit(sock, " N\n");
880 for (j=0; j<incexe->plugin_list.size(); j++) {
881 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
883 if (incexe->plugin_list.size()) {
884 sendit(sock, " N\n");
886 } /* end for over includes */
888 for (i=0; i<res->res_fs.num_excludes; i++) {
889 INCEXE *incexe = res->res_fs.exclude_items[i];
890 for (j=0; j<incexe->name_list.size(); j++) {
891 sendit(sock, " E %s\n", incexe->name_list.get(j));
893 if (incexe->name_list.size()) {
894 sendit(sock, " N\n");
898 } /* end case R_FILESET */
901 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
905 if (res->res_sch.run) {
907 RUN *run = res->res_sch.run;
908 char buf[1000], num[30];
909 sendit(sock, _("Schedule: Name=%s Enabled=%d\n"),
910 res->res_sch.hdr.name, res->res_sch.enabled);
915 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
916 if (run->MaxRunSchedTime) {
917 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
920 sendit(sock, _(" Priority=%u\n"), run->Priority);
922 bstrncpy(buf, _(" hour="), sizeof(buf));
923 for (i=0; i<24; i++) {
924 if (bit_is_set(i, run->hour)) {
925 bsnprintf(num, sizeof(num), "%d ", i);
926 bstrncat(buf, num, sizeof(buf));
929 bstrncat(buf, "\n", sizeof(buf));
931 bstrncpy(buf, _(" mday="), sizeof(buf));
932 for (i=0; i<32; i++) {
933 if (bit_is_set(i, run->mday)) {
934 bsnprintf(num, sizeof(num), "%d ", i);
935 bstrncat(buf, num, sizeof(buf));
938 bstrncat(buf, "\n", sizeof(buf));
940 bstrncpy(buf, _(" month="), sizeof(buf));
941 for (i=0; i<12; i++) {
942 if (bit_is_set(i, run->month)) {
943 bsnprintf(num, sizeof(num), "%d ", i);
944 bstrncat(buf, num, sizeof(buf));
947 bstrncat(buf, "\n", sizeof(buf));
949 bstrncpy(buf, _(" wday="), sizeof(buf));
950 for (i=0; i<7; i++) {
951 if (bit_is_set(i, run->wday)) {
952 bsnprintf(num, sizeof(num), "%d ", i);
953 bstrncat(buf, num, sizeof(buf));
956 bstrncat(buf, "\n", sizeof(buf));
958 bstrncpy(buf, _(" wom="), sizeof(buf));
959 for (i=0; i<6; i++) {
960 if (bit_is_set(i, run->wom)) {
961 bsnprintf(num, sizeof(num), "%d ", i);
962 bstrncat(buf, num, sizeof(buf));
965 bstrncat(buf, "\n", sizeof(buf));
967 bstrncpy(buf, _(" woy="), sizeof(buf));
968 for (i=0; i<54; i++) {
969 if (bit_is_set(i, run->woy)) {
970 bsnprintf(num, sizeof(num), "%d ", i);
971 bstrncat(buf, num, sizeof(buf));
974 bstrncat(buf, "\n", sizeof(buf));
976 sendit(sock, _(" mins=%d\n"), run->minute);
978 sendit(sock, _(" --> "));
979 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
982 sendit(sock, _(" --> "));
983 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
986 sendit(sock, _(" --> "));
987 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
989 /* If another Run record is chained in, go print it */
995 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
1000 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
1003 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
1004 res->res_pool.pool_type);
1005 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
1006 res->res_pool.use_catalog, res->res_pool.use_volume_once,
1007 res->res_pool.catalog_files);
1008 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
1009 res->res_pool.max_volumes, res->res_pool.AutoPrune,
1010 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
1011 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
1012 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
1013 res->res_pool.Recycle,
1014 NPRT(res->res_pool.label_format));
1015 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1016 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1017 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1018 res->res_pool.recycle_oldest_volume,
1019 res->res_pool.purge_oldest_volume,
1020 res->res_pool.action_on_purge);
1021 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1022 res->res_pool.MaxVolJobs,
1023 res->res_pool.MaxVolFiles,
1024 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1025 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1026 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1027 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1028 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1029 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1030 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1031 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1032 if (res->res_pool.NextPool) {
1033 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1035 if (res->res_pool.RecyclePool) {
1036 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1038 if (res->res_pool.ScratchPool) {
1039 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1041 if (res->res_pool.catalog) {
1042 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1044 if (res->res_pool.storage) {
1046 foreach_alist(store, res->res_pool.storage) {
1047 sendit(sock, _(" --> "));
1048 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1051 if (res->res_pool.CopyPool) {
1053 foreach_alist(copy, res->res_pool.CopyPool) {
1054 sendit(sock, _(" --> "));
1055 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1062 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1063 if (res->res_msgs.mail_cmd)
1064 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1065 if (res->res_msgs.operator_cmd)
1066 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1070 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1073 if (recurse && res->res_dir.hdr.next) {
1074 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1080 * Free all the members of an INCEXE structure
1082 static void free_incexe(INCEXE *incexe)
1084 incexe->name_list.destroy();
1085 incexe->plugin_list.destroy();
1086 for (int i=0; i<incexe->num_opts; i++) {
1087 FOPTS *fopt = incexe->opts_list[i];
1088 fopt->regex.destroy();
1089 fopt->regexdir.destroy();
1090 fopt->regexfile.destroy();
1091 fopt->wild.destroy();
1092 fopt->wilddir.destroy();
1093 fopt->wildfile.destroy();
1094 fopt->wildbase.destroy();
1095 fopt->base.destroy();
1096 fopt->fstype.destroy();
1097 fopt->drivetype.destroy();
1109 if (incexe->opts_list) {
1110 free(incexe->opts_list);
1112 if (incexe->ignoredir) {
1113 free(incexe->ignoredir);
1120 * Free memory of resource -- called when daemon terminates.
1121 * NB, we don't need to worry about freeing any references
1122 * to other resources as they will be freed when that
1123 * resource chain is traversed. Mainly we worry about freeing
1124 * allocated strings (names).
1126 void free_resource(RES *rres, int type)
1130 URES *res = (URES *)rres;
1136 Dmsg3(200, "type=%d res=%p name=%s\n", type, res, res->res_dir.hdr.name);
1137 /* common stuff -- free the resource name and description */
1138 nres = (RES *)res->res_dir.hdr.next;
1139 if (res->res_dir.hdr.name) {
1140 free(res->res_dir.hdr.name);
1142 if (res->res_dir.hdr.desc) {
1143 free(res->res_dir.hdr.desc);
1148 if (res->res_dir.working_directory) {
1149 free(res->res_dir.working_directory);
1151 if (res->res_dir.scripts_directory) {
1152 free((char *)res->res_dir.scripts_directory);
1154 if (res->res_dir.plugin_directory) {
1155 free((char *)res->res_dir.plugin_directory);
1157 if (res->res_dir.pid_directory) {
1158 free(res->res_dir.pid_directory);
1160 if (res->res_dir.subsys_directory) {
1161 free(res->res_dir.subsys_directory);
1163 if (res->res_dir.password) {
1164 free(res->res_dir.password);
1166 if (res->res_dir.query_file) {
1167 free(res->res_dir.query_file);
1169 if (res->res_dir.DIRaddrs) {
1170 free_addresses(res->res_dir.DIRaddrs);
1172 if (res->res_dir.DIRsrc_addr) {
1173 free_addresses(res->res_dir.DIRsrc_addr);
1175 if (res->res_dir.tls_ctx) {
1176 free_tls_context(res->res_dir.tls_ctx);
1178 if (res->res_dir.tls_ca_certfile) {
1179 free(res->res_dir.tls_ca_certfile);
1181 if (res->res_dir.tls_ca_certdir) {
1182 free(res->res_dir.tls_ca_certdir);
1184 if (res->res_dir.tls_certfile) {
1185 free(res->res_dir.tls_certfile);
1187 if (res->res_dir.tls_keyfile) {
1188 free(res->res_dir.tls_keyfile);
1190 if (res->res_dir.tls_dhfile) {
1191 free(res->res_dir.tls_dhfile);
1193 if (res->res_dir.tls_allowed_cns) {
1194 delete res->res_dir.tls_allowed_cns;
1196 if (res->res_dir.verid) {
1197 free(res->res_dir.verid);
1204 if (res->res_con.password) {
1205 free(res->res_con.password);
1207 if (res->res_con.tls_ctx) {
1208 free_tls_context(res->res_con.tls_ctx);
1210 if (res->res_con.tls_ca_certfile) {
1211 free(res->res_con.tls_ca_certfile);
1213 if (res->res_con.tls_ca_certdir) {
1214 free(res->res_con.tls_ca_certdir);
1216 if (res->res_con.tls_certfile) {
1217 free(res->res_con.tls_certfile);
1219 if (res->res_con.tls_keyfile) {
1220 free(res->res_con.tls_keyfile);
1222 if (res->res_con.tls_dhfile) {
1223 free(res->res_con.tls_dhfile);
1225 if (res->res_con.tls_allowed_cns) {
1226 delete res->res_con.tls_allowed_cns;
1228 for (int i=0; i<Num_ACL; i++) {
1229 if (res->res_con.ACL_lists[i]) {
1230 delete res->res_con.ACL_lists[i];
1231 res->res_con.ACL_lists[i] = NULL;
1236 if (res->res_client.address) {
1237 free(res->res_client.address);
1239 if (res->res_client.fd_storage_address) {
1240 free(res->res_client.fd_storage_address);
1242 if (res->res_client.password) {
1243 free(res->res_client.password);
1245 if (res->res_client.tls_ctx) {
1246 free_tls_context(res->res_client.tls_ctx);
1248 if (res->res_client.tls_ca_certfile) {
1249 free(res->res_client.tls_ca_certfile);
1251 if (res->res_client.tls_ca_certdir) {
1252 free(res->res_client.tls_ca_certdir);
1254 if (res->res_client.tls_certfile) {
1255 free(res->res_client.tls_certfile);
1257 if (res->res_client.tls_keyfile) {
1258 free(res->res_client.tls_keyfile);
1260 if (res->res_client.tls_allowed_cns) {
1261 delete res->res_client.tls_allowed_cns;
1265 if (res->res_store.address) {
1266 free(res->res_store.address);
1268 if (res->res_store.fd_storage_address) {
1269 free(res->res_store.fd_storage_address);
1271 if (res->res_store.password) {
1272 free(res->res_store.password);
1274 if (res->res_store.media_type) {
1275 free(res->res_store.media_type);
1277 if (res->res_store.device) {
1278 delete res->res_store.device;
1280 if (res->res_store.tls_ctx) {
1281 free_tls_context(res->res_store.tls_ctx);
1283 if (res->res_store.tls_ca_certfile) {
1284 free(res->res_store.tls_ca_certfile);
1286 if (res->res_store.tls_ca_certdir) {
1287 free(res->res_store.tls_ca_certdir);
1289 if (res->res_store.tls_certfile) {
1290 free(res->res_store.tls_certfile);
1292 if (res->res_store.tls_keyfile) {
1293 free(res->res_store.tls_keyfile);
1297 if (res->res_cat.db_address) {
1298 free(res->res_cat.db_address);
1300 if (res->res_cat.db_socket) {
1301 free(res->res_cat.db_socket);
1303 if (res->res_cat.db_user) {
1304 free(res->res_cat.db_user);
1306 if (res->res_cat.db_name) {
1307 free(res->res_cat.db_name);
1309 if (res->res_cat.db_driver) {
1310 free(res->res_cat.db_driver);
1312 if (res->res_cat.db_password) {
1313 free(res->res_cat.db_password);
1317 if ((num=res->res_fs.num_includes)) {
1318 while (--num >= 0) {
1319 free_incexe(res->res_fs.include_items[num]);
1321 free(res->res_fs.include_items);
1323 res->res_fs.num_includes = 0;
1324 if ((num=res->res_fs.num_excludes)) {
1325 while (--num >= 0) {
1326 free_incexe(res->res_fs.exclude_items[num]);
1328 free(res->res_fs.exclude_items);
1330 res->res_fs.num_excludes = 0;
1333 if (res->res_pool.pool_type) {
1334 free(res->res_pool.pool_type);
1336 if (res->res_pool.label_format) {
1337 free(res->res_pool.label_format);
1339 if (res->res_pool.cleaning_prefix) {
1340 free(res->res_pool.cleaning_prefix);
1342 if (res->res_pool.storage) {
1343 delete res->res_pool.storage;
1347 if (res->res_sch.run) {
1349 nrun = res->res_sch.run;
1359 if (res->res_job.RestoreWhere) {
1360 free(res->res_job.RestoreWhere);
1362 if (res->res_job.RegexWhere) {
1363 free(res->res_job.RegexWhere);
1365 if (res->res_job.strip_prefix) {
1366 free(res->res_job.strip_prefix);
1368 if (res->res_job.add_prefix) {
1369 free(res->res_job.add_prefix);
1371 if (res->res_job.add_suffix) {
1372 free(res->res_job.add_suffix);
1374 if (res->res_job.RestoreBootstrap) {
1375 free(res->res_job.RestoreBootstrap);
1377 if (res->res_job.WriteBootstrap) {
1378 free(res->res_job.WriteBootstrap);
1380 if (res->res_job.PluginOptions) {
1381 free(res->res_job.PluginOptions);
1383 if (res->res_job.selection_pattern) {
1384 free(res->res_job.selection_pattern);
1386 if (res->res_job.run_cmds) {
1387 delete res->res_job.run_cmds;
1389 if (res->res_job.storage) {
1390 delete res->res_job.storage;
1392 if (res->res_job.base) {
1393 delete res->res_job.base;
1395 if (res->res_job.RunScripts) {
1396 free_runscripts(res->res_job.RunScripts);
1397 delete res->res_job.RunScripts;
1401 if (res->res_msgs.mail_cmd) {
1402 free(res->res_msgs.mail_cmd);
1404 if (res->res_msgs.operator_cmd) {
1405 free(res->res_msgs.operator_cmd);
1407 free_msgs_res((MSGS *)res); /* free message resource */
1411 printf(_("Unknown resource type %d in free_resource.\n"), type);
1413 /* Common stuff again -- free the resource, recurse to next one */
1418 free_resource(nres, type);
1423 * Save the new resource by chaining it into the head list for
1424 * the resource. If this is pass 2, we update any resource
1425 * pointers because they may not have been defined until
1428 void save_resource(int type, RES_ITEM *items, int pass)
1431 int rindex = type - r_first;
1435 /* Check Job requirements after applying JobDefs */
1436 if (type != R_JOB && type != R_JOBDEFS) {
1438 * Ensure that all required items are present
1440 for (i=0; items[i].name; i++) {
1441 if (items[i].flags & ITEM_REQUIRED) {
1442 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1443 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1444 items[i].name, resources[rindex]);
1447 /* If this triggers, take a look at lib/parse_conf.h */
1448 if (i >= MAX_RES_ITEMS) {
1449 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1452 } else if (type == R_JOB) {
1454 * Ensure that the name item is present
1456 if (items[0].flags & ITEM_REQUIRED) {
1457 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1458 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1459 items[0].name, resources[rindex]);
1465 * During pass 2 in each "store" routine, we looked up pointers
1466 * to all the resources referrenced in the current resource, now we
1467 * must copy their addresses from the static record to the allocated
1472 /* Resources not containing a resource */
1480 * Resources containing another resource or alist. First
1481 * look up the resource which contains another resource. It
1482 * was written during pass 1. Then stuff in the pointers to
1483 * the resources it contains, which were inserted this pass.
1484 * Finally, it will all be stored back.
1487 /* Find resource saved in pass 1 */
1488 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1489 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1491 /* Explicitly copy resource pointers from this pass (res_all) */
1492 res->res_pool.NextPool = res_all.res_pool.NextPool;
1493 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1494 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1495 res->res_pool.storage = res_all.res_pool.storage;
1496 res->res_pool.catalog = res_all.res_pool.catalog;
1499 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1500 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1502 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1505 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1506 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1508 res->res_dir.messages = res_all.res_dir.messages;
1509 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1512 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1513 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1514 res_all.res_dir.hdr.name);
1516 /* we must explicitly copy the device alist pointer */
1517 res->res_store.device = res_all.res_store.device;
1521 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1522 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1523 res_all.res_dir.hdr.name);
1525 res->res_job.messages = res_all.res_job.messages;
1526 res->res_job.schedule = res_all.res_job.schedule;
1527 res->res_job.client = res_all.res_job.client;
1528 res->res_job.fileset = res_all.res_job.fileset;
1529 res->res_job.storage = res_all.res_job.storage;
1530 res->res_job.base = res_all.res_job.base;
1531 res->res_job.pool = res_all.res_job.pool;
1532 res->res_job.next_pool = res_all.res_job.next_pool;
1533 res->res_job.full_pool = res_all.res_job.full_pool;
1534 res->res_job.inc_pool = res_all.res_job.inc_pool;
1535 res->res_job.diff_pool = res_all.res_job.diff_pool;
1536 res->res_job.verify_job = res_all.res_job.verify_job;
1537 res->res_job.jobdefs = res_all.res_job.jobdefs;
1538 res->res_job.run_cmds = res_all.res_job.run_cmds;
1539 res->res_job.RunScripts = res_all.res_job.RunScripts;
1541 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1542 * is not very useful)
1543 * We have to set_bit(index, res_all.hdr.item_present);
1544 * or something like that
1547 /* we take RegexWhere before all other options */
1548 if (!res->res_job.RegexWhere
1550 (res->res_job.strip_prefix ||
1551 res->res_job.add_suffix ||
1552 res->res_job.add_prefix))
1554 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1555 res->res_job.add_prefix,
1556 res->res_job.add_suffix);
1557 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1558 bregexp_build_where(res->res_job.RegexWhere, len,
1559 res->res_job.strip_prefix,
1560 res->res_job.add_prefix,
1561 res->res_job.add_suffix);
1562 /* TODO: test bregexp */
1565 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1566 free(res->res_job.RestoreWhere);
1567 res->res_job.RestoreWhere = NULL;
1572 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1573 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1575 res->res_counter.Catalog = res_all.res_counter.Catalog;
1576 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1580 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1581 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1583 res->res_client.catalog = res_all.res_client.catalog;
1584 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1588 * Schedule is a bit different in that it contains a RUN record
1589 * chain which isn't a "named" resource. This chain was linked
1590 * in by run_conf.c during pass 2, so here we jam the pointer
1591 * into the Schedule resource.
1593 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1594 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1596 res->res_sch.run = res_all.res_sch.run;
1599 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1603 /* Note, the resource name was already saved during pass 1,
1604 * so here, we can just release it.
1606 if (res_all.res_dir.hdr.name) {
1607 free(res_all.res_dir.hdr.name);
1608 res_all.res_dir.hdr.name = NULL;
1610 if (res_all.res_dir.hdr.desc) {
1611 free(res_all.res_dir.hdr.desc);
1612 res_all.res_dir.hdr.desc = NULL;
1618 * The following code is only executed during pass 1
1622 size = sizeof(DIRRES);
1625 size = sizeof(CONRES);
1628 size =sizeof(CLIENT);
1631 size = sizeof(STORE);
1641 size = sizeof(FILESET);
1644 size = sizeof(SCHED);
1647 size = sizeof(POOL);
1650 size = sizeof(MSGS);
1653 size = sizeof(COUNTER);
1659 printf(_("Unknown resource type %d in save_resource.\n"), type);
1665 res = (URES *)malloc(size);
1666 memcpy(res, &res_all, size);
1667 if (!res_head[rindex]) {
1668 res_head[rindex] = (RES *)res; /* store first entry */
1669 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1670 res->res_dir.hdr.name, rindex);
1673 if (res->res_dir.hdr.name == NULL) {
1674 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1677 /* Add new res to end of chain */
1678 for (last=next=res_head[rindex]; next; next=next->next) {
1680 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1681 Emsg2(M_ERROR_TERM, 0,
1682 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1683 resources[rindex].name, res->res_dir.hdr.name);
1686 last->next = (RES *)res;
1687 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1688 res->res_dir.hdr.name, rindex, pass);
1693 void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1695 uint32_t *destination = (uint32_t*)item->value;
1696 lex_get_token(lc, T_NAME);
1697 if (strcasecmp(lc->str, "truncate") == 0) {
1698 *destination = (*destination) | ON_PURGE_TRUNCATE;
1700 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1704 set_bit(index, res_all.hdr.item_present);
1708 * Store Device. Note, the resource is created upon the
1709 * first reference. The details of the resource are obtained
1710 * later from the SD.
1712 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1715 int rindex = R_DEVICE - r_first;
1716 int size = sizeof(DEVICE);
1720 lex_get_token(lc, T_NAME);
1721 if (!res_head[rindex]) {
1722 res = (URES *)malloc(size);
1723 memset(res, 0, size);
1724 res->res_dev.hdr.name = bstrdup(lc->str);
1725 res_head[rindex] = (RES *)res; /* store first entry */
1726 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1727 res->res_dir.hdr.name, rindex);
1730 /* See if it is already defined */
1731 for (next=res_head[rindex]; next->next; next=next->next) {
1732 if (strcmp(next->name, lc->str) == 0) {
1738 res = (URES *)malloc(size);
1739 memset(res, 0, size);
1740 res->res_dev.hdr.name = bstrdup(lc->str);
1741 next->next = (RES *)res;
1742 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1743 res->res_dir.hdr.name, rindex, pass);
1748 set_bit(index, res_all.hdr.item_present);
1750 store_alist_res(lc, item, index, pass);
1755 * Store Migration/Copy type
1758 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1762 lex_get_token(lc, T_NAME);
1763 /* Store the type both pass 1 and pass 2 */
1764 for (i=0; migtypes[i].type_name; i++) {
1765 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1766 *(uint32_t *)(item->value) = migtypes[i].job_type;
1772 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1775 set_bit(index, res_all.hdr.item_present);
1781 * Store JobType (backup, verify, restore)
1784 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1788 lex_get_token(lc, T_NAME);
1789 /* Store the type both pass 1 and pass 2 */
1790 for (i=0; jobtypes[i].type_name; i++) {
1791 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1792 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1798 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1801 set_bit(index, res_all.hdr.item_present);
1805 * Store Job Level (Full, Incremental, ...)
1808 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1812 lex_get_token(lc, T_NAME);
1813 /* Store the level pass 2 so that type is defined */
1814 for (i=0; joblevels[i].level_name; i++) {
1815 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1816 *(uint32_t *)(item->value) = joblevels[i].level;
1822 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1825 set_bit(index, res_all.hdr.item_present);
1829 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1832 lex_get_token(lc, T_NAME);
1833 /* Scan Replacement options */
1834 for (i=0; ReplaceOptions[i].name; i++) {
1835 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1836 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1842 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1845 set_bit(index, res_all.hdr.item_present);
1849 * Store ACL (access control list)
1852 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1857 lex_get_token(lc, T_STRING);
1859 if (((alist **)item->value)[item->code] == NULL) {
1860 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1861 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1863 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1864 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1866 token = lex_get_token(lc, T_ALL);
1867 if (token == T_COMMA) {
1868 continue; /* get another ACL */
1872 set_bit(index, res_all.hdr.item_present);
1875 /* We build RunScripts items here */
1876 static RUNSCRIPT res_runscript;
1878 /* Store a runscript->when in a bit field */
1879 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1881 lex_get_token(lc, T_NAME);
1883 if (strcasecmp(lc->str, "before") == 0) {
1884 *(uint32_t *)(item->value) = SCRIPT_Before ;
1885 } else if (strcasecmp(lc->str, "after") == 0) {
1886 *(uint32_t *)(item->value) = SCRIPT_After;
1887 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1888 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1889 } else if (strcasecmp(lc->str, "aftersnapshot") == 0) {
1890 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1891 } else if (strcasecmp(lc->str, "always") == 0) {
1892 *(uint32_t *)(item->value) = SCRIPT_Any;
1894 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1899 /* Store a runscript->target
1902 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1904 lex_get_token(lc, T_STRING);
1907 if (strcmp(lc->str, "%c") == 0) {
1908 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1909 } else if (strcasecmp(lc->str, "yes") == 0) {
1910 ((RUNSCRIPT*) item->value)->set_target("%c");
1911 } else if (strcasecmp(lc->str, "no") == 0) {
1912 ((RUNSCRIPT*) item->value)->set_target("");
1914 RES *res = GetResWithName(R_CLIENT, lc->str);
1916 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1917 lc->str, lc->line_no, lc->line);
1920 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1927 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1929 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1931 lex_get_token(lc, T_STRING);
1934 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1935 POOLMEM *c = get_pool_memory(PM_FNAME);
1936 /* Each runscript command takes 2 entries in commands list */
1937 pm_strcpy(c, lc->str);
1938 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1939 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1944 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1946 lex_get_token(lc, T_STRING);
1947 alist **runscripts = (alist **)(item->value) ;
1950 RUNSCRIPT *script = new_runscript();
1951 script->set_job_code_callback(job_code_callback_director);
1953 script->set_command(lc->str);
1955 /* TODO: remove all script->old_proto with bacula 1.42 */
1957 if (strcasecmp(item->name, "runbeforejob") == 0) {
1958 script->when = SCRIPT_Before;
1959 script->fail_on_error = true;
1960 script->set_target("");
1962 } else if (strcasecmp(item->name, "runafterjob") == 0) {
1963 script->when = SCRIPT_After;
1964 script->on_success = true;
1965 script->on_failure = false;
1966 script->set_target("");
1968 } else if (strcasecmp(item->name, "clientrunafterjob") == 0) {
1969 script->old_proto = true;
1970 script->when = SCRIPT_After;
1971 script->set_target("%c");
1972 script->on_success = true;
1973 script->on_failure = false;
1975 } else if (strcasecmp(item->name, "clientrunbeforejob") == 0) {
1976 script->old_proto = true;
1977 script->when = SCRIPT_Before;
1978 script->set_target("%c");
1979 script->fail_on_error = true;
1981 } else if (strcasecmp(item->name, "runafterfailedjob") == 0) {
1982 script->when = SCRIPT_After;
1983 script->on_failure = true;
1984 script->on_success = false;
1985 script->set_target("");
1988 if (*runscripts == NULL) {
1989 *runscripts = New(alist(10, not_owned_by_alist));
1992 (*runscripts)->append(script);
1996 set_bit(index, res_all.hdr.item_present);
1999 /* Store a bool in a bit field without modifing res_all.hdr
2000 * We can also add an option to store_bool to skip res_all.hdr
2002 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
2004 lex_get_token(lc, T_NAME);
2005 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
2006 *(bool *)(item->value) = true;
2007 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
2008 *(bool *)(item->value) = false;
2010 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
2016 * new RunScript items
2017 * name handler value code flags default_value
2019 static RES_ITEM runscript_items[] = {
2020 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2021 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2022 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2023 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2024 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2025 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2026 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2027 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2028 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2029 {NULL, NULL, {0}, 0, 0, 0}
2033 * Store RunScript info
2035 * Note, when this routine is called, we are inside a Job
2036 * resource. We treat the RunScript like a sort of
2037 * mini-resource within the Job resource.
2039 void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2043 alist **runscripts = (alist **)(item->value) ;
2045 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2047 token = lex_get_token(lc, T_SKIP_EOL);
2049 if (token != T_BOB) {
2050 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2052 /* setting on_success, on_failure, fail_on_error */
2053 res_runscript.reset_default();
2056 res_runscript.commands = New(alist(10, not_owned_by_alist));
2059 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2060 if (token == T_EOB) {
2063 if (token != T_IDENTIFIER) {
2064 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2066 for (i=0; runscript_items[i].name; i++) {
2067 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2068 token = lex_get_token(lc, T_SKIP_EOL);
2069 if (token != T_EQUALS) {
2070 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2073 /* Call item handler */
2074 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2081 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2086 /* run on client by default */
2087 if (res_runscript.target == NULL) {
2088 res_runscript.set_target("%c");
2090 if (*runscripts == NULL) {
2091 *runscripts = New(alist(10, not_owned_by_alist));
2094 * commands list contains 2 values per command
2095 * - POOLMEM command string (ex: /bin/true)
2096 * - int command type (ex: SHELL_CMD)
2098 res_runscript.set_job_code_callback(job_code_callback_director);
2099 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2100 t = (intptr_t)res_runscript.commands->pop();
2101 RUNSCRIPT *script = new_runscript();
2102 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2103 script->command = c;
2104 script->cmd_type = t;
2105 /* target is taken from res_runscript, each runscript object have
2108 script->target = NULL;
2109 script->set_target(res_runscript.target);
2111 (*runscripts)->append(script);
2114 delete res_runscript.commands;
2115 /* setting on_success, on_failure... cleanup target field */
2116 res_runscript.reset_default(true);
2120 set_bit(index, res_all.hdr.item_present);
2123 /* callback function for edit_job_codes */
2124 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2125 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2127 static char yes[] = "yes";
2128 static char no[] = "no";
2132 return jcr->fileset->name();
2137 return jcr->client->address;
2142 return jcr->pool->name();
2147 return jcr->wstore->name();
2151 return jcr->spool_data ? yes : no;
2155 return jcr->cloned ? yes : no;
2160 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2162 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2163 r_first, r_last, resources, res_head);
2164 return config->parse_config();