2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula Directors,
30 * some parts may be split into separate files such as
31 * the schedule configuration (run_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, January MM
56 /* Define the first and last resource ID record
57 * types. Note, these should be unique for each
58 * daemon though not a requirement.
60 int r_first = R_FIRST;
62 static RES *sres_head[R_LAST - R_FIRST + 1];
63 RES **res_head = sres_head;
65 /* Imported subroutines */
66 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
68 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
71 /* Forward referenced subroutines */
73 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
77 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
84 /* We build the current resource here as we are
85 * scanning the resource configuration definition,
86 * then move it to allocated memory when the resource
90 extern "C" { // work around visual compiler mangling variables
96 int res_all_size = sizeof(res_all);
99 /* Definition of records permitted within each
100 * resource with the routine to process the record
101 * information. NOTE! quoted names must be in lower case.
106 * name handler value code flags default_value
108 static RES_ITEM dir_items[] = {
109 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
110 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
111 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
112 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
116 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
117 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
118 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
119 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
120 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
121 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
122 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
123 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
124 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
125 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
126 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
127 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
128 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
129 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
130 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
131 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
132 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
133 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
134 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
135 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
136 {NULL, NULL, {0}, 0, 0, 0}
142 * name handler value code flags default_value
144 static RES_ITEM con_items[] = {
145 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
146 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
147 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
148 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
149 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
150 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
151 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
152 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
153 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
154 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
155 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
156 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
157 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
158 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
159 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
160 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
161 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
162 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
163 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
164 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
165 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
166 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
167 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
168 {NULL, NULL, {0}, 0, 0, 0}
173 * Client or File daemon resource
175 * name handler value code flags default_value
178 static RES_ITEM cli_items[] = {
179 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
180 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
181 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
182 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
183 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
184 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
185 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
186 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
187 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
188 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
189 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
190 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
191 {"maximumconcurrentjobs", store_pint, 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 {NULL, NULL, {0}, 0, 0, 0}
203 /* Storage daemon resource
205 * name handler value code flags default_value
207 static RES_ITEM store_items[] = {
208 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
209 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
210 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
211 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
212 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
213 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
214 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
215 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
216 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
217 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
218 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
219 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
220 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
221 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
222 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
223 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
224 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
225 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
226 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
227 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
228 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
229 {NULL, NULL, {0}, 0, 0, 0}
233 * Catalog Resource Directives
235 * name handler value code flags default_value
237 static RES_ITEM cat_items[] = {
238 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
239 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
240 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
241 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
242 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
243 /* keep this password as store_str for the moment */
244 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
245 {"dbpassword", store_str, ITEM(res_cat.db_password), 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 {NULL, NULL, {0}, 0, 0, 0}
256 * Job Resource Directives
258 * name handler value code flags default_value
260 RES_ITEM job_items[] = {
261 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
262 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
263 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
264 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
265 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
266 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
267 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
268 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
269 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
270 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
271 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
272 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
273 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
274 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
275 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
276 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
277 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
278 /* Root of where to restore files */
279 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
280 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
281 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
282 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
283 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
284 /* Where to find bootstrap during restore */
285 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
286 /* Where to write bootstrap file during backup */
287 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
288 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
289 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
290 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
291 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
292 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
293 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
294 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
295 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
296 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
297 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
298 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
299 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
300 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
301 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
302 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
303 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
304 {"optimizejobscheduling",store_bool, ITEM(res_job.OptimizeJobScheduling), 0, ITEM_DEFAULT, false},
305 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
306 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
307 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
308 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
309 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
310 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
311 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
312 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
313 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
314 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
315 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
316 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
317 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
318 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
319 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
320 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
321 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
322 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
323 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
324 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
325 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
326 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
327 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
328 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
329 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
330 {NULL, NULL, {0}, 0, 0, 0}
335 * name handler value code flags default_value
337 static RES_ITEM fs_items[] = {
338 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
339 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
340 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
341 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
342 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
343 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
344 {NULL, NULL, {0}, 0, 0, 0}
347 /* Schedule -- see run_conf.c */
350 * name handler value code flags default_value
352 static RES_ITEM sch_items[] = {
353 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
354 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
355 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
356 {NULL, NULL, {0}, 0, 0, 0}
361 * name handler value code flags default_value
363 static RES_ITEM pool_items[] = {
364 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
365 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
366 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
367 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
368 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
369 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
370 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
371 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
372 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
373 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
374 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
375 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
376 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
377 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
378 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
379 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
380 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
381 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
382 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
383 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
384 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
385 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
386 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
387 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
388 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
389 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
390 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
391 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
392 {NULL, NULL, {0}, 0, 0, 0}
397 * name handler value code flags default_value
399 static RES_ITEM counter_items[] = {
400 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
401 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
402 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
403 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
404 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
405 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
406 {NULL, NULL, {0}, 0, 0, 0}
410 /* Message resource */
411 extern RES_ITEM msgs_items[];
414 * This is the master resource definition.
415 * It must have one item for each of the resources.
417 * NOTE!!! keep it in the same order as the R_codes
418 * or eliminate all resources[rindex].name
420 * name items rcode res_head
422 RES_TABLE resources[] = {
423 {"director", dir_items, R_DIRECTOR},
424 {"client", cli_items, R_CLIENT},
425 {"job", job_items, R_JOB},
426 {"storage", store_items, R_STORAGE},
427 {"catalog", cat_items, R_CATALOG},
428 {"schedule", sch_items, R_SCHEDULE},
429 {"fileset", fs_items, R_FILESET},
430 {"pool", pool_items, R_POOL},
431 {"messages", msgs_items, R_MSGS},
432 {"counter", counter_items, R_COUNTER},
433 {"console", con_items, R_CONSOLE},
434 {"jobdefs", job_items, R_JOBDEFS},
435 {"device", NULL, R_DEVICE}, /* info obtained from SD */
440 /* Keywords (RHS) permitted in Job Level records
442 * level_name level job_type
444 struct s_jl joblevels[] = {
445 {"Full", L_FULL, JT_BACKUP},
446 {"Base", L_BASE, JT_BACKUP},
447 {"Incremental", L_INCREMENTAL, JT_BACKUP},
448 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
449 {"Since", L_SINCE, JT_BACKUP},
450 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
451 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
452 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
453 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
454 {"Data", L_VERIFY_DATA, JT_VERIFY},
455 {" ", L_NONE, JT_ADMIN},
456 {" ", L_NONE, JT_RESTORE},
460 /* Keywords (RHS) permitted in Job type records
464 struct s_jt jobtypes[] = {
465 {"backup", JT_BACKUP},
467 {"verify", JT_VERIFY},
468 {"restore", JT_RESTORE},
469 {"migrate", JT_MIGRATE},
475 /* Keywords (RHS) permitted in Selection type records
479 struct s_jt migtypes[] = {
480 {"smallestvolume", MT_SMALLEST_VOL},
481 {"oldestvolume", MT_OLDEST_VOL},
482 {"pooloccupancy", MT_POOL_OCCUPANCY},
483 {"pooltime", MT_POOL_TIME},
484 {"client", MT_CLIENT},
485 {"volume", MT_VOLUME},
487 {"sqlquery", MT_SQLQUERY},
493 /* Options permitted in Restore replace= */
494 struct s_kw ReplaceOptions[] = {
495 {"always", REPLACE_ALWAYS},
496 {"ifnewer", REPLACE_IFNEWER},
497 {"ifolder", REPLACE_IFOLDER},
498 {"never", REPLACE_NEVER},
502 const char *level_to_str(int level)
505 static char level_no[30];
506 const char *str = level_no;
508 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
509 for (i=0; joblevels[i].level_name; i++) {
510 if (level == joblevels[i].level) {
511 str = joblevels[i].level_name;
518 /* Dump contents of resource */
519 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
521 URES *res = (URES *)reshdr;
523 char ed1[100], ed2[100], ed3[100];
527 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
530 if (type < 0) { /* no recursion */
536 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
537 reshdr->name, res->res_dir.MaxConcurrentJobs,
538 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
539 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
540 if (res->res_dir.query_file) {
541 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
543 if (res->res_dir.messages) {
544 sendit(sock, _(" --> "));
545 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
549 sendit(sock, _("Console: name=%s SSL=%d\n"),
550 res->res_con.hdr.name, res->res_con.tls_enable);
553 if (res->res_counter.WrapCounter) {
554 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
555 res->res_counter.hdr.name, res->res_counter.MinValue,
556 res->res_counter.MaxValue, res->res_counter.CurrentValue,
557 res->res_counter.WrapCounter->hdr.name);
559 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
560 res->res_counter.hdr.name, res->res_counter.MinValue,
561 res->res_counter.MaxValue);
563 if (res->res_counter.Catalog) {
564 sendit(sock, _(" --> "));
565 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
570 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
571 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
572 res->res_client.MaxConcurrentJobs);
573 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
574 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
575 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
576 res->res_client.AutoPrune);
577 if (res->res_client.catalog) {
578 sendit(sock, _(" --> "));
579 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
586 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
587 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
588 " poolid=%s volname=%s MediaType=%s\n"),
589 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
590 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
591 dev->offline, dev->autochanger,
592 edit_uint64(dev->PoolId, ed1),
593 dev->VolumeName, dev->MediaType);
597 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
598 " DeviceName=%s MediaType=%s StorageId=%s\n"),
599 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
600 res->res_store.MaxConcurrentJobs,
601 res->res_store.dev_name(),
602 res->res_store.media_type,
603 edit_int64(res->res_store.StorageId, ed1));
607 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
608 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
609 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
610 res->res_cat.db_port, res->res_cat.db_name,
611 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
612 res->res_cat.mult_db_connections);
617 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
618 type == R_JOB ? _("Job") : _("JobDefs"),
619 res->res_job.hdr.name, res->res_job.JobType,
620 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
621 res->res_job.enabled);
622 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
623 res->res_job.MaxConcurrentJobs,
624 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
625 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
626 res->res_job.spool_data, res->res_job.write_part_after_job);
627 if (res->res_job.spool_size) {
628 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
630 if (res->res_job.JobType == JT_BACKUP) {
631 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
633 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
634 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
636 if (res->res_job.client) {
637 sendit(sock, _(" --> "));
638 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
640 if (res->res_job.fileset) {
641 sendit(sock, _(" --> "));
642 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
644 if (res->res_job.schedule) {
645 sendit(sock, _(" --> "));
646 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
648 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
649 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
651 if (res->res_job.RegexWhere) {
652 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
654 if (res->res_job.RestoreBootstrap) {
655 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
657 if (res->res_job.WriteBootstrap) {
658 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
660 if (res->res_job.PluginOptions) {
661 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
663 if (res->res_job.storage) {
665 foreach_alist(store, res->res_job.storage) {
666 sendit(sock, _(" --> "));
667 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
670 if (res->res_job.RunScripts) {
672 foreach_alist(script, res->res_job.RunScripts) {
673 sendit(sock, _(" --> RunScript\n"));
674 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
675 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
676 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
677 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
678 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
679 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
682 if (res->res_job.pool) {
683 sendit(sock, _(" --> "));
684 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
686 if (res->res_job.full_pool) {
687 sendit(sock, _(" --> "));
688 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
690 if (res->res_job.inc_pool) {
691 sendit(sock, _(" --> "));
692 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
694 if (res->res_job.diff_pool) {
695 sendit(sock, _(" --> "));
696 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
698 if (res->res_job.verify_job) {
699 sendit(sock, _(" --> "));
700 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
702 if (res->res_job.run_cmds) {
704 foreach_alist(runcmd, res->res_job.run_cmds) {
705 sendit(sock, _(" --> Run=%s\n"), runcmd);
708 if (res->res_job.selection_pattern) {
709 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
711 if (res->res_job.messages) {
712 sendit(sock, _(" --> "));
713 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
720 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
721 for (i=0; i<res->res_fs.num_includes; i++) {
722 INCEXE *incexe = res->res_fs.include_items[i];
723 for (j=0; j<incexe->num_opts; j++) {
724 FOPTS *fo = incexe->opts_list[j];
725 sendit(sock, " O %s\n", fo->opts);
727 bool enhanced_wild = false;
728 for (k=0; fo->opts[k]!='\0'; k++) {
729 if (fo->opts[k]=='W') {
730 enhanced_wild = true;
735 for (k=0; k<fo->regex.size(); k++) {
736 sendit(sock, " R %s\n", fo->regex.get(k));
738 for (k=0; k<fo->regexdir.size(); k++) {
739 sendit(sock, " RD %s\n", fo->regexdir.get(k));
741 for (k=0; k<fo->regexfile.size(); k++) {
742 sendit(sock, " RF %s\n", fo->regexfile.get(k));
744 for (k=0; k<fo->wild.size(); k++) {
745 sendit(sock, " W %s\n", fo->wild.get(k));
747 for (k=0; k<fo->wilddir.size(); k++) {
748 sendit(sock, " WD %s\n", fo->wilddir.get(k));
750 for (k=0; k<fo->wildfile.size(); k++) {
751 sendit(sock, " WF %s\n", fo->wildfile.get(k));
753 for (k=0; k<fo->wildbase.size(); k++) {
754 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
756 for (k=0; k<fo->base.size(); k++) {
757 sendit(sock, " B %s\n", fo->base.get(k));
759 for (k=0; k<fo->fstype.size(); k++) {
760 sendit(sock, " X %s\n", fo->fstype.get(k));
762 for (k=0; k<fo->drivetype.size(); k++) {
763 sendit(sock, " XD %s\n", fo->drivetype.get(k));
766 sendit(sock, " G %s\n", fo->plugin);
769 sendit(sock, " D %s\n", fo->reader);
772 sendit(sock, " T %s\n", fo->writer);
774 sendit(sock, " N\n");
776 for (j=0; j<incexe->name_list.size(); j++) {
777 sendit(sock, " I %s\n", incexe->name_list.get(j));
779 if (incexe->name_list.size()) {
780 sendit(sock, " N\n");
782 for (j=0; j<incexe->plugin_list.size(); j++) {
783 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
785 if (incexe->plugin_list.size()) {
786 sendit(sock, " N\n");
791 for (i=0; i<res->res_fs.num_excludes; i++) {
792 INCEXE *incexe = res->res_fs.exclude_items[i];
793 for (j=0; j<incexe->name_list.size(); j++) {
794 sendit(sock, " E %s\n", incexe->name_list.get(j));
796 if (incexe->name_list.size()) {
797 sendit(sock, " N\n");
804 if (res->res_sch.run) {
806 RUN *run = res->res_sch.run;
807 char buf[1000], num[30];
808 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
813 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
814 bstrncpy(buf, _(" hour="), sizeof(buf));
815 for (i=0; i<24; i++) {
816 if (bit_is_set(i, run->hour)) {
817 bsnprintf(num, sizeof(num), "%d ", i);
818 bstrncat(buf, num, sizeof(buf));
821 bstrncat(buf, "\n", sizeof(buf));
823 bstrncpy(buf, _(" mday="), sizeof(buf));
824 for (i=0; i<31; i++) {
825 if (bit_is_set(i, run->mday)) {
826 bsnprintf(num, sizeof(num), "%d ", i);
827 bstrncat(buf, num, sizeof(buf));
830 bstrncat(buf, "\n", sizeof(buf));
832 bstrncpy(buf, _(" month="), sizeof(buf));
833 for (i=0; i<12; i++) {
834 if (bit_is_set(i, run->month)) {
835 bsnprintf(num, sizeof(num), "%d ", i);
836 bstrncat(buf, num, sizeof(buf));
839 bstrncat(buf, "\n", sizeof(buf));
841 bstrncpy(buf, _(" wday="), sizeof(buf));
842 for (i=0; i<7; i++) {
843 if (bit_is_set(i, run->wday)) {
844 bsnprintf(num, sizeof(num), "%d ", i);
845 bstrncat(buf, num, sizeof(buf));
848 bstrncat(buf, "\n", sizeof(buf));
850 bstrncpy(buf, _(" wom="), sizeof(buf));
851 for (i=0; i<5; i++) {
852 if (bit_is_set(i, run->wom)) {
853 bsnprintf(num, sizeof(num), "%d ", i);
854 bstrncat(buf, num, sizeof(buf));
857 bstrncat(buf, "\n", sizeof(buf));
859 bstrncpy(buf, _(" woy="), sizeof(buf));
860 for (i=0; i<54; i++) {
861 if (bit_is_set(i, run->woy)) {
862 bsnprintf(num, sizeof(num), "%d ", i);
863 bstrncat(buf, num, sizeof(buf));
866 bstrncat(buf, "\n", sizeof(buf));
868 sendit(sock, _(" mins=%d\n"), run->minute);
870 sendit(sock, _(" --> "));
871 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
874 sendit(sock, _(" --> "));
875 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
878 sendit(sock, _(" --> "));
879 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
881 /* If another Run record is chained in, go print it */
887 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
892 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
893 res->res_pool.pool_type);
894 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
895 res->res_pool.use_catalog, res->res_pool.use_volume_once,
896 res->res_pool.catalog_files);
897 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
898 res->res_pool.max_volumes, res->res_pool.AutoPrune,
899 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
900 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
901 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
902 res->res_pool.Recycle,
903 NPRT(res->res_pool.label_format));
904 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
905 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
906 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
907 res->res_pool.recycle_oldest_volume,
908 res->res_pool.purge_oldest_volume);
909 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
910 res->res_pool.MaxVolJobs,
911 res->res_pool.MaxVolFiles,
912 edit_uint64(res->res_pool.MaxVolFiles, ed1));
913 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
914 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
915 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
916 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
917 if (res->res_pool.NextPool) {
918 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
920 if (res->res_pool.RecyclePool) {
921 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
923 if (res->res_pool.catalog) {
924 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
926 if (res->res_pool.storage) {
928 foreach_alist(store, res->res_pool.storage) {
929 sendit(sock, _(" --> "));
930 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
933 if (res->res_pool.CopyPool) {
935 foreach_alist(copy, res->res_pool.CopyPool) {
936 sendit(sock, _(" --> "));
937 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
944 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
945 if (res->res_msgs.mail_cmd)
946 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
947 if (res->res_msgs.operator_cmd)
948 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
952 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
955 if (recurse && res->res_dir.hdr.next) {
956 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
961 * Free all the members of an INCEXE structure
963 static void free_incexe(INCEXE *incexe)
965 incexe->name_list.destroy();
966 incexe->plugin_list.destroy();
967 for (int i=0; i<incexe->num_opts; i++) {
968 FOPTS *fopt = incexe->opts_list[i];
969 fopt->regex.destroy();
970 fopt->regexdir.destroy();
971 fopt->regexfile.destroy();
972 fopt->wild.destroy();
973 fopt->wilddir.destroy();
974 fopt->wildfile.destroy();
975 fopt->wildbase.destroy();
976 fopt->base.destroy();
977 fopt->fstype.destroy();
978 fopt->drivetype.destroy();
990 if (incexe->opts_list) {
991 free(incexe->opts_list);
997 * Free memory of resource -- called when daemon terminates.
998 * NB, we don't need to worry about freeing any references
999 * to other resources as they will be freed when that
1000 * resource chain is traversed. Mainly we worry about freeing
1001 * allocated strings (names).
1003 void free_resource(RES *sres, int type)
1006 RES *nres; /* next resource if linked */
1007 URES *res = (URES *)sres;
1012 /* common stuff -- free the resource name and description */
1013 nres = (RES *)res->res_dir.hdr.next;
1014 if (res->res_dir.hdr.name) {
1015 free(res->res_dir.hdr.name);
1017 if (res->res_dir.hdr.desc) {
1018 free(res->res_dir.hdr.desc);
1023 if (res->res_dir.working_directory) {
1024 free(res->res_dir.working_directory);
1026 if (res->res_dir.scripts_directory) {
1027 free((char *)res->res_dir.scripts_directory);
1029 if (res->res_dir.plugin_directory) {
1030 free((char *)res->res_dir.plugin_directory);
1032 if (res->res_dir.pid_directory) {
1033 free(res->res_dir.pid_directory);
1035 if (res->res_dir.subsys_directory) {
1036 free(res->res_dir.subsys_directory);
1038 if (res->res_dir.password) {
1039 free(res->res_dir.password);
1041 if (res->res_dir.query_file) {
1042 free(res->res_dir.query_file);
1044 if (res->res_dir.DIRaddrs) {
1045 free_addresses(res->res_dir.DIRaddrs);
1047 if (res->res_dir.tls_ctx) {
1048 free_tls_context(res->res_dir.tls_ctx);
1050 if (res->res_dir.tls_ca_certfile) {
1051 free(res->res_dir.tls_ca_certfile);
1053 if (res->res_dir.tls_ca_certdir) {
1054 free(res->res_dir.tls_ca_certdir);
1056 if (res->res_dir.tls_certfile) {
1057 free(res->res_dir.tls_certfile);
1059 if (res->res_dir.tls_keyfile) {
1060 free(res->res_dir.tls_keyfile);
1062 if (res->res_dir.tls_dhfile) {
1063 free(res->res_dir.tls_dhfile);
1065 if (res->res_dir.tls_allowed_cns) {
1066 delete res->res_dir.tls_allowed_cns;
1073 if (res->res_con.password) {
1074 free(res->res_con.password);
1076 if (res->res_con.tls_ctx) {
1077 free_tls_context(res->res_con.tls_ctx);
1079 if (res->res_con.tls_ca_certfile) {
1080 free(res->res_con.tls_ca_certfile);
1082 if (res->res_con.tls_ca_certdir) {
1083 free(res->res_con.tls_ca_certdir);
1085 if (res->res_con.tls_certfile) {
1086 free(res->res_con.tls_certfile);
1088 if (res->res_con.tls_keyfile) {
1089 free(res->res_con.tls_keyfile);
1091 if (res->res_con.tls_dhfile) {
1092 free(res->res_con.tls_dhfile);
1094 if (res->res_con.tls_allowed_cns) {
1095 delete res->res_con.tls_allowed_cns;
1097 for (int i=0; i<Num_ACL; i++) {
1098 if (res->res_con.ACL_lists[i]) {
1099 delete res->res_con.ACL_lists[i];
1100 res->res_con.ACL_lists[i] = NULL;
1105 if (res->res_client.address) {
1106 free(res->res_client.address);
1108 if (res->res_client.password) {
1109 free(res->res_client.password);
1111 if (res->res_client.tls_ctx) {
1112 free_tls_context(res->res_client.tls_ctx);
1114 if (res->res_client.tls_ca_certfile) {
1115 free(res->res_client.tls_ca_certfile);
1117 if (res->res_client.tls_ca_certdir) {
1118 free(res->res_client.tls_ca_certdir);
1120 if (res->res_client.tls_certfile) {
1121 free(res->res_client.tls_certfile);
1123 if (res->res_client.tls_keyfile) {
1124 free(res->res_client.tls_keyfile);
1126 if (res->res_client.tls_allowed_cns) {
1127 delete res->res_client.tls_allowed_cns;
1131 if (res->res_store.address) {
1132 free(res->res_store.address);
1134 if (res->res_store.password) {
1135 free(res->res_store.password);
1137 if (res->res_store.media_type) {
1138 free(res->res_store.media_type);
1140 if (res->res_store.device) {
1141 delete res->res_store.device;
1143 if (res->res_store.tls_ctx) {
1144 free_tls_context(res->res_store.tls_ctx);
1146 if (res->res_store.tls_ca_certfile) {
1147 free(res->res_store.tls_ca_certfile);
1149 if (res->res_store.tls_ca_certdir) {
1150 free(res->res_store.tls_ca_certdir);
1152 if (res->res_store.tls_certfile) {
1153 free(res->res_store.tls_certfile);
1155 if (res->res_store.tls_keyfile) {
1156 free(res->res_store.tls_keyfile);
1160 if (res->res_cat.db_address) {
1161 free(res->res_cat.db_address);
1163 if (res->res_cat.db_socket) {
1164 free(res->res_cat.db_socket);
1166 if (res->res_cat.db_user) {
1167 free(res->res_cat.db_user);
1169 if (res->res_cat.db_name) {
1170 free(res->res_cat.db_name);
1172 if (res->res_cat.db_driver) {
1173 free(res->res_cat.db_driver);
1175 if (res->res_cat.db_password) {
1176 free(res->res_cat.db_password);
1180 if ((num=res->res_fs.num_includes)) {
1181 while (--num >= 0) {
1182 free_incexe(res->res_fs.include_items[num]);
1184 free(res->res_fs.include_items);
1186 res->res_fs.num_includes = 0;
1187 if ((num=res->res_fs.num_excludes)) {
1188 while (--num >= 0) {
1189 free_incexe(res->res_fs.exclude_items[num]);
1191 free(res->res_fs.exclude_items);
1193 res->res_fs.num_excludes = 0;
1196 if (res->res_pool.pool_type) {
1197 free(res->res_pool.pool_type);
1199 if (res->res_pool.label_format) {
1200 free(res->res_pool.label_format);
1202 if (res->res_pool.cleaning_prefix) {
1203 free(res->res_pool.cleaning_prefix);
1205 if (res->res_pool.storage) {
1206 delete res->res_pool.storage;
1210 if (res->res_sch.run) {
1212 nrun = res->res_sch.run;
1222 if (res->res_job.RestoreWhere) {
1223 free(res->res_job.RestoreWhere);
1225 if (res->res_job.RegexWhere) {
1226 free(res->res_job.RegexWhere);
1228 if (res->res_job.strip_prefix) {
1229 free(res->res_job.strip_prefix);
1231 if (res->res_job.add_prefix) {
1232 free(res->res_job.add_prefix);
1234 if (res->res_job.add_suffix) {
1235 free(res->res_job.add_suffix);
1237 if (res->res_job.RestoreBootstrap) {
1238 free(res->res_job.RestoreBootstrap);
1240 if (res->res_job.WriteBootstrap) {
1241 free(res->res_job.WriteBootstrap);
1243 if (res->res_job.PluginOptions) {
1244 free(res->res_job.PluginOptions);
1246 if (res->res_job.selection_pattern) {
1247 free(res->res_job.selection_pattern);
1249 if (res->res_job.run_cmds) {
1250 delete res->res_job.run_cmds;
1252 if (res->res_job.storage) {
1253 delete res->res_job.storage;
1255 if (res->res_job.RunScripts) {
1256 free_runscripts(res->res_job.RunScripts);
1257 delete res->res_job.RunScripts;
1261 if (res->res_msgs.mail_cmd) {
1262 free(res->res_msgs.mail_cmd);
1264 if (res->res_msgs.operator_cmd) {
1265 free(res->res_msgs.operator_cmd);
1267 free_msgs_res((MSGS *)res); /* free message resource */
1271 printf(_("Unknown resource type %d in free_resource.\n"), type);
1273 /* Common stuff again -- free the resource, recurse to next one */
1278 free_resource(nres, type);
1283 * Save the new resource by chaining it into the head list for
1284 * the resource. If this is pass 2, we update any resource
1285 * pointers because they may not have been defined until
1288 void save_resource(int type, RES_ITEM *items, int pass)
1291 int rindex = type - r_first;
1295 /* Check Job requirements after applying JobDefs */
1296 if (type != R_JOB && type != R_JOBDEFS) {
1298 * Ensure that all required items are present
1300 for (i=0; items[i].name; i++) {
1301 if (items[i].flags & ITEM_REQUIRED) {
1302 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1303 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1304 items[i].name, resources[rindex]);
1307 /* If this triggers, take a look at lib/parse_conf.h */
1308 if (i >= MAX_RES_ITEMS) {
1309 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1312 } else if (type == R_JOB) {
1314 * Ensure that the name item is present
1316 if (items[0].flags & ITEM_REQUIRED) {
1317 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1318 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1319 items[0].name, resources[rindex]);
1325 * During pass 2 in each "store" routine, we looked up pointers
1326 * to all the resources referrenced in the current resource, now we
1327 * must copy their addresses from the static record to the allocated
1332 /* Resources not containing a resource */
1340 * Resources containing another resource or alist. First
1341 * look up the resource which contains another resource. It
1342 * was written during pass 1. Then stuff in the pointers to
1343 * the resources it contains, which were inserted this pass.
1344 * Finally, it will all be stored back.
1347 /* Find resource saved in pass 1 */
1348 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1349 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1351 /* Explicitly copy resource pointers from this pass (res_all) */
1352 res->res_pool.NextPool = res_all.res_pool.NextPool;
1353 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1354 res->res_pool.storage = res_all.res_pool.storage;
1355 res->res_pool.catalog = res_all.res_pool.catalog;
1358 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1359 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1361 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1364 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1365 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1367 res->res_dir.messages = res_all.res_dir.messages;
1368 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1371 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1372 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1373 res_all.res_dir.hdr.name);
1375 /* we must explicitly copy the device alist pointer */
1376 res->res_store.device = res_all.res_store.device;
1380 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1381 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1382 res_all.res_dir.hdr.name);
1384 res->res_job.messages = res_all.res_job.messages;
1385 res->res_job.schedule = res_all.res_job.schedule;
1386 res->res_job.client = res_all.res_job.client;
1387 res->res_job.fileset = res_all.res_job.fileset;
1388 res->res_job.storage = res_all.res_job.storage;
1389 res->res_job.pool = res_all.res_job.pool;
1390 res->res_job.full_pool = res_all.res_job.full_pool;
1391 res->res_job.inc_pool = res_all.res_job.inc_pool;
1392 res->res_job.diff_pool = res_all.res_job.diff_pool;
1393 res->res_job.verify_job = res_all.res_job.verify_job;
1394 res->res_job.jobdefs = res_all.res_job.jobdefs;
1395 res->res_job.run_cmds = res_all.res_job.run_cmds;
1396 res->res_job.RunScripts = res_all.res_job.RunScripts;
1398 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1399 * is not very useful)
1400 * We have to set_bit(index, res_all.hdr.item_present);
1401 * or something like that
1404 /* we take RegexWhere before all other options */
1405 if (!res->res_job.RegexWhere
1407 (res->res_job.strip_prefix ||
1408 res->res_job.add_suffix ||
1409 res->res_job.add_prefix))
1411 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1412 res->res_job.add_prefix,
1413 res->res_job.add_suffix);
1414 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1415 bregexp_build_where(res->res_job.RegexWhere, len,
1416 res->res_job.strip_prefix,
1417 res->res_job.add_prefix,
1418 res->res_job.add_suffix);
1419 /* TODO: test bregexp */
1422 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1423 free(res->res_job.RestoreWhere);
1424 res->res_job.RestoreWhere = NULL;
1429 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1430 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1432 res->res_counter.Catalog = res_all.res_counter.Catalog;
1433 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1437 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1438 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1440 res->res_client.catalog = res_all.res_client.catalog;
1441 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1445 * Schedule is a bit different in that it contains a RUN record
1446 * chain which isn't a "named" resource. This chain was linked
1447 * in by run_conf.c during pass 2, so here we jam the pointer
1448 * into the Schedule resource.
1450 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1451 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1453 res->res_sch.run = res_all.res_sch.run;
1456 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1460 /* Note, the resource name was already saved during pass 1,
1461 * so here, we can just release it.
1463 if (res_all.res_dir.hdr.name) {
1464 free(res_all.res_dir.hdr.name);
1465 res_all.res_dir.hdr.name = NULL;
1467 if (res_all.res_dir.hdr.desc) {
1468 free(res_all.res_dir.hdr.desc);
1469 res_all.res_dir.hdr.desc = NULL;
1475 * The following code is only executed during pass 1
1479 size = sizeof(DIRRES);
1482 size = sizeof(CONRES);
1485 size =sizeof(CLIENT);
1488 size = sizeof(STORE);
1498 size = sizeof(FILESET);
1501 size = sizeof(SCHED);
1504 size = sizeof(POOL);
1507 size = sizeof(MSGS);
1510 size = sizeof(COUNTER);
1516 printf(_("Unknown resource type %d in save_resource.\n"), type);
1522 res = (URES *)malloc(size);
1523 memcpy(res, &res_all, size);
1524 if (!res_head[rindex]) {
1525 res_head[rindex] = (RES *)res; /* store first entry */
1526 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1527 res->res_dir.hdr.name, rindex);
1530 if (res->res_dir.hdr.name == NULL) {
1531 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1534 /* Add new res to end of chain */
1535 for (last=next=res_head[rindex]; next; next=next->next) {
1537 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1538 Emsg2(M_ERROR_TERM, 0,
1539 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1540 resources[rindex].name, res->res_dir.hdr.name);
1543 last->next = (RES *)res;
1544 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1545 res->res_dir.hdr.name, rindex, pass);
1551 * Store Device. Note, the resource is created upon the
1552 * first reference. The details of the resource are obtained
1553 * later from the SD.
1555 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1559 int rindex = R_DEVICE - r_first;
1560 int size = sizeof(DEVICE);
1564 token = lex_get_token(lc, T_NAME);
1565 if (!res_head[rindex]) {
1566 res = (URES *)malloc(size);
1567 memset(res, 0, size);
1568 res->res_dev.hdr.name = bstrdup(lc->str);
1569 res_head[rindex] = (RES *)res; /* store first entry */
1570 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1571 res->res_dir.hdr.name, rindex);
1574 /* See if it is already defined */
1575 for (next=res_head[rindex]; next->next; next=next->next) {
1576 if (strcmp(next->name, lc->str) == 0) {
1582 res = (URES *)malloc(size);
1583 memset(res, 0, size);
1584 res->res_dev.hdr.name = bstrdup(lc->str);
1585 next->next = (RES *)res;
1586 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1587 res->res_dir.hdr.name, rindex, pass);
1592 set_bit(index, res_all.hdr.item_present);
1594 store_alist_res(lc, item, index, pass);
1599 * Store JobType (backup, verify, restore)
1602 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1606 token = lex_get_token(lc, T_NAME);
1607 /* Store the type both pass 1 and pass 2 */
1608 for (i=0; migtypes[i].type_name; i++) {
1609 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1610 *(int *)(item->value) = migtypes[i].job_type;
1616 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1619 set_bit(index, res_all.hdr.item_present);
1625 * Store JobType (backup, verify, restore)
1628 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1632 token = lex_get_token(lc, T_NAME);
1633 /* Store the type both pass 1 and pass 2 */
1634 for (i=0; jobtypes[i].type_name; i++) {
1635 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1636 *(int *)(item->value) = jobtypes[i].job_type;
1642 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1645 set_bit(index, res_all.hdr.item_present);
1649 * Store Job Level (Full, Incremental, ...)
1652 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1656 token = lex_get_token(lc, T_NAME);
1657 /* Store the level pass 2 so that type is defined */
1658 for (i=0; joblevels[i].level_name; i++) {
1659 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1660 *(int *)(item->value) = joblevels[i].level;
1666 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1669 set_bit(index, res_all.hdr.item_present);
1673 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1676 token = lex_get_token(lc, T_NAME);
1677 /* Scan Replacement options */
1678 for (i=0; ReplaceOptions[i].name; i++) {
1679 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1680 *(int *)(item->value) = ReplaceOptions[i].token;
1686 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1689 set_bit(index, res_all.hdr.item_present);
1693 * Store ACL (access control list)
1696 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1701 token = lex_get_token(lc, T_STRING);
1703 if (((alist **)item->value)[item->code] == NULL) {
1704 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1705 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1707 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1708 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1710 token = lex_get_token(lc, T_ALL);
1711 if (token == T_COMMA) {
1712 continue; /* get another ACL */
1716 set_bit(index, res_all.hdr.item_present);
1719 /* We build RunScripts items here */
1720 static RUNSCRIPT res_runscript;
1722 /* Store a runscript->when in a bit field */
1723 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1725 lex_get_token(lc, T_NAME);
1727 if (strcasecmp(lc->str, "before") == 0) {
1728 *(int *)(item->value) = SCRIPT_Before ;
1729 } else if (strcasecmp(lc->str, "after") == 0) {
1730 *(int *)(item->value) = SCRIPT_After;
1731 } else if (strcasecmp(lc->str, "always") == 0) {
1732 *(int *)(item->value) = SCRIPT_Any;
1734 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1739 /* Store a runscript->target
1742 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1744 lex_get_token(lc, T_STRING);
1747 if (strcmp(lc->str, "%c") == 0) {
1748 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1749 } else if (strcasecmp(lc->str, "yes") == 0) {
1750 ((RUNSCRIPT*) item->value)->set_target("%c");
1751 } else if (strcasecmp(lc->str, "no") == 0) {
1752 ((RUNSCRIPT*) item->value)->set_target("");
1754 RES *res = GetResWithName(R_CLIENT, lc->str);
1756 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1757 lc->str, lc->line_no, lc->line);
1760 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1767 * Store a runscript->command as a string
1769 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1771 lex_get_token(lc, T_STRING);
1774 ((RUNSCRIPT*)item->value)->set_command(lc->str, item->code);
1779 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1781 lex_get_token(lc, T_STRING);
1782 alist **runscripts = (alist **)(item->value) ;
1785 RUNSCRIPT *script = new_runscript();
1786 script->set_job_code_callback(job_code_callback_filesetname);
1788 script->set_command(lc->str);
1790 /* TODO: remove all script->old_proto with bacula 1.42 */
1792 if (strcmp(item->name, "runbeforejob") == 0) {
1793 script->when = SCRIPT_Before;
1794 script->fail_on_error = true;
1795 script->set_target("");
1797 } else if (strcmp(item->name, "runafterjob") == 0) {
1798 script->when = SCRIPT_After;
1799 script->on_success = true;
1800 script->on_failure = false;
1801 script->set_target("");
1803 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1804 script->old_proto = true;
1805 script->when = SCRIPT_After;
1806 script->set_target("%c");
1807 script->on_success = true;
1808 script->on_failure = false;
1810 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1811 script->old_proto = true;
1812 script->when = SCRIPT_Before;
1813 script->set_target("%c");
1814 script->fail_on_error = true;
1816 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1817 script->when = SCRIPT_After;
1818 script->on_failure = true;
1819 script->on_success = false;
1820 script->set_target("");
1823 if (*runscripts == NULL) {
1824 *runscripts = New(alist(10, not_owned_by_alist));
1827 (*runscripts)->append(script);
1834 /* Store a bool in a bit field without modifing res_all.hdr
1835 * We can also add an option to store_bool to skip res_all.hdr
1837 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1839 lex_get_token(lc, T_NAME);
1840 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1841 *(bool *)(item->value) = true;
1842 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1843 *(bool *)(item->value) = false;
1845 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1851 * new RunScript items
1852 * name handler value code flags default_value
1854 static RES_ITEM runscript_items[] = {
1855 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1856 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1857 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1858 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1859 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1860 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1861 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1862 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1863 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1864 {NULL, NULL, {0}, 0, 0, 0}
1868 * Store RunScript info
1870 * Note, when this routine is called, we are inside a Job
1871 * resource. We treat the RunScript like a sort of
1872 * mini-resource within the Job resource.
1874 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1877 alist **runscripts = (alist **)(item->value) ;
1879 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1881 res_runscript.reset_default(); /* setting on_success, on_failure, fail_on_error */
1883 token = lex_get_token(lc, T_SKIP_EOL);
1885 if (token != T_BOB) {
1886 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1889 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1890 if (token == T_EOB) {
1893 if (token != T_IDENTIFIER) {
1894 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1896 for (i=0; runscript_items[i].name; i++) {
1897 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1898 token = lex_get_token(lc, T_SKIP_EOL);
1899 if (token != T_EQUALS) {
1900 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1903 /* Call item handler */
1904 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1911 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1916 if (res_runscript.command == NULL) {
1917 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1918 "command", "runscript");
1921 /* run on client by default */
1922 if (res_runscript.target == NULL) {
1923 res_runscript.set_target("%c");
1926 RUNSCRIPT *script = new_runscript();
1927 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1928 script->set_job_code_callback(job_code_callback_filesetname);
1930 if (*runscripts == NULL) {
1931 *runscripts = New(alist(10, not_owned_by_alist));
1934 (*runscripts)->append(script);
1939 set_bit(index, res_all.hdr.item_present);
1942 /* callback function for edit_job_codes */
1943 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1945 if (param[0] == 'f') {
1946 return jcr->fileset->name();