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 Kern Sibbald.
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 int32_t r_first = R_FIRST;
61 int32_t r_last = R_LAST;
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 int32_t 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 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
460 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
461 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
462 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
463 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
464 {"Data", L_VERIFY_DATA, JT_VERIFY},
465 {" ", L_NONE, JT_ADMIN},
466 {" ", L_NONE, JT_RESTORE},
470 /* Keywords (RHS) permitted in Job type records
474 struct s_jt jobtypes[] = {
475 {"backup", JT_BACKUP},
477 {"verify", JT_VERIFY},
478 {"restore", JT_RESTORE},
479 {"migrate", JT_MIGRATE},
485 /* Keywords (RHS) permitted in Selection type records
489 struct s_jt migtypes[] = {
490 {"smallestvolume", MT_SMALLEST_VOL},
491 {"oldestvolume", MT_OLDEST_VOL},
492 {"pooloccupancy", MT_POOL_OCCUPANCY},
493 {"pooltime", MT_POOL_TIME},
494 {"client", MT_CLIENT},
495 {"volume", MT_VOLUME},
497 {"sqlquery", MT_SQLQUERY},
503 /* Options permitted in Restore replace= */
504 struct s_kw ReplaceOptions[] = {
505 {"always", REPLACE_ALWAYS},
506 {"ifnewer", REPLACE_IFNEWER},
507 {"ifolder", REPLACE_IFOLDER},
508 {"never", REPLACE_NEVER},
512 const char *level_to_str(int level)
515 static char level_no[30];
516 const char *str = level_no;
518 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
519 for (i=0; joblevels[i].level_name; i++) {
520 if (level == (int)joblevels[i].level) {
521 str = joblevels[i].level_name;
528 /* Dump contents of resource */
529 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
531 URES *res = (URES *)reshdr;
533 char ed1[100], ed2[100], ed3[100];
537 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
540 if (type < 0) { /* no recursion */
546 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
547 reshdr->name, res->res_dir.MaxConcurrentJobs,
548 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
549 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
550 if (res->res_dir.query_file) {
551 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
553 if (res->res_dir.messages) {
554 sendit(sock, _(" --> "));
555 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
559 sendit(sock, _("Console: name=%s SSL=%d\n"),
560 res->res_con.hdr.name, res->res_con.tls_enable);
563 if (res->res_counter.WrapCounter) {
564 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
565 res->res_counter.hdr.name, res->res_counter.MinValue,
566 res->res_counter.MaxValue, res->res_counter.CurrentValue,
567 res->res_counter.WrapCounter->hdr.name);
569 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
570 res->res_counter.hdr.name, res->res_counter.MinValue,
571 res->res_counter.MaxValue);
573 if (res->res_counter.Catalog) {
574 sendit(sock, _(" --> "));
575 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
580 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
581 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
582 res->res_client.MaxConcurrentJobs);
583 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
584 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
585 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
586 res->res_client.AutoPrune);
587 if (res->res_client.catalog) {
588 sendit(sock, _(" --> "));
589 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
596 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
597 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
598 " poolid=%s volname=%s MediaType=%s\n"),
599 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
600 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
601 dev->offline, dev->autochanger,
602 edit_uint64(dev->PoolId, ed1),
603 dev->VolumeName, dev->MediaType);
607 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
608 " DeviceName=%s MediaType=%s StorageId=%s\n"),
609 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
610 res->res_store.MaxConcurrentJobs,
611 res->res_store.dev_name(),
612 res->res_store.media_type,
613 edit_int64(res->res_store.StorageId, ed1));
617 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
618 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
619 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
620 res->res_cat.db_port, res->res_cat.db_name,
621 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
622 res->res_cat.mult_db_connections);
627 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
628 type == R_JOB ? _("Job") : _("JobDefs"),
629 res->res_job.hdr.name, res->res_job.JobType,
630 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
631 res->res_job.enabled);
632 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
633 res->res_job.MaxConcurrentJobs,
634 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
635 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
636 res->res_job.spool_data, res->res_job.write_part_after_job);
637 if (res->res_job.spool_size) {
638 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
640 if (res->res_job.stats_enabled) {
641 sendit(sock, _(" StatsEnabled=%d\n"), res->res_job.stats_enabled);
643 if (res->res_job.JobType == JT_BACKUP) {
644 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
646 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
647 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
649 if (res->res_job.client) {
650 sendit(sock, _(" --> "));
651 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
653 if (res->res_job.fileset) {
654 sendit(sock, _(" --> "));
655 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
657 if (res->res_job.schedule) {
658 sendit(sock, _(" --> "));
659 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
661 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
662 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
664 if (res->res_job.RegexWhere) {
665 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
667 if (res->res_job.RestoreBootstrap) {
668 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
670 if (res->res_job.WriteBootstrap) {
671 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
673 if (res->res_job.PluginOptions) {
674 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
676 if (res->res_job.MaxRunTime) {
677 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
679 if (res->res_job.MaxWaitTime) {
680 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
682 if (res->res_job.MaxStartDelay) {
683 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
685 if (res->res_job.storage) {
687 foreach_alist(store, res->res_job.storage) {
688 sendit(sock, _(" --> "));
689 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
692 if (res->res_job.RunScripts) {
694 foreach_alist(script, res->res_job.RunScripts) {
695 sendit(sock, _(" --> RunScript\n"));
696 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
697 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
698 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
699 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
700 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
701 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
704 if (res->res_job.pool) {
705 sendit(sock, _(" --> "));
706 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
708 if (res->res_job.full_pool) {
709 sendit(sock, _(" --> "));
710 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
712 if (res->res_job.inc_pool) {
713 sendit(sock, _(" --> "));
714 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
716 if (res->res_job.diff_pool) {
717 sendit(sock, _(" --> "));
718 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
720 if (res->res_job.verify_job) {
721 sendit(sock, _(" --> "));
722 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
724 if (res->res_job.run_cmds) {
726 foreach_alist(runcmd, res->res_job.run_cmds) {
727 sendit(sock, _(" --> Run=%s\n"), runcmd);
730 if (res->res_job.selection_pattern) {
731 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
733 if (res->res_job.messages) {
734 sendit(sock, _(" --> "));
735 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
742 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
743 for (i=0; i<res->res_fs.num_includes; i++) {
744 INCEXE *incexe = res->res_fs.include_items[i];
745 for (j=0; j<incexe->num_opts; j++) {
746 FOPTS *fo = incexe->opts_list[j];
747 sendit(sock, " O %s\n", fo->opts);
749 bool enhanced_wild = false;
750 for (k=0; fo->opts[k]!='\0'; k++) {
751 if (fo->opts[k]=='W') {
752 enhanced_wild = true;
757 for (k=0; k<fo->regex.size(); k++) {
758 sendit(sock, " R %s\n", fo->regex.get(k));
760 for (k=0; k<fo->regexdir.size(); k++) {
761 sendit(sock, " RD %s\n", fo->regexdir.get(k));
763 for (k=0; k<fo->regexfile.size(); k++) {
764 sendit(sock, " RF %s\n", fo->regexfile.get(k));
766 for (k=0; k<fo->wild.size(); k++) {
767 sendit(sock, " W %s\n", fo->wild.get(k));
769 for (k=0; k<fo->wilddir.size(); k++) {
770 sendit(sock, " WD %s\n", fo->wilddir.get(k));
772 for (k=0; k<fo->wildfile.size(); k++) {
773 sendit(sock, " WF %s\n", fo->wildfile.get(k));
775 for (k=0; k<fo->wildbase.size(); k++) {
776 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
778 for (k=0; k<fo->base.size(); k++) {
779 sendit(sock, " B %s\n", fo->base.get(k));
781 for (k=0; k<fo->fstype.size(); k++) {
782 sendit(sock, " X %s\n", fo->fstype.get(k));
784 for (k=0; k<fo->drivetype.size(); k++) {
785 sendit(sock, " XD %s\n", fo->drivetype.get(k));
788 sendit(sock, " G %s\n", fo->plugin);
791 sendit(sock, " D %s\n", fo->reader);
794 sendit(sock, " T %s\n", fo->writer);
796 sendit(sock, " N\n");
798 for (j=0; j<incexe->name_list.size(); j++) {
799 sendit(sock, " I %s\n", incexe->name_list.get(j));
801 if (incexe->name_list.size()) {
802 sendit(sock, " N\n");
804 for (j=0; j<incexe->plugin_list.size(); j++) {
805 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
807 if (incexe->plugin_list.size()) {
808 sendit(sock, " N\n");
813 for (i=0; i<res->res_fs.num_excludes; i++) {
814 INCEXE *incexe = res->res_fs.exclude_items[i];
815 for (j=0; j<incexe->name_list.size(); j++) {
816 sendit(sock, " E %s\n", incexe->name_list.get(j));
818 if (incexe->name_list.size()) {
819 sendit(sock, " N\n");
826 if (res->res_sch.run) {
828 RUN *run = res->res_sch.run;
829 char buf[1000], num[30];
830 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
835 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
836 bstrncpy(buf, _(" hour="), sizeof(buf));
837 for (i=0; i<24; i++) {
838 if (bit_is_set(i, run->hour)) {
839 bsnprintf(num, sizeof(num), "%d ", i);
840 bstrncat(buf, num, sizeof(buf));
843 bstrncat(buf, "\n", sizeof(buf));
845 bstrncpy(buf, _(" mday="), sizeof(buf));
846 for (i=0; i<31; i++) {
847 if (bit_is_set(i, run->mday)) {
848 bsnprintf(num, sizeof(num), "%d ", i);
849 bstrncat(buf, num, sizeof(buf));
852 bstrncat(buf, "\n", sizeof(buf));
854 bstrncpy(buf, _(" month="), sizeof(buf));
855 for (i=0; i<12; i++) {
856 if (bit_is_set(i, run->month)) {
857 bsnprintf(num, sizeof(num), "%d ", i);
858 bstrncat(buf, num, sizeof(buf));
861 bstrncat(buf, "\n", sizeof(buf));
863 bstrncpy(buf, _(" wday="), sizeof(buf));
864 for (i=0; i<7; i++) {
865 if (bit_is_set(i, run->wday)) {
866 bsnprintf(num, sizeof(num), "%d ", i);
867 bstrncat(buf, num, sizeof(buf));
870 bstrncat(buf, "\n", sizeof(buf));
872 bstrncpy(buf, _(" wom="), sizeof(buf));
873 for (i=0; i<5; i++) {
874 if (bit_is_set(i, run->wom)) {
875 bsnprintf(num, sizeof(num), "%d ", i);
876 bstrncat(buf, num, sizeof(buf));
879 bstrncat(buf, "\n", sizeof(buf));
881 bstrncpy(buf, _(" woy="), sizeof(buf));
882 for (i=0; i<54; i++) {
883 if (bit_is_set(i, run->woy)) {
884 bsnprintf(num, sizeof(num), "%d ", i);
885 bstrncat(buf, num, sizeof(buf));
888 bstrncat(buf, "\n", sizeof(buf));
890 sendit(sock, _(" mins=%d\n"), run->minute);
892 sendit(sock, _(" --> "));
893 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
896 sendit(sock, _(" --> "));
897 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
900 sendit(sock, _(" --> "));
901 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
903 /* If another Run record is chained in, go print it */
909 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
914 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
915 res->res_pool.pool_type);
916 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
917 res->res_pool.use_catalog, res->res_pool.use_volume_once,
918 res->res_pool.catalog_files);
919 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
920 res->res_pool.max_volumes, res->res_pool.AutoPrune,
921 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
922 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
923 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
924 res->res_pool.Recycle,
925 NPRT(res->res_pool.label_format));
926 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
927 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
928 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
929 res->res_pool.recycle_oldest_volume,
930 res->res_pool.purge_oldest_volume);
931 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
932 res->res_pool.MaxVolJobs,
933 res->res_pool.MaxVolFiles,
934 edit_uint64(res->res_pool.MaxVolFiles, ed1));
935 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
936 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
937 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
938 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
939 if (res->res_pool.NextPool) {
940 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
942 if (res->res_pool.RecyclePool) {
943 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
945 if (res->res_pool.catalog) {
946 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
948 if (res->res_pool.storage) {
950 foreach_alist(store, res->res_pool.storage) {
951 sendit(sock, _(" --> "));
952 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
955 if (res->res_pool.CopyPool) {
957 foreach_alist(copy, res->res_pool.CopyPool) {
958 sendit(sock, _(" --> "));
959 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
966 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
967 if (res->res_msgs.mail_cmd)
968 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
969 if (res->res_msgs.operator_cmd)
970 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
974 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
977 if (recurse && res->res_dir.hdr.next) {
978 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
983 * Free all the members of an INCEXE structure
985 static void free_incexe(INCEXE *incexe)
987 incexe->name_list.destroy();
988 incexe->plugin_list.destroy();
989 for (int i=0; i<incexe->num_opts; i++) {
990 FOPTS *fopt = incexe->opts_list[i];
991 fopt->regex.destroy();
992 fopt->regexdir.destroy();
993 fopt->regexfile.destroy();
994 fopt->wild.destroy();
995 fopt->wilddir.destroy();
996 fopt->wildfile.destroy();
997 fopt->wildbase.destroy();
998 fopt->base.destroy();
999 fopt->fstype.destroy();
1000 fopt->drivetype.destroy();
1012 if (incexe->opts_list) {
1013 free(incexe->opts_list);
1019 * Free memory of resource -- called when daemon terminates.
1020 * NB, we don't need to worry about freeing any references
1021 * to other resources as they will be freed when that
1022 * resource chain is traversed. Mainly we worry about freeing
1023 * allocated strings (names).
1025 void free_resource(RES *sres, int type)
1028 RES *nres; /* next resource if linked */
1029 URES *res = (URES *)sres;
1034 /* common stuff -- free the resource name and description */
1035 nres = (RES *)res->res_dir.hdr.next;
1036 if (res->res_dir.hdr.name) {
1037 free(res->res_dir.hdr.name);
1039 if (res->res_dir.hdr.desc) {
1040 free(res->res_dir.hdr.desc);
1045 if (res->res_dir.working_directory) {
1046 free(res->res_dir.working_directory);
1048 if (res->res_dir.scripts_directory) {
1049 free((char *)res->res_dir.scripts_directory);
1051 if (res->res_dir.plugin_directory) {
1052 free((char *)res->res_dir.plugin_directory);
1054 if (res->res_dir.pid_directory) {
1055 free(res->res_dir.pid_directory);
1057 if (res->res_dir.subsys_directory) {
1058 free(res->res_dir.subsys_directory);
1060 if (res->res_dir.password) {
1061 free(res->res_dir.password);
1063 if (res->res_dir.query_file) {
1064 free(res->res_dir.query_file);
1066 if (res->res_dir.DIRaddrs) {
1067 free_addresses(res->res_dir.DIRaddrs);
1069 if (res->res_dir.tls_ctx) {
1070 free_tls_context(res->res_dir.tls_ctx);
1072 if (res->res_dir.tls_ca_certfile) {
1073 free(res->res_dir.tls_ca_certfile);
1075 if (res->res_dir.tls_ca_certdir) {
1076 free(res->res_dir.tls_ca_certdir);
1078 if (res->res_dir.tls_certfile) {
1079 free(res->res_dir.tls_certfile);
1081 if (res->res_dir.tls_keyfile) {
1082 free(res->res_dir.tls_keyfile);
1084 if (res->res_dir.tls_dhfile) {
1085 free(res->res_dir.tls_dhfile);
1087 if (res->res_dir.tls_allowed_cns) {
1088 delete res->res_dir.tls_allowed_cns;
1095 if (res->res_con.password) {
1096 free(res->res_con.password);
1098 if (res->res_con.tls_ctx) {
1099 free_tls_context(res->res_con.tls_ctx);
1101 if (res->res_con.tls_ca_certfile) {
1102 free(res->res_con.tls_ca_certfile);
1104 if (res->res_con.tls_ca_certdir) {
1105 free(res->res_con.tls_ca_certdir);
1107 if (res->res_con.tls_certfile) {
1108 free(res->res_con.tls_certfile);
1110 if (res->res_con.tls_keyfile) {
1111 free(res->res_con.tls_keyfile);
1113 if (res->res_con.tls_dhfile) {
1114 free(res->res_con.tls_dhfile);
1116 if (res->res_con.tls_allowed_cns) {
1117 delete res->res_con.tls_allowed_cns;
1119 for (int i=0; i<Num_ACL; i++) {
1120 if (res->res_con.ACL_lists[i]) {
1121 delete res->res_con.ACL_lists[i];
1122 res->res_con.ACL_lists[i] = NULL;
1127 if (res->res_client.address) {
1128 free(res->res_client.address);
1130 if (res->res_client.password) {
1131 free(res->res_client.password);
1133 if (res->res_client.tls_ctx) {
1134 free_tls_context(res->res_client.tls_ctx);
1136 if (res->res_client.tls_ca_certfile) {
1137 free(res->res_client.tls_ca_certfile);
1139 if (res->res_client.tls_ca_certdir) {
1140 free(res->res_client.tls_ca_certdir);
1142 if (res->res_client.tls_certfile) {
1143 free(res->res_client.tls_certfile);
1145 if (res->res_client.tls_keyfile) {
1146 free(res->res_client.tls_keyfile);
1148 if (res->res_client.tls_allowed_cns) {
1149 delete res->res_client.tls_allowed_cns;
1153 if (res->res_store.address) {
1154 free(res->res_store.address);
1156 if (res->res_store.password) {
1157 free(res->res_store.password);
1159 if (res->res_store.media_type) {
1160 free(res->res_store.media_type);
1162 if (res->res_store.device) {
1163 delete res->res_store.device;
1165 if (res->res_store.tls_ctx) {
1166 free_tls_context(res->res_store.tls_ctx);
1168 if (res->res_store.tls_ca_certfile) {
1169 free(res->res_store.tls_ca_certfile);
1171 if (res->res_store.tls_ca_certdir) {
1172 free(res->res_store.tls_ca_certdir);
1174 if (res->res_store.tls_certfile) {
1175 free(res->res_store.tls_certfile);
1177 if (res->res_store.tls_keyfile) {
1178 free(res->res_store.tls_keyfile);
1182 if (res->res_cat.db_address) {
1183 free(res->res_cat.db_address);
1185 if (res->res_cat.db_socket) {
1186 free(res->res_cat.db_socket);
1188 if (res->res_cat.db_user) {
1189 free(res->res_cat.db_user);
1191 if (res->res_cat.db_name) {
1192 free(res->res_cat.db_name);
1194 if (res->res_cat.db_driver) {
1195 free(res->res_cat.db_driver);
1197 if (res->res_cat.db_password) {
1198 free(res->res_cat.db_password);
1202 if ((num=res->res_fs.num_includes)) {
1203 while (--num >= 0) {
1204 free_incexe(res->res_fs.include_items[num]);
1206 free(res->res_fs.include_items);
1208 res->res_fs.num_includes = 0;
1209 if ((num=res->res_fs.num_excludes)) {
1210 while (--num >= 0) {
1211 free_incexe(res->res_fs.exclude_items[num]);
1213 free(res->res_fs.exclude_items);
1215 res->res_fs.num_excludes = 0;
1218 if (res->res_pool.pool_type) {
1219 free(res->res_pool.pool_type);
1221 if (res->res_pool.label_format) {
1222 free(res->res_pool.label_format);
1224 if (res->res_pool.cleaning_prefix) {
1225 free(res->res_pool.cleaning_prefix);
1227 if (res->res_pool.storage) {
1228 delete res->res_pool.storage;
1232 if (res->res_sch.run) {
1234 nrun = res->res_sch.run;
1244 if (res->res_job.RestoreWhere) {
1245 free(res->res_job.RestoreWhere);
1247 if (res->res_job.RegexWhere) {
1248 free(res->res_job.RegexWhere);
1250 if (res->res_job.strip_prefix) {
1251 free(res->res_job.strip_prefix);
1253 if (res->res_job.add_prefix) {
1254 free(res->res_job.add_prefix);
1256 if (res->res_job.add_suffix) {
1257 free(res->res_job.add_suffix);
1259 if (res->res_job.RestoreBootstrap) {
1260 free(res->res_job.RestoreBootstrap);
1262 if (res->res_job.WriteBootstrap) {
1263 free(res->res_job.WriteBootstrap);
1265 if (res->res_job.PluginOptions) {
1266 free(res->res_job.PluginOptions);
1268 if (res->res_job.selection_pattern) {
1269 free(res->res_job.selection_pattern);
1271 if (res->res_job.run_cmds) {
1272 delete res->res_job.run_cmds;
1274 if (res->res_job.storage) {
1275 delete res->res_job.storage;
1277 if (res->res_job.RunScripts) {
1278 free_runscripts(res->res_job.RunScripts);
1279 delete res->res_job.RunScripts;
1283 if (res->res_msgs.mail_cmd) {
1284 free(res->res_msgs.mail_cmd);
1286 if (res->res_msgs.operator_cmd) {
1287 free(res->res_msgs.operator_cmd);
1289 free_msgs_res((MSGS *)res); /* free message resource */
1293 printf(_("Unknown resource type %d in free_resource.\n"), type);
1295 /* Common stuff again -- free the resource, recurse to next one */
1300 free_resource(nres, type);
1305 * Save the new resource by chaining it into the head list for
1306 * the resource. If this is pass 2, we update any resource
1307 * pointers because they may not have been defined until
1310 void save_resource(int type, RES_ITEM *items, int pass)
1313 int rindex = type - r_first;
1317 /* Check Job requirements after applying JobDefs */
1318 if (type != R_JOB && type != R_JOBDEFS) {
1320 * Ensure that all required items are present
1322 for (i=0; items[i].name; i++) {
1323 if (items[i].flags & ITEM_REQUIRED) {
1324 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1325 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1326 items[i].name, resources[rindex]);
1329 /* If this triggers, take a look at lib/parse_conf.h */
1330 if (i >= MAX_RES_ITEMS) {
1331 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1334 } else if (type == R_JOB) {
1336 * Ensure that the name item is present
1338 if (items[0].flags & ITEM_REQUIRED) {
1339 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1340 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1341 items[0].name, resources[rindex]);
1347 * During pass 2 in each "store" routine, we looked up pointers
1348 * to all the resources referrenced in the current resource, now we
1349 * must copy their addresses from the static record to the allocated
1354 /* Resources not containing a resource */
1362 * Resources containing another resource or alist. First
1363 * look up the resource which contains another resource. It
1364 * was written during pass 1. Then stuff in the pointers to
1365 * the resources it contains, which were inserted this pass.
1366 * Finally, it will all be stored back.
1369 /* Find resource saved in pass 1 */
1370 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1371 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1373 /* Explicitly copy resource pointers from this pass (res_all) */
1374 res->res_pool.NextPool = res_all.res_pool.NextPool;
1375 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1376 res->res_pool.storage = res_all.res_pool.storage;
1377 res->res_pool.catalog = res_all.res_pool.catalog;
1380 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1381 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1383 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1386 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1387 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1389 res->res_dir.messages = res_all.res_dir.messages;
1390 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1393 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1394 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1395 res_all.res_dir.hdr.name);
1397 /* we must explicitly copy the device alist pointer */
1398 res->res_store.device = res_all.res_store.device;
1402 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1403 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1404 res_all.res_dir.hdr.name);
1406 res->res_job.messages = res_all.res_job.messages;
1407 res->res_job.schedule = res_all.res_job.schedule;
1408 res->res_job.client = res_all.res_job.client;
1409 res->res_job.fileset = res_all.res_job.fileset;
1410 res->res_job.storage = res_all.res_job.storage;
1411 res->res_job.pool = res_all.res_job.pool;
1412 res->res_job.full_pool = res_all.res_job.full_pool;
1413 res->res_job.inc_pool = res_all.res_job.inc_pool;
1414 res->res_job.diff_pool = res_all.res_job.diff_pool;
1415 res->res_job.verify_job = res_all.res_job.verify_job;
1416 res->res_job.jobdefs = res_all.res_job.jobdefs;
1417 res->res_job.run_cmds = res_all.res_job.run_cmds;
1418 res->res_job.RunScripts = res_all.res_job.RunScripts;
1420 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1421 * is not very useful)
1422 * We have to set_bit(index, res_all.hdr.item_present);
1423 * or something like that
1426 /* we take RegexWhere before all other options */
1427 if (!res->res_job.RegexWhere
1429 (res->res_job.strip_prefix ||
1430 res->res_job.add_suffix ||
1431 res->res_job.add_prefix))
1433 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1434 res->res_job.add_prefix,
1435 res->res_job.add_suffix);
1436 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1437 bregexp_build_where(res->res_job.RegexWhere, len,
1438 res->res_job.strip_prefix,
1439 res->res_job.add_prefix,
1440 res->res_job.add_suffix);
1441 /* TODO: test bregexp */
1444 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1445 free(res->res_job.RestoreWhere);
1446 res->res_job.RestoreWhere = NULL;
1451 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1452 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1454 res->res_counter.Catalog = res_all.res_counter.Catalog;
1455 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1459 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1460 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1462 res->res_client.catalog = res_all.res_client.catalog;
1463 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1467 * Schedule is a bit different in that it contains a RUN record
1468 * chain which isn't a "named" resource. This chain was linked
1469 * in by run_conf.c during pass 2, so here we jam the pointer
1470 * into the Schedule resource.
1472 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1473 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1475 res->res_sch.run = res_all.res_sch.run;
1478 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1482 /* Note, the resource name was already saved during pass 1,
1483 * so here, we can just release it.
1485 if (res_all.res_dir.hdr.name) {
1486 free(res_all.res_dir.hdr.name);
1487 res_all.res_dir.hdr.name = NULL;
1489 if (res_all.res_dir.hdr.desc) {
1490 free(res_all.res_dir.hdr.desc);
1491 res_all.res_dir.hdr.desc = NULL;
1497 * The following code is only executed during pass 1
1501 size = sizeof(DIRRES);
1504 size = sizeof(CONRES);
1507 size =sizeof(CLIENT);
1510 size = sizeof(STORE);
1520 size = sizeof(FILESET);
1523 size = sizeof(SCHED);
1526 size = sizeof(POOL);
1529 size = sizeof(MSGS);
1532 size = sizeof(COUNTER);
1538 printf(_("Unknown resource type %d in save_resource.\n"), type);
1544 res = (URES *)malloc(size);
1545 memcpy(res, &res_all, size);
1546 if (!res_head[rindex]) {
1547 res_head[rindex] = (RES *)res; /* store first entry */
1548 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1549 res->res_dir.hdr.name, rindex);
1552 if (res->res_dir.hdr.name == NULL) {
1553 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1556 /* Add new res to end of chain */
1557 for (last=next=res_head[rindex]; next; next=next->next) {
1559 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1560 Emsg2(M_ERROR_TERM, 0,
1561 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1562 resources[rindex].name, res->res_dir.hdr.name);
1565 last->next = (RES *)res;
1566 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1567 res->res_dir.hdr.name, rindex, pass);
1573 * Store Device. Note, the resource is created upon the
1574 * first reference. The details of the resource are obtained
1575 * later from the SD.
1577 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1581 int rindex = R_DEVICE - r_first;
1582 int size = sizeof(DEVICE);
1586 token = lex_get_token(lc, T_NAME);
1587 if (!res_head[rindex]) {
1588 res = (URES *)malloc(size);
1589 memset(res, 0, size);
1590 res->res_dev.hdr.name = bstrdup(lc->str);
1591 res_head[rindex] = (RES *)res; /* store first entry */
1592 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1593 res->res_dir.hdr.name, rindex);
1596 /* See if it is already defined */
1597 for (next=res_head[rindex]; next->next; next=next->next) {
1598 if (strcmp(next->name, lc->str) == 0) {
1604 res = (URES *)malloc(size);
1605 memset(res, 0, size);
1606 res->res_dev.hdr.name = bstrdup(lc->str);
1607 next->next = (RES *)res;
1608 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1609 res->res_dir.hdr.name, rindex, pass);
1614 set_bit(index, res_all.hdr.item_present);
1616 store_alist_res(lc, item, index, pass);
1621 * Store Migration/Copy type
1624 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1628 token = lex_get_token(lc, T_NAME);
1629 /* Store the type both pass 1 and pass 2 */
1630 for (i=0; migtypes[i].type_name; i++) {
1631 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1632 *(uint32_t *)(item->value) = migtypes[i].job_type;
1638 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1641 set_bit(index, res_all.hdr.item_present);
1647 * Store JobType (backup, verify, restore)
1650 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1654 token = lex_get_token(lc, T_NAME);
1655 /* Store the type both pass 1 and pass 2 */
1656 for (i=0; jobtypes[i].type_name; i++) {
1657 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1658 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1664 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1667 set_bit(index, res_all.hdr.item_present);
1671 * Store Job Level (Full, Incremental, ...)
1674 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1678 token = lex_get_token(lc, T_NAME);
1679 /* Store the level pass 2 so that type is defined */
1680 for (i=0; joblevels[i].level_name; i++) {
1681 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1682 *(uint32_t *)(item->value) = joblevels[i].level;
1688 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1691 set_bit(index, res_all.hdr.item_present);
1695 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1698 token = lex_get_token(lc, T_NAME);
1699 /* Scan Replacement options */
1700 for (i=0; ReplaceOptions[i].name; i++) {
1701 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1702 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1708 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1711 set_bit(index, res_all.hdr.item_present);
1715 * Store ACL (access control list)
1718 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1723 token = lex_get_token(lc, T_STRING);
1725 if (((alist **)item->value)[item->code] == NULL) {
1726 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1727 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1729 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1730 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1732 token = lex_get_token(lc, T_ALL);
1733 if (token == T_COMMA) {
1734 continue; /* get another ACL */
1738 set_bit(index, res_all.hdr.item_present);
1741 /* We build RunScripts items here */
1742 static RUNSCRIPT res_runscript;
1744 /* Store a runscript->when in a bit field */
1745 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1747 lex_get_token(lc, T_NAME);
1749 if (strcasecmp(lc->str, "before") == 0) {
1750 *(uint32_t *)(item->value) = SCRIPT_Before ;
1751 } else if (strcasecmp(lc->str, "after") == 0) {
1752 *(uint32_t *)(item->value) = SCRIPT_After;
1753 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1754 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1755 } else if (strcasecmp(lc->str, "always") == 0) {
1756 *(uint32_t *)(item->value) = SCRIPT_Any;
1758 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1763 /* Store a runscript->target
1766 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1768 lex_get_token(lc, T_STRING);
1771 if (strcmp(lc->str, "%c") == 0) {
1772 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1773 } else if (strcasecmp(lc->str, "yes") == 0) {
1774 ((RUNSCRIPT*) item->value)->set_target("%c");
1775 } else if (strcasecmp(lc->str, "no") == 0) {
1776 ((RUNSCRIPT*) item->value)->set_target("");
1778 RES *res = GetResWithName(R_CLIENT, lc->str);
1780 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1781 lc->str, lc->line_no, lc->line);
1784 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1791 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1793 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1795 lex_get_token(lc, T_STRING);
1798 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1799 POOLMEM *c = get_pool_memory(PM_FNAME);
1800 /* Each runscript command takes 2 entries in commands list */
1801 pm_strcpy(c, lc->str);
1802 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1803 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1808 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1810 lex_get_token(lc, T_STRING);
1811 alist **runscripts = (alist **)(item->value) ;
1814 RUNSCRIPT *script = new_runscript();
1815 script->set_job_code_callback(job_code_callback_filesetname);
1817 script->set_command(lc->str);
1819 /* TODO: remove all script->old_proto with bacula 1.42 */
1821 if (strcmp(item->name, "runbeforejob") == 0) {
1822 script->when = SCRIPT_Before;
1823 script->fail_on_error = true;
1824 script->set_target("");
1826 } else if (strcmp(item->name, "runafterjob") == 0) {
1827 script->when = SCRIPT_After;
1828 script->on_success = true;
1829 script->on_failure = false;
1830 script->set_target("");
1832 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1833 script->old_proto = true;
1834 script->when = SCRIPT_After;
1835 script->set_target("%c");
1836 script->on_success = true;
1837 script->on_failure = false;
1839 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1840 script->old_proto = true;
1841 script->when = SCRIPT_Before;
1842 script->set_target("%c");
1843 script->fail_on_error = true;
1845 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1846 script->when = SCRIPT_After;
1847 script->on_failure = true;
1848 script->on_success = false;
1849 script->set_target("");
1852 if (*runscripts == NULL) {
1853 *runscripts = New(alist(10, not_owned_by_alist));
1856 (*runscripts)->append(script);
1863 /* Store a bool in a bit field without modifing res_all.hdr
1864 * We can also add an option to store_bool to skip res_all.hdr
1866 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1868 lex_get_token(lc, T_NAME);
1869 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1870 *(bool *)(item->value) = true;
1871 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1872 *(bool *)(item->value) = false;
1874 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1880 * new RunScript items
1881 * name handler value code flags default_value
1883 static RES_ITEM runscript_items[] = {
1884 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1885 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1886 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1887 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1888 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1889 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1890 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1891 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1892 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1893 {NULL, NULL, {0}, 0, 0, 0}
1897 * Store RunScript info
1899 * Note, when this routine is called, we are inside a Job
1900 * resource. We treat the RunScript like a sort of
1901 * mini-resource within the Job resource.
1903 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1907 alist **runscripts = (alist **)(item->value) ;
1909 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1911 token = lex_get_token(lc, T_SKIP_EOL);
1913 if (token != T_BOB) {
1914 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1916 /* setting on_success, on_failure, fail_on_error */
1917 res_runscript.reset_default();
1920 res_runscript.commands = New(alist(10, not_owned_by_alist));
1923 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1924 if (token == T_EOB) {
1927 if (token != T_IDENTIFIER) {
1928 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1930 for (i=0; runscript_items[i].name; i++) {
1931 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1932 token = lex_get_token(lc, T_SKIP_EOL);
1933 if (token != T_EQUALS) {
1934 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1937 /* Call item handler */
1938 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1945 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1950 /* run on client by default */
1951 if (res_runscript.target == NULL) {
1952 res_runscript.set_target("%c");
1954 if (*runscripts == NULL) {
1955 *runscripts = New(alist(10, not_owned_by_alist));
1958 * commands list contains 2 values per command
1959 * - POOLMEM command string (ex: /bin/true)
1960 * - int command type (ex: SHELL_CMD)
1962 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1963 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1964 t = (long)res_runscript.commands->pop();
1965 RUNSCRIPT *script = new_runscript();
1966 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1967 script->command = c;
1968 script->cmd_type = t;
1969 /* target is taken from res_runscript, each runscript object have
1972 script->target = NULL;
1973 script->set_target(res_runscript.target);
1975 (*runscripts)->append(script);
1978 delete res_runscript.commands;
1979 /* setting on_success, on_failure... cleanup target field */
1980 res_runscript.reset_default(true);
1984 set_bit(index, res_all.hdr.item_present);
1987 /* callback function for edit_job_codes */
1988 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1990 if (param[0] == 'f') {
1991 return jcr->fileset->name();
1997 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
1999 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2000 r_first, r_last, resources, res_head);
2001 return config->parse_config();