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, 3 * 60},
124 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
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 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
313 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
314 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
315 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
316 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
317 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
318 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
319 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
320 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
323 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
324 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
325 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
326 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
327 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
328 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
329 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
330 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
331 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
332 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
333 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
334 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
335 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
336 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
337 {NULL, NULL, {0}, 0, 0, 0}
342 * name handler value code flags default_value
344 static RES_ITEM fs_items[] = {
345 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
346 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
347 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
348 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
349 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
350 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
351 {NULL, NULL, {0}, 0, 0, 0}
354 /* Schedule -- see run_conf.c */
357 * name handler value code flags default_value
359 static RES_ITEM sch_items[] = {
360 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
361 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
362 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
363 {NULL, NULL, {0}, 0, 0, 0}
368 * name handler value code flags default_value
370 static RES_ITEM pool_items[] = {
371 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
372 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
373 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
374 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
375 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
376 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
377 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
378 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
379 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
380 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
381 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
382 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
383 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
384 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
385 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
386 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
387 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
388 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
389 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
390 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
391 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
392 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
393 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
394 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
395 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
396 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
397 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
398 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
399 {NULL, NULL, {0}, 0, 0, 0}
404 * name handler value code flags default_value
406 static RES_ITEM counter_items[] = {
407 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
408 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
409 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
410 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
411 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
412 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
413 {NULL, NULL, {0}, 0, 0, 0}
417 /* Message resource */
418 extern RES_ITEM msgs_items[];
421 * This is the master resource definition.
422 * It must have one item for each of the resources.
424 * NOTE!!! keep it in the same order as the R_codes
425 * or eliminate all resources[rindex].name
427 * name items rcode res_head
429 RES_TABLE resources[] = {
430 {"director", dir_items, R_DIRECTOR},
431 {"client", cli_items, R_CLIENT},
432 {"job", job_items, R_JOB},
433 {"storage", store_items, R_STORAGE},
434 {"catalog", cat_items, R_CATALOG},
435 {"schedule", sch_items, R_SCHEDULE},
436 {"fileset", fs_items, R_FILESET},
437 {"pool", pool_items, R_POOL},
438 {"messages", msgs_items, R_MSGS},
439 {"counter", counter_items, R_COUNTER},
440 {"console", con_items, R_CONSOLE},
441 {"jobdefs", job_items, R_JOBDEFS},
442 {"device", NULL, R_DEVICE}, /* info obtained from SD */
447 /* Keywords (RHS) permitted in Job Level records
449 * level_name level job_type
451 struct s_jl joblevels[] = {
452 {"Full", L_FULL, JT_BACKUP},
453 {"Base", L_BASE, JT_BACKUP},
454 {"Incremental", L_INCREMENTAL, JT_BACKUP},
455 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
456 {"Since", L_SINCE, JT_BACKUP},
457 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
458 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
459 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
460 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
461 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
462 {"Data", L_VERIFY_DATA, JT_VERIFY},
463 {" ", L_NONE, JT_ADMIN},
464 {" ", L_NONE, JT_RESTORE},
468 /* Keywords (RHS) permitted in Job type records
472 struct s_jt jobtypes[] = {
473 {"backup", JT_BACKUP},
475 {"verify", JT_VERIFY},
476 {"restore", JT_RESTORE},
477 {"migrate", JT_MIGRATE},
483 /* Keywords (RHS) permitted in Selection type records
487 struct s_jt migtypes[] = {
488 {"smallestvolume", MT_SMALLEST_VOL},
489 {"oldestvolume", MT_OLDEST_VOL},
490 {"pooloccupancy", MT_POOL_OCCUPANCY},
491 {"pooltime", MT_POOL_TIME},
492 {"client", MT_CLIENT},
493 {"volume", MT_VOLUME},
495 {"sqlquery", MT_SQLQUERY},
501 /* Options permitted in Restore replace= */
502 struct s_kw ReplaceOptions[] = {
503 {"always", REPLACE_ALWAYS},
504 {"ifnewer", REPLACE_IFNEWER},
505 {"ifolder", REPLACE_IFOLDER},
506 {"never", REPLACE_NEVER},
510 const char *level_to_str(int level)
513 static char level_no[30];
514 const char *str = level_no;
516 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
517 for (i=0; joblevels[i].level_name; i++) {
518 if (level == (int)joblevels[i].level) {
519 str = joblevels[i].level_name;
526 /* Dump contents of resource */
527 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
529 URES *res = (URES *)reshdr;
531 char ed1[100], ed2[100], ed3[100];
535 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
538 if (type < 0) { /* no recursion */
544 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
545 reshdr->name, res->res_dir.MaxConcurrentJobs,
546 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
547 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
548 if (res->res_dir.query_file) {
549 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
551 if (res->res_dir.messages) {
552 sendit(sock, _(" --> "));
553 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
557 sendit(sock, _("Console: name=%s SSL=%d\n"),
558 res->res_con.hdr.name, res->res_con.tls_enable);
561 if (res->res_counter.WrapCounter) {
562 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
563 res->res_counter.hdr.name, res->res_counter.MinValue,
564 res->res_counter.MaxValue, res->res_counter.CurrentValue,
565 res->res_counter.WrapCounter->hdr.name);
567 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
568 res->res_counter.hdr.name, res->res_counter.MinValue,
569 res->res_counter.MaxValue);
571 if (res->res_counter.Catalog) {
572 sendit(sock, _(" --> "));
573 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
578 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
579 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
580 res->res_client.MaxConcurrentJobs);
581 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
582 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
583 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
584 res->res_client.AutoPrune);
585 if (res->res_client.catalog) {
586 sendit(sock, _(" --> "));
587 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
594 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
595 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
596 " poolid=%s volname=%s MediaType=%s\n"),
597 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
598 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
599 dev->offline, dev->autochanger,
600 edit_uint64(dev->PoolId, ed1),
601 dev->VolumeName, dev->MediaType);
605 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
606 " DeviceName=%s MediaType=%s StorageId=%s\n"),
607 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
608 res->res_store.MaxConcurrentJobs,
609 res->res_store.dev_name(),
610 res->res_store.media_type,
611 edit_int64(res->res_store.StorageId, ed1));
615 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
616 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
617 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
618 res->res_cat.db_port, res->res_cat.db_name,
619 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
620 res->res_cat.mult_db_connections);
625 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
626 type == R_JOB ? _("Job") : _("JobDefs"),
627 res->res_job.hdr.name, res->res_job.JobType,
628 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
629 res->res_job.enabled);
630 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
631 res->res_job.MaxConcurrentJobs,
632 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
633 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
634 res->res_job.spool_data, res->res_job.write_part_after_job);
635 if (res->res_job.spool_size) {
636 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
638 if (res->res_job.JobType == JT_BACKUP) {
639 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
641 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
642 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
644 if (res->res_job.client) {
645 sendit(sock, _(" --> "));
646 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
648 if (res->res_job.fileset) {
649 sendit(sock, _(" --> "));
650 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
652 if (res->res_job.schedule) {
653 sendit(sock, _(" --> "));
654 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
656 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
657 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
659 if (res->res_job.RegexWhere) {
660 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
662 if (res->res_job.RestoreBootstrap) {
663 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
665 if (res->res_job.WriteBootstrap) {
666 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
668 if (res->res_job.PluginOptions) {
669 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
671 if (res->res_job.MaxRunTime) {
672 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
674 if (res->res_job.MaxWaitTime) {
675 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
677 if (res->res_job.MaxStartDelay) {
678 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
680 if (res->res_job.storage) {
682 foreach_alist(store, res->res_job.storage) {
683 sendit(sock, _(" --> "));
684 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
687 if (res->res_job.RunScripts) {
689 foreach_alist(script, res->res_job.RunScripts) {
690 sendit(sock, _(" --> RunScript\n"));
691 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
692 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
693 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
694 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
695 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
696 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
699 if (res->res_job.pool) {
700 sendit(sock, _(" --> "));
701 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
703 if (res->res_job.full_pool) {
704 sendit(sock, _(" --> "));
705 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
707 if (res->res_job.inc_pool) {
708 sendit(sock, _(" --> "));
709 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
711 if (res->res_job.diff_pool) {
712 sendit(sock, _(" --> "));
713 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
715 if (res->res_job.verify_job) {
716 sendit(sock, _(" --> "));
717 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
719 if (res->res_job.run_cmds) {
721 foreach_alist(runcmd, res->res_job.run_cmds) {
722 sendit(sock, _(" --> Run=%s\n"), runcmd);
725 if (res->res_job.selection_pattern) {
726 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
728 if (res->res_job.messages) {
729 sendit(sock, _(" --> "));
730 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
737 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
738 for (i=0; i<res->res_fs.num_includes; i++) {
739 INCEXE *incexe = res->res_fs.include_items[i];
740 for (j=0; j<incexe->num_opts; j++) {
741 FOPTS *fo = incexe->opts_list[j];
742 sendit(sock, " O %s\n", fo->opts);
744 bool enhanced_wild = false;
745 for (k=0; fo->opts[k]!='\0'; k++) {
746 if (fo->opts[k]=='W') {
747 enhanced_wild = true;
752 for (k=0; k<fo->regex.size(); k++) {
753 sendit(sock, " R %s\n", fo->regex.get(k));
755 for (k=0; k<fo->regexdir.size(); k++) {
756 sendit(sock, " RD %s\n", fo->regexdir.get(k));
758 for (k=0; k<fo->regexfile.size(); k++) {
759 sendit(sock, " RF %s\n", fo->regexfile.get(k));
761 for (k=0; k<fo->wild.size(); k++) {
762 sendit(sock, " W %s\n", fo->wild.get(k));
764 for (k=0; k<fo->wilddir.size(); k++) {
765 sendit(sock, " WD %s\n", fo->wilddir.get(k));
767 for (k=0; k<fo->wildfile.size(); k++) {
768 sendit(sock, " WF %s\n", fo->wildfile.get(k));
770 for (k=0; k<fo->wildbase.size(); k++) {
771 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
773 for (k=0; k<fo->base.size(); k++) {
774 sendit(sock, " B %s\n", fo->base.get(k));
776 for (k=0; k<fo->fstype.size(); k++) {
777 sendit(sock, " X %s\n", fo->fstype.get(k));
779 for (k=0; k<fo->drivetype.size(); k++) {
780 sendit(sock, " XD %s\n", fo->drivetype.get(k));
783 sendit(sock, " G %s\n", fo->plugin);
786 sendit(sock, " D %s\n", fo->reader);
789 sendit(sock, " T %s\n", fo->writer);
791 sendit(sock, " N\n");
793 for (j=0; j<incexe->name_list.size(); j++) {
794 sendit(sock, " I %s\n", incexe->name_list.get(j));
796 if (incexe->name_list.size()) {
797 sendit(sock, " N\n");
799 for (j=0; j<incexe->plugin_list.size(); j++) {
800 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
802 if (incexe->plugin_list.size()) {
803 sendit(sock, " N\n");
808 for (i=0; i<res->res_fs.num_excludes; i++) {
809 INCEXE *incexe = res->res_fs.exclude_items[i];
810 for (j=0; j<incexe->name_list.size(); j++) {
811 sendit(sock, " E %s\n", incexe->name_list.get(j));
813 if (incexe->name_list.size()) {
814 sendit(sock, " N\n");
821 if (res->res_sch.run) {
823 RUN *run = res->res_sch.run;
824 char buf[1000], num[30];
825 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
830 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
831 bstrncpy(buf, _(" hour="), sizeof(buf));
832 for (i=0; i<24; i++) {
833 if (bit_is_set(i, run->hour)) {
834 bsnprintf(num, sizeof(num), "%d ", i);
835 bstrncat(buf, num, sizeof(buf));
838 bstrncat(buf, "\n", sizeof(buf));
840 bstrncpy(buf, _(" mday="), sizeof(buf));
841 for (i=0; i<31; i++) {
842 if (bit_is_set(i, run->mday)) {
843 bsnprintf(num, sizeof(num), "%d ", i);
844 bstrncat(buf, num, sizeof(buf));
847 bstrncat(buf, "\n", sizeof(buf));
849 bstrncpy(buf, _(" month="), sizeof(buf));
850 for (i=0; i<12; i++) {
851 if (bit_is_set(i, run->month)) {
852 bsnprintf(num, sizeof(num), "%d ", i);
853 bstrncat(buf, num, sizeof(buf));
856 bstrncat(buf, "\n", sizeof(buf));
858 bstrncpy(buf, _(" wday="), sizeof(buf));
859 for (i=0; i<7; i++) {
860 if (bit_is_set(i, run->wday)) {
861 bsnprintf(num, sizeof(num), "%d ", i);
862 bstrncat(buf, num, sizeof(buf));
865 bstrncat(buf, "\n", sizeof(buf));
867 bstrncpy(buf, _(" wom="), sizeof(buf));
868 for (i=0; i<5; i++) {
869 if (bit_is_set(i, run->wom)) {
870 bsnprintf(num, sizeof(num), "%d ", i);
871 bstrncat(buf, num, sizeof(buf));
874 bstrncat(buf, "\n", sizeof(buf));
876 bstrncpy(buf, _(" woy="), sizeof(buf));
877 for (i=0; i<54; i++) {
878 if (bit_is_set(i, run->woy)) {
879 bsnprintf(num, sizeof(num), "%d ", i);
880 bstrncat(buf, num, sizeof(buf));
883 bstrncat(buf, "\n", sizeof(buf));
885 sendit(sock, _(" mins=%d\n"), run->minute);
887 sendit(sock, _(" --> "));
888 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
891 sendit(sock, _(" --> "));
892 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
895 sendit(sock, _(" --> "));
896 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
898 /* If another Run record is chained in, go print it */
904 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
909 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
910 res->res_pool.pool_type);
911 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
912 res->res_pool.use_catalog, res->res_pool.use_volume_once,
913 res->res_pool.catalog_files);
914 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
915 res->res_pool.max_volumes, res->res_pool.AutoPrune,
916 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
917 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
918 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
919 res->res_pool.Recycle,
920 NPRT(res->res_pool.label_format));
921 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
922 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
923 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
924 res->res_pool.recycle_oldest_volume,
925 res->res_pool.purge_oldest_volume);
926 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
927 res->res_pool.MaxVolJobs,
928 res->res_pool.MaxVolFiles,
929 edit_uint64(res->res_pool.MaxVolFiles, ed1));
930 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
931 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
932 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
933 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
934 if (res->res_pool.NextPool) {
935 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
937 if (res->res_pool.RecyclePool) {
938 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
940 if (res->res_pool.catalog) {
941 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
943 if (res->res_pool.storage) {
945 foreach_alist(store, res->res_pool.storage) {
946 sendit(sock, _(" --> "));
947 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
950 if (res->res_pool.CopyPool) {
952 foreach_alist(copy, res->res_pool.CopyPool) {
953 sendit(sock, _(" --> "));
954 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
961 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
962 if (res->res_msgs.mail_cmd)
963 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
964 if (res->res_msgs.operator_cmd)
965 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
969 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
972 if (recurse && res->res_dir.hdr.next) {
973 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
978 * Free all the members of an INCEXE structure
980 static void free_incexe(INCEXE *incexe)
982 incexe->name_list.destroy();
983 incexe->plugin_list.destroy();
984 for (int i=0; i<incexe->num_opts; i++) {
985 FOPTS *fopt = incexe->opts_list[i];
986 fopt->regex.destroy();
987 fopt->regexdir.destroy();
988 fopt->regexfile.destroy();
989 fopt->wild.destroy();
990 fopt->wilddir.destroy();
991 fopt->wildfile.destroy();
992 fopt->wildbase.destroy();
993 fopt->base.destroy();
994 fopt->fstype.destroy();
995 fopt->drivetype.destroy();
1007 if (incexe->opts_list) {
1008 free(incexe->opts_list);
1014 * Free memory of resource -- called when daemon terminates.
1015 * NB, we don't need to worry about freeing any references
1016 * to other resources as they will be freed when that
1017 * resource chain is traversed. Mainly we worry about freeing
1018 * allocated strings (names).
1020 void free_resource(RES *sres, int type)
1023 RES *nres; /* next resource if linked */
1024 URES *res = (URES *)sres;
1029 /* common stuff -- free the resource name and description */
1030 nres = (RES *)res->res_dir.hdr.next;
1031 if (res->res_dir.hdr.name) {
1032 free(res->res_dir.hdr.name);
1034 if (res->res_dir.hdr.desc) {
1035 free(res->res_dir.hdr.desc);
1040 if (res->res_dir.working_directory) {
1041 free(res->res_dir.working_directory);
1043 if (res->res_dir.scripts_directory) {
1044 free((char *)res->res_dir.scripts_directory);
1046 if (res->res_dir.plugin_directory) {
1047 free((char *)res->res_dir.plugin_directory);
1049 if (res->res_dir.pid_directory) {
1050 free(res->res_dir.pid_directory);
1052 if (res->res_dir.subsys_directory) {
1053 free(res->res_dir.subsys_directory);
1055 if (res->res_dir.password) {
1056 free(res->res_dir.password);
1058 if (res->res_dir.query_file) {
1059 free(res->res_dir.query_file);
1061 if (res->res_dir.DIRaddrs) {
1062 free_addresses(res->res_dir.DIRaddrs);
1064 if (res->res_dir.tls_ctx) {
1065 free_tls_context(res->res_dir.tls_ctx);
1067 if (res->res_dir.tls_ca_certfile) {
1068 free(res->res_dir.tls_ca_certfile);
1070 if (res->res_dir.tls_ca_certdir) {
1071 free(res->res_dir.tls_ca_certdir);
1073 if (res->res_dir.tls_certfile) {
1074 free(res->res_dir.tls_certfile);
1076 if (res->res_dir.tls_keyfile) {
1077 free(res->res_dir.tls_keyfile);
1079 if (res->res_dir.tls_dhfile) {
1080 free(res->res_dir.tls_dhfile);
1082 if (res->res_dir.tls_allowed_cns) {
1083 delete res->res_dir.tls_allowed_cns;
1090 if (res->res_con.password) {
1091 free(res->res_con.password);
1093 if (res->res_con.tls_ctx) {
1094 free_tls_context(res->res_con.tls_ctx);
1096 if (res->res_con.tls_ca_certfile) {
1097 free(res->res_con.tls_ca_certfile);
1099 if (res->res_con.tls_ca_certdir) {
1100 free(res->res_con.tls_ca_certdir);
1102 if (res->res_con.tls_certfile) {
1103 free(res->res_con.tls_certfile);
1105 if (res->res_con.tls_keyfile) {
1106 free(res->res_con.tls_keyfile);
1108 if (res->res_con.tls_dhfile) {
1109 free(res->res_con.tls_dhfile);
1111 if (res->res_con.tls_allowed_cns) {
1112 delete res->res_con.tls_allowed_cns;
1114 for (int i=0; i<Num_ACL; i++) {
1115 if (res->res_con.ACL_lists[i]) {
1116 delete res->res_con.ACL_lists[i];
1117 res->res_con.ACL_lists[i] = NULL;
1122 if (res->res_client.address) {
1123 free(res->res_client.address);
1125 if (res->res_client.password) {
1126 free(res->res_client.password);
1128 if (res->res_client.tls_ctx) {
1129 free_tls_context(res->res_client.tls_ctx);
1131 if (res->res_client.tls_ca_certfile) {
1132 free(res->res_client.tls_ca_certfile);
1134 if (res->res_client.tls_ca_certdir) {
1135 free(res->res_client.tls_ca_certdir);
1137 if (res->res_client.tls_certfile) {
1138 free(res->res_client.tls_certfile);
1140 if (res->res_client.tls_keyfile) {
1141 free(res->res_client.tls_keyfile);
1143 if (res->res_client.tls_allowed_cns) {
1144 delete res->res_client.tls_allowed_cns;
1148 if (res->res_store.address) {
1149 free(res->res_store.address);
1151 if (res->res_store.password) {
1152 free(res->res_store.password);
1154 if (res->res_store.media_type) {
1155 free(res->res_store.media_type);
1157 if (res->res_store.device) {
1158 delete res->res_store.device;
1160 if (res->res_store.tls_ctx) {
1161 free_tls_context(res->res_store.tls_ctx);
1163 if (res->res_store.tls_ca_certfile) {
1164 free(res->res_store.tls_ca_certfile);
1166 if (res->res_store.tls_ca_certdir) {
1167 free(res->res_store.tls_ca_certdir);
1169 if (res->res_store.tls_certfile) {
1170 free(res->res_store.tls_certfile);
1172 if (res->res_store.tls_keyfile) {
1173 free(res->res_store.tls_keyfile);
1177 if (res->res_cat.db_address) {
1178 free(res->res_cat.db_address);
1180 if (res->res_cat.db_socket) {
1181 free(res->res_cat.db_socket);
1183 if (res->res_cat.db_user) {
1184 free(res->res_cat.db_user);
1186 if (res->res_cat.db_name) {
1187 free(res->res_cat.db_name);
1189 if (res->res_cat.db_driver) {
1190 free(res->res_cat.db_driver);
1192 if (res->res_cat.db_password) {
1193 free(res->res_cat.db_password);
1197 if ((num=res->res_fs.num_includes)) {
1198 while (--num >= 0) {
1199 free_incexe(res->res_fs.include_items[num]);
1201 free(res->res_fs.include_items);
1203 res->res_fs.num_includes = 0;
1204 if ((num=res->res_fs.num_excludes)) {
1205 while (--num >= 0) {
1206 free_incexe(res->res_fs.exclude_items[num]);
1208 free(res->res_fs.exclude_items);
1210 res->res_fs.num_excludes = 0;
1213 if (res->res_pool.pool_type) {
1214 free(res->res_pool.pool_type);
1216 if (res->res_pool.label_format) {
1217 free(res->res_pool.label_format);
1219 if (res->res_pool.cleaning_prefix) {
1220 free(res->res_pool.cleaning_prefix);
1222 if (res->res_pool.storage) {
1223 delete res->res_pool.storage;
1227 if (res->res_sch.run) {
1229 nrun = res->res_sch.run;
1239 if (res->res_job.RestoreWhere) {
1240 free(res->res_job.RestoreWhere);
1242 if (res->res_job.RegexWhere) {
1243 free(res->res_job.RegexWhere);
1245 if (res->res_job.strip_prefix) {
1246 free(res->res_job.strip_prefix);
1248 if (res->res_job.add_prefix) {
1249 free(res->res_job.add_prefix);
1251 if (res->res_job.add_suffix) {
1252 free(res->res_job.add_suffix);
1254 if (res->res_job.RestoreBootstrap) {
1255 free(res->res_job.RestoreBootstrap);
1257 if (res->res_job.WriteBootstrap) {
1258 free(res->res_job.WriteBootstrap);
1260 if (res->res_job.PluginOptions) {
1261 free(res->res_job.PluginOptions);
1263 if (res->res_job.selection_pattern) {
1264 free(res->res_job.selection_pattern);
1266 if (res->res_job.run_cmds) {
1267 delete res->res_job.run_cmds;
1269 if (res->res_job.storage) {
1270 delete res->res_job.storage;
1272 if (res->res_job.RunScripts) {
1273 free_runscripts(res->res_job.RunScripts);
1274 delete res->res_job.RunScripts;
1278 if (res->res_msgs.mail_cmd) {
1279 free(res->res_msgs.mail_cmd);
1281 if (res->res_msgs.operator_cmd) {
1282 free(res->res_msgs.operator_cmd);
1284 free_msgs_res((MSGS *)res); /* free message resource */
1288 printf(_("Unknown resource type %d in free_resource.\n"), type);
1290 /* Common stuff again -- free the resource, recurse to next one */
1295 free_resource(nres, type);
1300 * Save the new resource by chaining it into the head list for
1301 * the resource. If this is pass 2, we update any resource
1302 * pointers because they may not have been defined until
1305 void save_resource(int type, RES_ITEM *items, int pass)
1308 int rindex = type - r_first;
1312 /* Check Job requirements after applying JobDefs */
1313 if (type != R_JOB && type != R_JOBDEFS) {
1315 * Ensure that all required items are present
1317 for (i=0; items[i].name; i++) {
1318 if (items[i].flags & ITEM_REQUIRED) {
1319 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1320 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1321 items[i].name, resources[rindex]);
1324 /* If this triggers, take a look at lib/parse_conf.h */
1325 if (i >= MAX_RES_ITEMS) {
1326 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1329 } else if (type == R_JOB) {
1331 * Ensure that the name item is present
1333 if (items[0].flags & ITEM_REQUIRED) {
1334 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1335 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1336 items[0].name, resources[rindex]);
1342 * During pass 2 in each "store" routine, we looked up pointers
1343 * to all the resources referrenced in the current resource, now we
1344 * must copy their addresses from the static record to the allocated
1349 /* Resources not containing a resource */
1357 * Resources containing another resource or alist. First
1358 * look up the resource which contains another resource. It
1359 * was written during pass 1. Then stuff in the pointers to
1360 * the resources it contains, which were inserted this pass.
1361 * Finally, it will all be stored back.
1364 /* Find resource saved in pass 1 */
1365 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1366 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1368 /* Explicitly copy resource pointers from this pass (res_all) */
1369 res->res_pool.NextPool = res_all.res_pool.NextPool;
1370 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1371 res->res_pool.storage = res_all.res_pool.storage;
1372 res->res_pool.catalog = res_all.res_pool.catalog;
1375 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1376 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1378 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1381 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1382 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1384 res->res_dir.messages = res_all.res_dir.messages;
1385 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1388 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1389 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1390 res_all.res_dir.hdr.name);
1392 /* we must explicitly copy the device alist pointer */
1393 res->res_store.device = res_all.res_store.device;
1397 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1398 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1399 res_all.res_dir.hdr.name);
1401 res->res_job.messages = res_all.res_job.messages;
1402 res->res_job.schedule = res_all.res_job.schedule;
1403 res->res_job.client = res_all.res_job.client;
1404 res->res_job.fileset = res_all.res_job.fileset;
1405 res->res_job.storage = res_all.res_job.storage;
1406 res->res_job.pool = res_all.res_job.pool;
1407 res->res_job.full_pool = res_all.res_job.full_pool;
1408 res->res_job.inc_pool = res_all.res_job.inc_pool;
1409 res->res_job.diff_pool = res_all.res_job.diff_pool;
1410 res->res_job.verify_job = res_all.res_job.verify_job;
1411 res->res_job.jobdefs = res_all.res_job.jobdefs;
1412 res->res_job.run_cmds = res_all.res_job.run_cmds;
1413 res->res_job.RunScripts = res_all.res_job.RunScripts;
1415 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1416 * is not very useful)
1417 * We have to set_bit(index, res_all.hdr.item_present);
1418 * or something like that
1421 /* we take RegexWhere before all other options */
1422 if (!res->res_job.RegexWhere
1424 (res->res_job.strip_prefix ||
1425 res->res_job.add_suffix ||
1426 res->res_job.add_prefix))
1428 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1429 res->res_job.add_prefix,
1430 res->res_job.add_suffix);
1431 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1432 bregexp_build_where(res->res_job.RegexWhere, len,
1433 res->res_job.strip_prefix,
1434 res->res_job.add_prefix,
1435 res->res_job.add_suffix);
1436 /* TODO: test bregexp */
1439 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1440 free(res->res_job.RestoreWhere);
1441 res->res_job.RestoreWhere = NULL;
1446 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1447 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1449 res->res_counter.Catalog = res_all.res_counter.Catalog;
1450 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1454 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1455 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1457 res->res_client.catalog = res_all.res_client.catalog;
1458 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1462 * Schedule is a bit different in that it contains a RUN record
1463 * chain which isn't a "named" resource. This chain was linked
1464 * in by run_conf.c during pass 2, so here we jam the pointer
1465 * into the Schedule resource.
1467 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1468 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1470 res->res_sch.run = res_all.res_sch.run;
1473 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1477 /* Note, the resource name was already saved during pass 1,
1478 * so here, we can just release it.
1480 if (res_all.res_dir.hdr.name) {
1481 free(res_all.res_dir.hdr.name);
1482 res_all.res_dir.hdr.name = NULL;
1484 if (res_all.res_dir.hdr.desc) {
1485 free(res_all.res_dir.hdr.desc);
1486 res_all.res_dir.hdr.desc = NULL;
1492 * The following code is only executed during pass 1
1496 size = sizeof(DIRRES);
1499 size = sizeof(CONRES);
1502 size =sizeof(CLIENT);
1505 size = sizeof(STORE);
1515 size = sizeof(FILESET);
1518 size = sizeof(SCHED);
1521 size = sizeof(POOL);
1524 size = sizeof(MSGS);
1527 size = sizeof(COUNTER);
1533 printf(_("Unknown resource type %d in save_resource.\n"), type);
1539 res = (URES *)malloc(size);
1540 memcpy(res, &res_all, size);
1541 if (!res_head[rindex]) {
1542 res_head[rindex] = (RES *)res; /* store first entry */
1543 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1544 res->res_dir.hdr.name, rindex);
1547 if (res->res_dir.hdr.name == NULL) {
1548 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1551 /* Add new res to end of chain */
1552 for (last=next=res_head[rindex]; next; next=next->next) {
1554 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1555 Emsg2(M_ERROR_TERM, 0,
1556 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1557 resources[rindex].name, res->res_dir.hdr.name);
1560 last->next = (RES *)res;
1561 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1562 res->res_dir.hdr.name, rindex, pass);
1568 * Store Device. Note, the resource is created upon the
1569 * first reference. The details of the resource are obtained
1570 * later from the SD.
1572 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1576 int rindex = R_DEVICE - r_first;
1577 int size = sizeof(DEVICE);
1581 token = lex_get_token(lc, T_NAME);
1582 if (!res_head[rindex]) {
1583 res = (URES *)malloc(size);
1584 memset(res, 0, size);
1585 res->res_dev.hdr.name = bstrdup(lc->str);
1586 res_head[rindex] = (RES *)res; /* store first entry */
1587 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1588 res->res_dir.hdr.name, rindex);
1591 /* See if it is already defined */
1592 for (next=res_head[rindex]; next->next; next=next->next) {
1593 if (strcmp(next->name, lc->str) == 0) {
1599 res = (URES *)malloc(size);
1600 memset(res, 0, size);
1601 res->res_dev.hdr.name = bstrdup(lc->str);
1602 next->next = (RES *)res;
1603 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1604 res->res_dir.hdr.name, rindex, pass);
1609 set_bit(index, res_all.hdr.item_present);
1611 store_alist_res(lc, item, index, pass);
1616 * Store Migration/Copy type
1619 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1623 token = lex_get_token(lc, T_NAME);
1624 /* Store the type both pass 1 and pass 2 */
1625 for (i=0; migtypes[i].type_name; i++) {
1626 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1627 *(uint32_t *)(item->value) = migtypes[i].job_type;
1633 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1636 set_bit(index, res_all.hdr.item_present);
1642 * Store JobType (backup, verify, restore)
1645 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1649 token = lex_get_token(lc, T_NAME);
1650 /* Store the type both pass 1 and pass 2 */
1651 for (i=0; jobtypes[i].type_name; i++) {
1652 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1653 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1659 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1662 set_bit(index, res_all.hdr.item_present);
1666 * Store Job Level (Full, Incremental, ...)
1669 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1673 token = lex_get_token(lc, T_NAME);
1674 /* Store the level pass 2 so that type is defined */
1675 for (i=0; joblevels[i].level_name; i++) {
1676 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1677 *(uint32_t *)(item->value) = joblevels[i].level;
1683 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1686 set_bit(index, res_all.hdr.item_present);
1690 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1693 token = lex_get_token(lc, T_NAME);
1694 /* Scan Replacement options */
1695 for (i=0; ReplaceOptions[i].name; i++) {
1696 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1697 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1703 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1706 set_bit(index, res_all.hdr.item_present);
1710 * Store ACL (access control list)
1713 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1718 token = lex_get_token(lc, T_STRING);
1720 if (((alist **)item->value)[item->code] == NULL) {
1721 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1722 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1724 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1725 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1727 token = lex_get_token(lc, T_ALL);
1728 if (token == T_COMMA) {
1729 continue; /* get another ACL */
1733 set_bit(index, res_all.hdr.item_present);
1736 /* We build RunScripts items here */
1737 static RUNSCRIPT res_runscript;
1739 /* Store a runscript->when in a bit field */
1740 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1742 lex_get_token(lc, T_NAME);
1744 if (strcasecmp(lc->str, "before") == 0) {
1745 *(uint32_t *)(item->value) = SCRIPT_Before ;
1746 } else if (strcasecmp(lc->str, "after") == 0) {
1747 *(uint32_t *)(item->value) = SCRIPT_After;
1748 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1749 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1750 } else if (strcasecmp(lc->str, "always") == 0) {
1751 *(uint32_t *)(item->value) = SCRIPT_Any;
1753 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1758 /* Store a runscript->target
1761 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1763 lex_get_token(lc, T_STRING);
1766 if (strcmp(lc->str, "%c") == 0) {
1767 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1768 } else if (strcasecmp(lc->str, "yes") == 0) {
1769 ((RUNSCRIPT*) item->value)->set_target("%c");
1770 } else if (strcasecmp(lc->str, "no") == 0) {
1771 ((RUNSCRIPT*) item->value)->set_target("");
1773 RES *res = GetResWithName(R_CLIENT, lc->str);
1775 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1776 lc->str, lc->line_no, lc->line);
1779 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1786 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1788 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1790 lex_get_token(lc, T_STRING);
1793 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1794 POOLMEM *c = get_pool_memory(PM_FNAME);
1795 /* Each runscript command takes 2 entries in commands list */
1796 pm_strcpy(c, lc->str);
1797 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1798 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1803 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1805 lex_get_token(lc, T_STRING);
1806 alist **runscripts = (alist **)(item->value) ;
1809 RUNSCRIPT *script = new_runscript();
1810 script->set_job_code_callback(job_code_callback_filesetname);
1812 script->set_command(lc->str);
1814 /* TODO: remove all script->old_proto with bacula 1.42 */
1816 if (strcmp(item->name, "runbeforejob") == 0) {
1817 script->when = SCRIPT_Before;
1818 script->fail_on_error = true;
1819 script->set_target("");
1821 } else if (strcmp(item->name, "runafterjob") == 0) {
1822 script->when = SCRIPT_After;
1823 script->on_success = true;
1824 script->on_failure = false;
1825 script->set_target("");
1827 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1828 script->old_proto = true;
1829 script->when = SCRIPT_After;
1830 script->set_target("%c");
1831 script->on_success = true;
1832 script->on_failure = false;
1834 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1835 script->old_proto = true;
1836 script->when = SCRIPT_Before;
1837 script->set_target("%c");
1838 script->fail_on_error = true;
1840 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1841 script->when = SCRIPT_After;
1842 script->on_failure = true;
1843 script->on_success = false;
1844 script->set_target("");
1847 if (*runscripts == NULL) {
1848 *runscripts = New(alist(10, not_owned_by_alist));
1851 (*runscripts)->append(script);
1858 /* Store a bool in a bit field without modifing res_all.hdr
1859 * We can also add an option to store_bool to skip res_all.hdr
1861 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1863 lex_get_token(lc, T_NAME);
1864 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1865 *(bool *)(item->value) = true;
1866 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1867 *(bool *)(item->value) = false;
1869 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1875 * new RunScript items
1876 * name handler value code flags default_value
1878 static RES_ITEM runscript_items[] = {
1879 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1880 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1881 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1882 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1883 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1884 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1885 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1886 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1887 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1888 {NULL, NULL, {0}, 0, 0, 0}
1892 * Store RunScript info
1894 * Note, when this routine is called, we are inside a Job
1895 * resource. We treat the RunScript like a sort of
1896 * mini-resource within the Job resource.
1898 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1902 alist **runscripts = (alist **)(item->value) ;
1904 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1906 token = lex_get_token(lc, T_SKIP_EOL);
1908 if (token != T_BOB) {
1909 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1911 /* setting on_success, on_failure, fail_on_error */
1912 res_runscript.reset_default();
1915 res_runscript.commands = New(alist(10, not_owned_by_alist));
1918 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1919 if (token == T_EOB) {
1922 if (token != T_IDENTIFIER) {
1923 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1925 for (i=0; runscript_items[i].name; i++) {
1926 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1927 token = lex_get_token(lc, T_SKIP_EOL);
1928 if (token != T_EQUALS) {
1929 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1932 /* Call item handler */
1933 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1940 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1945 /* run on client by default */
1946 if (res_runscript.target == NULL) {
1947 res_runscript.set_target("%c");
1949 if (*runscripts == NULL) {
1950 *runscripts = New(alist(10, not_owned_by_alist));
1953 * commands list contains 2 values per command
1954 * - POOLMEM command string (ex: /bin/true)
1955 * - int command type (ex: SHELL_CMD)
1957 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1958 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1959 t = (long)res_runscript.commands->pop();
1960 RUNSCRIPT *script = new_runscript();
1961 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1962 script->command = c;
1963 script->cmd_type = t;
1964 /* target is taken from res_runscript, each runscript object have
1967 script->target = NULL;
1968 script->set_target(res_runscript.target);
1970 (*runscripts)->append(script);
1973 delete res_runscript.commands;
1974 /* setting on_success, on_failure... cleanup target field */
1975 res_runscript.reset_default(true);
1979 set_bit(index, res_all.hdr.item_present);
1982 /* callback function for edit_job_codes */
1983 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1985 if (param[0] == 'f') {
1986 return jcr->fileset->name();
1992 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
1994 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
1995 r_first, r_last, resources, res_head);
1996 return config->parse_config();