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_pint32, 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 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
137 {NULL, NULL, {0}, 0, 0, 0}
143 * name handler value code flags default_value
145 static RES_ITEM con_items[] = {
146 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
147 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
148 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
149 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
150 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
151 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
152 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
153 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
154 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
155 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
156 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
157 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
158 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
159 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
160 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
161 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
162 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
163 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
164 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
165 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
166 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
167 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
168 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
169 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
170 {NULL, NULL, {0}, 0, 0, 0}
175 * Client or File daemon resource
177 * name handler value code flags default_value
180 static RES_ITEM cli_items[] = {
181 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
182 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
183 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
184 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
185 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
186 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
187 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
188 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
189 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
190 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
191 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
192 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
193 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
194 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
195 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
196 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
197 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
198 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
199 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
200 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
201 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
202 {NULL, NULL, {0}, 0, 0, 0}
205 /* Storage daemon resource
207 * name handler value code flags default_value
209 static RES_ITEM store_items[] = {
210 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
211 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
212 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
213 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
214 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
215 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
216 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
217 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
218 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
219 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
220 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
221 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
222 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
223 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
224 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
225 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
226 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
227 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
228 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
229 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
230 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
231 {NULL, NULL, {0}, 0, 0, 0}
235 * Catalog Resource Directives
237 * name handler value code flags default_value
239 static RES_ITEM cat_items[] = {
240 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
241 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
242 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
243 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
244 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
245 /* keep this password as store_str for the moment */
246 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
247 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
248 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
249 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
250 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
251 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
252 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
253 /* Turned off for the moment */
254 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
255 {NULL, NULL, {0}, 0, 0, 0}
259 * Job Resource Directives
261 * name handler value code flags default_value
263 RES_ITEM job_items[] = {
264 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
265 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
266 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
267 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
268 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
269 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
270 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
271 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
272 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
273 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
274 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
275 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
276 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
277 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
278 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
279 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
280 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
281 /* Root of where to restore files */
282 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
283 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
284 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
285 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
286 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
287 /* Where to find bootstrap during restore */
288 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
289 /* Where to write bootstrap file during backup */
290 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
291 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
292 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
293 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
294 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
295 /* xxxMaxWaitTime are deprecated */
296 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
297 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
298 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
299 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
300 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
301 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
302 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
303 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
304 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
305 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
306 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
307 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
308 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
309 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
310 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
311 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
312 {"optimizejobscheduling",store_bool, ITEM(res_job.OptimizeJobScheduling), 0, ITEM_DEFAULT, false},
313 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
314 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
315 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
316 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
317 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
318 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
319 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
320 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
324 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
325 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
326 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
327 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
328 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
329 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
330 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
331 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
332 {"usestatistics", store_bool, ITEM(res_job.stats_enabled), 0, 0, 0},
333 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
334 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
335 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
336 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
337 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
338 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
339 {NULL, NULL, {0}, 0, 0, 0}
344 * name handler value code flags default_value
346 static RES_ITEM fs_items[] = {
347 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
348 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
349 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
350 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
351 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
352 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
353 {NULL, NULL, {0}, 0, 0, 0}
356 /* Schedule -- see run_conf.c */
359 * name handler value code flags default_value
361 static RES_ITEM sch_items[] = {
362 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
363 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
364 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
365 {NULL, NULL, {0}, 0, 0, 0}
370 * name handler value code flags default_value
372 static RES_ITEM pool_items[] = {
373 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
374 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
375 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
376 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
377 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
378 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
379 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
380 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
381 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
382 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
383 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
384 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
385 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
386 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
387 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
388 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
389 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
390 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
391 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
392 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
393 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
394 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
395 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
396 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
397 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
398 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
399 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
400 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
401 {NULL, NULL, {0}, 0, 0, 0}
406 * name handler value code flags default_value
408 static RES_ITEM counter_items[] = {
409 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
410 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
411 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
412 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
413 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
414 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
415 {NULL, NULL, {0}, 0, 0, 0}
419 /* Message resource */
420 extern RES_ITEM msgs_items[];
423 * This is the master resource definition.
424 * It must have one item for each of the resources.
426 * NOTE!!! keep it in the same order as the R_codes
427 * or eliminate all resources[rindex].name
429 * name items rcode res_head
431 RES_TABLE resources[] = {
432 {"director", dir_items, R_DIRECTOR},
433 {"client", cli_items, R_CLIENT},
434 {"job", job_items, R_JOB},
435 {"storage", store_items, R_STORAGE},
436 {"catalog", cat_items, R_CATALOG},
437 {"schedule", sch_items, R_SCHEDULE},
438 {"fileset", fs_items, R_FILESET},
439 {"pool", pool_items, R_POOL},
440 {"messages", msgs_items, R_MSGS},
441 {"counter", counter_items, R_COUNTER},
442 {"console", con_items, R_CONSOLE},
443 {"jobdefs", job_items, R_JOBDEFS},
444 {"device", NULL, R_DEVICE}, /* info obtained from SD */
449 /* Keywords (RHS) permitted in Job Level records
451 * level_name level job_type
453 struct s_jl joblevels[] = {
454 {"Full", L_FULL, JT_BACKUP},
455 {"Base", L_BASE, JT_BACKUP},
456 {"Incremental", L_INCREMENTAL, JT_BACKUP},
457 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
458 {"Since", L_SINCE, JT_BACKUP},
459 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
460 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
461 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
462 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
463 {"Data", L_VERIFY_DATA, JT_VERIFY},
464 {" ", L_NONE, JT_ADMIN},
465 {" ", L_NONE, JT_RESTORE},
469 /* Keywords (RHS) permitted in Job type records
473 struct s_jt jobtypes[] = {
474 {"backup", JT_BACKUP},
476 {"verify", JT_VERIFY},
477 {"restore", JT_RESTORE},
478 {"migrate", JT_MIGRATE},
484 /* Keywords (RHS) permitted in Selection type records
488 struct s_jt migtypes[] = {
489 {"smallestvolume", MT_SMALLEST_VOL},
490 {"oldestvolume", MT_OLDEST_VOL},
491 {"pooloccupancy", MT_POOL_OCCUPANCY},
492 {"pooltime", MT_POOL_TIME},
493 {"client", MT_CLIENT},
494 {"volume", MT_VOLUME},
496 {"sqlquery", MT_SQLQUERY},
502 /* Options permitted in Restore replace= */
503 struct s_kw ReplaceOptions[] = {
504 {"always", REPLACE_ALWAYS},
505 {"ifnewer", REPLACE_IFNEWER},
506 {"ifolder", REPLACE_IFOLDER},
507 {"never", REPLACE_NEVER},
511 const char *level_to_str(int level)
514 static char level_no[30];
515 const char *str = level_no;
517 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
518 for (i=0; joblevels[i].level_name; i++) {
519 if (level == (int)joblevels[i].level) {
520 str = joblevels[i].level_name;
527 /* Dump contents of resource */
528 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
530 URES *res = (URES *)reshdr;
532 char ed1[100], ed2[100], ed3[100];
536 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
539 if (type < 0) { /* no recursion */
545 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
546 reshdr->name, res->res_dir.MaxConcurrentJobs,
547 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
548 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
549 if (res->res_dir.query_file) {
550 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
552 if (res->res_dir.messages) {
553 sendit(sock, _(" --> "));
554 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
558 sendit(sock, _("Console: name=%s SSL=%d\n"),
559 res->res_con.hdr.name, res->res_con.tls_enable);
562 if (res->res_counter.WrapCounter) {
563 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
564 res->res_counter.hdr.name, res->res_counter.MinValue,
565 res->res_counter.MaxValue, res->res_counter.CurrentValue,
566 res->res_counter.WrapCounter->hdr.name);
568 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
569 res->res_counter.hdr.name, res->res_counter.MinValue,
570 res->res_counter.MaxValue);
572 if (res->res_counter.Catalog) {
573 sendit(sock, _(" --> "));
574 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
579 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
580 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
581 res->res_client.MaxConcurrentJobs);
582 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
583 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
584 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
585 res->res_client.AutoPrune);
586 if (res->res_client.catalog) {
587 sendit(sock, _(" --> "));
588 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
595 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
596 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
597 " poolid=%s volname=%s MediaType=%s\n"),
598 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
599 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
600 dev->offline, dev->autochanger,
601 edit_uint64(dev->PoolId, ed1),
602 dev->VolumeName, dev->MediaType);
606 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
607 " DeviceName=%s MediaType=%s StorageId=%s\n"),
608 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
609 res->res_store.MaxConcurrentJobs,
610 res->res_store.dev_name(),
611 res->res_store.media_type,
612 edit_int64(res->res_store.StorageId, ed1));
616 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
617 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
618 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
619 res->res_cat.db_port, res->res_cat.db_name,
620 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
621 res->res_cat.mult_db_connections);
626 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
627 type == R_JOB ? _("Job") : _("JobDefs"),
628 res->res_job.hdr.name, res->res_job.JobType,
629 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
630 res->res_job.enabled);
631 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
632 res->res_job.MaxConcurrentJobs,
633 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
634 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
635 res->res_job.spool_data, res->res_job.write_part_after_job);
636 if (res->res_job.spool_size) {
637 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
639 if (res->res_job.stats_enabled) {
640 sendit(sock, _(" StatsEnabled=%d\n"), res->res_job.stats_enabled);
642 if (res->res_job.JobType == JT_BACKUP) {
643 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
645 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
646 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
648 if (res->res_job.client) {
649 sendit(sock, _(" --> "));
650 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
652 if (res->res_job.fileset) {
653 sendit(sock, _(" --> "));
654 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
656 if (res->res_job.schedule) {
657 sendit(sock, _(" --> "));
658 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
660 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
661 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
663 if (res->res_job.RegexWhere) {
664 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
666 if (res->res_job.RestoreBootstrap) {
667 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
669 if (res->res_job.WriteBootstrap) {
670 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
672 if (res->res_job.PluginOptions) {
673 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
675 if (res->res_job.MaxRunTime) {
676 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
678 if (res->res_job.MaxWaitTime) {
679 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
681 if (res->res_job.MaxStartDelay) {
682 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
684 if (res->res_job.storage) {
686 foreach_alist(store, res->res_job.storage) {
687 sendit(sock, _(" --> "));
688 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
691 if (res->res_job.RunScripts) {
693 foreach_alist(script, res->res_job.RunScripts) {
694 sendit(sock, _(" --> RunScript\n"));
695 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
696 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
697 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
698 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
699 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
700 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
703 if (res->res_job.pool) {
704 sendit(sock, _(" --> "));
705 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
707 if (res->res_job.full_pool) {
708 sendit(sock, _(" --> "));
709 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
711 if (res->res_job.inc_pool) {
712 sendit(sock, _(" --> "));
713 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
715 if (res->res_job.diff_pool) {
716 sendit(sock, _(" --> "));
717 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
719 if (res->res_job.verify_job) {
720 sendit(sock, _(" --> "));
721 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
723 if (res->res_job.run_cmds) {
725 foreach_alist(runcmd, res->res_job.run_cmds) {
726 sendit(sock, _(" --> Run=%s\n"), runcmd);
729 if (res->res_job.selection_pattern) {
730 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
732 if (res->res_job.messages) {
733 sendit(sock, _(" --> "));
734 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
741 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
742 for (i=0; i<res->res_fs.num_includes; i++) {
743 INCEXE *incexe = res->res_fs.include_items[i];
744 for (j=0; j<incexe->num_opts; j++) {
745 FOPTS *fo = incexe->opts_list[j];
746 sendit(sock, " O %s\n", fo->opts);
748 bool enhanced_wild = false;
749 for (k=0; fo->opts[k]!='\0'; k++) {
750 if (fo->opts[k]=='W') {
751 enhanced_wild = true;
756 for (k=0; k<fo->regex.size(); k++) {
757 sendit(sock, " R %s\n", fo->regex.get(k));
759 for (k=0; k<fo->regexdir.size(); k++) {
760 sendit(sock, " RD %s\n", fo->regexdir.get(k));
762 for (k=0; k<fo->regexfile.size(); k++) {
763 sendit(sock, " RF %s\n", fo->regexfile.get(k));
765 for (k=0; k<fo->wild.size(); k++) {
766 sendit(sock, " W %s\n", fo->wild.get(k));
768 for (k=0; k<fo->wilddir.size(); k++) {
769 sendit(sock, " WD %s\n", fo->wilddir.get(k));
771 for (k=0; k<fo->wildfile.size(); k++) {
772 sendit(sock, " WF %s\n", fo->wildfile.get(k));
774 for (k=0; k<fo->wildbase.size(); k++) {
775 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
777 for (k=0; k<fo->base.size(); k++) {
778 sendit(sock, " B %s\n", fo->base.get(k));
780 for (k=0; k<fo->fstype.size(); k++) {
781 sendit(sock, " X %s\n", fo->fstype.get(k));
783 for (k=0; k<fo->drivetype.size(); k++) {
784 sendit(sock, " XD %s\n", fo->drivetype.get(k));
787 sendit(sock, " G %s\n", fo->plugin);
790 sendit(sock, " D %s\n", fo->reader);
793 sendit(sock, " T %s\n", fo->writer);
795 sendit(sock, " N\n");
797 for (j=0; j<incexe->name_list.size(); j++) {
798 sendit(sock, " I %s\n", incexe->name_list.get(j));
800 if (incexe->name_list.size()) {
801 sendit(sock, " N\n");
803 for (j=0; j<incexe->plugin_list.size(); j++) {
804 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
806 if (incexe->plugin_list.size()) {
807 sendit(sock, " N\n");
812 for (i=0; i<res->res_fs.num_excludes; i++) {
813 INCEXE *incexe = res->res_fs.exclude_items[i];
814 for (j=0; j<incexe->name_list.size(); j++) {
815 sendit(sock, " E %s\n", incexe->name_list.get(j));
817 if (incexe->name_list.size()) {
818 sendit(sock, " N\n");
825 if (res->res_sch.run) {
827 RUN *run = res->res_sch.run;
828 char buf[1000], num[30];
829 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
834 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
835 bstrncpy(buf, _(" hour="), sizeof(buf));
836 for (i=0; i<24; i++) {
837 if (bit_is_set(i, run->hour)) {
838 bsnprintf(num, sizeof(num), "%d ", i);
839 bstrncat(buf, num, sizeof(buf));
842 bstrncat(buf, "\n", sizeof(buf));
844 bstrncpy(buf, _(" mday="), sizeof(buf));
845 for (i=0; i<31; i++) {
846 if (bit_is_set(i, run->mday)) {
847 bsnprintf(num, sizeof(num), "%d ", i);
848 bstrncat(buf, num, sizeof(buf));
851 bstrncat(buf, "\n", sizeof(buf));
853 bstrncpy(buf, _(" month="), sizeof(buf));
854 for (i=0; i<12; i++) {
855 if (bit_is_set(i, run->month)) {
856 bsnprintf(num, sizeof(num), "%d ", i);
857 bstrncat(buf, num, sizeof(buf));
860 bstrncat(buf, "\n", sizeof(buf));
862 bstrncpy(buf, _(" wday="), sizeof(buf));
863 for (i=0; i<7; i++) {
864 if (bit_is_set(i, run->wday)) {
865 bsnprintf(num, sizeof(num), "%d ", i);
866 bstrncat(buf, num, sizeof(buf));
869 bstrncat(buf, "\n", sizeof(buf));
871 bstrncpy(buf, _(" wom="), sizeof(buf));
872 for (i=0; i<5; i++) {
873 if (bit_is_set(i, run->wom)) {
874 bsnprintf(num, sizeof(num), "%d ", i);
875 bstrncat(buf, num, sizeof(buf));
878 bstrncat(buf, "\n", sizeof(buf));
880 bstrncpy(buf, _(" woy="), sizeof(buf));
881 for (i=0; i<54; i++) {
882 if (bit_is_set(i, run->woy)) {
883 bsnprintf(num, sizeof(num), "%d ", i);
884 bstrncat(buf, num, sizeof(buf));
887 bstrncat(buf, "\n", sizeof(buf));
889 sendit(sock, _(" mins=%d\n"), run->minute);
891 sendit(sock, _(" --> "));
892 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
895 sendit(sock, _(" --> "));
896 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
899 sendit(sock, _(" --> "));
900 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
902 /* If another Run record is chained in, go print it */
908 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
913 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
914 res->res_pool.pool_type);
915 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
916 res->res_pool.use_catalog, res->res_pool.use_volume_once,
917 res->res_pool.catalog_files);
918 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
919 res->res_pool.max_volumes, res->res_pool.AutoPrune,
920 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
921 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
922 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
923 res->res_pool.Recycle,
924 NPRT(res->res_pool.label_format));
925 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
926 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
927 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
928 res->res_pool.recycle_oldest_volume,
929 res->res_pool.purge_oldest_volume);
930 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
931 res->res_pool.MaxVolJobs,
932 res->res_pool.MaxVolFiles,
933 edit_uint64(res->res_pool.MaxVolFiles, ed1));
934 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
935 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
936 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
937 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
938 if (res->res_pool.NextPool) {
939 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
941 if (res->res_pool.RecyclePool) {
942 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
944 if (res->res_pool.catalog) {
945 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
947 if (res->res_pool.storage) {
949 foreach_alist(store, res->res_pool.storage) {
950 sendit(sock, _(" --> "));
951 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
954 if (res->res_pool.CopyPool) {
956 foreach_alist(copy, res->res_pool.CopyPool) {
957 sendit(sock, _(" --> "));
958 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
965 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
966 if (res->res_msgs.mail_cmd)
967 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
968 if (res->res_msgs.operator_cmd)
969 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
973 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
976 if (recurse && res->res_dir.hdr.next) {
977 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
982 * Free all the members of an INCEXE structure
984 static void free_incexe(INCEXE *incexe)
986 incexe->name_list.destroy();
987 incexe->plugin_list.destroy();
988 for (int i=0; i<incexe->num_opts; i++) {
989 FOPTS *fopt = incexe->opts_list[i];
990 fopt->regex.destroy();
991 fopt->regexdir.destroy();
992 fopt->regexfile.destroy();
993 fopt->wild.destroy();
994 fopt->wilddir.destroy();
995 fopt->wildfile.destroy();
996 fopt->wildbase.destroy();
997 fopt->base.destroy();
998 fopt->fstype.destroy();
999 fopt->drivetype.destroy();
1011 if (incexe->opts_list) {
1012 free(incexe->opts_list);
1018 * Free memory of resource -- called when daemon terminates.
1019 * NB, we don't need to worry about freeing any references
1020 * to other resources as they will be freed when that
1021 * resource chain is traversed. Mainly we worry about freeing
1022 * allocated strings (names).
1024 void free_resource(RES *sres, int type)
1027 RES *nres; /* next resource if linked */
1028 URES *res = (URES *)sres;
1033 /* common stuff -- free the resource name and description */
1034 nres = (RES *)res->res_dir.hdr.next;
1035 if (res->res_dir.hdr.name) {
1036 free(res->res_dir.hdr.name);
1038 if (res->res_dir.hdr.desc) {
1039 free(res->res_dir.hdr.desc);
1044 if (res->res_dir.working_directory) {
1045 free(res->res_dir.working_directory);
1047 if (res->res_dir.scripts_directory) {
1048 free((char *)res->res_dir.scripts_directory);
1050 if (res->res_dir.plugin_directory) {
1051 free((char *)res->res_dir.plugin_directory);
1053 if (res->res_dir.pid_directory) {
1054 free(res->res_dir.pid_directory);
1056 if (res->res_dir.subsys_directory) {
1057 free(res->res_dir.subsys_directory);
1059 if (res->res_dir.password) {
1060 free(res->res_dir.password);
1062 if (res->res_dir.query_file) {
1063 free(res->res_dir.query_file);
1065 if (res->res_dir.DIRaddrs) {
1066 free_addresses(res->res_dir.DIRaddrs);
1068 if (res->res_dir.tls_ctx) {
1069 free_tls_context(res->res_dir.tls_ctx);
1071 if (res->res_dir.tls_ca_certfile) {
1072 free(res->res_dir.tls_ca_certfile);
1074 if (res->res_dir.tls_ca_certdir) {
1075 free(res->res_dir.tls_ca_certdir);
1077 if (res->res_dir.tls_certfile) {
1078 free(res->res_dir.tls_certfile);
1080 if (res->res_dir.tls_keyfile) {
1081 free(res->res_dir.tls_keyfile);
1083 if (res->res_dir.tls_dhfile) {
1084 free(res->res_dir.tls_dhfile);
1086 if (res->res_dir.tls_allowed_cns) {
1087 delete res->res_dir.tls_allowed_cns;
1094 if (res->res_con.password) {
1095 free(res->res_con.password);
1097 if (res->res_con.tls_ctx) {
1098 free_tls_context(res->res_con.tls_ctx);
1100 if (res->res_con.tls_ca_certfile) {
1101 free(res->res_con.tls_ca_certfile);
1103 if (res->res_con.tls_ca_certdir) {
1104 free(res->res_con.tls_ca_certdir);
1106 if (res->res_con.tls_certfile) {
1107 free(res->res_con.tls_certfile);
1109 if (res->res_con.tls_keyfile) {
1110 free(res->res_con.tls_keyfile);
1112 if (res->res_con.tls_dhfile) {
1113 free(res->res_con.tls_dhfile);
1115 if (res->res_con.tls_allowed_cns) {
1116 delete res->res_con.tls_allowed_cns;
1118 for (int i=0; i<Num_ACL; i++) {
1119 if (res->res_con.ACL_lists[i]) {
1120 delete res->res_con.ACL_lists[i];
1121 res->res_con.ACL_lists[i] = NULL;
1126 if (res->res_client.address) {
1127 free(res->res_client.address);
1129 if (res->res_client.password) {
1130 free(res->res_client.password);
1132 if (res->res_client.tls_ctx) {
1133 free_tls_context(res->res_client.tls_ctx);
1135 if (res->res_client.tls_ca_certfile) {
1136 free(res->res_client.tls_ca_certfile);
1138 if (res->res_client.tls_ca_certdir) {
1139 free(res->res_client.tls_ca_certdir);
1141 if (res->res_client.tls_certfile) {
1142 free(res->res_client.tls_certfile);
1144 if (res->res_client.tls_keyfile) {
1145 free(res->res_client.tls_keyfile);
1147 if (res->res_client.tls_allowed_cns) {
1148 delete res->res_client.tls_allowed_cns;
1152 if (res->res_store.address) {
1153 free(res->res_store.address);
1155 if (res->res_store.password) {
1156 free(res->res_store.password);
1158 if (res->res_store.media_type) {
1159 free(res->res_store.media_type);
1161 if (res->res_store.device) {
1162 delete res->res_store.device;
1164 if (res->res_store.tls_ctx) {
1165 free_tls_context(res->res_store.tls_ctx);
1167 if (res->res_store.tls_ca_certfile) {
1168 free(res->res_store.tls_ca_certfile);
1170 if (res->res_store.tls_ca_certdir) {
1171 free(res->res_store.tls_ca_certdir);
1173 if (res->res_store.tls_certfile) {
1174 free(res->res_store.tls_certfile);
1176 if (res->res_store.tls_keyfile) {
1177 free(res->res_store.tls_keyfile);
1181 if (res->res_cat.db_address) {
1182 free(res->res_cat.db_address);
1184 if (res->res_cat.db_socket) {
1185 free(res->res_cat.db_socket);
1187 if (res->res_cat.db_user) {
1188 free(res->res_cat.db_user);
1190 if (res->res_cat.db_name) {
1191 free(res->res_cat.db_name);
1193 if (res->res_cat.db_driver) {
1194 free(res->res_cat.db_driver);
1196 if (res->res_cat.db_password) {
1197 free(res->res_cat.db_password);
1201 if ((num=res->res_fs.num_includes)) {
1202 while (--num >= 0) {
1203 free_incexe(res->res_fs.include_items[num]);
1205 free(res->res_fs.include_items);
1207 res->res_fs.num_includes = 0;
1208 if ((num=res->res_fs.num_excludes)) {
1209 while (--num >= 0) {
1210 free_incexe(res->res_fs.exclude_items[num]);
1212 free(res->res_fs.exclude_items);
1214 res->res_fs.num_excludes = 0;
1217 if (res->res_pool.pool_type) {
1218 free(res->res_pool.pool_type);
1220 if (res->res_pool.label_format) {
1221 free(res->res_pool.label_format);
1223 if (res->res_pool.cleaning_prefix) {
1224 free(res->res_pool.cleaning_prefix);
1226 if (res->res_pool.storage) {
1227 delete res->res_pool.storage;
1231 if (res->res_sch.run) {
1233 nrun = res->res_sch.run;
1243 if (res->res_job.RestoreWhere) {
1244 free(res->res_job.RestoreWhere);
1246 if (res->res_job.RegexWhere) {
1247 free(res->res_job.RegexWhere);
1249 if (res->res_job.strip_prefix) {
1250 free(res->res_job.strip_prefix);
1252 if (res->res_job.add_prefix) {
1253 free(res->res_job.add_prefix);
1255 if (res->res_job.add_suffix) {
1256 free(res->res_job.add_suffix);
1258 if (res->res_job.RestoreBootstrap) {
1259 free(res->res_job.RestoreBootstrap);
1261 if (res->res_job.WriteBootstrap) {
1262 free(res->res_job.WriteBootstrap);
1264 if (res->res_job.PluginOptions) {
1265 free(res->res_job.PluginOptions);
1267 if (res->res_job.selection_pattern) {
1268 free(res->res_job.selection_pattern);
1270 if (res->res_job.run_cmds) {
1271 delete res->res_job.run_cmds;
1273 if (res->res_job.storage) {
1274 delete res->res_job.storage;
1276 if (res->res_job.RunScripts) {
1277 free_runscripts(res->res_job.RunScripts);
1278 delete res->res_job.RunScripts;
1282 if (res->res_msgs.mail_cmd) {
1283 free(res->res_msgs.mail_cmd);
1285 if (res->res_msgs.operator_cmd) {
1286 free(res->res_msgs.operator_cmd);
1288 free_msgs_res((MSGS *)res); /* free message resource */
1292 printf(_("Unknown resource type %d in free_resource.\n"), type);
1294 /* Common stuff again -- free the resource, recurse to next one */
1299 free_resource(nres, type);
1304 * Save the new resource by chaining it into the head list for
1305 * the resource. If this is pass 2, we update any resource
1306 * pointers because they may not have been defined until
1309 void save_resource(int type, RES_ITEM *items, int pass)
1312 int rindex = type - r_first;
1316 /* Check Job requirements after applying JobDefs */
1317 if (type != R_JOB && type != R_JOBDEFS) {
1319 * Ensure that all required items are present
1321 for (i=0; items[i].name; i++) {
1322 if (items[i].flags & ITEM_REQUIRED) {
1323 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1324 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1325 items[i].name, resources[rindex]);
1328 /* If this triggers, take a look at lib/parse_conf.h */
1329 if (i >= MAX_RES_ITEMS) {
1330 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1333 } else if (type == R_JOB) {
1335 * Ensure that the name item is present
1337 if (items[0].flags & ITEM_REQUIRED) {
1338 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1339 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1340 items[0].name, resources[rindex]);
1346 * During pass 2 in each "store" routine, we looked up pointers
1347 * to all the resources referrenced in the current resource, now we
1348 * must copy their addresses from the static record to the allocated
1353 /* Resources not containing a resource */
1361 * Resources containing another resource or alist. First
1362 * look up the resource which contains another resource. It
1363 * was written during pass 1. Then stuff in the pointers to
1364 * the resources it contains, which were inserted this pass.
1365 * Finally, it will all be stored back.
1368 /* Find resource saved in pass 1 */
1369 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1370 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1372 /* Explicitly copy resource pointers from this pass (res_all) */
1373 res->res_pool.NextPool = res_all.res_pool.NextPool;
1374 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1375 res->res_pool.storage = res_all.res_pool.storage;
1376 res->res_pool.catalog = res_all.res_pool.catalog;
1379 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1380 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1382 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1385 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1386 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1388 res->res_dir.messages = res_all.res_dir.messages;
1389 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1392 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1393 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1394 res_all.res_dir.hdr.name);
1396 /* we must explicitly copy the device alist pointer */
1397 res->res_store.device = res_all.res_store.device;
1401 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1402 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1403 res_all.res_dir.hdr.name);
1405 res->res_job.messages = res_all.res_job.messages;
1406 res->res_job.schedule = res_all.res_job.schedule;
1407 res->res_job.client = res_all.res_job.client;
1408 res->res_job.fileset = res_all.res_job.fileset;
1409 res->res_job.storage = res_all.res_job.storage;
1410 res->res_job.pool = res_all.res_job.pool;
1411 res->res_job.full_pool = res_all.res_job.full_pool;
1412 res->res_job.inc_pool = res_all.res_job.inc_pool;
1413 res->res_job.diff_pool = res_all.res_job.diff_pool;
1414 res->res_job.verify_job = res_all.res_job.verify_job;
1415 res->res_job.jobdefs = res_all.res_job.jobdefs;
1416 res->res_job.run_cmds = res_all.res_job.run_cmds;
1417 res->res_job.RunScripts = res_all.res_job.RunScripts;
1419 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1420 * is not very useful)
1421 * We have to set_bit(index, res_all.hdr.item_present);
1422 * or something like that
1425 /* we take RegexWhere before all other options */
1426 if (!res->res_job.RegexWhere
1428 (res->res_job.strip_prefix ||
1429 res->res_job.add_suffix ||
1430 res->res_job.add_prefix))
1432 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1433 res->res_job.add_prefix,
1434 res->res_job.add_suffix);
1435 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1436 bregexp_build_where(res->res_job.RegexWhere, len,
1437 res->res_job.strip_prefix,
1438 res->res_job.add_prefix,
1439 res->res_job.add_suffix);
1440 /* TODO: test bregexp */
1443 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1444 free(res->res_job.RestoreWhere);
1445 res->res_job.RestoreWhere = NULL;
1450 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1451 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1453 res->res_counter.Catalog = res_all.res_counter.Catalog;
1454 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1458 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1459 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1461 res->res_client.catalog = res_all.res_client.catalog;
1462 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1466 * Schedule is a bit different in that it contains a RUN record
1467 * chain which isn't a "named" resource. This chain was linked
1468 * in by run_conf.c during pass 2, so here we jam the pointer
1469 * into the Schedule resource.
1471 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1472 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1474 res->res_sch.run = res_all.res_sch.run;
1477 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1481 /* Note, the resource name was already saved during pass 1,
1482 * so here, we can just release it.
1484 if (res_all.res_dir.hdr.name) {
1485 free(res_all.res_dir.hdr.name);
1486 res_all.res_dir.hdr.name = NULL;
1488 if (res_all.res_dir.hdr.desc) {
1489 free(res_all.res_dir.hdr.desc);
1490 res_all.res_dir.hdr.desc = NULL;
1496 * The following code is only executed during pass 1
1500 size = sizeof(DIRRES);
1503 size = sizeof(CONRES);
1506 size =sizeof(CLIENT);
1509 size = sizeof(STORE);
1519 size = sizeof(FILESET);
1522 size = sizeof(SCHED);
1525 size = sizeof(POOL);
1528 size = sizeof(MSGS);
1531 size = sizeof(COUNTER);
1537 printf(_("Unknown resource type %d in save_resource.\n"), type);
1543 res = (URES *)malloc(size);
1544 memcpy(res, &res_all, size);
1545 if (!res_head[rindex]) {
1546 res_head[rindex] = (RES *)res; /* store first entry */
1547 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1548 res->res_dir.hdr.name, rindex);
1551 if (res->res_dir.hdr.name == NULL) {
1552 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1555 /* Add new res to end of chain */
1556 for (last=next=res_head[rindex]; next; next=next->next) {
1558 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1559 Emsg2(M_ERROR_TERM, 0,
1560 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1561 resources[rindex].name, res->res_dir.hdr.name);
1564 last->next = (RES *)res;
1565 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1566 res->res_dir.hdr.name, rindex, pass);
1572 * Store Device. Note, the resource is created upon the
1573 * first reference. The details of the resource are obtained
1574 * later from the SD.
1576 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1580 int rindex = R_DEVICE - r_first;
1581 int size = sizeof(DEVICE);
1585 token = lex_get_token(lc, T_NAME);
1586 if (!res_head[rindex]) {
1587 res = (URES *)malloc(size);
1588 memset(res, 0, size);
1589 res->res_dev.hdr.name = bstrdup(lc->str);
1590 res_head[rindex] = (RES *)res; /* store first entry */
1591 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1592 res->res_dir.hdr.name, rindex);
1595 /* See if it is already defined */
1596 for (next=res_head[rindex]; next->next; next=next->next) {
1597 if (strcmp(next->name, lc->str) == 0) {
1603 res = (URES *)malloc(size);
1604 memset(res, 0, size);
1605 res->res_dev.hdr.name = bstrdup(lc->str);
1606 next->next = (RES *)res;
1607 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1608 res->res_dir.hdr.name, rindex, pass);
1613 set_bit(index, res_all.hdr.item_present);
1615 store_alist_res(lc, item, index, pass);
1620 * Store Migration/Copy type
1623 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1627 token = lex_get_token(lc, T_NAME);
1628 /* Store the type both pass 1 and pass 2 */
1629 for (i=0; migtypes[i].type_name; i++) {
1630 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1631 *(uint32_t *)(item->value) = migtypes[i].job_type;
1637 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1640 set_bit(index, res_all.hdr.item_present);
1646 * Store JobType (backup, verify, restore)
1649 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1653 token = lex_get_token(lc, T_NAME);
1654 /* Store the type both pass 1 and pass 2 */
1655 for (i=0; jobtypes[i].type_name; i++) {
1656 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1657 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1663 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1666 set_bit(index, res_all.hdr.item_present);
1670 * Store Job Level (Full, Incremental, ...)
1673 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1677 token = lex_get_token(lc, T_NAME);
1678 /* Store the level pass 2 so that type is defined */
1679 for (i=0; joblevels[i].level_name; i++) {
1680 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1681 *(uint32_t *)(item->value) = joblevels[i].level;
1687 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1690 set_bit(index, res_all.hdr.item_present);
1694 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1697 token = lex_get_token(lc, T_NAME);
1698 /* Scan Replacement options */
1699 for (i=0; ReplaceOptions[i].name; i++) {
1700 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1701 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1707 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1710 set_bit(index, res_all.hdr.item_present);
1714 * Store ACL (access control list)
1717 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1722 token = lex_get_token(lc, T_STRING);
1724 if (((alist **)item->value)[item->code] == NULL) {
1725 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1726 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1728 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1729 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1731 token = lex_get_token(lc, T_ALL);
1732 if (token == T_COMMA) {
1733 continue; /* get another ACL */
1737 set_bit(index, res_all.hdr.item_present);
1740 /* We build RunScripts items here */
1741 static RUNSCRIPT res_runscript;
1743 /* Store a runscript->when in a bit field */
1744 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1746 lex_get_token(lc, T_NAME);
1748 if (strcasecmp(lc->str, "before") == 0) {
1749 *(uint32_t *)(item->value) = SCRIPT_Before ;
1750 } else if (strcasecmp(lc->str, "after") == 0) {
1751 *(uint32_t *)(item->value) = SCRIPT_After;
1752 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1753 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1754 } else if (strcasecmp(lc->str, "always") == 0) {
1755 *(uint32_t *)(item->value) = SCRIPT_Any;
1757 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1762 /* Store a runscript->target
1765 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1767 lex_get_token(lc, T_STRING);
1770 if (strcmp(lc->str, "%c") == 0) {
1771 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1772 } else if (strcasecmp(lc->str, "yes") == 0) {
1773 ((RUNSCRIPT*) item->value)->set_target("%c");
1774 } else if (strcasecmp(lc->str, "no") == 0) {
1775 ((RUNSCRIPT*) item->value)->set_target("");
1777 RES *res = GetResWithName(R_CLIENT, lc->str);
1779 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1780 lc->str, lc->line_no, lc->line);
1783 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1790 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1792 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1794 lex_get_token(lc, T_STRING);
1797 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1798 POOLMEM *c = get_pool_memory(PM_FNAME);
1799 /* Each runscript command takes 2 entries in commands list */
1800 pm_strcpy(c, lc->str);
1801 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1802 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1807 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1809 lex_get_token(lc, T_STRING);
1810 alist **runscripts = (alist **)(item->value) ;
1813 RUNSCRIPT *script = new_runscript();
1814 script->set_job_code_callback(job_code_callback_filesetname);
1816 script->set_command(lc->str);
1818 /* TODO: remove all script->old_proto with bacula 1.42 */
1820 if (strcmp(item->name, "runbeforejob") == 0) {
1821 script->when = SCRIPT_Before;
1822 script->fail_on_error = true;
1823 script->set_target("");
1825 } else if (strcmp(item->name, "runafterjob") == 0) {
1826 script->when = SCRIPT_After;
1827 script->on_success = true;
1828 script->on_failure = false;
1829 script->set_target("");
1831 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1832 script->old_proto = true;
1833 script->when = SCRIPT_After;
1834 script->set_target("%c");
1835 script->on_success = true;
1836 script->on_failure = false;
1838 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1839 script->old_proto = true;
1840 script->when = SCRIPT_Before;
1841 script->set_target("%c");
1842 script->fail_on_error = true;
1844 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1845 script->when = SCRIPT_After;
1846 script->on_failure = true;
1847 script->on_success = false;
1848 script->set_target("");
1851 if (*runscripts == NULL) {
1852 *runscripts = New(alist(10, not_owned_by_alist));
1855 (*runscripts)->append(script);
1862 /* Store a bool in a bit field without modifing res_all.hdr
1863 * We can also add an option to store_bool to skip res_all.hdr
1865 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1867 lex_get_token(lc, T_NAME);
1868 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1869 *(bool *)(item->value) = true;
1870 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1871 *(bool *)(item->value) = false;
1873 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1879 * new RunScript items
1880 * name handler value code flags default_value
1882 static RES_ITEM runscript_items[] = {
1883 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1884 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1885 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1886 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1887 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1888 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1889 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1890 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1891 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1892 {NULL, NULL, {0}, 0, 0, 0}
1896 * Store RunScript info
1898 * Note, when this routine is called, we are inside a Job
1899 * resource. We treat the RunScript like a sort of
1900 * mini-resource within the Job resource.
1902 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1906 alist **runscripts = (alist **)(item->value) ;
1908 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1910 token = lex_get_token(lc, T_SKIP_EOL);
1912 if (token != T_BOB) {
1913 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1915 /* setting on_success, on_failure, fail_on_error */
1916 res_runscript.reset_default();
1919 res_runscript.commands = New(alist(10, not_owned_by_alist));
1922 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1923 if (token == T_EOB) {
1926 if (token != T_IDENTIFIER) {
1927 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1929 for (i=0; runscript_items[i].name; i++) {
1930 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1931 token = lex_get_token(lc, T_SKIP_EOL);
1932 if (token != T_EQUALS) {
1933 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1936 /* Call item handler */
1937 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1944 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1949 /* run on client by default */
1950 if (res_runscript.target == NULL) {
1951 res_runscript.set_target("%c");
1953 if (*runscripts == NULL) {
1954 *runscripts = New(alist(10, not_owned_by_alist));
1957 * commands list contains 2 values per command
1958 * - POOLMEM command string (ex: /bin/true)
1959 * - int command type (ex: SHELL_CMD)
1961 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1962 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1963 t = (long)res_runscript.commands->pop();
1964 RUNSCRIPT *script = new_runscript();
1965 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1966 script->command = c;
1967 script->cmd_type = t;
1968 /* target is taken from res_runscript, each runscript object have
1971 script->target = NULL;
1972 script->set_target(res_runscript.target);
1974 (*runscripts)->append(script);
1977 delete res_runscript.commands;
1978 /* setting on_success, on_failure... cleanup target field */
1979 res_runscript.reset_default(true);
1983 set_bit(index, res_all.hdr.item_present);
1986 /* callback function for edit_job_codes */
1987 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1989 if (param[0] == 'f') {
1990 return jcr->fileset->name();