2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 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 Bacula® is a registered trademark of Kern Sibbald.
17 * Main configuration file parser for Bacula Directors,
18 * some parts may be split into separate files such as
19 * the schedule configuration (run_config.c).
21 * Note, the configuration file parser consists of three parts
23 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
25 * 2. The generic config scanner in lib/parse_config.c and
27 * These files contain the parser code, some utility
28 * routines, and the common store routines (name, int,
31 * 3. The daemon specific file, which contains the Resource
32 * definitions as well as any specific store routines
33 * for the resource records.
35 * Kern Sibbald, January MM
43 /* Define the first and last resource ID record
44 * types. Note, these should be unique for each
45 * daemon though not a requirement.
47 int32_t r_first = R_FIRST;
48 int32_t r_last = R_LAST;
49 static RES *sres_head[R_LAST - R_FIRST + 1];
50 RES **res_head = sres_head;
52 /* Imported subroutines */
53 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
54 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
55 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
58 /* Forward referenced subroutines */
60 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
61 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
62 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
63 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
64 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
65 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
66 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
67 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
68 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
69 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
70 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
72 /* We build the current resource here as we are
73 * scanning the resource configuration definition,
74 * then move it to allocated memory when the resource
78 extern "C" { // work around visual compiler mangling variables
84 int32_t res_all_size = sizeof(res_all);
87 /* Definition of records permitted within each
88 * resource with the routine to process the record
89 * information. NOTE! quoted names must be in lower case.
94 * name handler value code flags default_value
96 static RES_ITEM dir_items[] = {
97 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
98 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
99 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
100 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
101 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
102 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
103 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
104 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
105 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
106 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
107 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
108 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
109 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
110 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
111 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
112 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
113 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
114 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
115 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
116 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
117 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
118 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
119 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
120 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
121 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
122 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
123 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
124 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
125 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
126 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
127 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
128 {NULL, NULL, {0}, 0, 0, 0}
134 * name handler value code flags default_value
136 static RES_ITEM con_items[] = {
137 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
138 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
139 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
140 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
141 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
142 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
143 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
144 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
145 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
146 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
147 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
148 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
149 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
150 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
151 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
152 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
153 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
154 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
155 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
156 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
157 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
158 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
159 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
160 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
161 {NULL, NULL, {0}, 0, 0, 0}
166 * Client or File daemon resource
168 * name handler value code flags default_value
171 static RES_ITEM cli_items[] = {
172 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
173 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
174 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
175 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
176 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
177 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
178 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
179 {"fdstorageaddress", store_str, ITEM(res_client.fd_storage_address), 0, 0, 0},
180 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
181 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
182 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
183 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
184 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
185 {"sdcallsclient", store_bool, ITEM(res_client.sd_calls_client), 0, ITEM_DEFAULT, false},
186 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
187 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
188 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
189 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
190 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
191 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
192 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
193 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
194 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
195 {"maximumbandwidthperjob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
196 {NULL, NULL, {0}, 0, 0, 0}
199 /* Storage daemon resource
201 * name handler value code flags default_value
203 static RES_ITEM store_items[] = {
204 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
205 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
206 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
207 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
208 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
209 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
210 {"fdstorageaddress", store_str, ITEM(res_store.fd_storage_address), 0, 0, 0},
211 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
212 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
213 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
214 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
215 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
216 {"allowcompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
217 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
218 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
219 {"maximumconcurrentreadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
220 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
221 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
222 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
223 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
224 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
225 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
226 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
227 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
228 {NULL, NULL, {0}, 0, 0, 0}
232 * Catalog Resource Directives
234 * name handler value code flags default_value
236 static RES_ITEM cat_items[] = {
237 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
238 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
239 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
240 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
241 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
242 /* keep this password as store_str for the moment */
243 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
244 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
245 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
246 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
247 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
248 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
249 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
250 /* Turned off for the moment */
251 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
252 {"disablebatchinsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
253 {NULL, NULL, {0}, 0, 0, 0}
257 * Job Resource Directives
259 * name handler value code flags default_value
261 RES_ITEM job_items[] = {
262 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
263 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
264 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
265 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
266 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
267 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
268 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
269 {"nextpool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
270 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
271 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
272 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
273 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
274 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
275 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
276 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
277 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
278 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
279 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
280 /* Root of where to restore files */
281 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
282 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
283 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
284 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
285 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
286 /* Where to find bootstrap during restore */
287 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
288 /* Where to write bootstrap file during backup */
289 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
290 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
291 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
292 {"maximumbandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
293 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
294 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
295 /* xxxMaxWaitTime are deprecated */
296 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
297 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
298 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
299 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
300 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
301 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
302 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
303 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
304 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
305 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
306 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
307 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
308 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
309 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
310 {"purgemigrationjob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
311 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
312 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
313 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
314 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
315 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
316 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
317 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
318 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
319 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
320 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
323 {"maximumspawnedjobs", store_pint32, ITEM(res_job.MaxSpawnedJobs), 0, ITEM_DEFAULT, 600},
324 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
325 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
326 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
327 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
328 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
329 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
330 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
331 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
332 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
333 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
334 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
335 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
336 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
337 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
338 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
339 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
340 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
341 {NULL, NULL, {0}, 0, 0, 0}
346 * name handler value code flags default_value
348 static RES_ITEM fs_items[] = {
349 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
350 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
351 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
352 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
353 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
354 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
355 {NULL, NULL, {0}, 0, 0, 0}
358 /* Schedule -- see run_conf.c */
361 * name handler value code flags default_value
363 static RES_ITEM sch_items[] = {
364 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
365 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
366 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
367 {NULL, NULL, {0}, 0, 0, 0}
372 * name handler value code flags default_value
374 static RES_ITEM pool_items[] = {
375 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
376 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
377 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
378 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
379 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
380 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
381 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
382 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
383 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
384 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
385 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
386 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
387 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
388 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
389 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
390 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
391 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
392 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
393 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
394 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
395 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
396 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
397 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
398 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
399 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
400 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
401 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
402 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
403 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
404 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
405 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
406 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
408 {NULL, NULL, {0}, 0, 0, 0}
413 * name handler value code flags default_value
415 static RES_ITEM counter_items[] = {
416 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
417 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
418 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
419 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
420 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
421 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
422 {NULL, NULL, {0}, 0, 0, 0}
426 /* Message resource */
427 extern RES_ITEM msgs_items[];
430 * This is the master resource definition.
431 * It must have one item for each of the resources.
433 * NOTE!!! keep it in the same order as the R_codes
434 * or eliminate all resources[rindex].name
436 * name items rcode res_head
438 RES_TABLE resources[] = {
439 {"director", dir_items, R_DIRECTOR},
440 {"client", cli_items, R_CLIENT},
441 {"job", job_items, R_JOB},
442 {"storage", store_items, R_STORAGE},
443 {"catalog", cat_items, R_CATALOG},
444 {"schedule", sch_items, R_SCHEDULE},
445 {"fileset", fs_items, R_FILESET},
446 {"pool", pool_items, R_POOL},
447 {"messages", msgs_items, R_MSGS},
448 {"counter", counter_items, R_COUNTER},
449 {"console", con_items, R_CONSOLE},
450 {"jobdefs", job_items, R_JOBDEFS},
451 {"device", NULL, R_DEVICE}, /* info obtained from SD */
456 /* Keywords (RHS) permitted in Job Level records
458 * level_name level job_type
460 struct s_jl joblevels[] = {
461 {"Full", L_FULL, JT_BACKUP},
462 {"Base", L_BASE, JT_BACKUP},
463 {"Incremental", L_INCREMENTAL, JT_BACKUP},
464 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
465 {"Since", L_SINCE, JT_BACKUP},
466 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
467 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
468 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
469 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
470 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
471 {"Data", L_VERIFY_DATA, JT_VERIFY},
472 {"Full", L_FULL, JT_COPY},
473 {"Incremental", L_INCREMENTAL, JT_COPY},
474 {"Differential", L_DIFFERENTIAL, JT_COPY},
475 {"Full", L_FULL, JT_MIGRATE},
476 {"Incremental", L_INCREMENTAL, JT_MIGRATE},
477 {"Differential", L_DIFFERENTIAL, JT_MIGRATE},
478 {" ", L_NONE, JT_ADMIN},
479 {" ", L_NONE, JT_RESTORE},
483 /* Keywords (RHS) permitted in Job type records
487 struct s_jt jobtypes[] = {
488 {"backup", JT_BACKUP},
490 {"verify", JT_VERIFY},
491 {"restore", JT_RESTORE},
492 {"migrate", JT_MIGRATE},
498 /* Keywords (RHS) permitted in Selection type records
502 struct s_jt migtypes[] = {
503 {"smallestvolume", MT_SMALLEST_VOL},
504 {"oldestvolume", MT_OLDEST_VOL},
505 {"pooloccupancy", MT_POOL_OCCUPANCY},
506 {"pooltime", MT_POOL_TIME},
507 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
508 {"client", MT_CLIENT},
509 {"volume", MT_VOLUME},
511 {"sqlquery", MT_SQLQUERY},
517 /* Options permitted in Restore replace= */
518 struct s_kw ReplaceOptions[] = {
519 {"always", REPLACE_ALWAYS},
520 {"ifnewer", REPLACE_IFNEWER},
521 {"ifolder", REPLACE_IFOLDER},
522 {"never", REPLACE_NEVER},
526 char *CAT::display(POOLMEM *dst) {
527 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
528 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
530 name(), NPRTB(db_name),
531 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
532 NPRTB(db_address), db_port, NPRTB(db_socket));
536 const char *level_to_str(int level)
539 static char level_no[30];
540 const char *str = level_no;
542 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
543 for (i=0; joblevels[i].level_name; i++) {
544 if (level == (int)joblevels[i].level) {
545 str = joblevels[i].level_name;
552 /* Dump contents of resource */
553 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
555 URES *res = (URES *)reshdr;
557 char ed1[100], ed2[100], ed3[100];
559 UAContext *ua = (UAContext *)sock;
562 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
565 if (type < 0) { /* no recursion */
571 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
572 reshdr->name, res->res_dir.MaxConcurrentJobs,
573 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
574 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
575 if (res->res_dir.query_file) {
576 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
578 if (res->res_dir.messages) {
579 sendit(sock, _(" --> "));
580 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
584 sendit(sock, _("Console: name=%s SSL=%d\n"),
585 res->res_con.hdr.name, res->res_con.tls_enable);
588 if (res->res_counter.WrapCounter) {
589 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
590 res->res_counter.hdr.name, res->res_counter.MinValue,
591 res->res_counter.MaxValue, res->res_counter.CurrentValue,
592 res->res_counter.WrapCounter->hdr.name);
594 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
595 res->res_counter.hdr.name, res->res_counter.MinValue,
596 res->res_counter.MaxValue);
598 if (res->res_counter.Catalog) {
599 sendit(sock, _(" --> "));
600 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
605 if (!acl_access_ok(ua, Client_ACL, res->res_client.hdr.name)) {
608 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
609 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
610 res->res_client.MaxConcurrentJobs);
611 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
612 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
613 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
614 res->res_client.AutoPrune);
615 if (res->res_client.fd_storage_address) {
616 sendit(sock, " FDStorageAddress=%s\n", res->res_client.fd_storage_address);
618 if (res->res_client.max_bandwidth) {
619 sendit(sock, _(" MaximumBandwidth=%lld\n"),
620 res->res_client.max_bandwidth);
622 if (res->res_client.catalog) {
623 sendit(sock, _(" --> "));
624 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
631 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
632 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
633 " poolid=%s volname=%s MediaType=%s\n"),
634 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
635 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
636 dev->offline, dev->autochanger,
637 edit_uint64(dev->PoolId, ed1),
638 dev->VolumeName, dev->MediaType);
642 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
645 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
646 " DeviceName=%s MediaType=%s StorageId=%s\n"),
647 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
648 res->res_store.MaxConcurrentJobs,
649 res->res_store.dev_name(),
650 res->res_store.media_type,
651 edit_int64(res->res_store.StorageId, ed1));
652 if (res->res_store.fd_storage_address) {
653 sendit(sock, " FDStorageAddress=%s\n", res->res_store.fd_storage_address);
658 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
661 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
662 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
663 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
664 res->res_cat.db_port, res->res_cat.db_name,
665 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
666 res->res_cat.mult_db_connections);
671 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
674 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
675 type == R_JOB ? _("Job") : _("JobDefs"),
676 res->res_job.hdr.name, res->res_job.JobType,
677 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
678 res->res_job.enabled);
679 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
680 res->res_job.MaxConcurrentJobs,
681 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
682 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
683 res->res_job.spool_data, res->res_job.write_part_after_job);
684 if (res->res_job.spool_size) {
685 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
687 if (res->res_job.JobType == JT_BACKUP) {
688 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
690 if (res->res_job.max_bandwidth) {
691 sendit(sock, _(" MaximumBandwidth=%lld\n"),
692 res->res_job.max_bandwidth);
694 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
695 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
697 if (res->res_job.client) {
698 sendit(sock, _(" --> "));
699 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
701 if (res->res_job.fileset) {
702 sendit(sock, _(" --> "));
703 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
705 if (res->res_job.schedule) {
706 sendit(sock, _(" --> "));
707 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
709 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
710 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
712 if (res->res_job.RegexWhere) {
713 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
715 if (res->res_job.RestoreBootstrap) {
716 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
718 if (res->res_job.WriteBootstrap) {
719 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
721 if (res->res_job.PluginOptions) {
722 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
724 if (res->res_job.MaxRunTime) {
725 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
727 if (res->res_job.MaxWaitTime) {
728 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
730 if (res->res_job.MaxStartDelay) {
731 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
733 if (res->res_job.MaxRunSchedTime) {
734 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
736 if (res->res_job.storage) {
738 foreach_alist(store, res->res_job.storage) {
739 sendit(sock, _(" --> "));
740 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
743 if (res->res_job.base) {
745 foreach_alist(job, res->res_job.base) {
746 sendit(sock, _(" --> Base %s\n"), job->name());
749 if (res->res_job.RunScripts) {
751 foreach_alist(script, res->res_job.RunScripts) {
752 sendit(sock, _(" --> RunScript\n"));
753 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
754 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
755 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
756 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
757 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
758 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
761 if (res->res_job.pool) {
762 sendit(sock, _(" --> "));
763 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
765 if (res->res_job.full_pool) {
766 sendit(sock, _(" --> "));
767 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
769 if (res->res_job.inc_pool) {
770 sendit(sock, _(" --> "));
771 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
773 if (res->res_job.diff_pool) {
774 sendit(sock, _(" --> "));
775 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
777 if (res->res_job.verify_job) {
778 sendit(sock, _(" --> "));
779 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
781 if (res->res_job.run_cmds) {
783 foreach_alist(runcmd, res->res_job.run_cmds) {
784 sendit(sock, _(" --> Run=%s\n"), runcmd);
787 if (res->res_job.selection_pattern) {
788 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
790 if (res->res_job.messages) {
791 sendit(sock, _(" --> "));
792 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
799 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
802 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
803 for (i=0; i<res->res_fs.num_includes; i++) {
804 INCEXE *incexe = res->res_fs.include_items[i];
805 for (j=0; j<incexe->num_opts; j++) {
806 FOPTS *fo = incexe->opts_list[j];
807 sendit(sock, " O %s\n", fo->opts);
809 bool enhanced_wild = false;
810 for (k=0; fo->opts[k]!='\0'; k++) {
811 if (fo->opts[k]=='W') {
812 enhanced_wild = true;
817 for (k=0; k<fo->regex.size(); k++) {
818 sendit(sock, " R %s\n", fo->regex.get(k));
820 for (k=0; k<fo->regexdir.size(); k++) {
821 sendit(sock, " RD %s\n", fo->regexdir.get(k));
823 for (k=0; k<fo->regexfile.size(); k++) {
824 sendit(sock, " RF %s\n", fo->regexfile.get(k));
826 for (k=0; k<fo->wild.size(); k++) {
827 sendit(sock, " W %s\n", fo->wild.get(k));
829 for (k=0; k<fo->wilddir.size(); k++) {
830 sendit(sock, " WD %s\n", fo->wilddir.get(k));
832 for (k=0; k<fo->wildfile.size(); k++) {
833 sendit(sock, " WF %s\n", fo->wildfile.get(k));
835 for (k=0; k<fo->wildbase.size(); k++) {
836 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
838 for (k=0; k<fo->base.size(); k++) {
839 sendit(sock, " B %s\n", fo->base.get(k));
841 for (k=0; k<fo->fstype.size(); k++) {
842 sendit(sock, " X %s\n", fo->fstype.get(k));
844 for (k=0; k<fo->drivetype.size(); k++) {
845 sendit(sock, " XD %s\n", fo->drivetype.get(k));
848 sendit(sock, " G %s\n", fo->plugin);
851 sendit(sock, " D %s\n", fo->reader);
854 sendit(sock, " T %s\n", fo->writer);
856 sendit(sock, " N\n");
858 if (incexe->ignoredir) {
859 sendit(sock, " Z %s\n", incexe->ignoredir);
861 for (j=0; j<incexe->name_list.size(); j++) {
862 sendit(sock, " I %s\n", incexe->name_list.get(j));
864 if (incexe->name_list.size()) {
865 sendit(sock, " N\n");
867 for (j=0; j<incexe->plugin_list.size(); j++) {
868 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
870 if (incexe->plugin_list.size()) {
871 sendit(sock, " N\n");
876 for (i=0; i<res->res_fs.num_excludes; i++) {
877 INCEXE *incexe = res->res_fs.exclude_items[i];
878 for (j=0; j<incexe->name_list.size(); j++) {
879 sendit(sock, " E %s\n", incexe->name_list.get(j));
881 if (incexe->name_list.size()) {
882 sendit(sock, " N\n");
889 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
892 if (res->res_sch.run) {
894 RUN *run = res->res_sch.run;
895 char buf[1000], num[30];
896 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
901 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
902 if (run->MaxRunSchedTime) {
903 sendit(sock, _(" MaxRunSchedTime=%u\n"), run->MaxRunSchedTime);
906 sendit(sock, _(" Priority=%u\n"), run->Priority);
908 bstrncpy(buf, _(" hour="), sizeof(buf));
909 for (i=0; i<24; i++) {
910 if (bit_is_set(i, run->hour)) {
911 bsnprintf(num, sizeof(num), "%d ", i);
912 bstrncat(buf, num, sizeof(buf));
915 bstrncat(buf, "\n", sizeof(buf));
917 bstrncpy(buf, _(" mday="), sizeof(buf));
918 for (i=0; i<32; i++) {
919 if (bit_is_set(i, run->mday)) {
920 bsnprintf(num, sizeof(num), "%d ", i);
921 bstrncat(buf, num, sizeof(buf));
924 bstrncat(buf, "\n", sizeof(buf));
926 bstrncpy(buf, _(" month="), sizeof(buf));
927 for (i=0; i<12; i++) {
928 if (bit_is_set(i, run->month)) {
929 bsnprintf(num, sizeof(num), "%d ", i);
930 bstrncat(buf, num, sizeof(buf));
933 bstrncat(buf, "\n", sizeof(buf));
935 bstrncpy(buf, _(" wday="), sizeof(buf));
936 for (i=0; i<7; i++) {
937 if (bit_is_set(i, run->wday)) {
938 bsnprintf(num, sizeof(num), "%d ", i);
939 bstrncat(buf, num, sizeof(buf));
942 bstrncat(buf, "\n", sizeof(buf));
944 bstrncpy(buf, _(" wom="), sizeof(buf));
945 for (i=0; i<6; i++) {
946 if (bit_is_set(i, run->wom)) {
947 bsnprintf(num, sizeof(num), "%d ", i);
948 bstrncat(buf, num, sizeof(buf));
951 bstrncat(buf, "\n", sizeof(buf));
953 bstrncpy(buf, _(" woy="), sizeof(buf));
954 for (i=0; i<54; i++) {
955 if (bit_is_set(i, run->woy)) {
956 bsnprintf(num, sizeof(num), "%d ", i);
957 bstrncat(buf, num, sizeof(buf));
960 bstrncat(buf, "\n", sizeof(buf));
962 sendit(sock, _(" mins=%d\n"), run->minute);
964 sendit(sock, _(" --> "));
965 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
968 sendit(sock, _(" --> "));
969 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
972 sendit(sock, _(" --> "));
973 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
975 /* If another Run record is chained in, go print it */
981 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
986 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
989 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
990 res->res_pool.pool_type);
991 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
992 res->res_pool.use_catalog, res->res_pool.use_volume_once,
993 res->res_pool.catalog_files);
994 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
995 res->res_pool.max_volumes, res->res_pool.AutoPrune,
996 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
997 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
998 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
999 res->res_pool.Recycle,
1000 NPRT(res->res_pool.label_format));
1001 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
1002 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
1003 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
1004 res->res_pool.recycle_oldest_volume,
1005 res->res_pool.purge_oldest_volume,
1006 res->res_pool.action_on_purge);
1007 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
1008 res->res_pool.MaxVolJobs,
1009 res->res_pool.MaxVolFiles,
1010 edit_uint64(res->res_pool.MaxVolBytes, ed1));
1011 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
1012 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
1013 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
1014 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
1015 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
1016 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
1017 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
1018 if (res->res_pool.NextPool) {
1019 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1021 if (res->res_pool.RecyclePool) {
1022 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1024 if (res->res_pool.ScratchPool) {
1025 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1027 if (res->res_pool.catalog) {
1028 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1030 if (res->res_pool.storage) {
1032 foreach_alist(store, res->res_pool.storage) {
1033 sendit(sock, _(" --> "));
1034 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1037 if (res->res_pool.CopyPool) {
1039 foreach_alist(copy, res->res_pool.CopyPool) {
1040 sendit(sock, _(" --> "));
1041 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1048 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1049 if (res->res_msgs.mail_cmd)
1050 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1051 if (res->res_msgs.operator_cmd)
1052 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1056 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1059 if (recurse && res->res_dir.hdr.next) {
1060 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1065 * Free all the members of an INCEXE structure
1067 static void free_incexe(INCEXE *incexe)
1069 incexe->name_list.destroy();
1070 incexe->plugin_list.destroy();
1071 for (int i=0; i<incexe->num_opts; i++) {
1072 FOPTS *fopt = incexe->opts_list[i];
1073 fopt->regex.destroy();
1074 fopt->regexdir.destroy();
1075 fopt->regexfile.destroy();
1076 fopt->wild.destroy();
1077 fopt->wilddir.destroy();
1078 fopt->wildfile.destroy();
1079 fopt->wildbase.destroy();
1080 fopt->base.destroy();
1081 fopt->fstype.destroy();
1082 fopt->drivetype.destroy();
1094 if (incexe->opts_list) {
1095 free(incexe->opts_list);
1097 if (incexe->ignoredir) {
1098 free(incexe->ignoredir);
1104 * Free memory of resource -- called when daemon terminates.
1105 * NB, we don't need to worry about freeing any references
1106 * to other resources as they will be freed when that
1107 * resource chain is traversed. Mainly we worry about freeing
1108 * allocated strings (names).
1110 void free_resource(RES *sres, int type)
1113 RES *nres; /* next resource if linked */
1114 URES *res = (URES *)sres;
1119 /* common stuff -- free the resource name and description */
1120 nres = (RES *)res->res_dir.hdr.next;
1121 if (res->res_dir.hdr.name) {
1122 free(res->res_dir.hdr.name);
1124 if (res->res_dir.hdr.desc) {
1125 free(res->res_dir.hdr.desc);
1130 if (res->res_dir.working_directory) {
1131 free(res->res_dir.working_directory);
1133 if (res->res_dir.scripts_directory) {
1134 free((char *)res->res_dir.scripts_directory);
1136 if (res->res_dir.plugin_directory) {
1137 free((char *)res->res_dir.plugin_directory);
1139 if (res->res_dir.pid_directory) {
1140 free(res->res_dir.pid_directory);
1142 if (res->res_dir.subsys_directory) {
1143 free(res->res_dir.subsys_directory);
1145 if (res->res_dir.password) {
1146 free(res->res_dir.password);
1148 if (res->res_dir.query_file) {
1149 free(res->res_dir.query_file);
1151 if (res->res_dir.DIRaddrs) {
1152 free_addresses(res->res_dir.DIRaddrs);
1154 if (res->res_dir.DIRsrc_addr) {
1155 free_addresses(res->res_dir.DIRsrc_addr);
1157 if (res->res_dir.tls_ctx) {
1158 free_tls_context(res->res_dir.tls_ctx);
1160 if (res->res_dir.tls_ca_certfile) {
1161 free(res->res_dir.tls_ca_certfile);
1163 if (res->res_dir.tls_ca_certdir) {
1164 free(res->res_dir.tls_ca_certdir);
1166 if (res->res_dir.tls_certfile) {
1167 free(res->res_dir.tls_certfile);
1169 if (res->res_dir.tls_keyfile) {
1170 free(res->res_dir.tls_keyfile);
1172 if (res->res_dir.tls_dhfile) {
1173 free(res->res_dir.tls_dhfile);
1175 if (res->res_dir.tls_allowed_cns) {
1176 delete res->res_dir.tls_allowed_cns;
1178 if (res->res_dir.verid) {
1179 free(res->res_dir.verid);
1186 if (res->res_con.password) {
1187 free(res->res_con.password);
1189 if (res->res_con.tls_ctx) {
1190 free_tls_context(res->res_con.tls_ctx);
1192 if (res->res_con.tls_ca_certfile) {
1193 free(res->res_con.tls_ca_certfile);
1195 if (res->res_con.tls_ca_certdir) {
1196 free(res->res_con.tls_ca_certdir);
1198 if (res->res_con.tls_certfile) {
1199 free(res->res_con.tls_certfile);
1201 if (res->res_con.tls_keyfile) {
1202 free(res->res_con.tls_keyfile);
1204 if (res->res_con.tls_dhfile) {
1205 free(res->res_con.tls_dhfile);
1207 if (res->res_con.tls_allowed_cns) {
1208 delete res->res_con.tls_allowed_cns;
1210 for (int i=0; i<Num_ACL; i++) {
1211 if (res->res_con.ACL_lists[i]) {
1212 delete res->res_con.ACL_lists[i];
1213 res->res_con.ACL_lists[i] = NULL;
1218 if (res->res_client.address) {
1219 free(res->res_client.address);
1221 if (res->res_client.fd_storage_address) {
1222 free(res->res_client.fd_storage_address);
1224 if (res->res_client.password) {
1225 free(res->res_client.password);
1227 if (res->res_client.tls_ctx) {
1228 free_tls_context(res->res_client.tls_ctx);
1230 if (res->res_client.tls_ca_certfile) {
1231 free(res->res_client.tls_ca_certfile);
1233 if (res->res_client.tls_ca_certdir) {
1234 free(res->res_client.tls_ca_certdir);
1236 if (res->res_client.tls_certfile) {
1237 free(res->res_client.tls_certfile);
1239 if (res->res_client.tls_keyfile) {
1240 free(res->res_client.tls_keyfile);
1242 if (res->res_client.tls_allowed_cns) {
1243 delete res->res_client.tls_allowed_cns;
1247 if (res->res_store.address) {
1248 free(res->res_store.address);
1250 if (res->res_store.fd_storage_address) {
1251 free(res->res_store.fd_storage_address);
1253 if (res->res_store.password) {
1254 free(res->res_store.password);
1256 if (res->res_store.media_type) {
1257 free(res->res_store.media_type);
1259 if (res->res_store.device) {
1260 delete res->res_store.device;
1262 if (res->res_store.tls_ctx) {
1263 free_tls_context(res->res_store.tls_ctx);
1265 if (res->res_store.tls_ca_certfile) {
1266 free(res->res_store.tls_ca_certfile);
1268 if (res->res_store.tls_ca_certdir) {
1269 free(res->res_store.tls_ca_certdir);
1271 if (res->res_store.tls_certfile) {
1272 free(res->res_store.tls_certfile);
1274 if (res->res_store.tls_keyfile) {
1275 free(res->res_store.tls_keyfile);
1279 if (res->res_cat.db_address) {
1280 free(res->res_cat.db_address);
1282 if (res->res_cat.db_socket) {
1283 free(res->res_cat.db_socket);
1285 if (res->res_cat.db_user) {
1286 free(res->res_cat.db_user);
1288 if (res->res_cat.db_name) {
1289 free(res->res_cat.db_name);
1291 if (res->res_cat.db_driver) {
1292 free(res->res_cat.db_driver);
1294 if (res->res_cat.db_password) {
1295 free(res->res_cat.db_password);
1299 if ((num=res->res_fs.num_includes)) {
1300 while (--num >= 0) {
1301 free_incexe(res->res_fs.include_items[num]);
1303 free(res->res_fs.include_items);
1305 res->res_fs.num_includes = 0;
1306 if ((num=res->res_fs.num_excludes)) {
1307 while (--num >= 0) {
1308 free_incexe(res->res_fs.exclude_items[num]);
1310 free(res->res_fs.exclude_items);
1312 res->res_fs.num_excludes = 0;
1315 if (res->res_pool.pool_type) {
1316 free(res->res_pool.pool_type);
1318 if (res->res_pool.label_format) {
1319 free(res->res_pool.label_format);
1321 if (res->res_pool.cleaning_prefix) {
1322 free(res->res_pool.cleaning_prefix);
1324 if (res->res_pool.storage) {
1325 delete res->res_pool.storage;
1329 if (res->res_sch.run) {
1331 nrun = res->res_sch.run;
1341 if (res->res_job.RestoreWhere) {
1342 free(res->res_job.RestoreWhere);
1344 if (res->res_job.RegexWhere) {
1345 free(res->res_job.RegexWhere);
1347 if (res->res_job.strip_prefix) {
1348 free(res->res_job.strip_prefix);
1350 if (res->res_job.add_prefix) {
1351 free(res->res_job.add_prefix);
1353 if (res->res_job.add_suffix) {
1354 free(res->res_job.add_suffix);
1356 if (res->res_job.RestoreBootstrap) {
1357 free(res->res_job.RestoreBootstrap);
1359 if (res->res_job.WriteBootstrap) {
1360 free(res->res_job.WriteBootstrap);
1362 if (res->res_job.PluginOptions) {
1363 free(res->res_job.PluginOptions);
1365 if (res->res_job.selection_pattern) {
1366 free(res->res_job.selection_pattern);
1368 if (res->res_job.run_cmds) {
1369 delete res->res_job.run_cmds;
1371 if (res->res_job.storage) {
1372 delete res->res_job.storage;
1374 if (res->res_job.base) {
1375 delete res->res_job.base;
1377 if (res->res_job.RunScripts) {
1378 free_runscripts(res->res_job.RunScripts);
1379 delete res->res_job.RunScripts;
1383 if (res->res_msgs.mail_cmd) {
1384 free(res->res_msgs.mail_cmd);
1386 if (res->res_msgs.operator_cmd) {
1387 free(res->res_msgs.operator_cmd);
1389 free_msgs_res((MSGS *)res); /* free message resource */
1393 printf(_("Unknown resource type %d in free_resource.\n"), type);
1395 /* Common stuff again -- free the resource, recurse to next one */
1400 free_resource(nres, type);
1405 * Save the new resource by chaining it into the head list for
1406 * the resource. If this is pass 2, we update any resource
1407 * pointers because they may not have been defined until
1410 void save_resource(int type, RES_ITEM *items, int pass)
1413 int rindex = type - r_first;
1417 /* Check Job requirements after applying JobDefs */
1418 if (type != R_JOB && type != R_JOBDEFS) {
1420 * Ensure that all required items are present
1422 for (i=0; items[i].name; i++) {
1423 if (items[i].flags & ITEM_REQUIRED) {
1424 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1425 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1426 items[i].name, resources[rindex]);
1429 /* If this triggers, take a look at lib/parse_conf.h */
1430 if (i >= MAX_RES_ITEMS) {
1431 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1434 } else if (type == R_JOB) {
1436 * Ensure that the name item is present
1438 if (items[0].flags & ITEM_REQUIRED) {
1439 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1440 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1441 items[0].name, resources[rindex]);
1447 * During pass 2 in each "store" routine, we looked up pointers
1448 * to all the resources referrenced in the current resource, now we
1449 * must copy their addresses from the static record to the allocated
1454 /* Resources not containing a resource */
1462 * Resources containing another resource or alist. First
1463 * look up the resource which contains another resource. It
1464 * was written during pass 1. Then stuff in the pointers to
1465 * the resources it contains, which were inserted this pass.
1466 * Finally, it will all be stored back.
1469 /* Find resource saved in pass 1 */
1470 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1471 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1473 /* Explicitly copy resource pointers from this pass (res_all) */
1474 res->res_pool.NextPool = res_all.res_pool.NextPool;
1475 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1476 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1477 res->res_pool.storage = res_all.res_pool.storage;
1478 res->res_pool.catalog = res_all.res_pool.catalog;
1481 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1482 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1484 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1487 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1488 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1490 res->res_dir.messages = res_all.res_dir.messages;
1491 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1494 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1495 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1496 res_all.res_dir.hdr.name);
1498 /* we must explicitly copy the device alist pointer */
1499 res->res_store.device = res_all.res_store.device;
1503 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1504 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1505 res_all.res_dir.hdr.name);
1507 res->res_job.messages = res_all.res_job.messages;
1508 res->res_job.schedule = res_all.res_job.schedule;
1509 res->res_job.client = res_all.res_job.client;
1510 res->res_job.fileset = res_all.res_job.fileset;
1511 res->res_job.storage = res_all.res_job.storage;
1512 res->res_job.base = res_all.res_job.base;
1513 res->res_job.pool = res_all.res_job.pool;
1514 res->res_job.next_pool = res_all.res_job.next_pool;
1515 res->res_job.full_pool = res_all.res_job.full_pool;
1516 res->res_job.inc_pool = res_all.res_job.inc_pool;
1517 res->res_job.diff_pool = res_all.res_job.diff_pool;
1518 res->res_job.verify_job = res_all.res_job.verify_job;
1519 res->res_job.jobdefs = res_all.res_job.jobdefs;
1520 res->res_job.run_cmds = res_all.res_job.run_cmds;
1521 res->res_job.RunScripts = res_all.res_job.RunScripts;
1523 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1524 * is not very useful)
1525 * We have to set_bit(index, res_all.hdr.item_present);
1526 * or something like that
1529 /* we take RegexWhere before all other options */
1530 if (!res->res_job.RegexWhere
1532 (res->res_job.strip_prefix ||
1533 res->res_job.add_suffix ||
1534 res->res_job.add_prefix))
1536 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1537 res->res_job.add_prefix,
1538 res->res_job.add_suffix);
1539 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1540 bregexp_build_where(res->res_job.RegexWhere, len,
1541 res->res_job.strip_prefix,
1542 res->res_job.add_prefix,
1543 res->res_job.add_suffix);
1544 /* TODO: test bregexp */
1547 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1548 free(res->res_job.RestoreWhere);
1549 res->res_job.RestoreWhere = NULL;
1554 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1555 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1557 res->res_counter.Catalog = res_all.res_counter.Catalog;
1558 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1562 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1563 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1565 res->res_client.catalog = res_all.res_client.catalog;
1566 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1570 * Schedule is a bit different in that it contains a RUN record
1571 * chain which isn't a "named" resource. This chain was linked
1572 * in by run_conf.c during pass 2, so here we jam the pointer
1573 * into the Schedule resource.
1575 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1576 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1578 res->res_sch.run = res_all.res_sch.run;
1581 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1585 /* Note, the resource name was already saved during pass 1,
1586 * so here, we can just release it.
1588 if (res_all.res_dir.hdr.name) {
1589 free(res_all.res_dir.hdr.name);
1590 res_all.res_dir.hdr.name = NULL;
1592 if (res_all.res_dir.hdr.desc) {
1593 free(res_all.res_dir.hdr.desc);
1594 res_all.res_dir.hdr.desc = NULL;
1600 * The following code is only executed during pass 1
1604 size = sizeof(DIRRES);
1607 size = sizeof(CONRES);
1610 size =sizeof(CLIENT);
1613 size = sizeof(STORE);
1623 size = sizeof(FILESET);
1626 size = sizeof(SCHED);
1629 size = sizeof(POOL);
1632 size = sizeof(MSGS);
1635 size = sizeof(COUNTER);
1641 printf(_("Unknown resource type %d in save_resource.\n"), type);
1647 res = (URES *)malloc(size);
1648 memcpy(res, &res_all, size);
1649 if (!res_head[rindex]) {
1650 res_head[rindex] = (RES *)res; /* store first entry */
1651 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1652 res->res_dir.hdr.name, rindex);
1655 if (res->res_dir.hdr.name == NULL) {
1656 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1659 /* Add new res to end of chain */
1660 for (last=next=res_head[rindex]; next; next=next->next) {
1662 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1663 Emsg2(M_ERROR_TERM, 0,
1664 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1665 resources[rindex].name, res->res_dir.hdr.name);
1668 last->next = (RES *)res;
1669 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1670 res->res_dir.hdr.name, rindex, pass);
1675 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1677 uint32_t *destination = (uint32_t*)item->value;
1678 lex_get_token(lc, T_NAME);
1679 if (strcasecmp(lc->str, "truncate") == 0) {
1680 *destination = (*destination) | ON_PURGE_TRUNCATE;
1682 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1686 set_bit(index, res_all.hdr.item_present);
1690 * Store Device. Note, the resource is created upon the
1691 * first reference. The details of the resource are obtained
1692 * later from the SD.
1694 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1697 int rindex = R_DEVICE - r_first;
1698 int size = sizeof(DEVICE);
1702 lex_get_token(lc, T_NAME);
1703 if (!res_head[rindex]) {
1704 res = (URES *)malloc(size);
1705 memset(res, 0, size);
1706 res->res_dev.hdr.name = bstrdup(lc->str);
1707 res_head[rindex] = (RES *)res; /* store first entry */
1708 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1709 res->res_dir.hdr.name, rindex);
1712 /* See if it is already defined */
1713 for (next=res_head[rindex]; next->next; next=next->next) {
1714 if (strcmp(next->name, lc->str) == 0) {
1720 res = (URES *)malloc(size);
1721 memset(res, 0, size);
1722 res->res_dev.hdr.name = bstrdup(lc->str);
1723 next->next = (RES *)res;
1724 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1725 res->res_dir.hdr.name, rindex, pass);
1730 set_bit(index, res_all.hdr.item_present);
1732 store_alist_res(lc, item, index, pass);
1737 * Store Migration/Copy type
1740 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1744 lex_get_token(lc, T_NAME);
1745 /* Store the type both pass 1 and pass 2 */
1746 for (i=0; migtypes[i].type_name; i++) {
1747 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1748 *(uint32_t *)(item->value) = migtypes[i].job_type;
1754 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1757 set_bit(index, res_all.hdr.item_present);
1763 * Store JobType (backup, verify, restore)
1766 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1770 lex_get_token(lc, T_NAME);
1771 /* Store the type both pass 1 and pass 2 */
1772 for (i=0; jobtypes[i].type_name; i++) {
1773 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1774 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1780 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1783 set_bit(index, res_all.hdr.item_present);
1787 * Store Job Level (Full, Incremental, ...)
1790 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1794 lex_get_token(lc, T_NAME);
1795 /* Store the level pass 2 so that type is defined */
1796 for (i=0; joblevels[i].level_name; i++) {
1797 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1798 *(uint32_t *)(item->value) = joblevels[i].level;
1804 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1807 set_bit(index, res_all.hdr.item_present);
1811 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1814 lex_get_token(lc, T_NAME);
1815 /* Scan Replacement options */
1816 for (i=0; ReplaceOptions[i].name; i++) {
1817 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1818 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1824 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1827 set_bit(index, res_all.hdr.item_present);
1831 * Store ACL (access control list)
1834 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1839 lex_get_token(lc, T_STRING);
1841 if (((alist **)item->value)[item->code] == NULL) {
1842 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1843 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1845 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1846 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1848 token = lex_get_token(lc, T_ALL);
1849 if (token == T_COMMA) {
1850 continue; /* get another ACL */
1854 set_bit(index, res_all.hdr.item_present);
1857 /* We build RunScripts items here */
1858 static RUNSCRIPT res_runscript;
1860 /* Store a runscript->when in a bit field */
1861 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1863 lex_get_token(lc, T_NAME);
1865 if (strcasecmp(lc->str, "before") == 0) {
1866 *(uint32_t *)(item->value) = SCRIPT_Before ;
1867 } else if (strcasecmp(lc->str, "after") == 0) {
1868 *(uint32_t *)(item->value) = SCRIPT_After;
1869 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1870 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1871 } else if (strcasecmp(lc->str, "always") == 0) {
1872 *(uint32_t *)(item->value) = SCRIPT_Any;
1874 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1879 /* Store a runscript->target
1882 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1884 lex_get_token(lc, T_STRING);
1887 if (strcmp(lc->str, "%c") == 0) {
1888 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1889 } else if (strcasecmp(lc->str, "yes") == 0) {
1890 ((RUNSCRIPT*) item->value)->set_target("%c");
1891 } else if (strcasecmp(lc->str, "no") == 0) {
1892 ((RUNSCRIPT*) item->value)->set_target("");
1894 RES *res = GetResWithName(R_CLIENT, lc->str);
1896 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1897 lc->str, lc->line_no, lc->line);
1900 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1907 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1909 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1911 lex_get_token(lc, T_STRING);
1914 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1915 POOLMEM *c = get_pool_memory(PM_FNAME);
1916 /* Each runscript command takes 2 entries in commands list */
1917 pm_strcpy(c, lc->str);
1918 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1919 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1924 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1926 lex_get_token(lc, T_STRING);
1927 alist **runscripts = (alist **)(item->value) ;
1930 RUNSCRIPT *script = new_runscript();
1931 script->set_job_code_callback(job_code_callback_director);
1933 script->set_command(lc->str);
1935 /* TODO: remove all script->old_proto with bacula 1.42 */
1937 if (strcmp(item->name, "runbeforejob") == 0) {
1938 script->when = SCRIPT_Before;
1939 script->fail_on_error = true;
1940 script->set_target("");
1942 } else if (strcmp(item->name, "runafterjob") == 0) {
1943 script->when = SCRIPT_After;
1944 script->on_success = true;
1945 script->on_failure = false;
1946 script->set_target("");
1948 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1949 script->old_proto = true;
1950 script->when = SCRIPT_After;
1951 script->set_target("%c");
1952 script->on_success = true;
1953 script->on_failure = false;
1955 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1956 script->old_proto = true;
1957 script->when = SCRIPT_Before;
1958 script->set_target("%c");
1959 script->fail_on_error = true;
1961 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1962 script->when = SCRIPT_After;
1963 script->on_failure = true;
1964 script->on_success = false;
1965 script->set_target("");
1968 if (*runscripts == NULL) {
1969 *runscripts = New(alist(10, not_owned_by_alist));
1972 (*runscripts)->append(script);
1979 /* Store a bool in a bit field without modifing res_all.hdr
1980 * We can also add an option to store_bool to skip res_all.hdr
1982 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1984 lex_get_token(lc, T_NAME);
1985 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1986 *(bool *)(item->value) = true;
1987 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1988 *(bool *)(item->value) = false;
1990 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1996 * new RunScript items
1997 * name handler value code flags default_value
1999 static RES_ITEM runscript_items[] = {
2000 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
2001 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
2002 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
2003 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
2004 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
2005 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2006 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
2007 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
2008 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
2009 {NULL, NULL, {0}, 0, 0, 0}
2013 * Store RunScript info
2015 * Note, when this routine is called, we are inside a Job
2016 * resource. We treat the RunScript like a sort of
2017 * mini-resource within the Job resource.
2019 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
2023 alist **runscripts = (alist **)(item->value) ;
2025 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
2027 token = lex_get_token(lc, T_SKIP_EOL);
2029 if (token != T_BOB) {
2030 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2032 /* setting on_success, on_failure, fail_on_error */
2033 res_runscript.reset_default();
2036 res_runscript.commands = New(alist(10, not_owned_by_alist));
2039 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2040 if (token == T_EOB) {
2043 if (token != T_IDENTIFIER) {
2044 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2046 for (i=0; runscript_items[i].name; i++) {
2047 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2048 token = lex_get_token(lc, T_SKIP_EOL);
2049 if (token != T_EQUALS) {
2050 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2053 /* Call item handler */
2054 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2061 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2066 /* run on client by default */
2067 if (res_runscript.target == NULL) {
2068 res_runscript.set_target("%c");
2070 if (*runscripts == NULL) {
2071 *runscripts = New(alist(10, not_owned_by_alist));
2074 * commands list contains 2 values per command
2075 * - POOLMEM command string (ex: /bin/true)
2076 * - int command type (ex: SHELL_CMD)
2078 res_runscript.set_job_code_callback(job_code_callback_director);
2079 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2080 t = (intptr_t)res_runscript.commands->pop();
2081 RUNSCRIPT *script = new_runscript();
2082 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2083 script->command = c;
2084 script->cmd_type = t;
2085 /* target is taken from res_runscript, each runscript object have
2088 script->target = NULL;
2089 script->set_target(res_runscript.target);
2091 (*runscripts)->append(script);
2094 delete res_runscript.commands;
2095 /* setting on_success, on_failure... cleanup target field */
2096 res_runscript.reset_default(true);
2100 set_bit(index, res_all.hdr.item_present);
2103 /* callback function for edit_job_codes */
2104 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2105 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2107 static char yes[] = "yes";
2108 static char no[] = "no";
2112 return jcr->fileset->name();
2117 return jcr->client->address;
2122 return jcr->pool->name();
2127 return jcr->wstore->name();
2131 return jcr->spool_data ? yes : no;
2135 return jcr->cloned ? yes : no;
2140 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2142 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2143 r_first, r_last, resources, res_head);
2144 return config->parse_config();