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 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
159 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
160 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
161 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
162 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
163 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
164 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
165 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
166 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
167 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
168 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
169 {NULL, NULL, {0}, 0, 0, 0}
174 * Client or File daemon resource
176 * name handler value code flags default_value
179 static RES_ITEM cli_items[] = {
180 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
181 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
182 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
183 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
184 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
185 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
186 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
187 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
188 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
189 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
190 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
191 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
192 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
193 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
194 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
195 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
196 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
197 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
198 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
199 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
200 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
201 {NULL, NULL, {0}, 0, 0, 0}
204 /* Storage daemon resource
206 * name handler value code flags default_value
208 static RES_ITEM store_items[] = {
209 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
210 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
211 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
212 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
213 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
214 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
215 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
216 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
217 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
218 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
219 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
220 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
221 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
222 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
223 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
224 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
225 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
226 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
227 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
228 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
229 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
230 {NULL, NULL, {0}, 0, 0, 0}
234 * Catalog Resource Directives
236 * name handler value code flags default_value
238 static RES_ITEM cat_items[] = {
239 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
240 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
241 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
242 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
243 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
244 /* keep this password as store_str for the moment */
245 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
246 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
247 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
248 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
249 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
250 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
251 /* Turned off for the moment */
252 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
253 {NULL, NULL, {0}, 0, 0, 0}
257 * Job Resource Directives
259 * name handler value code flags default_value
261 RES_ITEM job_items[] = {
262 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
263 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
264 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
265 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
266 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
267 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
268 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
269 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
270 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
271 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
272 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
273 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
274 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
275 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
276 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
277 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
278 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
279 /* Root of where to restore files */
280 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
281 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
282 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
283 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
284 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
285 /* Where to find bootstrap during restore */
286 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
287 /* Where to write bootstrap file during backup */
288 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
289 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
290 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
291 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
292 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
293 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
294 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
295 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
296 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
297 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
298 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
299 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
300 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
301 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
302 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
303 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
304 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
305 {"optimizejobscheduling",store_bool, ITEM(res_job.OptimizeJobScheduling), 0, ITEM_DEFAULT, false},
306 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
307 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
308 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
309 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
310 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
311 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
312 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
313 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
314 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
315 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
316 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
317 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
318 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
319 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
320 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
321 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
322 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
323 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
324 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
325 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
326 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
327 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
328 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
329 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
330 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
331 {NULL, NULL, {0}, 0, 0, 0}
336 * name handler value code flags default_value
338 static RES_ITEM fs_items[] = {
339 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
340 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
341 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
342 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
343 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
344 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
345 {NULL, NULL, {0}, 0, 0, 0}
348 /* Schedule -- see run_conf.c */
351 * name handler value code flags default_value
353 static RES_ITEM sch_items[] = {
354 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
355 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
356 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
357 {NULL, NULL, {0}, 0, 0, 0}
362 * name handler value code flags default_value
364 static RES_ITEM pool_items[] = {
365 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
366 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
367 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
368 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
369 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
370 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
371 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
372 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
373 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
374 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
375 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
376 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
377 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
378 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
379 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
380 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
381 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
382 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
383 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
384 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
385 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
386 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
387 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
388 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
389 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
390 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
391 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
392 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
393 {NULL, NULL, {0}, 0, 0, 0}
398 * name handler value code flags default_value
400 static RES_ITEM counter_items[] = {
401 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
402 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
403 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
404 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
405 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
406 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
407 {NULL, NULL, {0}, 0, 0, 0}
411 /* Message resource */
412 extern RES_ITEM msgs_items[];
415 * This is the master resource definition.
416 * It must have one item for each of the resources.
418 * NOTE!!! keep it in the same order as the R_codes
419 * or eliminate all resources[rindex].name
421 * name items rcode res_head
423 RES_TABLE resources[] = {
424 {"director", dir_items, R_DIRECTOR},
425 {"client", cli_items, R_CLIENT},
426 {"job", job_items, R_JOB},
427 {"storage", store_items, R_STORAGE},
428 {"catalog", cat_items, R_CATALOG},
429 {"schedule", sch_items, R_SCHEDULE},
430 {"fileset", fs_items, R_FILESET},
431 {"pool", pool_items, R_POOL},
432 {"messages", msgs_items, R_MSGS},
433 {"counter", counter_items, R_COUNTER},
434 {"console", con_items, R_CONSOLE},
435 {"jobdefs", job_items, R_JOBDEFS},
436 {"device", NULL, R_DEVICE}, /* info obtained from SD */
441 /* Keywords (RHS) permitted in Job Level records
443 * level_name level job_type
445 struct s_jl joblevels[] = {
446 {"Full", L_FULL, JT_BACKUP},
447 {"Base", L_BASE, JT_BACKUP},
448 {"Incremental", L_INCREMENTAL, JT_BACKUP},
449 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
450 {"Since", L_SINCE, JT_BACKUP},
451 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
452 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
453 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
454 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
455 {"Data", L_VERIFY_DATA, JT_VERIFY},
456 {" ", L_NONE, JT_ADMIN},
457 {" ", L_NONE, JT_RESTORE},
461 /* Keywords (RHS) permitted in Job type records
465 struct s_jt jobtypes[] = {
466 {"backup", JT_BACKUP},
468 {"verify", JT_VERIFY},
469 {"restore", JT_RESTORE},
470 {"migrate", JT_MIGRATE},
476 /* Keywords (RHS) permitted in Selection type records
480 struct s_jt migtypes[] = {
481 {"smallestvolume", MT_SMALLEST_VOL},
482 {"oldestvolume", MT_OLDEST_VOL},
483 {"pooloccupancy", MT_POOL_OCCUPANCY},
484 {"pooltime", MT_POOL_TIME},
485 {"client", MT_CLIENT},
486 {"volume", MT_VOLUME},
488 {"sqlquery", MT_SQLQUERY},
494 /* Options permitted in Restore replace= */
495 struct s_kw ReplaceOptions[] = {
496 {"always", REPLACE_ALWAYS},
497 {"ifnewer", REPLACE_IFNEWER},
498 {"ifolder", REPLACE_IFOLDER},
499 {"never", REPLACE_NEVER},
503 const char *level_to_str(int level)
506 static char level_no[30];
507 const char *str = level_no;
509 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
510 for (i=0; joblevels[i].level_name; i++) {
511 if (level == joblevels[i].level) {
512 str = joblevels[i].level_name;
519 /* Dump contents of resource */
520 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
522 URES *res = (URES *)reshdr;
524 char ed1[100], ed2[100], ed3[100];
528 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
531 if (type < 0) { /* no recursion */
537 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
538 reshdr->name, res->res_dir.MaxConcurrentJobs,
539 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
540 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
541 if (res->res_dir.query_file) {
542 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
544 if (res->res_dir.messages) {
545 sendit(sock, _(" --> "));
546 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
550 sendit(sock, _("Console: name=%s SSL=%d\n"),
551 res->res_con.hdr.name, res->res_con.tls_enable);
554 if (res->res_counter.WrapCounter) {
555 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
556 res->res_counter.hdr.name, res->res_counter.MinValue,
557 res->res_counter.MaxValue, res->res_counter.CurrentValue,
558 res->res_counter.WrapCounter->hdr.name);
560 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
561 res->res_counter.hdr.name, res->res_counter.MinValue,
562 res->res_counter.MaxValue);
564 if (res->res_counter.Catalog) {
565 sendit(sock, _(" --> "));
566 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
571 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
572 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
573 res->res_client.MaxConcurrentJobs);
574 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
575 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
576 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
577 res->res_client.AutoPrune);
578 if (res->res_client.catalog) {
579 sendit(sock, _(" --> "));
580 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
587 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
588 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
589 " poolid=%s volname=%s MediaType=%s\n"),
590 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
591 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
592 dev->offline, dev->autochanger,
593 edit_uint64(dev->PoolId, ed1),
594 dev->VolumeName, dev->MediaType);
598 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
599 " DeviceName=%s MediaType=%s StorageId=%s\n"),
600 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
601 res->res_store.MaxConcurrentJobs,
602 res->res_store.dev_name(),
603 res->res_store.media_type,
604 edit_int64(res->res_store.StorageId, ed1));
608 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
609 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
610 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
611 res->res_cat.db_port, res->res_cat.db_name,
612 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
613 res->res_cat.mult_db_connections);
618 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
619 type == R_JOB ? _("Job") : _("JobDefs"),
620 res->res_job.hdr.name, res->res_job.JobType,
621 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
622 res->res_job.enabled);
623 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
624 res->res_job.MaxConcurrentJobs,
625 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
626 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
627 res->res_job.spool_data, res->res_job.write_part_after_job);
628 if (res->res_job.spool_size) {
629 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
631 if (res->res_job.JobType == JT_BACKUP) {
632 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
634 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
635 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
637 if (res->res_job.client) {
638 sendit(sock, _(" --> "));
639 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
641 if (res->res_job.fileset) {
642 sendit(sock, _(" --> "));
643 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
645 if (res->res_job.schedule) {
646 sendit(sock, _(" --> "));
647 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
649 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
650 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
652 if (res->res_job.RegexWhere) {
653 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
655 if (res->res_job.RestoreBootstrap) {
656 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
658 if (res->res_job.WriteBootstrap) {
659 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
661 if (res->res_job.PluginOptions) {
662 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
664 if (res->res_job.storage) {
666 foreach_alist(store, res->res_job.storage) {
667 sendit(sock, _(" --> "));
668 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
671 if (res->res_job.RunScripts) {
673 foreach_alist(script, res->res_job.RunScripts) {
674 sendit(sock, _(" --> RunScript\n"));
675 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
676 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
677 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
678 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
679 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
680 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
683 if (res->res_job.pool) {
684 sendit(sock, _(" --> "));
685 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
687 if (res->res_job.full_pool) {
688 sendit(sock, _(" --> "));
689 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
691 if (res->res_job.inc_pool) {
692 sendit(sock, _(" --> "));
693 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
695 if (res->res_job.diff_pool) {
696 sendit(sock, _(" --> "));
697 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
699 if (res->res_job.verify_job) {
700 sendit(sock, _(" --> "));
701 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
703 if (res->res_job.run_cmds) {
705 foreach_alist(runcmd, res->res_job.run_cmds) {
706 sendit(sock, _(" --> Run=%s\n"), runcmd);
709 if (res->res_job.selection_pattern) {
710 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
712 if (res->res_job.messages) {
713 sendit(sock, _(" --> "));
714 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
721 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
722 for (i=0; i<res->res_fs.num_includes; i++) {
723 INCEXE *incexe = res->res_fs.include_items[i];
724 for (j=0; j<incexe->num_opts; j++) {
725 FOPTS *fo = incexe->opts_list[j];
726 sendit(sock, " O %s\n", fo->opts);
728 bool enhanced_wild = false;
729 for (k=0; fo->opts[k]!='\0'; k++) {
730 if (fo->opts[k]=='W') {
731 enhanced_wild = true;
736 for (k=0; k<fo->regex.size(); k++) {
737 sendit(sock, " R %s\n", fo->regex.get(k));
739 for (k=0; k<fo->regexdir.size(); k++) {
740 sendit(sock, " RD %s\n", fo->regexdir.get(k));
742 for (k=0; k<fo->regexfile.size(); k++) {
743 sendit(sock, " RF %s\n", fo->regexfile.get(k));
745 for (k=0; k<fo->wild.size(); k++) {
746 sendit(sock, " W %s\n", fo->wild.get(k));
748 for (k=0; k<fo->wilddir.size(); k++) {
749 sendit(sock, " WD %s\n", fo->wilddir.get(k));
751 for (k=0; k<fo->wildfile.size(); k++) {
752 sendit(sock, " WF %s\n", fo->wildfile.get(k));
754 for (k=0; k<fo->wildbase.size(); k++) {
755 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
757 for (k=0; k<fo->base.size(); k++) {
758 sendit(sock, " B %s\n", fo->base.get(k));
760 for (k=0; k<fo->fstype.size(); k++) {
761 sendit(sock, " X %s\n", fo->fstype.get(k));
763 for (k=0; k<fo->drivetype.size(); k++) {
764 sendit(sock, " XD %s\n", fo->drivetype.get(k));
767 sendit(sock, " G %s\n", fo->plugin);
770 sendit(sock, " D %s\n", fo->reader);
773 sendit(sock, " T %s\n", fo->writer);
775 sendit(sock, " N\n");
777 for (j=0; j<incexe->name_list.size(); j++) {
778 sendit(sock, " I %s\n", incexe->name_list.get(j));
780 if (incexe->name_list.size()) {
781 sendit(sock, " N\n");
783 for (j=0; j<incexe->plugin_list.size(); j++) {
784 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
786 if (incexe->plugin_list.size()) {
787 sendit(sock, " N\n");
792 for (i=0; i<res->res_fs.num_excludes; i++) {
793 INCEXE *incexe = res->res_fs.exclude_items[i];
794 for (j=0; j<incexe->name_list.size(); j++) {
795 sendit(sock, " E %s\n", incexe->name_list.get(j));
797 if (incexe->name_list.size()) {
798 sendit(sock, " N\n");
805 if (res->res_sch.run) {
807 RUN *run = res->res_sch.run;
808 char buf[1000], num[30];
809 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
814 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
815 bstrncpy(buf, _(" hour="), sizeof(buf));
816 for (i=0; i<24; i++) {
817 if (bit_is_set(i, run->hour)) {
818 bsnprintf(num, sizeof(num), "%d ", i);
819 bstrncat(buf, num, sizeof(buf));
822 bstrncat(buf, "\n", sizeof(buf));
824 bstrncpy(buf, _(" mday="), sizeof(buf));
825 for (i=0; i<31; i++) {
826 if (bit_is_set(i, run->mday)) {
827 bsnprintf(num, sizeof(num), "%d ", i);
828 bstrncat(buf, num, sizeof(buf));
831 bstrncat(buf, "\n", sizeof(buf));
833 bstrncpy(buf, _(" month="), sizeof(buf));
834 for (i=0; i<12; i++) {
835 if (bit_is_set(i, run->month)) {
836 bsnprintf(num, sizeof(num), "%d ", i);
837 bstrncat(buf, num, sizeof(buf));
840 bstrncat(buf, "\n", sizeof(buf));
842 bstrncpy(buf, _(" wday="), sizeof(buf));
843 for (i=0; i<7; i++) {
844 if (bit_is_set(i, run->wday)) {
845 bsnprintf(num, sizeof(num), "%d ", i);
846 bstrncat(buf, num, sizeof(buf));
849 bstrncat(buf, "\n", sizeof(buf));
851 bstrncpy(buf, _(" wom="), sizeof(buf));
852 for (i=0; i<5; i++) {
853 if (bit_is_set(i, run->wom)) {
854 bsnprintf(num, sizeof(num), "%d ", i);
855 bstrncat(buf, num, sizeof(buf));
858 bstrncat(buf, "\n", sizeof(buf));
860 bstrncpy(buf, _(" woy="), sizeof(buf));
861 for (i=0; i<54; i++) {
862 if (bit_is_set(i, run->woy)) {
863 bsnprintf(num, sizeof(num), "%d ", i);
864 bstrncat(buf, num, sizeof(buf));
867 bstrncat(buf, "\n", sizeof(buf));
869 sendit(sock, _(" mins=%d\n"), run->minute);
871 sendit(sock, _(" --> "));
872 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
875 sendit(sock, _(" --> "));
876 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
879 sendit(sock, _(" --> "));
880 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
882 /* If another Run record is chained in, go print it */
888 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
893 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
894 res->res_pool.pool_type);
895 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
896 res->res_pool.use_catalog, res->res_pool.use_volume_once,
897 res->res_pool.catalog_files);
898 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
899 res->res_pool.max_volumes, res->res_pool.AutoPrune,
900 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
901 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
902 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
903 res->res_pool.Recycle,
904 NPRT(res->res_pool.label_format));
905 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
906 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
907 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
908 res->res_pool.recycle_oldest_volume,
909 res->res_pool.purge_oldest_volume);
910 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
911 res->res_pool.MaxVolJobs,
912 res->res_pool.MaxVolFiles,
913 edit_uint64(res->res_pool.MaxVolFiles, ed1));
914 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
915 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
916 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
917 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
918 if (res->res_pool.NextPool) {
919 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
921 if (res->res_pool.RecyclePool) {
922 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
924 if (res->res_pool.catalog) {
925 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
927 if (res->res_pool.storage) {
929 foreach_alist(store, res->res_pool.storage) {
930 sendit(sock, _(" --> "));
931 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
934 if (res->res_pool.CopyPool) {
936 foreach_alist(copy, res->res_pool.CopyPool) {
937 sendit(sock, _(" --> "));
938 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
945 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
946 if (res->res_msgs.mail_cmd)
947 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
948 if (res->res_msgs.operator_cmd)
949 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
953 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
956 if (recurse && res->res_dir.hdr.next) {
957 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
962 * Free all the members of an INCEXE structure
964 static void free_incexe(INCEXE *incexe)
966 incexe->name_list.destroy();
967 incexe->plugin_list.destroy();
968 for (int i=0; i<incexe->num_opts; i++) {
969 FOPTS *fopt = incexe->opts_list[i];
970 fopt->regex.destroy();
971 fopt->regexdir.destroy();
972 fopt->regexfile.destroy();
973 fopt->wild.destroy();
974 fopt->wilddir.destroy();
975 fopt->wildfile.destroy();
976 fopt->wildbase.destroy();
977 fopt->base.destroy();
978 fopt->fstype.destroy();
979 fopt->drivetype.destroy();
991 if (incexe->opts_list) {
992 free(incexe->opts_list);
998 * Free memory of resource -- called when daemon terminates.
999 * NB, we don't need to worry about freeing any references
1000 * to other resources as they will be freed when that
1001 * resource chain is traversed. Mainly we worry about freeing
1002 * allocated strings (names).
1004 void free_resource(RES *sres, int type)
1007 RES *nres; /* next resource if linked */
1008 URES *res = (URES *)sres;
1013 /* common stuff -- free the resource name and description */
1014 nres = (RES *)res->res_dir.hdr.next;
1015 if (res->res_dir.hdr.name) {
1016 free(res->res_dir.hdr.name);
1018 if (res->res_dir.hdr.desc) {
1019 free(res->res_dir.hdr.desc);
1024 if (res->res_dir.working_directory) {
1025 free(res->res_dir.working_directory);
1027 if (res->res_dir.scripts_directory) {
1028 free((char *)res->res_dir.scripts_directory);
1030 if (res->res_dir.plugin_directory) {
1031 free((char *)res->res_dir.plugin_directory);
1033 if (res->res_dir.pid_directory) {
1034 free(res->res_dir.pid_directory);
1036 if (res->res_dir.subsys_directory) {
1037 free(res->res_dir.subsys_directory);
1039 if (res->res_dir.password) {
1040 free(res->res_dir.password);
1042 if (res->res_dir.query_file) {
1043 free(res->res_dir.query_file);
1045 if (res->res_dir.DIRaddrs) {
1046 free_addresses(res->res_dir.DIRaddrs);
1048 if (res->res_dir.tls_ctx) {
1049 free_tls_context(res->res_dir.tls_ctx);
1051 if (res->res_dir.tls_ca_certfile) {
1052 free(res->res_dir.tls_ca_certfile);
1054 if (res->res_dir.tls_ca_certdir) {
1055 free(res->res_dir.tls_ca_certdir);
1057 if (res->res_dir.tls_certfile) {
1058 free(res->res_dir.tls_certfile);
1060 if (res->res_dir.tls_keyfile) {
1061 free(res->res_dir.tls_keyfile);
1063 if (res->res_dir.tls_dhfile) {
1064 free(res->res_dir.tls_dhfile);
1066 if (res->res_dir.tls_allowed_cns) {
1067 delete res->res_dir.tls_allowed_cns;
1074 if (res->res_con.password) {
1075 free(res->res_con.password);
1077 if (res->res_con.tls_ctx) {
1078 free_tls_context(res->res_con.tls_ctx);
1080 if (res->res_con.tls_ca_certfile) {
1081 free(res->res_con.tls_ca_certfile);
1083 if (res->res_con.tls_ca_certdir) {
1084 free(res->res_con.tls_ca_certdir);
1086 if (res->res_con.tls_certfile) {
1087 free(res->res_con.tls_certfile);
1089 if (res->res_con.tls_keyfile) {
1090 free(res->res_con.tls_keyfile);
1092 if (res->res_con.tls_dhfile) {
1093 free(res->res_con.tls_dhfile);
1095 if (res->res_con.tls_allowed_cns) {
1096 delete res->res_con.tls_allowed_cns;
1098 for (int i=0; i<Num_ACL; i++) {
1099 if (res->res_con.ACL_lists[i]) {
1100 delete res->res_con.ACL_lists[i];
1101 res->res_con.ACL_lists[i] = NULL;
1106 if (res->res_client.address) {
1107 free(res->res_client.address);
1109 if (res->res_client.password) {
1110 free(res->res_client.password);
1112 if (res->res_client.tls_ctx) {
1113 free_tls_context(res->res_client.tls_ctx);
1115 if (res->res_client.tls_ca_certfile) {
1116 free(res->res_client.tls_ca_certfile);
1118 if (res->res_client.tls_ca_certdir) {
1119 free(res->res_client.tls_ca_certdir);
1121 if (res->res_client.tls_certfile) {
1122 free(res->res_client.tls_certfile);
1124 if (res->res_client.tls_keyfile) {
1125 free(res->res_client.tls_keyfile);
1127 if (res->res_client.tls_allowed_cns) {
1128 delete res->res_client.tls_allowed_cns;
1132 if (res->res_store.address) {
1133 free(res->res_store.address);
1135 if (res->res_store.password) {
1136 free(res->res_store.password);
1138 if (res->res_store.media_type) {
1139 free(res->res_store.media_type);
1141 if (res->res_store.device) {
1142 delete res->res_store.device;
1144 if (res->res_store.tls_ctx) {
1145 free_tls_context(res->res_store.tls_ctx);
1147 if (res->res_store.tls_ca_certfile) {
1148 free(res->res_store.tls_ca_certfile);
1150 if (res->res_store.tls_ca_certdir) {
1151 free(res->res_store.tls_ca_certdir);
1153 if (res->res_store.tls_certfile) {
1154 free(res->res_store.tls_certfile);
1156 if (res->res_store.tls_keyfile) {
1157 free(res->res_store.tls_keyfile);
1161 if (res->res_cat.db_address) {
1162 free(res->res_cat.db_address);
1164 if (res->res_cat.db_socket) {
1165 free(res->res_cat.db_socket);
1167 if (res->res_cat.db_user) {
1168 free(res->res_cat.db_user);
1170 if (res->res_cat.db_name) {
1171 free(res->res_cat.db_name);
1173 if (res->res_cat.db_driver) {
1174 free(res->res_cat.db_driver);
1176 if (res->res_cat.db_password) {
1177 free(res->res_cat.db_password);
1181 if ((num=res->res_fs.num_includes)) {
1182 while (--num >= 0) {
1183 free_incexe(res->res_fs.include_items[num]);
1185 free(res->res_fs.include_items);
1187 res->res_fs.num_includes = 0;
1188 if ((num=res->res_fs.num_excludes)) {
1189 while (--num >= 0) {
1190 free_incexe(res->res_fs.exclude_items[num]);
1192 free(res->res_fs.exclude_items);
1194 res->res_fs.num_excludes = 0;
1197 if (res->res_pool.pool_type) {
1198 free(res->res_pool.pool_type);
1200 if (res->res_pool.label_format) {
1201 free(res->res_pool.label_format);
1203 if (res->res_pool.cleaning_prefix) {
1204 free(res->res_pool.cleaning_prefix);
1206 if (res->res_pool.storage) {
1207 delete res->res_pool.storage;
1211 if (res->res_sch.run) {
1213 nrun = res->res_sch.run;
1223 if (res->res_job.RestoreWhere) {
1224 free(res->res_job.RestoreWhere);
1226 if (res->res_job.RegexWhere) {
1227 free(res->res_job.RegexWhere);
1229 if (res->res_job.strip_prefix) {
1230 free(res->res_job.strip_prefix);
1232 if (res->res_job.add_prefix) {
1233 free(res->res_job.add_prefix);
1235 if (res->res_job.add_suffix) {
1236 free(res->res_job.add_suffix);
1238 if (res->res_job.RestoreBootstrap) {
1239 free(res->res_job.RestoreBootstrap);
1241 if (res->res_job.WriteBootstrap) {
1242 free(res->res_job.WriteBootstrap);
1244 if (res->res_job.PluginOptions) {
1245 free(res->res_job.PluginOptions);
1247 if (res->res_job.selection_pattern) {
1248 free(res->res_job.selection_pattern);
1250 if (res->res_job.run_cmds) {
1251 delete res->res_job.run_cmds;
1253 if (res->res_job.storage) {
1254 delete res->res_job.storage;
1256 if (res->res_job.RunScripts) {
1257 free_runscripts(res->res_job.RunScripts);
1258 delete res->res_job.RunScripts;
1262 if (res->res_msgs.mail_cmd) {
1263 free(res->res_msgs.mail_cmd);
1265 if (res->res_msgs.operator_cmd) {
1266 free(res->res_msgs.operator_cmd);
1268 free_msgs_res((MSGS *)res); /* free message resource */
1272 printf(_("Unknown resource type %d in free_resource.\n"), type);
1274 /* Common stuff again -- free the resource, recurse to next one */
1279 free_resource(nres, type);
1284 * Save the new resource by chaining it into the head list for
1285 * the resource. If this is pass 2, we update any resource
1286 * pointers because they may not have been defined until
1289 void save_resource(int type, RES_ITEM *items, int pass)
1292 int rindex = type - r_first;
1296 /* Check Job requirements after applying JobDefs */
1297 if (type != R_JOB && type != R_JOBDEFS) {
1299 * Ensure that all required items are present
1301 for (i=0; items[i].name; i++) {
1302 if (items[i].flags & ITEM_REQUIRED) {
1303 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1304 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1305 items[i].name, resources[rindex]);
1308 /* If this triggers, take a look at lib/parse_conf.h */
1309 if (i >= MAX_RES_ITEMS) {
1310 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1313 } else if (type == R_JOB) {
1315 * Ensure that the name item is present
1317 if (items[0].flags & ITEM_REQUIRED) {
1318 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1319 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1320 items[0].name, resources[rindex]);
1326 * During pass 2 in each "store" routine, we looked up pointers
1327 * to all the resources referrenced in the current resource, now we
1328 * must copy their addresses from the static record to the allocated
1333 /* Resources not containing a resource */
1341 * Resources containing another resource or alist. First
1342 * look up the resource which contains another resource. It
1343 * was written during pass 1. Then stuff in the pointers to
1344 * the resources it contains, which were inserted this pass.
1345 * Finally, it will all be stored back.
1348 /* Find resource saved in pass 1 */
1349 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1350 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1352 /* Explicitly copy resource pointers from this pass (res_all) */
1353 res->res_pool.NextPool = res_all.res_pool.NextPool;
1354 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1355 res->res_pool.storage = res_all.res_pool.storage;
1356 res->res_pool.catalog = res_all.res_pool.catalog;
1359 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1360 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1362 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1365 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1366 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1368 res->res_dir.messages = res_all.res_dir.messages;
1369 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1372 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1373 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1374 res_all.res_dir.hdr.name);
1376 /* we must explicitly copy the device alist pointer */
1377 res->res_store.device = res_all.res_store.device;
1381 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1382 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1383 res_all.res_dir.hdr.name);
1385 res->res_job.messages = res_all.res_job.messages;
1386 res->res_job.schedule = res_all.res_job.schedule;
1387 res->res_job.client = res_all.res_job.client;
1388 res->res_job.fileset = res_all.res_job.fileset;
1389 res->res_job.storage = res_all.res_job.storage;
1390 res->res_job.pool = res_all.res_job.pool;
1391 res->res_job.full_pool = res_all.res_job.full_pool;
1392 res->res_job.inc_pool = res_all.res_job.inc_pool;
1393 res->res_job.diff_pool = res_all.res_job.diff_pool;
1394 res->res_job.verify_job = res_all.res_job.verify_job;
1395 res->res_job.jobdefs = res_all.res_job.jobdefs;
1396 res->res_job.run_cmds = res_all.res_job.run_cmds;
1397 res->res_job.RunScripts = res_all.res_job.RunScripts;
1399 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1400 * is not very useful)
1401 * We have to set_bit(index, res_all.hdr.item_present);
1402 * or something like that
1405 /* we take RegexWhere before all other options */
1406 if (!res->res_job.RegexWhere
1408 (res->res_job.strip_prefix ||
1409 res->res_job.add_suffix ||
1410 res->res_job.add_prefix))
1412 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1413 res->res_job.add_prefix,
1414 res->res_job.add_suffix);
1415 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1416 bregexp_build_where(res->res_job.RegexWhere, len,
1417 res->res_job.strip_prefix,
1418 res->res_job.add_prefix,
1419 res->res_job.add_suffix);
1420 /* TODO: test bregexp */
1423 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1424 free(res->res_job.RestoreWhere);
1425 res->res_job.RestoreWhere = NULL;
1430 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1431 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1433 res->res_counter.Catalog = res_all.res_counter.Catalog;
1434 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1438 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1439 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1441 res->res_client.catalog = res_all.res_client.catalog;
1442 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1446 * Schedule is a bit different in that it contains a RUN record
1447 * chain which isn't a "named" resource. This chain was linked
1448 * in by run_conf.c during pass 2, so here we jam the pointer
1449 * into the Schedule resource.
1451 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1452 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1454 res->res_sch.run = res_all.res_sch.run;
1457 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1461 /* Note, the resource name was already saved during pass 1,
1462 * so here, we can just release it.
1464 if (res_all.res_dir.hdr.name) {
1465 free(res_all.res_dir.hdr.name);
1466 res_all.res_dir.hdr.name = NULL;
1468 if (res_all.res_dir.hdr.desc) {
1469 free(res_all.res_dir.hdr.desc);
1470 res_all.res_dir.hdr.desc = NULL;
1476 * The following code is only executed during pass 1
1480 size = sizeof(DIRRES);
1483 size = sizeof(CONRES);
1486 size =sizeof(CLIENT);
1489 size = sizeof(STORE);
1499 size = sizeof(FILESET);
1502 size = sizeof(SCHED);
1505 size = sizeof(POOL);
1508 size = sizeof(MSGS);
1511 size = sizeof(COUNTER);
1517 printf(_("Unknown resource type %d in save_resource.\n"), type);
1523 res = (URES *)malloc(size);
1524 memcpy(res, &res_all, size);
1525 if (!res_head[rindex]) {
1526 res_head[rindex] = (RES *)res; /* store first entry */
1527 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1528 res->res_dir.hdr.name, rindex);
1531 if (res->res_dir.hdr.name == NULL) {
1532 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1535 /* Add new res to end of chain */
1536 for (last=next=res_head[rindex]; next; next=next->next) {
1538 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1539 Emsg2(M_ERROR_TERM, 0,
1540 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1541 resources[rindex].name, res->res_dir.hdr.name);
1544 last->next = (RES *)res;
1545 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1546 res->res_dir.hdr.name, rindex, pass);
1552 * Store Device. Note, the resource is created upon the
1553 * first reference. The details of the resource are obtained
1554 * later from the SD.
1556 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1560 int rindex = R_DEVICE - r_first;
1561 int size = sizeof(DEVICE);
1565 token = lex_get_token(lc, T_NAME);
1566 if (!res_head[rindex]) {
1567 res = (URES *)malloc(size);
1568 memset(res, 0, size);
1569 res->res_dev.hdr.name = bstrdup(lc->str);
1570 res_head[rindex] = (RES *)res; /* store first entry */
1571 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1572 res->res_dir.hdr.name, rindex);
1575 /* See if it is already defined */
1576 for (next=res_head[rindex]; next->next; next=next->next) {
1577 if (strcmp(next->name, lc->str) == 0) {
1583 res = (URES *)malloc(size);
1584 memset(res, 0, size);
1585 res->res_dev.hdr.name = bstrdup(lc->str);
1586 next->next = (RES *)res;
1587 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1588 res->res_dir.hdr.name, rindex, pass);
1593 set_bit(index, res_all.hdr.item_present);
1595 store_alist_res(lc, item, index, pass);
1600 * Store JobType (backup, verify, restore)
1603 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1607 token = lex_get_token(lc, T_NAME);
1608 /* Store the type both pass 1 and pass 2 */
1609 for (i=0; migtypes[i].type_name; i++) {
1610 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1611 *(int *)(item->value) = migtypes[i].job_type;
1617 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1620 set_bit(index, res_all.hdr.item_present);
1626 * Store JobType (backup, verify, restore)
1629 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1633 token = lex_get_token(lc, T_NAME);
1634 /* Store the type both pass 1 and pass 2 */
1635 for (i=0; jobtypes[i].type_name; i++) {
1636 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1637 *(int *)(item->value) = jobtypes[i].job_type;
1643 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1646 set_bit(index, res_all.hdr.item_present);
1650 * Store Job Level (Full, Incremental, ...)
1653 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1657 token = lex_get_token(lc, T_NAME);
1658 /* Store the level pass 2 so that type is defined */
1659 for (i=0; joblevels[i].level_name; i++) {
1660 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1661 *(int *)(item->value) = joblevels[i].level;
1667 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1670 set_bit(index, res_all.hdr.item_present);
1674 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1677 token = lex_get_token(lc, T_NAME);
1678 /* Scan Replacement options */
1679 for (i=0; ReplaceOptions[i].name; i++) {
1680 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1681 *(int *)(item->value) = ReplaceOptions[i].token;
1687 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1690 set_bit(index, res_all.hdr.item_present);
1694 * Store ACL (access control list)
1697 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1702 token = lex_get_token(lc, T_STRING);
1704 if (((alist **)item->value)[item->code] == NULL) {
1705 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1706 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1708 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1709 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1711 token = lex_get_token(lc, T_ALL);
1712 if (token == T_COMMA) {
1713 continue; /* get another ACL */
1717 set_bit(index, res_all.hdr.item_present);
1720 /* We build RunScripts items here */
1721 static RUNSCRIPT res_runscript;
1723 /* Store a runscript->when in a bit field */
1724 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1726 lex_get_token(lc, T_NAME);
1728 if (strcasecmp(lc->str, "before") == 0) {
1729 *(int *)(item->value) = SCRIPT_Before ;
1730 } else if (strcasecmp(lc->str, "after") == 0) {
1731 *(int *)(item->value) = SCRIPT_After;
1732 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1733 *(int *)(item->value) = SCRIPT_AfterVSS;
1734 } else if (strcasecmp(lc->str, "always") == 0) {
1735 *(int *)(item->value) = SCRIPT_Any;
1737 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1742 /* Store a runscript->target
1745 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1747 lex_get_token(lc, T_STRING);
1750 if (strcmp(lc->str, "%c") == 0) {
1751 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1752 } else if (strcasecmp(lc->str, "yes") == 0) {
1753 ((RUNSCRIPT*) item->value)->set_target("%c");
1754 } else if (strcasecmp(lc->str, "no") == 0) {
1755 ((RUNSCRIPT*) item->value)->set_target("");
1757 RES *res = GetResWithName(R_CLIENT, lc->str);
1759 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1760 lc->str, lc->line_no, lc->line);
1763 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1770 * Store a runscript->command as a string
1772 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1774 lex_get_token(lc, T_STRING);
1777 ((RUNSCRIPT*)item->value)->set_command(lc->str, item->code);
1782 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1784 lex_get_token(lc, T_STRING);
1785 alist **runscripts = (alist **)(item->value) ;
1788 RUNSCRIPT *script = new_runscript();
1789 script->set_job_code_callback(job_code_callback_filesetname);
1791 script->set_command(lc->str);
1793 /* TODO: remove all script->old_proto with bacula 1.42 */
1795 if (strcmp(item->name, "runbeforejob") == 0) {
1796 script->when = SCRIPT_Before;
1797 script->fail_on_error = true;
1798 script->set_target("");
1800 } else if (strcmp(item->name, "runafterjob") == 0) {
1801 script->when = SCRIPT_After;
1802 script->on_success = true;
1803 script->on_failure = false;
1804 script->set_target("");
1806 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1807 script->old_proto = true;
1808 script->when = SCRIPT_After;
1809 script->set_target("%c");
1810 script->on_success = true;
1811 script->on_failure = false;
1813 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1814 script->old_proto = true;
1815 script->when = SCRIPT_Before;
1816 script->set_target("%c");
1817 script->fail_on_error = true;
1819 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1820 script->when = SCRIPT_After;
1821 script->on_failure = true;
1822 script->on_success = false;
1823 script->set_target("");
1826 if (*runscripts == NULL) {
1827 *runscripts = New(alist(10, not_owned_by_alist));
1830 (*runscripts)->append(script);
1837 /* Store a bool in a bit field without modifing res_all.hdr
1838 * We can also add an option to store_bool to skip res_all.hdr
1840 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1842 lex_get_token(lc, T_NAME);
1843 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1844 *(bool *)(item->value) = true;
1845 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1846 *(bool *)(item->value) = false;
1848 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1854 * new RunScript items
1855 * name handler value code flags default_value
1857 static RES_ITEM runscript_items[] = {
1858 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1859 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1860 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1861 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1862 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1863 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1864 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1865 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1866 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1867 {NULL, NULL, {0}, 0, 0, 0}
1871 * Store RunScript info
1873 * Note, when this routine is called, we are inside a Job
1874 * resource. We treat the RunScript like a sort of
1875 * mini-resource within the Job resource.
1877 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1880 alist **runscripts = (alist **)(item->value) ;
1882 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1884 res_runscript.reset_default(); /* setting on_success, on_failure, fail_on_error */
1886 token = lex_get_token(lc, T_SKIP_EOL);
1888 if (token != T_BOB) {
1889 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1892 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1893 if (token == T_EOB) {
1896 if (token != T_IDENTIFIER) {
1897 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1899 for (i=0; runscript_items[i].name; i++) {
1900 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1901 token = lex_get_token(lc, T_SKIP_EOL);
1902 if (token != T_EQUALS) {
1903 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1906 /* Call item handler */
1907 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1914 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1919 if (res_runscript.command == NULL) {
1920 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1921 "command", "runscript");
1924 /* run on client by default */
1925 if (res_runscript.target == NULL) {
1926 res_runscript.set_target("%c");
1929 RUNSCRIPT *script = new_runscript();
1930 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1931 script->set_job_code_callback(job_code_callback_filesetname);
1933 if (*runscripts == NULL) {
1934 *runscripts = New(alist(10, not_owned_by_alist));
1937 (*runscripts)->append(script);
1942 set_bit(index, res_all.hdr.item_present);
1945 /* callback function for edit_job_codes */
1946 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1948 if (param[0] == 'f') {
1949 return jcr->fileset->name();