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 {NULL, NULL, {0}, 0, 0, 0}
334 * name handler value code flags default_value
336 static RES_ITEM fs_items[] = {
337 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
338 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
339 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
340 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
341 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
342 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
343 {NULL, NULL, {0}, 0, 0, 0}
346 /* Schedule -- see run_conf.c */
349 * name handler value code flags default_value
351 static RES_ITEM sch_items[] = {
352 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
353 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
354 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
355 {NULL, NULL, {0}, 0, 0, 0}
360 * name handler value code flags default_value
362 static RES_ITEM pool_items[] = {
363 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
364 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
365 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
366 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
367 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
368 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
369 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
370 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
371 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
372 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
373 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
374 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
375 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
376 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
377 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
378 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
379 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
380 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
381 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
382 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
383 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
384 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
385 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
386 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
387 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
388 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
389 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
390 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
391 {NULL, NULL, {0}, 0, 0, 0}
396 * name handler value code flags default_value
398 static RES_ITEM counter_items[] = {
399 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
400 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
401 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
402 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
403 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
404 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
405 {NULL, NULL, {0}, 0, 0, 0}
409 /* Message resource */
410 extern RES_ITEM msgs_items[];
413 * This is the master resource definition.
414 * It must have one item for each of the resources.
416 * NOTE!!! keep it in the same order as the R_codes
417 * or eliminate all resources[rindex].name
419 * name items rcode res_head
421 RES_TABLE resources[] = {
422 {"director", dir_items, R_DIRECTOR},
423 {"client", cli_items, R_CLIENT},
424 {"job", job_items, R_JOB},
425 {"storage", store_items, R_STORAGE},
426 {"catalog", cat_items, R_CATALOG},
427 {"schedule", sch_items, R_SCHEDULE},
428 {"fileset", fs_items, R_FILESET},
429 {"pool", pool_items, R_POOL},
430 {"messages", msgs_items, R_MSGS},
431 {"counter", counter_items, R_COUNTER},
432 {"console", con_items, R_CONSOLE},
433 {"jobdefs", job_items, R_JOBDEFS},
434 {"device", NULL, R_DEVICE}, /* info obtained from SD */
439 /* Keywords (RHS) permitted in Job Level records
441 * level_name level job_type
443 struct s_jl joblevels[] = {
444 {"Full", L_FULL, JT_BACKUP},
445 {"Base", L_BASE, JT_BACKUP},
446 {"Incremental", L_INCREMENTAL, JT_BACKUP},
447 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
448 {"Since", L_SINCE, JT_BACKUP},
449 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
450 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
451 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
452 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
453 {"Data", L_VERIFY_DATA, JT_VERIFY},
454 {" ", L_NONE, JT_ADMIN},
455 {" ", L_NONE, JT_RESTORE},
459 /* Keywords (RHS) permitted in Job type records
463 struct s_jt jobtypes[] = {
464 {"backup", JT_BACKUP},
466 {"verify", JT_VERIFY},
467 {"restore", JT_RESTORE},
468 {"migrate", JT_MIGRATE},
474 /* Keywords (RHS) permitted in Selection type records
478 struct s_jt migtypes[] = {
479 {"smallestvolume", MT_SMALLEST_VOL},
480 {"oldestvolume", MT_OLDEST_VOL},
481 {"pooloccupancy", MT_POOL_OCCUPANCY},
482 {"pooltime", MT_POOL_TIME},
483 {"client", MT_CLIENT},
484 {"volume", MT_VOLUME},
486 {"sqlquery", MT_SQLQUERY},
492 /* Options permitted in Restore replace= */
493 struct s_kw ReplaceOptions[] = {
494 {"always", REPLACE_ALWAYS},
495 {"ifnewer", REPLACE_IFNEWER},
496 {"ifolder", REPLACE_IFOLDER},
497 {"never", REPLACE_NEVER},
501 const char *level_to_str(int level)
504 static char level_no[30];
505 const char *str = level_no;
507 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
508 for (i=0; joblevels[i].level_name; i++) {
509 if (level == joblevels[i].level) {
510 str = joblevels[i].level_name;
517 /* Dump contents of resource */
518 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
520 URES *res = (URES *)reshdr;
522 char ed1[100], ed2[100], ed3[100];
526 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
529 if (type < 0) { /* no recursion */
535 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
536 reshdr->name, res->res_dir.MaxConcurrentJobs,
537 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
538 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
539 if (res->res_dir.query_file) {
540 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
542 if (res->res_dir.messages) {
543 sendit(sock, _(" --> "));
544 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
548 sendit(sock, _("Console: name=%s SSL=%d\n"),
549 res->res_con.hdr.name, res->res_con.tls_enable);
552 if (res->res_counter.WrapCounter) {
553 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
554 res->res_counter.hdr.name, res->res_counter.MinValue,
555 res->res_counter.MaxValue, res->res_counter.CurrentValue,
556 res->res_counter.WrapCounter->hdr.name);
558 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
559 res->res_counter.hdr.name, res->res_counter.MinValue,
560 res->res_counter.MaxValue);
562 if (res->res_counter.Catalog) {
563 sendit(sock, _(" --> "));
564 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
569 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
570 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
571 res->res_client.MaxConcurrentJobs);
572 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
573 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
574 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
575 res->res_client.AutoPrune);
576 if (res->res_client.catalog) {
577 sendit(sock, _(" --> "));
578 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
585 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
586 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
587 " poolid=%s volname=%s MediaType=%s\n"),
588 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
589 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
590 dev->offline, dev->autochanger,
591 edit_uint64(dev->PoolId, ed1),
592 dev->VolumeName, dev->MediaType);
596 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
597 " DeviceName=%s MediaType=%s StorageId=%s\n"),
598 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
599 res->res_store.MaxConcurrentJobs,
600 res->res_store.dev_name(),
601 res->res_store.media_type,
602 edit_int64(res->res_store.StorageId, ed1));
606 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
607 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
608 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
609 res->res_cat.db_port, res->res_cat.db_name,
610 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
611 res->res_cat.mult_db_connections);
616 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
617 type == R_JOB ? _("Job") : _("JobDefs"),
618 res->res_job.hdr.name, res->res_job.JobType,
619 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
620 res->res_job.enabled);
621 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
622 res->res_job.MaxConcurrentJobs,
623 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
624 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
625 res->res_job.spool_data, res->res_job.write_part_after_job);
626 if (res->res_job.spool_size) {
627 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
629 if (res->res_job.JobType == JT_BACKUP) {
630 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
632 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
633 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
635 if (res->res_job.client) {
636 sendit(sock, _(" --> "));
637 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
639 if (res->res_job.fileset) {
640 sendit(sock, _(" --> "));
641 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
643 if (res->res_job.schedule) {
644 sendit(sock, _(" --> "));
645 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
647 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
648 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
650 if (res->res_job.RegexWhere) {
651 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
653 if (res->res_job.RestoreBootstrap) {
654 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
656 if (res->res_job.WriteBootstrap) {
657 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
659 if (res->res_job.storage) {
661 foreach_alist(store, res->res_job.storage) {
662 sendit(sock, _(" --> "));
663 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
666 if (res->res_job.RunScripts) {
668 foreach_alist(script, res->res_job.RunScripts) {
669 sendit(sock, _(" --> RunScript\n"));
670 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
671 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
672 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
673 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
674 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
675 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
678 if (res->res_job.pool) {
679 sendit(sock, _(" --> "));
680 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
682 if (res->res_job.full_pool) {
683 sendit(sock, _(" --> "));
684 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
686 if (res->res_job.inc_pool) {
687 sendit(sock, _(" --> "));
688 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
690 if (res->res_job.diff_pool) {
691 sendit(sock, _(" --> "));
692 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
694 if (res->res_job.verify_job) {
695 sendit(sock, _(" --> "));
696 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
698 if (res->res_job.run_cmds) {
700 foreach_alist(runcmd, res->res_job.run_cmds) {
701 sendit(sock, _(" --> Run=%s\n"), runcmd);
704 if (res->res_job.selection_pattern) {
705 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
707 if (res->res_job.messages) {
708 sendit(sock, _(" --> "));
709 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
716 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
717 for (i=0; i<res->res_fs.num_includes; i++) {
718 INCEXE *incexe = res->res_fs.include_items[i];
719 for (j=0; j<incexe->num_opts; j++) {
720 FOPTS *fo = incexe->opts_list[j];
721 sendit(sock, " O %s\n", fo->opts);
723 bool enhanced_wild = false;
724 for (k=0; fo->opts[k]!='\0'; k++) {
725 if (fo->opts[k]=='W') {
726 enhanced_wild = true;
731 for (k=0; k<fo->regex.size(); k++) {
732 sendit(sock, " R %s\n", fo->regex.get(k));
734 for (k=0; k<fo->regexdir.size(); k++) {
735 sendit(sock, " RD %s\n", fo->regexdir.get(k));
737 for (k=0; k<fo->regexfile.size(); k++) {
738 sendit(sock, " RF %s\n", fo->regexfile.get(k));
740 for (k=0; k<fo->wild.size(); k++) {
741 sendit(sock, " W %s\n", fo->wild.get(k));
743 for (k=0; k<fo->wilddir.size(); k++) {
744 sendit(sock, " WD %s\n", fo->wilddir.get(k));
746 for (k=0; k<fo->wildfile.size(); k++) {
747 sendit(sock, " WF %s\n", fo->wildfile.get(k));
749 for (k=0; k<fo->wildbase.size(); k++) {
750 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
752 for (k=0; k<fo->base.size(); k++) {
753 sendit(sock, " B %s\n", fo->base.get(k));
755 for (k=0; k<fo->fstype.size(); k++) {
756 sendit(sock, " X %s\n", fo->fstype.get(k));
758 for (k=0; k<fo->drivetype.size(); k++) {
759 sendit(sock, " XD %s\n", fo->drivetype.get(k));
762 sendit(sock, " G %s\n", fo->plugin);
765 sendit(sock, " D %s\n", fo->reader);
768 sendit(sock, " T %s\n", fo->writer);
770 sendit(sock, " N\n");
772 for (j=0; j<incexe->name_list.size(); j++) {
773 sendit(sock, " I %s\n", incexe->name_list.get(j));
775 if (incexe->name_list.size()) {
776 sendit(sock, " N\n");
778 for (j=0; j<incexe->plugin_list.size(); j++) {
779 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
781 if (incexe->plugin_list.size()) {
782 sendit(sock, " N\n");
787 for (i=0; i<res->res_fs.num_excludes; i++) {
788 INCEXE *incexe = res->res_fs.exclude_items[i];
789 for (j=0; j<incexe->name_list.size(); j++) {
790 sendit(sock, " E %s\n", incexe->name_list.get(j));
792 if (incexe->name_list.size()) {
793 sendit(sock, " N\n");
800 if (res->res_sch.run) {
802 RUN *run = res->res_sch.run;
803 char buf[1000], num[30];
804 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
809 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
810 bstrncpy(buf, _(" hour="), sizeof(buf));
811 for (i=0; i<24; i++) {
812 if (bit_is_set(i, run->hour)) {
813 bsnprintf(num, sizeof(num), "%d ", i);
814 bstrncat(buf, num, sizeof(buf));
817 bstrncat(buf, "\n", sizeof(buf));
819 bstrncpy(buf, _(" mday="), sizeof(buf));
820 for (i=0; i<31; i++) {
821 if (bit_is_set(i, run->mday)) {
822 bsnprintf(num, sizeof(num), "%d ", i);
823 bstrncat(buf, num, sizeof(buf));
826 bstrncat(buf, "\n", sizeof(buf));
828 bstrncpy(buf, _(" month="), sizeof(buf));
829 for (i=0; i<12; i++) {
830 if (bit_is_set(i, run->month)) {
831 bsnprintf(num, sizeof(num), "%d ", i);
832 bstrncat(buf, num, sizeof(buf));
835 bstrncat(buf, "\n", sizeof(buf));
837 bstrncpy(buf, _(" wday="), sizeof(buf));
838 for (i=0; i<7; i++) {
839 if (bit_is_set(i, run->wday)) {
840 bsnprintf(num, sizeof(num), "%d ", i);
841 bstrncat(buf, num, sizeof(buf));
844 bstrncat(buf, "\n", sizeof(buf));
846 bstrncpy(buf, _(" wom="), sizeof(buf));
847 for (i=0; i<5; i++) {
848 if (bit_is_set(i, run->wom)) {
849 bsnprintf(num, sizeof(num), "%d ", i);
850 bstrncat(buf, num, sizeof(buf));
853 bstrncat(buf, "\n", sizeof(buf));
855 bstrncpy(buf, _(" woy="), sizeof(buf));
856 for (i=0; i<54; i++) {
857 if (bit_is_set(i, run->woy)) {
858 bsnprintf(num, sizeof(num), "%d ", i);
859 bstrncat(buf, num, sizeof(buf));
862 bstrncat(buf, "\n", sizeof(buf));
864 sendit(sock, _(" mins=%d\n"), run->minute);
866 sendit(sock, _(" --> "));
867 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
870 sendit(sock, _(" --> "));
871 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
874 sendit(sock, _(" --> "));
875 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
877 /* If another Run record is chained in, go print it */
883 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
888 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
889 res->res_pool.pool_type);
890 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
891 res->res_pool.use_catalog, res->res_pool.use_volume_once,
892 res->res_pool.catalog_files);
893 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
894 res->res_pool.max_volumes, res->res_pool.AutoPrune,
895 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
896 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
897 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
898 res->res_pool.Recycle,
899 NPRT(res->res_pool.label_format));
900 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
901 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
902 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
903 res->res_pool.recycle_oldest_volume,
904 res->res_pool.purge_oldest_volume);
905 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
906 res->res_pool.MaxVolJobs,
907 res->res_pool.MaxVolFiles,
908 edit_uint64(res->res_pool.MaxVolFiles, ed1));
909 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
910 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
911 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
912 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
913 if (res->res_pool.NextPool) {
914 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
916 if (res->res_pool.RecyclePool) {
917 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
919 if (res->res_pool.catalog) {
920 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
922 if (res->res_pool.storage) {
924 foreach_alist(store, res->res_pool.storage) {
925 sendit(sock, _(" --> "));
926 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
929 if (res->res_pool.CopyPool) {
931 foreach_alist(copy, res->res_pool.CopyPool) {
932 sendit(sock, _(" --> "));
933 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
940 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
941 if (res->res_msgs.mail_cmd)
942 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
943 if (res->res_msgs.operator_cmd)
944 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
948 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
951 if (recurse && res->res_dir.hdr.next) {
952 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
957 * Free all the members of an INCEXE structure
959 static void free_incexe(INCEXE *incexe)
961 incexe->name_list.destroy();
962 incexe->plugin_list.destroy();
963 for (int i=0; i<incexe->num_opts; i++) {
964 FOPTS *fopt = incexe->opts_list[i];
965 fopt->regex.destroy();
966 fopt->regexdir.destroy();
967 fopt->regexfile.destroy();
968 fopt->wild.destroy();
969 fopt->wilddir.destroy();
970 fopt->wildfile.destroy();
971 fopt->wildbase.destroy();
972 fopt->base.destroy();
973 fopt->fstype.destroy();
974 fopt->drivetype.destroy();
986 if (incexe->opts_list) {
987 free(incexe->opts_list);
993 * Free memory of resource -- called when daemon terminates.
994 * NB, we don't need to worry about freeing any references
995 * to other resources as they will be freed when that
996 * resource chain is traversed. Mainly we worry about freeing
997 * allocated strings (names).
999 void free_resource(RES *sres, int type)
1002 RES *nres; /* next resource if linked */
1003 URES *res = (URES *)sres;
1008 /* common stuff -- free the resource name and description */
1009 nres = (RES *)res->res_dir.hdr.next;
1010 if (res->res_dir.hdr.name) {
1011 free(res->res_dir.hdr.name);
1013 if (res->res_dir.hdr.desc) {
1014 free(res->res_dir.hdr.desc);
1019 if (res->res_dir.working_directory) {
1020 free(res->res_dir.working_directory);
1022 if (res->res_dir.scripts_directory) {
1023 free((char *)res->res_dir.scripts_directory);
1025 if (res->res_dir.plugin_directory) {
1026 free((char *)res->res_dir.plugin_directory);
1028 if (res->res_dir.pid_directory) {
1029 free(res->res_dir.pid_directory);
1031 if (res->res_dir.subsys_directory) {
1032 free(res->res_dir.subsys_directory);
1034 if (res->res_dir.password) {
1035 free(res->res_dir.password);
1037 if (res->res_dir.query_file) {
1038 free(res->res_dir.query_file);
1040 if (res->res_dir.DIRaddrs) {
1041 free_addresses(res->res_dir.DIRaddrs);
1043 if (res->res_dir.tls_ctx) {
1044 free_tls_context(res->res_dir.tls_ctx);
1046 if (res->res_dir.tls_ca_certfile) {
1047 free(res->res_dir.tls_ca_certfile);
1049 if (res->res_dir.tls_ca_certdir) {
1050 free(res->res_dir.tls_ca_certdir);
1052 if (res->res_dir.tls_certfile) {
1053 free(res->res_dir.tls_certfile);
1055 if (res->res_dir.tls_keyfile) {
1056 free(res->res_dir.tls_keyfile);
1058 if (res->res_dir.tls_dhfile) {
1059 free(res->res_dir.tls_dhfile);
1061 if (res->res_dir.tls_allowed_cns) {
1062 delete res->res_dir.tls_allowed_cns;
1069 if (res->res_con.password) {
1070 free(res->res_con.password);
1072 if (res->res_con.tls_ctx) {
1073 free_tls_context(res->res_con.tls_ctx);
1075 if (res->res_con.tls_ca_certfile) {
1076 free(res->res_con.tls_ca_certfile);
1078 if (res->res_con.tls_ca_certdir) {
1079 free(res->res_con.tls_ca_certdir);
1081 if (res->res_con.tls_certfile) {
1082 free(res->res_con.tls_certfile);
1084 if (res->res_con.tls_keyfile) {
1085 free(res->res_con.tls_keyfile);
1087 if (res->res_con.tls_dhfile) {
1088 free(res->res_con.tls_dhfile);
1090 if (res->res_con.tls_allowed_cns) {
1091 delete res->res_con.tls_allowed_cns;
1093 for (int i=0; i<Num_ACL; i++) {
1094 if (res->res_con.ACL_lists[i]) {
1095 delete res->res_con.ACL_lists[i];
1096 res->res_con.ACL_lists[i] = NULL;
1101 if (res->res_client.address) {
1102 free(res->res_client.address);
1104 if (res->res_client.password) {
1105 free(res->res_client.password);
1107 if (res->res_client.tls_ctx) {
1108 free_tls_context(res->res_client.tls_ctx);
1110 if (res->res_client.tls_ca_certfile) {
1111 free(res->res_client.tls_ca_certfile);
1113 if (res->res_client.tls_ca_certdir) {
1114 free(res->res_client.tls_ca_certdir);
1116 if (res->res_client.tls_certfile) {
1117 free(res->res_client.tls_certfile);
1119 if (res->res_client.tls_keyfile) {
1120 free(res->res_client.tls_keyfile);
1122 if (res->res_client.tls_allowed_cns) {
1123 delete res->res_client.tls_allowed_cns;
1127 if (res->res_store.address) {
1128 free(res->res_store.address);
1130 if (res->res_store.password) {
1131 free(res->res_store.password);
1133 if (res->res_store.media_type) {
1134 free(res->res_store.media_type);
1136 if (res->res_store.device) {
1137 delete res->res_store.device;
1139 if (res->res_store.tls_ctx) {
1140 free_tls_context(res->res_store.tls_ctx);
1142 if (res->res_store.tls_ca_certfile) {
1143 free(res->res_store.tls_ca_certfile);
1145 if (res->res_store.tls_ca_certdir) {
1146 free(res->res_store.tls_ca_certdir);
1148 if (res->res_store.tls_certfile) {
1149 free(res->res_store.tls_certfile);
1151 if (res->res_store.tls_keyfile) {
1152 free(res->res_store.tls_keyfile);
1156 if (res->res_cat.db_address) {
1157 free(res->res_cat.db_address);
1159 if (res->res_cat.db_socket) {
1160 free(res->res_cat.db_socket);
1162 if (res->res_cat.db_user) {
1163 free(res->res_cat.db_user);
1165 if (res->res_cat.db_name) {
1166 free(res->res_cat.db_name);
1168 if (res->res_cat.db_driver) {
1169 free(res->res_cat.db_driver);
1171 if (res->res_cat.db_password) {
1172 free(res->res_cat.db_password);
1176 if ((num=res->res_fs.num_includes)) {
1177 while (--num >= 0) {
1178 free_incexe(res->res_fs.include_items[num]);
1180 free(res->res_fs.include_items);
1182 res->res_fs.num_includes = 0;
1183 if ((num=res->res_fs.num_excludes)) {
1184 while (--num >= 0) {
1185 free_incexe(res->res_fs.exclude_items[num]);
1187 free(res->res_fs.exclude_items);
1189 res->res_fs.num_excludes = 0;
1192 if (res->res_pool.pool_type) {
1193 free(res->res_pool.pool_type);
1195 if (res->res_pool.label_format) {
1196 free(res->res_pool.label_format);
1198 if (res->res_pool.cleaning_prefix) {
1199 free(res->res_pool.cleaning_prefix);
1201 if (res->res_pool.storage) {
1202 delete res->res_pool.storage;
1206 if (res->res_sch.run) {
1208 nrun = res->res_sch.run;
1218 if (res->res_job.RestoreWhere) {
1219 free(res->res_job.RestoreWhere);
1221 if (res->res_job.RegexWhere) {
1222 free(res->res_job.RegexWhere);
1224 if (res->res_job.strip_prefix) {
1225 free(res->res_job.strip_prefix);
1227 if (res->res_job.add_prefix) {
1228 free(res->res_job.add_prefix);
1230 if (res->res_job.add_suffix) {
1231 free(res->res_job.add_suffix);
1233 if (res->res_job.RestoreBootstrap) {
1234 free(res->res_job.RestoreBootstrap);
1236 if (res->res_job.WriteBootstrap) {
1237 free(res->res_job.WriteBootstrap);
1239 if (res->res_job.selection_pattern) {
1240 free(res->res_job.selection_pattern);
1242 if (res->res_job.run_cmds) {
1243 delete res->res_job.run_cmds;
1245 if (res->res_job.storage) {
1246 delete res->res_job.storage;
1248 if (res->res_job.RunScripts) {
1249 free_runscripts(res->res_job.RunScripts);
1250 delete res->res_job.RunScripts;
1254 if (res->res_msgs.mail_cmd) {
1255 free(res->res_msgs.mail_cmd);
1257 if (res->res_msgs.operator_cmd) {
1258 free(res->res_msgs.operator_cmd);
1260 free_msgs_res((MSGS *)res); /* free message resource */
1264 printf(_("Unknown resource type %d in free_resource.\n"), type);
1266 /* Common stuff again -- free the resource, recurse to next one */
1271 free_resource(nres, type);
1276 * Save the new resource by chaining it into the head list for
1277 * the resource. If this is pass 2, we update any resource
1278 * pointers because they may not have been defined until
1281 void save_resource(int type, RES_ITEM *items, int pass)
1284 int rindex = type - r_first;
1288 /* Check Job requirements after applying JobDefs */
1289 if (type != R_JOB && type != R_JOBDEFS) {
1291 * Ensure that all required items are present
1293 for (i=0; items[i].name; i++) {
1294 if (items[i].flags & ITEM_REQUIRED) {
1295 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1296 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1297 items[i].name, resources[rindex]);
1300 /* If this triggers, take a look at lib/parse_conf.h */
1301 if (i >= MAX_RES_ITEMS) {
1302 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1305 } else if (type == R_JOB) {
1307 * Ensure that the name item is present
1309 if (items[0].flags & ITEM_REQUIRED) {
1310 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1311 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1312 items[0].name, resources[rindex]);
1318 * During pass 2 in each "store" routine, we looked up pointers
1319 * to all the resources referrenced in the current resource, now we
1320 * must copy their addresses from the static record to the allocated
1325 /* Resources not containing a resource */
1333 * Resources containing another resource or alist. First
1334 * look up the resource which contains another resource. It
1335 * was written during pass 1. Then stuff in the pointers to
1336 * the resources it contains, which were inserted this pass.
1337 * Finally, it will all be stored back.
1340 /* Find resource saved in pass 1 */
1341 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1342 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1344 /* Explicitly copy resource pointers from this pass (res_all) */
1345 res->res_pool.NextPool = res_all.res_pool.NextPool;
1346 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1347 res->res_pool.storage = res_all.res_pool.storage;
1348 res->res_pool.catalog = res_all.res_pool.catalog;
1351 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1352 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1354 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1357 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1358 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1360 res->res_dir.messages = res_all.res_dir.messages;
1361 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1364 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1365 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1366 res_all.res_dir.hdr.name);
1368 /* we must explicitly copy the device alist pointer */
1369 res->res_store.device = res_all.res_store.device;
1373 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1374 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1375 res_all.res_dir.hdr.name);
1377 res->res_job.messages = res_all.res_job.messages;
1378 res->res_job.schedule = res_all.res_job.schedule;
1379 res->res_job.client = res_all.res_job.client;
1380 res->res_job.fileset = res_all.res_job.fileset;
1381 res->res_job.storage = res_all.res_job.storage;
1382 res->res_job.pool = res_all.res_job.pool;
1383 res->res_job.full_pool = res_all.res_job.full_pool;
1384 res->res_job.inc_pool = res_all.res_job.inc_pool;
1385 res->res_job.diff_pool = res_all.res_job.diff_pool;
1386 res->res_job.verify_job = res_all.res_job.verify_job;
1387 res->res_job.jobdefs = res_all.res_job.jobdefs;
1388 res->res_job.run_cmds = res_all.res_job.run_cmds;
1389 res->res_job.RunScripts = res_all.res_job.RunScripts;
1391 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1392 * is not very useful)
1393 * We have to set_bit(index, res_all.hdr.item_present);
1394 * or something like that
1397 /* we take RegexWhere before all other options */
1398 if (!res->res_job.RegexWhere
1400 (res->res_job.strip_prefix ||
1401 res->res_job.add_suffix ||
1402 res->res_job.add_prefix))
1404 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1405 res->res_job.add_prefix,
1406 res->res_job.add_suffix);
1407 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1408 bregexp_build_where(res->res_job.RegexWhere, len,
1409 res->res_job.strip_prefix,
1410 res->res_job.add_prefix,
1411 res->res_job.add_suffix);
1412 /* TODO: test bregexp */
1415 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1416 free(res->res_job.RestoreWhere);
1417 res->res_job.RestoreWhere = NULL;
1422 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1423 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1425 res->res_counter.Catalog = res_all.res_counter.Catalog;
1426 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1430 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1431 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1433 res->res_client.catalog = res_all.res_client.catalog;
1434 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1438 * Schedule is a bit different in that it contains a RUN record
1439 * chain which isn't a "named" resource. This chain was linked
1440 * in by run_conf.c during pass 2, so here we jam the pointer
1441 * into the Schedule resource.
1443 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1444 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1446 res->res_sch.run = res_all.res_sch.run;
1449 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1453 /* Note, the resource name was already saved during pass 1,
1454 * so here, we can just release it.
1456 if (res_all.res_dir.hdr.name) {
1457 free(res_all.res_dir.hdr.name);
1458 res_all.res_dir.hdr.name = NULL;
1460 if (res_all.res_dir.hdr.desc) {
1461 free(res_all.res_dir.hdr.desc);
1462 res_all.res_dir.hdr.desc = NULL;
1468 * The following code is only executed during pass 1
1472 size = sizeof(DIRRES);
1475 size = sizeof(CONRES);
1478 size =sizeof(CLIENT);
1481 size = sizeof(STORE);
1491 size = sizeof(FILESET);
1494 size = sizeof(SCHED);
1497 size = sizeof(POOL);
1500 size = sizeof(MSGS);
1503 size = sizeof(COUNTER);
1509 printf(_("Unknown resource type %d in save_resource.\n"), type);
1515 res = (URES *)malloc(size);
1516 memcpy(res, &res_all, size);
1517 if (!res_head[rindex]) {
1518 res_head[rindex] = (RES *)res; /* store first entry */
1519 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1520 res->res_dir.hdr.name, rindex);
1523 if (res->res_dir.hdr.name == NULL) {
1524 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1527 /* Add new res to end of chain */
1528 for (last=next=res_head[rindex]; next; next=next->next) {
1530 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1531 Emsg2(M_ERROR_TERM, 0,
1532 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1533 resources[rindex].name, res->res_dir.hdr.name);
1536 last->next = (RES *)res;
1537 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1538 res->res_dir.hdr.name, rindex, pass);
1544 * Store Device. Note, the resource is created upon the
1545 * first reference. The details of the resource are obtained
1546 * later from the SD.
1548 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1552 int rindex = R_DEVICE - r_first;
1553 int size = sizeof(DEVICE);
1557 token = lex_get_token(lc, T_NAME);
1558 if (!res_head[rindex]) {
1559 res = (URES *)malloc(size);
1560 memset(res, 0, size);
1561 res->res_dev.hdr.name = bstrdup(lc->str);
1562 res_head[rindex] = (RES *)res; /* store first entry */
1563 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1564 res->res_dir.hdr.name, rindex);
1567 /* See if it is already defined */
1568 for (next=res_head[rindex]; next->next; next=next->next) {
1569 if (strcmp(next->name, lc->str) == 0) {
1575 res = (URES *)malloc(size);
1576 memset(res, 0, size);
1577 res->res_dev.hdr.name = bstrdup(lc->str);
1578 next->next = (RES *)res;
1579 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1580 res->res_dir.hdr.name, rindex, pass);
1585 set_bit(index, res_all.hdr.item_present);
1587 store_alist_res(lc, item, index, pass);
1592 * Store JobType (backup, verify, restore)
1595 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1599 token = lex_get_token(lc, T_NAME);
1600 /* Store the type both pass 1 and pass 2 */
1601 for (i=0; migtypes[i].type_name; i++) {
1602 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1603 *(int *)(item->value) = migtypes[i].job_type;
1609 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1612 set_bit(index, res_all.hdr.item_present);
1618 * Store JobType (backup, verify, restore)
1621 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1625 token = lex_get_token(lc, T_NAME);
1626 /* Store the type both pass 1 and pass 2 */
1627 for (i=0; jobtypes[i].type_name; i++) {
1628 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1629 *(int *)(item->value) = jobtypes[i].job_type;
1635 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1638 set_bit(index, res_all.hdr.item_present);
1642 * Store Job Level (Full, Incremental, ...)
1645 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1649 token = lex_get_token(lc, T_NAME);
1650 /* Store the level pass 2 so that type is defined */
1651 for (i=0; joblevels[i].level_name; i++) {
1652 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1653 *(int *)(item->value) = joblevels[i].level;
1659 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1662 set_bit(index, res_all.hdr.item_present);
1666 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1669 token = lex_get_token(lc, T_NAME);
1670 /* Scan Replacement options */
1671 for (i=0; ReplaceOptions[i].name; i++) {
1672 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1673 *(int *)(item->value) = ReplaceOptions[i].token;
1679 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1682 set_bit(index, res_all.hdr.item_present);
1686 * Store ACL (access control list)
1689 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1694 token = lex_get_token(lc, T_STRING);
1696 if (((alist **)item->value)[item->code] == NULL) {
1697 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1698 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1700 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1701 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1703 token = lex_get_token(lc, T_ALL);
1704 if (token == T_COMMA) {
1705 continue; /* get another ACL */
1709 set_bit(index, res_all.hdr.item_present);
1712 /* We build RunScripts items here */
1713 static RUNSCRIPT res_runscript;
1715 /* Store a runscript->when in a bit field */
1716 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1718 lex_get_token(lc, T_NAME);
1720 if (strcasecmp(lc->str, "before") == 0) {
1721 *(int *)(item->value) = SCRIPT_Before ;
1722 } else if (strcasecmp(lc->str, "after") == 0) {
1723 *(int *)(item->value) = SCRIPT_After;
1724 } else if (strcasecmp(lc->str, "always") == 0) {
1725 *(int *)(item->value) = SCRIPT_Any;
1727 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1732 /* Store a runscript->target
1735 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1737 lex_get_token(lc, T_STRING);
1740 if (strcmp(lc->str, "%c") == 0) {
1741 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1742 } else if (strcasecmp(lc->str, "yes") == 0) {
1743 ((RUNSCRIPT*) item->value)->set_target("%c");
1744 } else if (strcasecmp(lc->str, "no") == 0) {
1745 ((RUNSCRIPT*) item->value)->set_target("");
1747 RES *res = GetResWithName(R_CLIENT, lc->str);
1749 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1750 lc->str, lc->line_no, lc->line);
1753 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1760 * Store a runscript->command as a string
1762 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1764 lex_get_token(lc, T_STRING);
1767 ((RUNSCRIPT*)item->value)->set_command(lc->str, item->code);
1772 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1774 lex_get_token(lc, T_STRING);
1775 alist **runscripts = (alist **)(item->value) ;
1778 RUNSCRIPT *script = new_runscript();
1779 script->set_job_code_callback(job_code_callback_filesetname);
1781 script->set_command(lc->str);
1783 /* TODO: remove all script->old_proto with bacula 1.42 */
1785 if (strcmp(item->name, "runbeforejob") == 0) {
1786 script->when = SCRIPT_Before;
1787 script->fail_on_error = true;
1788 script->set_target("");
1790 } else if (strcmp(item->name, "runafterjob") == 0) {
1791 script->when = SCRIPT_After;
1792 script->on_success = true;
1793 script->on_failure = false;
1794 script->set_target("");
1796 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1797 script->old_proto = true;
1798 script->when = SCRIPT_After;
1799 script->set_target("%c");
1800 script->on_success = true;
1801 script->on_failure = false;
1803 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1804 script->old_proto = true;
1805 script->when = SCRIPT_Before;
1806 script->set_target("%c");
1807 script->fail_on_error = true;
1809 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1810 script->when = SCRIPT_After;
1811 script->on_failure = true;
1812 script->on_success = false;
1813 script->set_target("");
1816 if (*runscripts == NULL) {
1817 *runscripts = New(alist(10, not_owned_by_alist));
1820 (*runscripts)->append(script);
1827 /* Store a bool in a bit field without modifing res_all.hdr
1828 * We can also add an option to store_bool to skip res_all.hdr
1830 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1832 lex_get_token(lc, T_NAME);
1833 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1834 *(bool *)(item->value) = true;
1835 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1836 *(bool *)(item->value) = false;
1838 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1844 * new RunScript items
1845 * name handler value code flags default_value
1847 static RES_ITEM runscript_items[] = {
1848 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1849 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1850 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1851 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1852 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1853 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1854 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1855 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1856 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1857 {NULL, NULL, {0}, 0, 0, 0}
1861 * Store RunScript info
1863 * Note, when this routine is called, we are inside a Job
1864 * resource. We treat the RunScript like a sort of
1865 * mini-resource within the Job resource.
1867 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1870 alist **runscripts = (alist **)(item->value) ;
1872 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1874 res_runscript.reset_default(); /* setting on_success, on_failure, fail_on_error */
1876 token = lex_get_token(lc, T_SKIP_EOL);
1878 if (token != T_BOB) {
1879 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1882 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1883 if (token == T_EOB) {
1886 if (token != T_IDENTIFIER) {
1887 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1889 for (i=0; runscript_items[i].name; i++) {
1890 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1891 token = lex_get_token(lc, T_SKIP_EOL);
1892 if (token != T_EQUALS) {
1893 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1896 /* Call item handler */
1897 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1904 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1909 if (res_runscript.command == NULL) {
1910 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1911 "command", "runscript");
1914 /* run on client by default */
1915 if (res_runscript.target == NULL) {
1916 res_runscript.set_target("%c");
1919 RUNSCRIPT *script = new_runscript();
1920 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1921 script->set_job_code_callback(job_code_callback_filesetname);
1923 if (*runscripts == NULL) {
1924 *runscripts = New(alist(10, not_owned_by_alist));
1927 (*runscripts)->append(script);
1932 set_bit(index, res_all.hdr.item_present);
1935 /* callback function for edit_job_codes */
1936 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1938 if (param[0] == 'f') {
1939 return jcr->fileset->name();