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 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
333 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
334 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
335 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
336 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
337 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
338 {NULL, NULL, {0}, 0, 0, 0}
343 * name handler value code flags default_value
345 static RES_ITEM fs_items[] = {
346 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
347 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
348 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
349 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
350 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
351 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
352 {NULL, NULL, {0}, 0, 0, 0}
355 /* Schedule -- see run_conf.c */
358 * name handler value code flags default_value
360 static RES_ITEM sch_items[] = {
361 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
362 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
363 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
364 {NULL, NULL, {0}, 0, 0, 0}
369 * name handler value code flags default_value
371 static RES_ITEM pool_items[] = {
372 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
373 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
374 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
375 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
376 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
377 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
378 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
379 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
380 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
381 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
382 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
383 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
384 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
385 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
386 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
387 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
388 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
389 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
390 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
391 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
392 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
393 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
394 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
395 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
396 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
397 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
398 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
399 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
400 {NULL, NULL, {0}, 0, 0, 0}
405 * name handler value code flags default_value
407 static RES_ITEM counter_items[] = {
408 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
409 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
410 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
411 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
412 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
413 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
414 {NULL, NULL, {0}, 0, 0, 0}
418 /* Message resource */
419 extern RES_ITEM msgs_items[];
422 * This is the master resource definition.
423 * It must have one item for each of the resources.
425 * NOTE!!! keep it in the same order as the R_codes
426 * or eliminate all resources[rindex].name
428 * name items rcode res_head
430 RES_TABLE resources[] = {
431 {"director", dir_items, R_DIRECTOR},
432 {"client", cli_items, R_CLIENT},
433 {"job", job_items, R_JOB},
434 {"storage", store_items, R_STORAGE},
435 {"catalog", cat_items, R_CATALOG},
436 {"schedule", sch_items, R_SCHEDULE},
437 {"fileset", fs_items, R_FILESET},
438 {"pool", pool_items, R_POOL},
439 {"messages", msgs_items, R_MSGS},
440 {"counter", counter_items, R_COUNTER},
441 {"console", con_items, R_CONSOLE},
442 {"jobdefs", job_items, R_JOBDEFS},
443 {"device", NULL, R_DEVICE}, /* info obtained from SD */
448 /* Keywords (RHS) permitted in Job Level records
450 * level_name level job_type
452 struct s_jl joblevels[] = {
453 {"Full", L_FULL, JT_BACKUP},
454 {"Base", L_BASE, JT_BACKUP},
455 {"Incremental", L_INCREMENTAL, JT_BACKUP},
456 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
457 {"Since", L_SINCE, JT_BACKUP},
458 {"VirtualFull", L_VIRTUAL_FULL, 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.JobType == JT_BACKUP) {
640 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
642 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
643 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
645 if (res->res_job.client) {
646 sendit(sock, _(" --> "));
647 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
649 if (res->res_job.fileset) {
650 sendit(sock, _(" --> "));
651 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
653 if (res->res_job.schedule) {
654 sendit(sock, _(" --> "));
655 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
657 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
658 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
660 if (res->res_job.RegexWhere) {
661 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
663 if (res->res_job.RestoreBootstrap) {
664 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
666 if (res->res_job.WriteBootstrap) {
667 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
669 if (res->res_job.PluginOptions) {
670 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
672 if (res->res_job.MaxRunTime) {
673 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
675 if (res->res_job.MaxWaitTime) {
676 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
678 if (res->res_job.MaxStartDelay) {
679 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
681 if (res->res_job.storage) {
683 foreach_alist(store, res->res_job.storage) {
684 sendit(sock, _(" --> "));
685 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
688 if (res->res_job.RunScripts) {
690 foreach_alist(script, res->res_job.RunScripts) {
691 sendit(sock, _(" --> RunScript\n"));
692 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
693 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
694 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
695 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
696 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
697 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
700 if (res->res_job.pool) {
701 sendit(sock, _(" --> "));
702 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
704 if (res->res_job.full_pool) {
705 sendit(sock, _(" --> "));
706 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
708 if (res->res_job.inc_pool) {
709 sendit(sock, _(" --> "));
710 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
712 if (res->res_job.diff_pool) {
713 sendit(sock, _(" --> "));
714 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
716 if (res->res_job.verify_job) {
717 sendit(sock, _(" --> "));
718 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
720 if (res->res_job.run_cmds) {
722 foreach_alist(runcmd, res->res_job.run_cmds) {
723 sendit(sock, _(" --> Run=%s\n"), runcmd);
726 if (res->res_job.selection_pattern) {
727 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
729 if (res->res_job.messages) {
730 sendit(sock, _(" --> "));
731 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
738 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
739 for (i=0; i<res->res_fs.num_includes; i++) {
740 INCEXE *incexe = res->res_fs.include_items[i];
741 for (j=0; j<incexe->num_opts; j++) {
742 FOPTS *fo = incexe->opts_list[j];
743 sendit(sock, " O %s\n", fo->opts);
745 bool enhanced_wild = false;
746 for (k=0; fo->opts[k]!='\0'; k++) {
747 if (fo->opts[k]=='W') {
748 enhanced_wild = true;
753 for (k=0; k<fo->regex.size(); k++) {
754 sendit(sock, " R %s\n", fo->regex.get(k));
756 for (k=0; k<fo->regexdir.size(); k++) {
757 sendit(sock, " RD %s\n", fo->regexdir.get(k));
759 for (k=0; k<fo->regexfile.size(); k++) {
760 sendit(sock, " RF %s\n", fo->regexfile.get(k));
762 for (k=0; k<fo->wild.size(); k++) {
763 sendit(sock, " W %s\n", fo->wild.get(k));
765 for (k=0; k<fo->wilddir.size(); k++) {
766 sendit(sock, " WD %s\n", fo->wilddir.get(k));
768 for (k=0; k<fo->wildfile.size(); k++) {
769 sendit(sock, " WF %s\n", fo->wildfile.get(k));
771 for (k=0; k<fo->wildbase.size(); k++) {
772 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
774 for (k=0; k<fo->base.size(); k++) {
775 sendit(sock, " B %s\n", fo->base.get(k));
777 for (k=0; k<fo->fstype.size(); k++) {
778 sendit(sock, " X %s\n", fo->fstype.get(k));
780 for (k=0; k<fo->drivetype.size(); k++) {
781 sendit(sock, " XD %s\n", fo->drivetype.get(k));
784 sendit(sock, " G %s\n", fo->plugin);
787 sendit(sock, " D %s\n", fo->reader);
790 sendit(sock, " T %s\n", fo->writer);
792 sendit(sock, " N\n");
794 for (j=0; j<incexe->name_list.size(); j++) {
795 sendit(sock, " I %s\n", incexe->name_list.get(j));
797 if (incexe->name_list.size()) {
798 sendit(sock, " N\n");
800 for (j=0; j<incexe->plugin_list.size(); j++) {
801 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
803 if (incexe->plugin_list.size()) {
804 sendit(sock, " N\n");
809 for (i=0; i<res->res_fs.num_excludes; i++) {
810 INCEXE *incexe = res->res_fs.exclude_items[i];
811 for (j=0; j<incexe->name_list.size(); j++) {
812 sendit(sock, " E %s\n", incexe->name_list.get(j));
814 if (incexe->name_list.size()) {
815 sendit(sock, " N\n");
822 if (res->res_sch.run) {
824 RUN *run = res->res_sch.run;
825 char buf[1000], num[30];
826 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
831 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
832 bstrncpy(buf, _(" hour="), sizeof(buf));
833 for (i=0; i<24; i++) {
834 if (bit_is_set(i, run->hour)) {
835 bsnprintf(num, sizeof(num), "%d ", i);
836 bstrncat(buf, num, sizeof(buf));
839 bstrncat(buf, "\n", sizeof(buf));
841 bstrncpy(buf, _(" mday="), sizeof(buf));
842 for (i=0; i<31; i++) {
843 if (bit_is_set(i, run->mday)) {
844 bsnprintf(num, sizeof(num), "%d ", i);
845 bstrncat(buf, num, sizeof(buf));
848 bstrncat(buf, "\n", sizeof(buf));
850 bstrncpy(buf, _(" month="), sizeof(buf));
851 for (i=0; i<12; i++) {
852 if (bit_is_set(i, run->month)) {
853 bsnprintf(num, sizeof(num), "%d ", i);
854 bstrncat(buf, num, sizeof(buf));
857 bstrncat(buf, "\n", sizeof(buf));
859 bstrncpy(buf, _(" wday="), sizeof(buf));
860 for (i=0; i<7; i++) {
861 if (bit_is_set(i, run->wday)) {
862 bsnprintf(num, sizeof(num), "%d ", i);
863 bstrncat(buf, num, sizeof(buf));
866 bstrncat(buf, "\n", sizeof(buf));
868 bstrncpy(buf, _(" wom="), sizeof(buf));
869 for (i=0; i<5; i++) {
870 if (bit_is_set(i, run->wom)) {
871 bsnprintf(num, sizeof(num), "%d ", i);
872 bstrncat(buf, num, sizeof(buf));
875 bstrncat(buf, "\n", sizeof(buf));
877 bstrncpy(buf, _(" woy="), sizeof(buf));
878 for (i=0; i<54; i++) {
879 if (bit_is_set(i, run->woy)) {
880 bsnprintf(num, sizeof(num), "%d ", i);
881 bstrncat(buf, num, sizeof(buf));
884 bstrncat(buf, "\n", sizeof(buf));
886 sendit(sock, _(" mins=%d\n"), run->minute);
888 sendit(sock, _(" --> "));
889 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
892 sendit(sock, _(" --> "));
893 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
896 sendit(sock, _(" --> "));
897 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
899 /* If another Run record is chained in, go print it */
905 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
910 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
911 res->res_pool.pool_type);
912 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
913 res->res_pool.use_catalog, res->res_pool.use_volume_once,
914 res->res_pool.catalog_files);
915 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
916 res->res_pool.max_volumes, res->res_pool.AutoPrune,
917 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
918 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
919 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
920 res->res_pool.Recycle,
921 NPRT(res->res_pool.label_format));
922 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
923 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
924 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
925 res->res_pool.recycle_oldest_volume,
926 res->res_pool.purge_oldest_volume);
927 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
928 res->res_pool.MaxVolJobs,
929 res->res_pool.MaxVolFiles,
930 edit_uint64(res->res_pool.MaxVolFiles, ed1));
931 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
932 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
933 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
934 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
935 if (res->res_pool.NextPool) {
936 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
938 if (res->res_pool.RecyclePool) {
939 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
941 if (res->res_pool.catalog) {
942 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
944 if (res->res_pool.storage) {
946 foreach_alist(store, res->res_pool.storage) {
947 sendit(sock, _(" --> "));
948 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
951 if (res->res_pool.CopyPool) {
953 foreach_alist(copy, res->res_pool.CopyPool) {
954 sendit(sock, _(" --> "));
955 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
962 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
963 if (res->res_msgs.mail_cmd)
964 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
965 if (res->res_msgs.operator_cmd)
966 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
970 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
973 if (recurse && res->res_dir.hdr.next) {
974 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
979 * Free all the members of an INCEXE structure
981 static void free_incexe(INCEXE *incexe)
983 incexe->name_list.destroy();
984 incexe->plugin_list.destroy();
985 for (int i=0; i<incexe->num_opts; i++) {
986 FOPTS *fopt = incexe->opts_list[i];
987 fopt->regex.destroy();
988 fopt->regexdir.destroy();
989 fopt->regexfile.destroy();
990 fopt->wild.destroy();
991 fopt->wilddir.destroy();
992 fopt->wildfile.destroy();
993 fopt->wildbase.destroy();
994 fopt->base.destroy();
995 fopt->fstype.destroy();
996 fopt->drivetype.destroy();
1008 if (incexe->opts_list) {
1009 free(incexe->opts_list);
1015 * Free memory of resource -- called when daemon terminates.
1016 * NB, we don't need to worry about freeing any references
1017 * to other resources as they will be freed when that
1018 * resource chain is traversed. Mainly we worry about freeing
1019 * allocated strings (names).
1021 void free_resource(RES *sres, int type)
1024 RES *nres; /* next resource if linked */
1025 URES *res = (URES *)sres;
1030 /* common stuff -- free the resource name and description */
1031 nres = (RES *)res->res_dir.hdr.next;
1032 if (res->res_dir.hdr.name) {
1033 free(res->res_dir.hdr.name);
1035 if (res->res_dir.hdr.desc) {
1036 free(res->res_dir.hdr.desc);
1041 if (res->res_dir.working_directory) {
1042 free(res->res_dir.working_directory);
1044 if (res->res_dir.scripts_directory) {
1045 free((char *)res->res_dir.scripts_directory);
1047 if (res->res_dir.plugin_directory) {
1048 free((char *)res->res_dir.plugin_directory);
1050 if (res->res_dir.pid_directory) {
1051 free(res->res_dir.pid_directory);
1053 if (res->res_dir.subsys_directory) {
1054 free(res->res_dir.subsys_directory);
1056 if (res->res_dir.password) {
1057 free(res->res_dir.password);
1059 if (res->res_dir.query_file) {
1060 free(res->res_dir.query_file);
1062 if (res->res_dir.DIRaddrs) {
1063 free_addresses(res->res_dir.DIRaddrs);
1065 if (res->res_dir.tls_ctx) {
1066 free_tls_context(res->res_dir.tls_ctx);
1068 if (res->res_dir.tls_ca_certfile) {
1069 free(res->res_dir.tls_ca_certfile);
1071 if (res->res_dir.tls_ca_certdir) {
1072 free(res->res_dir.tls_ca_certdir);
1074 if (res->res_dir.tls_certfile) {
1075 free(res->res_dir.tls_certfile);
1077 if (res->res_dir.tls_keyfile) {
1078 free(res->res_dir.tls_keyfile);
1080 if (res->res_dir.tls_dhfile) {
1081 free(res->res_dir.tls_dhfile);
1083 if (res->res_dir.tls_allowed_cns) {
1084 delete res->res_dir.tls_allowed_cns;
1091 if (res->res_con.password) {
1092 free(res->res_con.password);
1094 if (res->res_con.tls_ctx) {
1095 free_tls_context(res->res_con.tls_ctx);
1097 if (res->res_con.tls_ca_certfile) {
1098 free(res->res_con.tls_ca_certfile);
1100 if (res->res_con.tls_ca_certdir) {
1101 free(res->res_con.tls_ca_certdir);
1103 if (res->res_con.tls_certfile) {
1104 free(res->res_con.tls_certfile);
1106 if (res->res_con.tls_keyfile) {
1107 free(res->res_con.tls_keyfile);
1109 if (res->res_con.tls_dhfile) {
1110 free(res->res_con.tls_dhfile);
1112 if (res->res_con.tls_allowed_cns) {
1113 delete res->res_con.tls_allowed_cns;
1115 for (int i=0; i<Num_ACL; i++) {
1116 if (res->res_con.ACL_lists[i]) {
1117 delete res->res_con.ACL_lists[i];
1118 res->res_con.ACL_lists[i] = NULL;
1123 if (res->res_client.address) {
1124 free(res->res_client.address);
1126 if (res->res_client.password) {
1127 free(res->res_client.password);
1129 if (res->res_client.tls_ctx) {
1130 free_tls_context(res->res_client.tls_ctx);
1132 if (res->res_client.tls_ca_certfile) {
1133 free(res->res_client.tls_ca_certfile);
1135 if (res->res_client.tls_ca_certdir) {
1136 free(res->res_client.tls_ca_certdir);
1138 if (res->res_client.tls_certfile) {
1139 free(res->res_client.tls_certfile);
1141 if (res->res_client.tls_keyfile) {
1142 free(res->res_client.tls_keyfile);
1144 if (res->res_client.tls_allowed_cns) {
1145 delete res->res_client.tls_allowed_cns;
1149 if (res->res_store.address) {
1150 free(res->res_store.address);
1152 if (res->res_store.password) {
1153 free(res->res_store.password);
1155 if (res->res_store.media_type) {
1156 free(res->res_store.media_type);
1158 if (res->res_store.device) {
1159 delete res->res_store.device;
1161 if (res->res_store.tls_ctx) {
1162 free_tls_context(res->res_store.tls_ctx);
1164 if (res->res_store.tls_ca_certfile) {
1165 free(res->res_store.tls_ca_certfile);
1167 if (res->res_store.tls_ca_certdir) {
1168 free(res->res_store.tls_ca_certdir);
1170 if (res->res_store.tls_certfile) {
1171 free(res->res_store.tls_certfile);
1173 if (res->res_store.tls_keyfile) {
1174 free(res->res_store.tls_keyfile);
1178 if (res->res_cat.db_address) {
1179 free(res->res_cat.db_address);
1181 if (res->res_cat.db_socket) {
1182 free(res->res_cat.db_socket);
1184 if (res->res_cat.db_user) {
1185 free(res->res_cat.db_user);
1187 if (res->res_cat.db_name) {
1188 free(res->res_cat.db_name);
1190 if (res->res_cat.db_driver) {
1191 free(res->res_cat.db_driver);
1193 if (res->res_cat.db_password) {
1194 free(res->res_cat.db_password);
1198 if ((num=res->res_fs.num_includes)) {
1199 while (--num >= 0) {
1200 free_incexe(res->res_fs.include_items[num]);
1202 free(res->res_fs.include_items);
1204 res->res_fs.num_includes = 0;
1205 if ((num=res->res_fs.num_excludes)) {
1206 while (--num >= 0) {
1207 free_incexe(res->res_fs.exclude_items[num]);
1209 free(res->res_fs.exclude_items);
1211 res->res_fs.num_excludes = 0;
1214 if (res->res_pool.pool_type) {
1215 free(res->res_pool.pool_type);
1217 if (res->res_pool.label_format) {
1218 free(res->res_pool.label_format);
1220 if (res->res_pool.cleaning_prefix) {
1221 free(res->res_pool.cleaning_prefix);
1223 if (res->res_pool.storage) {
1224 delete res->res_pool.storage;
1228 if (res->res_sch.run) {
1230 nrun = res->res_sch.run;
1240 if (res->res_job.RestoreWhere) {
1241 free(res->res_job.RestoreWhere);
1243 if (res->res_job.RegexWhere) {
1244 free(res->res_job.RegexWhere);
1246 if (res->res_job.strip_prefix) {
1247 free(res->res_job.strip_prefix);
1249 if (res->res_job.add_prefix) {
1250 free(res->res_job.add_prefix);
1252 if (res->res_job.add_suffix) {
1253 free(res->res_job.add_suffix);
1255 if (res->res_job.RestoreBootstrap) {
1256 free(res->res_job.RestoreBootstrap);
1258 if (res->res_job.WriteBootstrap) {
1259 free(res->res_job.WriteBootstrap);
1261 if (res->res_job.PluginOptions) {
1262 free(res->res_job.PluginOptions);
1264 if (res->res_job.selection_pattern) {
1265 free(res->res_job.selection_pattern);
1267 if (res->res_job.run_cmds) {
1268 delete res->res_job.run_cmds;
1270 if (res->res_job.storage) {
1271 delete res->res_job.storage;
1273 if (res->res_job.RunScripts) {
1274 free_runscripts(res->res_job.RunScripts);
1275 delete res->res_job.RunScripts;
1279 if (res->res_msgs.mail_cmd) {
1280 free(res->res_msgs.mail_cmd);
1282 if (res->res_msgs.operator_cmd) {
1283 free(res->res_msgs.operator_cmd);
1285 free_msgs_res((MSGS *)res); /* free message resource */
1289 printf(_("Unknown resource type %d in free_resource.\n"), type);
1291 /* Common stuff again -- free the resource, recurse to next one */
1296 free_resource(nres, type);
1301 * Save the new resource by chaining it into the head list for
1302 * the resource. If this is pass 2, we update any resource
1303 * pointers because they may not have been defined until
1306 void save_resource(int type, RES_ITEM *items, int pass)
1309 int rindex = type - r_first;
1313 /* Check Job requirements after applying JobDefs */
1314 if (type != R_JOB && type != R_JOBDEFS) {
1316 * Ensure that all required items are present
1318 for (i=0; items[i].name; i++) {
1319 if (items[i].flags & ITEM_REQUIRED) {
1320 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1321 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1322 items[i].name, resources[rindex]);
1325 /* If this triggers, take a look at lib/parse_conf.h */
1326 if (i >= MAX_RES_ITEMS) {
1327 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1330 } else if (type == R_JOB) {
1332 * Ensure that the name item is present
1334 if (items[0].flags & ITEM_REQUIRED) {
1335 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1336 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1337 items[0].name, resources[rindex]);
1343 * During pass 2 in each "store" routine, we looked up pointers
1344 * to all the resources referrenced in the current resource, now we
1345 * must copy their addresses from the static record to the allocated
1350 /* Resources not containing a resource */
1358 * Resources containing another resource or alist. First
1359 * look up the resource which contains another resource. It
1360 * was written during pass 1. Then stuff in the pointers to
1361 * the resources it contains, which were inserted this pass.
1362 * Finally, it will all be stored back.
1365 /* Find resource saved in pass 1 */
1366 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1367 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1369 /* Explicitly copy resource pointers from this pass (res_all) */
1370 res->res_pool.NextPool = res_all.res_pool.NextPool;
1371 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1372 res->res_pool.storage = res_all.res_pool.storage;
1373 res->res_pool.catalog = res_all.res_pool.catalog;
1376 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1377 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1379 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1382 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1383 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1385 res->res_dir.messages = res_all.res_dir.messages;
1386 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1389 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1390 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1391 res_all.res_dir.hdr.name);
1393 /* we must explicitly copy the device alist pointer */
1394 res->res_store.device = res_all.res_store.device;
1398 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1399 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1400 res_all.res_dir.hdr.name);
1402 res->res_job.messages = res_all.res_job.messages;
1403 res->res_job.schedule = res_all.res_job.schedule;
1404 res->res_job.client = res_all.res_job.client;
1405 res->res_job.fileset = res_all.res_job.fileset;
1406 res->res_job.storage = res_all.res_job.storage;
1407 res->res_job.pool = res_all.res_job.pool;
1408 res->res_job.full_pool = res_all.res_job.full_pool;
1409 res->res_job.inc_pool = res_all.res_job.inc_pool;
1410 res->res_job.diff_pool = res_all.res_job.diff_pool;
1411 res->res_job.verify_job = res_all.res_job.verify_job;
1412 res->res_job.jobdefs = res_all.res_job.jobdefs;
1413 res->res_job.run_cmds = res_all.res_job.run_cmds;
1414 res->res_job.RunScripts = res_all.res_job.RunScripts;
1416 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1417 * is not very useful)
1418 * We have to set_bit(index, res_all.hdr.item_present);
1419 * or something like that
1422 /* we take RegexWhere before all other options */
1423 if (!res->res_job.RegexWhere
1425 (res->res_job.strip_prefix ||
1426 res->res_job.add_suffix ||
1427 res->res_job.add_prefix))
1429 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1430 res->res_job.add_prefix,
1431 res->res_job.add_suffix);
1432 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1433 bregexp_build_where(res->res_job.RegexWhere, len,
1434 res->res_job.strip_prefix,
1435 res->res_job.add_prefix,
1436 res->res_job.add_suffix);
1437 /* TODO: test bregexp */
1440 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1441 free(res->res_job.RestoreWhere);
1442 res->res_job.RestoreWhere = NULL;
1447 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1448 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1450 res->res_counter.Catalog = res_all.res_counter.Catalog;
1451 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1455 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1456 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1458 res->res_client.catalog = res_all.res_client.catalog;
1459 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1463 * Schedule is a bit different in that it contains a RUN record
1464 * chain which isn't a "named" resource. This chain was linked
1465 * in by run_conf.c during pass 2, so here we jam the pointer
1466 * into the Schedule resource.
1468 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1469 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1471 res->res_sch.run = res_all.res_sch.run;
1474 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1478 /* Note, the resource name was already saved during pass 1,
1479 * so here, we can just release it.
1481 if (res_all.res_dir.hdr.name) {
1482 free(res_all.res_dir.hdr.name);
1483 res_all.res_dir.hdr.name = NULL;
1485 if (res_all.res_dir.hdr.desc) {
1486 free(res_all.res_dir.hdr.desc);
1487 res_all.res_dir.hdr.desc = NULL;
1493 * The following code is only executed during pass 1
1497 size = sizeof(DIRRES);
1500 size = sizeof(CONRES);
1503 size =sizeof(CLIENT);
1506 size = sizeof(STORE);
1516 size = sizeof(FILESET);
1519 size = sizeof(SCHED);
1522 size = sizeof(POOL);
1525 size = sizeof(MSGS);
1528 size = sizeof(COUNTER);
1534 printf(_("Unknown resource type %d in save_resource.\n"), type);
1540 res = (URES *)malloc(size);
1541 memcpy(res, &res_all, size);
1542 if (!res_head[rindex]) {
1543 res_head[rindex] = (RES *)res; /* store first entry */
1544 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1545 res->res_dir.hdr.name, rindex);
1548 if (res->res_dir.hdr.name == NULL) {
1549 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1552 /* Add new res to end of chain */
1553 for (last=next=res_head[rindex]; next; next=next->next) {
1555 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1556 Emsg2(M_ERROR_TERM, 0,
1557 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1558 resources[rindex].name, res->res_dir.hdr.name);
1561 last->next = (RES *)res;
1562 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1563 res->res_dir.hdr.name, rindex, pass);
1569 * Store Device. Note, the resource is created upon the
1570 * first reference. The details of the resource are obtained
1571 * later from the SD.
1573 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1577 int rindex = R_DEVICE - r_first;
1578 int size = sizeof(DEVICE);
1582 token = lex_get_token(lc, T_NAME);
1583 if (!res_head[rindex]) {
1584 res = (URES *)malloc(size);
1585 memset(res, 0, size);
1586 res->res_dev.hdr.name = bstrdup(lc->str);
1587 res_head[rindex] = (RES *)res; /* store first entry */
1588 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1589 res->res_dir.hdr.name, rindex);
1592 /* See if it is already defined */
1593 for (next=res_head[rindex]; next->next; next=next->next) {
1594 if (strcmp(next->name, lc->str) == 0) {
1600 res = (URES *)malloc(size);
1601 memset(res, 0, size);
1602 res->res_dev.hdr.name = bstrdup(lc->str);
1603 next->next = (RES *)res;
1604 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1605 res->res_dir.hdr.name, rindex, pass);
1610 set_bit(index, res_all.hdr.item_present);
1612 store_alist_res(lc, item, index, pass);
1617 * Store Migration/Copy type
1620 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1624 token = lex_get_token(lc, T_NAME);
1625 /* Store the type both pass 1 and pass 2 */
1626 for (i=0; migtypes[i].type_name; i++) {
1627 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1628 *(uint32_t *)(item->value) = migtypes[i].job_type;
1634 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1637 set_bit(index, res_all.hdr.item_present);
1643 * Store JobType (backup, verify, restore)
1646 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1650 token = lex_get_token(lc, T_NAME);
1651 /* Store the type both pass 1 and pass 2 */
1652 for (i=0; jobtypes[i].type_name; i++) {
1653 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1654 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1660 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1663 set_bit(index, res_all.hdr.item_present);
1667 * Store Job Level (Full, Incremental, ...)
1670 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1674 token = lex_get_token(lc, T_NAME);
1675 /* Store the level pass 2 so that type is defined */
1676 for (i=0; joblevels[i].level_name; i++) {
1677 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1678 *(uint32_t *)(item->value) = joblevels[i].level;
1684 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1687 set_bit(index, res_all.hdr.item_present);
1691 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1694 token = lex_get_token(lc, T_NAME);
1695 /* Scan Replacement options */
1696 for (i=0; ReplaceOptions[i].name; i++) {
1697 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1698 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1704 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1707 set_bit(index, res_all.hdr.item_present);
1711 * Store ACL (access control list)
1714 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1719 token = lex_get_token(lc, T_STRING);
1721 if (((alist **)item->value)[item->code] == NULL) {
1722 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1723 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1725 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1726 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1728 token = lex_get_token(lc, T_ALL);
1729 if (token == T_COMMA) {
1730 continue; /* get another ACL */
1734 set_bit(index, res_all.hdr.item_present);
1737 /* We build RunScripts items here */
1738 static RUNSCRIPT res_runscript;
1740 /* Store a runscript->when in a bit field */
1741 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1743 lex_get_token(lc, T_NAME);
1745 if (strcasecmp(lc->str, "before") == 0) {
1746 *(uint32_t *)(item->value) = SCRIPT_Before ;
1747 } else if (strcasecmp(lc->str, "after") == 0) {
1748 *(uint32_t *)(item->value) = SCRIPT_After;
1749 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1750 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1751 } else if (strcasecmp(lc->str, "always") == 0) {
1752 *(uint32_t *)(item->value) = SCRIPT_Any;
1754 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1759 /* Store a runscript->target
1762 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1764 lex_get_token(lc, T_STRING);
1767 if (strcmp(lc->str, "%c") == 0) {
1768 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1769 } else if (strcasecmp(lc->str, "yes") == 0) {
1770 ((RUNSCRIPT*) item->value)->set_target("%c");
1771 } else if (strcasecmp(lc->str, "no") == 0) {
1772 ((RUNSCRIPT*) item->value)->set_target("");
1774 RES *res = GetResWithName(R_CLIENT, lc->str);
1776 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1777 lc->str, lc->line_no, lc->line);
1780 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1787 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1789 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1791 lex_get_token(lc, T_STRING);
1794 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1795 POOLMEM *c = get_pool_memory(PM_FNAME);
1796 /* Each runscript command takes 2 entries in commands list */
1797 pm_strcpy(c, lc->str);
1798 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1799 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1804 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1806 lex_get_token(lc, T_STRING);
1807 alist **runscripts = (alist **)(item->value) ;
1810 RUNSCRIPT *script = new_runscript();
1811 script->set_job_code_callback(job_code_callback_filesetname);
1813 script->set_command(lc->str);
1815 /* TODO: remove all script->old_proto with bacula 1.42 */
1817 if (strcmp(item->name, "runbeforejob") == 0) {
1818 script->when = SCRIPT_Before;
1819 script->fail_on_error = true;
1820 script->set_target("");
1822 } else if (strcmp(item->name, "runafterjob") == 0) {
1823 script->when = SCRIPT_After;
1824 script->on_success = true;
1825 script->on_failure = false;
1826 script->set_target("");
1828 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1829 script->old_proto = true;
1830 script->when = SCRIPT_After;
1831 script->set_target("%c");
1832 script->on_success = true;
1833 script->on_failure = false;
1835 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1836 script->old_proto = true;
1837 script->when = SCRIPT_Before;
1838 script->set_target("%c");
1839 script->fail_on_error = true;
1841 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1842 script->when = SCRIPT_After;
1843 script->on_failure = true;
1844 script->on_success = false;
1845 script->set_target("");
1848 if (*runscripts == NULL) {
1849 *runscripts = New(alist(10, not_owned_by_alist));
1852 (*runscripts)->append(script);
1859 /* Store a bool in a bit field without modifing res_all.hdr
1860 * We can also add an option to store_bool to skip res_all.hdr
1862 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1864 lex_get_token(lc, T_NAME);
1865 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1866 *(bool *)(item->value) = true;
1867 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1868 *(bool *)(item->value) = false;
1870 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1876 * new RunScript items
1877 * name handler value code flags default_value
1879 static RES_ITEM runscript_items[] = {
1880 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1881 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1882 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1883 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1884 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1885 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1886 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1887 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1888 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1889 {NULL, NULL, {0}, 0, 0, 0}
1893 * Store RunScript info
1895 * Note, when this routine is called, we are inside a Job
1896 * resource. We treat the RunScript like a sort of
1897 * mini-resource within the Job resource.
1899 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1903 alist **runscripts = (alist **)(item->value) ;
1905 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1907 token = lex_get_token(lc, T_SKIP_EOL);
1909 if (token != T_BOB) {
1910 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1912 /* setting on_success, on_failure, fail_on_error */
1913 res_runscript.reset_default();
1916 res_runscript.commands = New(alist(10, not_owned_by_alist));
1919 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1920 if (token == T_EOB) {
1923 if (token != T_IDENTIFIER) {
1924 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1926 for (i=0; runscript_items[i].name; i++) {
1927 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1928 token = lex_get_token(lc, T_SKIP_EOL);
1929 if (token != T_EQUALS) {
1930 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1933 /* Call item handler */
1934 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1941 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1946 /* run on client by default */
1947 if (res_runscript.target == NULL) {
1948 res_runscript.set_target("%c");
1950 if (*runscripts == NULL) {
1951 *runscripts = New(alist(10, not_owned_by_alist));
1954 * commands list contains 2 values per command
1955 * - POOLMEM command string (ex: /bin/true)
1956 * - int command type (ex: SHELL_CMD)
1958 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1959 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1960 t = (long)res_runscript.commands->pop();
1961 RUNSCRIPT *script = new_runscript();
1962 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1963 script->command = c;
1964 script->cmd_type = t;
1965 /* target is taken from res_runscript, each runscript object have
1968 script->target = NULL;
1969 script->set_target(res_runscript.target);
1971 (*runscripts)->append(script);
1974 delete res_runscript.commands;
1975 /* setting on_success, on_failure... cleanup target field */
1976 res_runscript.reset_default(true);
1980 set_bit(index, res_all.hdr.item_present);
1983 /* callback function for edit_job_codes */
1984 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1986 if (param[0] == 'f') {
1987 return jcr->fileset->name();
1993 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
1995 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
1996 r_first, r_last, resources, res_head);
1997 return config->parse_config();