2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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 {"maxfullage", store_time, ITEM(res_job.MaxFullAge), 0, 0, 0},
297 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
298 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
299 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
300 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
301 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
302 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
303 {"optimizejobscheduling",store_bool, ITEM(res_job.OptimizeJobScheduling), 0, ITEM_DEFAULT, false},
304 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
305 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
306 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
307 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
308 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
309 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
310 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
311 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
312 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
313 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
314 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
315 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
316 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
317 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
318 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
319 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
320 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
321 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
322 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
323 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
324 {NULL, NULL, {0}, 0, 0, 0}
329 * name handler value code flags default_value
331 static RES_ITEM fs_items[] = {
332 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
333 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
334 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
335 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
336 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
337 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
338 {NULL, NULL, {0}, 0, 0, 0}
341 /* Schedule -- see run_conf.c */
344 * name handler value code flags default_value
346 static RES_ITEM sch_items[] = {
347 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
348 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
349 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
350 {NULL, NULL, {0}, 0, 0, 0}
355 * name handler value code flags default_value
357 static RES_ITEM pool_items[] = {
358 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
359 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
360 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
361 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
362 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
363 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
364 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
365 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
366 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
367 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
368 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
369 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
370 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
371 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
372 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
373 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
374 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
375 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
376 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
377 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
378 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
379 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
380 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
381 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
382 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
383 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
384 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
385 {"catalog", store_res, ITEM(res_pool.Catalog), R_CATALOG, 0, 0},
386 {NULL, NULL, {0}, 0, 0, 0}
391 * name handler value code flags default_value
393 static RES_ITEM counter_items[] = {
394 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
395 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
396 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
397 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
398 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
399 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
400 {NULL, NULL, {0}, 0, 0, 0}
404 /* Message resource */
405 extern RES_ITEM msgs_items[];
408 * This is the master resource definition.
409 * It must have one item for each of the resources.
411 * NOTE!!! keep it in the same order as the R_codes
412 * or eliminate all resources[rindex].name
414 * name items rcode res_head
416 RES_TABLE resources[] = {
417 {"director", dir_items, R_DIRECTOR},
418 {"client", cli_items, R_CLIENT},
419 {"job", job_items, R_JOB},
420 {"storage", store_items, R_STORAGE},
421 {"catalog", cat_items, R_CATALOG},
422 {"schedule", sch_items, R_SCHEDULE},
423 {"fileset", fs_items, R_FILESET},
424 {"pool", pool_items, R_POOL},
425 {"messages", msgs_items, R_MSGS},
426 {"counter", counter_items, R_COUNTER},
427 {"console", con_items, R_CONSOLE},
428 {"jobdefs", job_items, R_JOBDEFS},
429 {"device", NULL, R_DEVICE}, /* info obtained from SD */
434 /* Keywords (RHS) permitted in Job Level records
436 * level_name level job_type
438 struct s_jl joblevels[] = {
439 {"Full", L_FULL, JT_BACKUP},
440 {"Base", L_BASE, JT_BACKUP},
441 {"Incremental", L_INCREMENTAL, JT_BACKUP},
442 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
443 {"Since", L_SINCE, JT_BACKUP},
444 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
445 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
446 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
447 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
448 {"Data", L_VERIFY_DATA, JT_VERIFY},
449 {" ", L_NONE, JT_ADMIN},
450 {" ", L_NONE, JT_RESTORE},
454 /* Keywords (RHS) permitted in Job type records
458 struct s_jt jobtypes[] = {
459 {"backup", JT_BACKUP},
461 {"verify", JT_VERIFY},
462 {"restore", JT_RESTORE},
463 {"migrate", JT_MIGRATE},
468 /* Keywords (RHS) permitted in Selection type records
472 struct s_jt migtypes[] = {
473 {"smallestvolume", MT_SMALLEST_VOL},
474 {"oldestvolume", MT_OLDEST_VOL},
475 {"pooloccupancy", MT_POOL_OCCUPANCY},
476 {"pooltime", MT_POOL_TIME},
477 {"client", MT_CLIENT},
478 {"volume", MT_VOLUME},
480 {"sqlquery", MT_SQLQUERY},
486 /* Options permitted in Restore replace= */
487 struct s_kw ReplaceOptions[] = {
488 {"always", REPLACE_ALWAYS},
489 {"ifnewer", REPLACE_IFNEWER},
490 {"ifolder", REPLACE_IFOLDER},
491 {"never", REPLACE_NEVER},
495 const char *level_to_str(int level)
498 static char level_no[30];
499 const char *str = level_no;
501 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
502 for (i=0; joblevels[i].level_name; i++) {
503 if (level == joblevels[i].level) {
504 str = joblevels[i].level_name;
511 /* Dump contents of resource */
512 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
514 URES *res = (URES *)reshdr;
516 char ed1[100], ed2[100], ed3[100];
520 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
523 if (type < 0) { /* no recursion */
529 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
530 reshdr->name, res->res_dir.MaxConcurrentJobs,
531 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
532 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
533 if (res->res_dir.query_file) {
534 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
536 if (res->res_dir.messages) {
537 sendit(sock, _(" --> "));
538 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
542 sendit(sock, _("Console: name=%s SSL=%d\n"),
543 res->res_con.hdr.name, res->res_con.tls_enable);
546 if (res->res_counter.WrapCounter) {
547 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
548 res->res_counter.hdr.name, res->res_counter.MinValue,
549 res->res_counter.MaxValue, res->res_counter.CurrentValue,
550 res->res_counter.WrapCounter->hdr.name);
552 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
553 res->res_counter.hdr.name, res->res_counter.MinValue,
554 res->res_counter.MaxValue);
556 if (res->res_counter.Catalog) {
557 sendit(sock, _(" --> "));
558 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
563 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
564 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
565 res->res_client.MaxConcurrentJobs);
566 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
567 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
568 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
569 res->res_client.AutoPrune);
570 if (res->res_client.catalog) {
571 sendit(sock, _(" --> "));
572 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
579 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
580 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
581 " poolid=%s volname=%s MediaType=%s\n"),
582 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
583 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
584 dev->offline, dev->autochanger,
585 edit_uint64(dev->PoolId, ed1),
586 dev->VolumeName, dev->MediaType);
590 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
591 " DeviceName=%s MediaType=%s StorageId=%s\n"),
592 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
593 res->res_store.MaxConcurrentJobs,
594 res->res_store.dev_name(),
595 res->res_store.media_type,
596 edit_int64(res->res_store.StorageId, ed1));
600 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
601 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
602 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
603 res->res_cat.db_port, res->res_cat.db_name,
604 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
605 res->res_cat.mult_db_connections);
610 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
611 type == R_JOB ? _("Job") : _("JobDefs"),
612 res->res_job.hdr.name, res->res_job.JobType,
613 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
614 res->res_job.enabled);
615 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
616 res->res_job.MaxConcurrentJobs,
617 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
618 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
619 res->res_job.spool_data, res->res_job.write_part_after_job);
620 if (res->res_job.spool_size) {
621 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
623 if (res->res_job.JobType == JT_BACKUP) {
624 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
626 if (res->res_job.JobType == JT_MIGRATE) {
627 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
629 if (res->res_job.client) {
630 sendit(sock, _(" --> "));
631 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
633 if (res->res_job.fileset) {
634 sendit(sock, _(" --> "));
635 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
637 if (res->res_job.schedule) {
638 sendit(sock, _(" --> "));
639 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
641 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
642 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
644 if (res->res_job.RegexWhere) {
645 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
647 if (res->res_job.RestoreBootstrap) {
648 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
650 if (res->res_job.WriteBootstrap) {
651 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
653 if (res->res_job.storage) {
655 foreach_alist(store, res->res_job.storage) {
656 sendit(sock, _(" --> "));
657 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
660 if (res->res_job.RunScripts) {
662 foreach_alist(script, res->res_job.RunScripts) {
663 sendit(sock, _(" --> RunScript\n"));
664 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
665 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
666 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
667 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
668 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
669 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
672 if (res->res_job.pool) {
673 sendit(sock, _(" --> "));
674 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
676 if (res->res_job.full_pool) {
677 sendit(sock, _(" --> "));
678 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
680 if (res->res_job.inc_pool) {
681 sendit(sock, _(" --> "));
682 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
684 if (res->res_job.diff_pool) {
685 sendit(sock, _(" --> "));
686 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
688 if (res->res_job.verify_job) {
689 sendit(sock, _(" --> "));
690 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
692 if (res->res_job.run_cmds) {
694 foreach_alist(runcmd, res->res_job.run_cmds) {
695 sendit(sock, _(" --> Run=%s\n"), runcmd);
698 if (res->res_job.selection_pattern) {
699 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
701 if (res->res_job.messages) {
702 sendit(sock, _(" --> "));
703 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
710 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
711 for (i=0; i<res->res_fs.num_includes; i++) {
712 INCEXE *incexe = res->res_fs.include_items[i];
713 for (j=0; j<incexe->num_opts; j++) {
714 FOPTS *fo = incexe->opts_list[j];
715 sendit(sock, " O %s\n", fo->opts);
717 bool enhanced_wild = false;
718 for (k=0; fo->opts[k]!='\0'; k++) {
719 if (fo->opts[k]=='W') {
720 enhanced_wild = true;
725 for (k=0; k<fo->regex.size(); k++) {
726 sendit(sock, " R %s\n", fo->regex.get(k));
728 for (k=0; k<fo->regexdir.size(); k++) {
729 sendit(sock, " RD %s\n", fo->regexdir.get(k));
731 for (k=0; k<fo->regexfile.size(); k++) {
732 sendit(sock, " RF %s\n", fo->regexfile.get(k));
734 for (k=0; k<fo->wild.size(); k++) {
735 sendit(sock, " W %s\n", fo->wild.get(k));
737 for (k=0; k<fo->wilddir.size(); k++) {
738 sendit(sock, " WD %s\n", fo->wilddir.get(k));
740 for (k=0; k<fo->wildfile.size(); k++) {
741 sendit(sock, " WF %s\n", fo->wildfile.get(k));
743 for (k=0; k<fo->wildbase.size(); k++) {
744 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
746 for (k=0; k<fo->base.size(); k++) {
747 sendit(sock, " B %s\n", fo->base.get(k));
749 for (k=0; k<fo->fstype.size(); k++) {
750 sendit(sock, " X %s\n", fo->fstype.get(k));
752 for (k=0; k<fo->drivetype.size(); k++) {
753 sendit(sock, " XD %s\n", fo->drivetype.get(k));
756 sendit(sock, " G %s\n", fo->plugin);
759 sendit(sock, " D %s\n", fo->reader);
762 sendit(sock, " T %s\n", fo->writer);
764 sendit(sock, " N\n");
766 for (j=0; j<incexe->name_list.size(); j++) {
767 sendit(sock, " I %s\n", incexe->name_list.get(j));
769 if (incexe->name_list.size()) {
770 sendit(sock, " N\n");
772 for (j=0; j<incexe->plugin_list.size(); j++) {
773 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
775 if (incexe->plugin_list.size()) {
776 sendit(sock, " N\n");
781 for (i=0; i<res->res_fs.num_excludes; i++) {
782 INCEXE *incexe = res->res_fs.exclude_items[i];
783 for (j=0; j<incexe->name_list.size(); j++) {
784 sendit(sock, " E %s\n", incexe->name_list.get(j));
786 if (incexe->name_list.size()) {
787 sendit(sock, " N\n");
794 if (res->res_sch.run) {
796 RUN *run = res->res_sch.run;
797 char buf[1000], num[30];
798 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
803 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
804 bstrncpy(buf, _(" hour="), sizeof(buf));
805 for (i=0; i<24; i++) {
806 if (bit_is_set(i, run->hour)) {
807 bsnprintf(num, sizeof(num), "%d ", i);
808 bstrncat(buf, num, sizeof(buf));
811 bstrncat(buf, "\n", sizeof(buf));
813 bstrncpy(buf, _(" mday="), sizeof(buf));
814 for (i=0; i<31; i++) {
815 if (bit_is_set(i, run->mday)) {
816 bsnprintf(num, sizeof(num), "%d ", i);
817 bstrncat(buf, num, sizeof(buf));
820 bstrncat(buf, "\n", sizeof(buf));
822 bstrncpy(buf, _(" month="), sizeof(buf));
823 for (i=0; i<12; i++) {
824 if (bit_is_set(i, run->month)) {
825 bsnprintf(num, sizeof(num), "%d ", i);
826 bstrncat(buf, num, sizeof(buf));
829 bstrncat(buf, "\n", sizeof(buf));
831 bstrncpy(buf, _(" wday="), sizeof(buf));
832 for (i=0; i<7; i++) {
833 if (bit_is_set(i, run->wday)) {
834 bsnprintf(num, sizeof(num), "%d ", i);
835 bstrncat(buf, num, sizeof(buf));
838 bstrncat(buf, "\n", sizeof(buf));
840 bstrncpy(buf, _(" wom="), sizeof(buf));
841 for (i=0; i<5; i++) {
842 if (bit_is_set(i, run->wom)) {
843 bsnprintf(num, sizeof(num), "%d ", i);
844 bstrncat(buf, num, sizeof(buf));
847 bstrncat(buf, "\n", sizeof(buf));
849 bstrncpy(buf, _(" woy="), sizeof(buf));
850 for (i=0; i<54; i++) {
851 if (bit_is_set(i, run->woy)) {
852 bsnprintf(num, sizeof(num), "%d ", i);
853 bstrncat(buf, num, sizeof(buf));
856 bstrncat(buf, "\n", sizeof(buf));
858 sendit(sock, _(" mins=%d\n"), run->minute);
860 sendit(sock, _(" --> "));
861 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
864 sendit(sock, _(" --> "));
865 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
868 sendit(sock, _(" --> "));
869 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
871 /* If another Run record is chained in, go print it */
877 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
882 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
883 res->res_pool.pool_type);
884 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
885 res->res_pool.use_catalog, res->res_pool.use_volume_once,
886 res->res_pool.catalog_files);
887 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
888 res->res_pool.max_volumes, res->res_pool.AutoPrune,
889 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
890 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
891 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
892 res->res_pool.Recycle,
893 NPRT(res->res_pool.label_format));
894 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
895 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
896 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
897 res->res_pool.recycle_oldest_volume,
898 res->res_pool.purge_oldest_volume);
899 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
900 res->res_pool.MaxVolJobs,
901 res->res_pool.MaxVolFiles,
902 edit_uint64(res->res_pool.MaxVolFiles, ed1));
903 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
904 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
905 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
906 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
907 if (res->res_pool.NextPool) {
908 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
910 if (res->res_pool.RecyclePool) {
911 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
913 if (res->res_pool.Catalog) {
914 sendit(sock, _(" Catalog=%s\n"), res->res_pool.Catalog->name());
916 if (res->res_pool.storage) {
918 foreach_alist(store, res->res_pool.storage) {
919 sendit(sock, _(" --> "));
920 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
923 if (res->res_pool.CopyPool) {
925 foreach_alist(copy, res->res_pool.CopyPool) {
926 sendit(sock, _(" --> "));
927 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
934 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
935 if (res->res_msgs.mail_cmd)
936 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
937 if (res->res_msgs.operator_cmd)
938 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
942 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
945 if (recurse && res->res_dir.hdr.next) {
946 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
951 * Free all the members of an INCEXE structure
953 static void free_incexe(INCEXE *incexe)
955 incexe->name_list.destroy();
956 incexe->plugin_list.destroy();
957 for (int i=0; i<incexe->num_opts; i++) {
958 FOPTS *fopt = incexe->opts_list[i];
959 fopt->regex.destroy();
960 fopt->regexdir.destroy();
961 fopt->regexfile.destroy();
962 fopt->wild.destroy();
963 fopt->wilddir.destroy();
964 fopt->wildfile.destroy();
965 fopt->wildbase.destroy();
966 fopt->base.destroy();
967 fopt->fstype.destroy();
968 fopt->drivetype.destroy();
980 if (incexe->opts_list) {
981 free(incexe->opts_list);
987 * Free memory of resource -- called when daemon terminates.
988 * NB, we don't need to worry about freeing any references
989 * to other resources as they will be freed when that
990 * resource chain is traversed. Mainly we worry about freeing
991 * allocated strings (names).
993 void free_resource(RES *sres, int type)
996 RES *nres; /* next resource if linked */
997 URES *res = (URES *)sres;
1002 /* common stuff -- free the resource name and description */
1003 nres = (RES *)res->res_dir.hdr.next;
1004 if (res->res_dir.hdr.name) {
1005 free(res->res_dir.hdr.name);
1007 if (res->res_dir.hdr.desc) {
1008 free(res->res_dir.hdr.desc);
1013 if (res->res_dir.working_directory) {
1014 free(res->res_dir.working_directory);
1016 if (res->res_dir.scripts_directory) {
1017 free((char *)res->res_dir.scripts_directory);
1019 if (res->res_dir.plugin_directory) {
1020 free((char *)res->res_dir.plugin_directory);
1022 if (res->res_dir.pid_directory) {
1023 free(res->res_dir.pid_directory);
1025 if (res->res_dir.subsys_directory) {
1026 free(res->res_dir.subsys_directory);
1028 if (res->res_dir.password) {
1029 free(res->res_dir.password);
1031 if (res->res_dir.query_file) {
1032 free(res->res_dir.query_file);
1034 if (res->res_dir.DIRaddrs) {
1035 free_addresses(res->res_dir.DIRaddrs);
1037 if (res->res_dir.tls_ctx) {
1038 free_tls_context(res->res_dir.tls_ctx);
1040 if (res->res_dir.tls_ca_certfile) {
1041 free(res->res_dir.tls_ca_certfile);
1043 if (res->res_dir.tls_ca_certdir) {
1044 free(res->res_dir.tls_ca_certdir);
1046 if (res->res_dir.tls_certfile) {
1047 free(res->res_dir.tls_certfile);
1049 if (res->res_dir.tls_keyfile) {
1050 free(res->res_dir.tls_keyfile);
1052 if (res->res_dir.tls_dhfile) {
1053 free(res->res_dir.tls_dhfile);
1055 if (res->res_dir.tls_allowed_cns) {
1056 delete res->res_dir.tls_allowed_cns;
1063 if (res->res_con.password) {
1064 free(res->res_con.password);
1066 if (res->res_con.tls_ctx) {
1067 free_tls_context(res->res_con.tls_ctx);
1069 if (res->res_con.tls_ca_certfile) {
1070 free(res->res_con.tls_ca_certfile);
1072 if (res->res_con.tls_ca_certdir) {
1073 free(res->res_con.tls_ca_certdir);
1075 if (res->res_con.tls_certfile) {
1076 free(res->res_con.tls_certfile);
1078 if (res->res_con.tls_keyfile) {
1079 free(res->res_con.tls_keyfile);
1081 if (res->res_con.tls_dhfile) {
1082 free(res->res_con.tls_dhfile);
1084 if (res->res_con.tls_allowed_cns) {
1085 delete res->res_con.tls_allowed_cns;
1087 for (int i=0; i<Num_ACL; i++) {
1088 if (res->res_con.ACL_lists[i]) {
1089 delete res->res_con.ACL_lists[i];
1090 res->res_con.ACL_lists[i] = NULL;
1095 if (res->res_client.address) {
1096 free(res->res_client.address);
1098 if (res->res_client.password) {
1099 free(res->res_client.password);
1101 if (res->res_client.tls_ctx) {
1102 free_tls_context(res->res_client.tls_ctx);
1104 if (res->res_client.tls_ca_certfile) {
1105 free(res->res_client.tls_ca_certfile);
1107 if (res->res_client.tls_ca_certdir) {
1108 free(res->res_client.tls_ca_certdir);
1110 if (res->res_client.tls_certfile) {
1111 free(res->res_client.tls_certfile);
1113 if (res->res_client.tls_keyfile) {
1114 free(res->res_client.tls_keyfile);
1116 if (res->res_client.tls_allowed_cns) {
1117 delete res->res_client.tls_allowed_cns;
1121 if (res->res_store.address) {
1122 free(res->res_store.address);
1124 if (res->res_store.password) {
1125 free(res->res_store.password);
1127 if (res->res_store.media_type) {
1128 free(res->res_store.media_type);
1130 if (res->res_store.device) {
1131 delete res->res_store.device;
1133 if (res->res_store.tls_ctx) {
1134 free_tls_context(res->res_store.tls_ctx);
1136 if (res->res_store.tls_ca_certfile) {
1137 free(res->res_store.tls_ca_certfile);
1139 if (res->res_store.tls_ca_certdir) {
1140 free(res->res_store.tls_ca_certdir);
1142 if (res->res_store.tls_certfile) {
1143 free(res->res_store.tls_certfile);
1145 if (res->res_store.tls_keyfile) {
1146 free(res->res_store.tls_keyfile);
1150 if (res->res_cat.db_address) {
1151 free(res->res_cat.db_address);
1153 if (res->res_cat.db_socket) {
1154 free(res->res_cat.db_socket);
1156 if (res->res_cat.db_user) {
1157 free(res->res_cat.db_user);
1159 if (res->res_cat.db_name) {
1160 free(res->res_cat.db_name);
1162 if (res->res_cat.db_driver) {
1163 free(res->res_cat.db_driver);
1165 if (res->res_cat.db_password) {
1166 free(res->res_cat.db_password);
1170 if ((num=res->res_fs.num_includes)) {
1171 while (--num >= 0) {
1172 free_incexe(res->res_fs.include_items[num]);
1174 free(res->res_fs.include_items);
1176 res->res_fs.num_includes = 0;
1177 if ((num=res->res_fs.num_excludes)) {
1178 while (--num >= 0) {
1179 free_incexe(res->res_fs.exclude_items[num]);
1181 free(res->res_fs.exclude_items);
1183 res->res_fs.num_excludes = 0;
1186 if (res->res_pool.pool_type) {
1187 free(res->res_pool.pool_type);
1189 if (res->res_pool.label_format) {
1190 free(res->res_pool.label_format);
1192 if (res->res_pool.cleaning_prefix) {
1193 free(res->res_pool.cleaning_prefix);
1195 if (res->res_pool.storage) {
1196 delete res->res_pool.storage;
1200 if (res->res_sch.run) {
1202 nrun = res->res_sch.run;
1212 if (res->res_job.RestoreWhere) {
1213 free(res->res_job.RestoreWhere);
1215 if (res->res_job.RegexWhere) {
1216 free(res->res_job.RegexWhere);
1218 if (res->res_job.strip_prefix) {
1219 free(res->res_job.strip_prefix);
1221 if (res->res_job.add_prefix) {
1222 free(res->res_job.add_prefix);
1224 if (res->res_job.add_suffix) {
1225 free(res->res_job.add_suffix);
1227 if (res->res_job.RestoreBootstrap) {
1228 free(res->res_job.RestoreBootstrap);
1230 if (res->res_job.WriteBootstrap) {
1231 free(res->res_job.WriteBootstrap);
1233 if (res->res_job.selection_pattern) {
1234 free(res->res_job.selection_pattern);
1236 if (res->res_job.run_cmds) {
1237 delete res->res_job.run_cmds;
1239 if (res->res_job.storage) {
1240 delete res->res_job.storage;
1242 if (res->res_job.RunScripts) {
1243 free_runscripts(res->res_job.RunScripts);
1244 delete res->res_job.RunScripts;
1248 if (res->res_msgs.mail_cmd) {
1249 free(res->res_msgs.mail_cmd);
1251 if (res->res_msgs.operator_cmd) {
1252 free(res->res_msgs.operator_cmd);
1254 free_msgs_res((MSGS *)res); /* free message resource */
1258 printf(_("Unknown resource type %d in free_resource.\n"), type);
1260 /* Common stuff again -- free the resource, recurse to next one */
1265 free_resource(nres, type);
1270 * Save the new resource by chaining it into the head list for
1271 * the resource. If this is pass 2, we update any resource
1272 * pointers because they may not have been defined until
1275 void save_resource(int type, RES_ITEM *items, int pass)
1278 int rindex = type - r_first;
1282 /* Check Job requirements after applying JobDefs */
1283 if (type != R_JOB && type != R_JOBDEFS) {
1285 * Ensure that all required items are present
1287 for (i=0; items[i].name; i++) {
1288 if (items[i].flags & ITEM_REQUIRED) {
1289 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1290 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1291 items[i].name, resources[rindex]);
1294 /* If this triggers, take a look at lib/parse_conf.h */
1295 if (i >= MAX_RES_ITEMS) {
1296 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1299 } else if (type == R_JOB) {
1301 * Ensure that the name item is present
1303 if (items[0].flags & ITEM_REQUIRED) {
1304 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1305 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1306 items[0].name, resources[rindex]);
1312 * During pass 2 in each "store" routine, we looked up pointers
1313 * to all the resources referrenced in the current resource, now we
1314 * must copy their addresses from the static record to the allocated
1319 /* Resources not containing a resource */
1327 * Resources containing another resource or alist. First
1328 * look up the resource which contains another resource. It
1329 * was written during pass 1. Then stuff in the pointers to
1330 * the resources it contains, which were inserted this pass.
1331 * Finally, it will all be stored back.
1334 /* Find resource saved in pass 1 */
1335 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1336 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1338 /* Explicitly copy resource pointers from this pass (res_all) */
1339 res->res_pool.NextPool = res_all.res_pool.NextPool;
1340 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1341 res->res_pool.storage = res_all.res_pool.storage;
1342 res->res_pool.Catalog = res_all.res_pool.Catalog;
1345 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1346 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1348 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1351 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1352 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1354 res->res_dir.messages = res_all.res_dir.messages;
1355 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1358 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1359 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1360 res_all.res_dir.hdr.name);
1362 /* we must explicitly copy the device alist pointer */
1363 res->res_store.device = res_all.res_store.device;
1367 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1368 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1369 res_all.res_dir.hdr.name);
1371 res->res_job.messages = res_all.res_job.messages;
1372 res->res_job.schedule = res_all.res_job.schedule;
1373 res->res_job.client = res_all.res_job.client;
1374 res->res_job.fileset = res_all.res_job.fileset;
1375 res->res_job.storage = res_all.res_job.storage;
1376 res->res_job.pool = res_all.res_job.pool;
1377 res->res_job.full_pool = res_all.res_job.full_pool;
1378 res->res_job.inc_pool = res_all.res_job.inc_pool;
1379 res->res_job.diff_pool = res_all.res_job.diff_pool;
1380 res->res_job.verify_job = res_all.res_job.verify_job;
1381 res->res_job.jobdefs = res_all.res_job.jobdefs;
1382 res->res_job.run_cmds = res_all.res_job.run_cmds;
1383 res->res_job.RunScripts = res_all.res_job.RunScripts;
1385 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1386 * is not very useful)
1387 * We have to set_bit(index, res_all.hdr.item_present);
1388 * or something like that
1391 /* we take RegexWhere before all other options */
1392 if (!res->res_job.RegexWhere
1394 (res->res_job.strip_prefix ||
1395 res->res_job.add_suffix ||
1396 res->res_job.add_prefix))
1398 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1399 res->res_job.add_prefix,
1400 res->res_job.add_suffix);
1401 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1402 bregexp_build_where(res->res_job.RegexWhere, len,
1403 res->res_job.strip_prefix,
1404 res->res_job.add_prefix,
1405 res->res_job.add_suffix);
1406 /* TODO: test bregexp */
1409 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1410 free(res->res_job.RestoreWhere);
1411 res->res_job.RestoreWhere = NULL;
1416 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1417 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1419 res->res_counter.Catalog = res_all.res_counter.Catalog;
1420 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1424 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1425 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1427 res->res_client.catalog = res_all.res_client.catalog;
1428 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1432 * Schedule is a bit different in that it contains a RUN record
1433 * chain which isn't a "named" resource. This chain was linked
1434 * in by run_conf.c during pass 2, so here we jam the pointer
1435 * into the Schedule resource.
1437 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1438 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1440 res->res_sch.run = res_all.res_sch.run;
1443 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1447 /* Note, the resource name was already saved during pass 1,
1448 * so here, we can just release it.
1450 if (res_all.res_dir.hdr.name) {
1451 free(res_all.res_dir.hdr.name);
1452 res_all.res_dir.hdr.name = NULL;
1454 if (res_all.res_dir.hdr.desc) {
1455 free(res_all.res_dir.hdr.desc);
1456 res_all.res_dir.hdr.desc = NULL;
1462 * The following code is only executed during pass 1
1466 size = sizeof(DIRRES);
1469 size = sizeof(CONRES);
1472 size =sizeof(CLIENT);
1475 size = sizeof(STORE);
1485 size = sizeof(FILESET);
1488 size = sizeof(SCHED);
1491 size = sizeof(POOL);
1494 size = sizeof(MSGS);
1497 size = sizeof(COUNTER);
1503 printf(_("Unknown resource type %d in save_resource.\n"), type);
1509 res = (URES *)malloc(size);
1510 memcpy(res, &res_all, size);
1511 if (!res_head[rindex]) {
1512 res_head[rindex] = (RES *)res; /* store first entry */
1513 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1514 res->res_dir.hdr.name, rindex);
1517 if (res->res_dir.hdr.name == NULL) {
1518 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1521 /* Add new res to end of chain */
1522 for (last=next=res_head[rindex]; next; next=next->next) {
1524 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1525 Emsg2(M_ERROR_TERM, 0,
1526 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1527 resources[rindex].name, res->res_dir.hdr.name);
1530 last->next = (RES *)res;
1531 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1532 res->res_dir.hdr.name, rindex, pass);
1538 * Store Device. Note, the resource is created upon the
1539 * first reference. The details of the resource are obtained
1540 * later from the SD.
1542 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1546 int rindex = R_DEVICE - r_first;
1547 int size = sizeof(DEVICE);
1551 token = lex_get_token(lc, T_NAME);
1552 if (!res_head[rindex]) {
1553 res = (URES *)malloc(size);
1554 memset(res, 0, size);
1555 res->res_dev.hdr.name = bstrdup(lc->str);
1556 res_head[rindex] = (RES *)res; /* store first entry */
1557 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1558 res->res_dir.hdr.name, rindex);
1561 /* See if it is already defined */
1562 for (next=res_head[rindex]; next->next; next=next->next) {
1563 if (strcmp(next->name, lc->str) == 0) {
1569 res = (URES *)malloc(size);
1570 memset(res, 0, size);
1571 res->res_dev.hdr.name = bstrdup(lc->str);
1572 next->next = (RES *)res;
1573 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1574 res->res_dir.hdr.name, rindex, pass);
1579 set_bit(index, res_all.hdr.item_present);
1581 store_alist_res(lc, item, index, pass);
1586 * Store JobType (backup, verify, restore)
1589 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1593 token = lex_get_token(lc, T_NAME);
1594 /* Store the type both pass 1 and pass 2 */
1595 for (i=0; migtypes[i].type_name; i++) {
1596 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1597 *(int *)(item->value) = migtypes[i].job_type;
1603 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1606 set_bit(index, res_all.hdr.item_present);
1612 * Store JobType (backup, verify, restore)
1615 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1619 token = lex_get_token(lc, T_NAME);
1620 /* Store the type both pass 1 and pass 2 */
1621 for (i=0; jobtypes[i].type_name; i++) {
1622 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1623 *(int *)(item->value) = jobtypes[i].job_type;
1629 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1632 set_bit(index, res_all.hdr.item_present);
1636 * Store Job Level (Full, Incremental, ...)
1639 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1643 token = lex_get_token(lc, T_NAME);
1644 /* Store the level pass 2 so that type is defined */
1645 for (i=0; joblevels[i].level_name; i++) {
1646 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1647 *(int *)(item->value) = joblevels[i].level;
1653 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1656 set_bit(index, res_all.hdr.item_present);
1660 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1663 token = lex_get_token(lc, T_NAME);
1664 /* Scan Replacement options */
1665 for (i=0; ReplaceOptions[i].name; i++) {
1666 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1667 *(int *)(item->value) = ReplaceOptions[i].token;
1673 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1676 set_bit(index, res_all.hdr.item_present);
1680 * Store ACL (access control list)
1683 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1688 token = lex_get_token(lc, T_STRING);
1690 if (((alist **)item->value)[item->code] == NULL) {
1691 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1692 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1694 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1695 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1697 token = lex_get_token(lc, T_ALL);
1698 if (token == T_COMMA) {
1699 continue; /* get another ACL */
1703 set_bit(index, res_all.hdr.item_present);
1706 /* We build RunScripts items here */
1707 static RUNSCRIPT res_runscript;
1709 /* Store a runscript->when in a bit field */
1710 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1712 lex_get_token(lc, T_NAME);
1714 if (strcasecmp(lc->str, "before") == 0) {
1715 *(int *)(item->value) = SCRIPT_Before ;
1716 } else if (strcasecmp(lc->str, "after") == 0) {
1717 *(int *)(item->value) = SCRIPT_After;
1718 } else if (strcasecmp(lc->str, "always") == 0) {
1719 *(int *)(item->value) = SCRIPT_Any;
1721 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1726 /* Store a runscript->target
1729 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1731 lex_get_token(lc, T_STRING);
1734 if (strcmp(lc->str, "%c") == 0) {
1735 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1736 } else if (strcasecmp(lc->str, "yes") == 0) {
1737 ((RUNSCRIPT*) item->value)->set_target("%c");
1738 } else if (strcasecmp(lc->str, "no") == 0) {
1739 ((RUNSCRIPT*) item->value)->set_target("");
1741 RES *res = GetResWithName(R_CLIENT, lc->str);
1743 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1744 lc->str, lc->line_no, lc->line);
1747 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1754 * Store a runscript->command as a string
1756 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1758 lex_get_token(lc, T_STRING);
1761 ((RUNSCRIPT*)item->value)->set_command(lc->str, item->code);
1766 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1768 lex_get_token(lc, T_STRING);
1769 alist **runscripts = (alist **)(item->value) ;
1772 RUNSCRIPT *script = new_runscript();
1773 script->set_job_code_callback(job_code_callback_filesetname);
1775 script->set_command(lc->str);
1777 /* TODO: remove all script->old_proto with bacula 1.42 */
1779 if (strcmp(item->name, "runbeforejob") == 0) {
1780 script->when = SCRIPT_Before;
1781 script->fail_on_error = true;
1782 script->set_target("");
1784 } else if (strcmp(item->name, "runafterjob") == 0) {
1785 script->when = SCRIPT_After;
1786 script->on_success = true;
1787 script->on_failure = false;
1788 script->set_target("");
1790 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1791 script->old_proto = true;
1792 script->when = SCRIPT_After;
1793 script->set_target("%c");
1794 script->on_success = true;
1795 script->on_failure = false;
1797 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1798 script->old_proto = true;
1799 script->when = SCRIPT_Before;
1800 script->set_target("%c");
1801 script->fail_on_error = true;
1803 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1804 script->when = SCRIPT_After;
1805 script->on_failure = true;
1806 script->on_success = false;
1807 script->set_target("");
1810 if (*runscripts == NULL) {
1811 *runscripts = New(alist(10, not_owned_by_alist));
1814 (*runscripts)->append(script);
1821 /* Store a bool in a bit field without modifing res_all.hdr
1822 * We can also add an option to store_bool to skip res_all.hdr
1824 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1826 lex_get_token(lc, T_NAME);
1827 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1828 *(bool *)(item->value) = true;
1829 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1830 *(bool *)(item->value) = false;
1832 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1838 * new RunScript items
1839 * name handler value code flags default_value
1841 static RES_ITEM runscript_items[] = {
1842 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1843 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1844 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1845 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1846 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1847 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1848 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1849 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1850 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1851 {NULL, NULL, {0}, 0, 0, 0}
1855 * Store RunScript info
1857 * Note, when this routine is called, we are inside a Job
1858 * resource. We treat the RunScript like a sort of
1859 * mini-resource within the Job resource.
1861 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1864 alist **runscripts = (alist **)(item->value) ;
1866 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1868 res_runscript.reset_default(); /* setting on_success, on_failure, fail_on_error */
1870 token = lex_get_token(lc, T_SKIP_EOL);
1872 if (token != T_BOB) {
1873 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1876 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1877 if (token == T_EOB) {
1880 if (token != T_IDENTIFIER) {
1881 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1883 for (i=0; runscript_items[i].name; i++) {
1884 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1885 token = lex_get_token(lc, T_SKIP_EOL);
1886 if (token != T_EQUALS) {
1887 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1890 /* Call item handler */
1891 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1898 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1903 if (res_runscript.command == NULL) {
1904 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1905 "command", "runscript");
1908 /* run on client by default */
1909 if (res_runscript.target == NULL) {
1910 res_runscript.set_target("%c");
1913 RUNSCRIPT *script = new_runscript();
1914 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1915 script->set_job_code_callback(job_code_callback_filesetname);
1917 if (*runscripts == NULL) {
1918 *runscripts = New(alist(10, not_owned_by_alist));
1921 (*runscripts)->append(script);
1926 set_bit(index, res_all.hdr.item_present);
1929 /* callback function for edit_job_codes */
1930 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1932 if (param[0] == 'f') {
1933 return jcr->fileset->name();