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 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
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 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
494 {"client", MT_CLIENT},
495 {"volume", MT_VOLUME},
497 {"sqlquery", MT_SQLQUERY},
503 /* Options permitted in Restore replace= */
504 struct s_kw ReplaceOptions[] = {
505 {"always", REPLACE_ALWAYS},
506 {"ifnewer", REPLACE_IFNEWER},
507 {"ifolder", REPLACE_IFOLDER},
508 {"never", REPLACE_NEVER},
512 char *CAT::display(POOLMEM *dst) {
513 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
514 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
516 name(), NPRTB(db_name),
517 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
518 NPRTB(db_address), db_port, NPRTB(db_socket));
522 const char *level_to_str(int level)
525 static char level_no[30];
526 const char *str = level_no;
528 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
529 for (i=0; joblevels[i].level_name; i++) {
530 if (level == (int)joblevels[i].level) {
531 str = joblevels[i].level_name;
538 /* Dump contents of resource */
539 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
541 URES *res = (URES *)reshdr;
543 char ed1[100], ed2[100], ed3[100];
547 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
550 if (type < 0) { /* no recursion */
556 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
557 reshdr->name, res->res_dir.MaxConcurrentJobs,
558 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
559 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
560 if (res->res_dir.query_file) {
561 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
563 if (res->res_dir.messages) {
564 sendit(sock, _(" --> "));
565 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
569 sendit(sock, _("Console: name=%s SSL=%d\n"),
570 res->res_con.hdr.name, res->res_con.tls_enable);
573 if (res->res_counter.WrapCounter) {
574 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
575 res->res_counter.hdr.name, res->res_counter.MinValue,
576 res->res_counter.MaxValue, res->res_counter.CurrentValue,
577 res->res_counter.WrapCounter->hdr.name);
579 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
580 res->res_counter.hdr.name, res->res_counter.MinValue,
581 res->res_counter.MaxValue);
583 if (res->res_counter.Catalog) {
584 sendit(sock, _(" --> "));
585 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
590 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
591 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
592 res->res_client.MaxConcurrentJobs);
593 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
594 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
595 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
596 res->res_client.AutoPrune);
597 if (res->res_client.catalog) {
598 sendit(sock, _(" --> "));
599 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
606 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
607 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
608 " poolid=%s volname=%s MediaType=%s\n"),
609 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
610 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
611 dev->offline, dev->autochanger,
612 edit_uint64(dev->PoolId, ed1),
613 dev->VolumeName, dev->MediaType);
617 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
618 " DeviceName=%s MediaType=%s StorageId=%s\n"),
619 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
620 res->res_store.MaxConcurrentJobs,
621 res->res_store.dev_name(),
622 res->res_store.media_type,
623 edit_int64(res->res_store.StorageId, ed1));
627 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
628 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
629 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
630 res->res_cat.db_port, res->res_cat.db_name,
631 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
632 res->res_cat.mult_db_connections);
637 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
638 type == R_JOB ? _("Job") : _("JobDefs"),
639 res->res_job.hdr.name, res->res_job.JobType,
640 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
641 res->res_job.enabled);
642 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
643 res->res_job.MaxConcurrentJobs,
644 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
645 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
646 res->res_job.spool_data, res->res_job.write_part_after_job);
647 if (res->res_job.spool_size) {
648 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
650 if (res->res_job.JobType == JT_BACKUP) {
651 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
653 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
654 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
656 if (res->res_job.client) {
657 sendit(sock, _(" --> "));
658 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
660 if (res->res_job.fileset) {
661 sendit(sock, _(" --> "));
662 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
664 if (res->res_job.schedule) {
665 sendit(sock, _(" --> "));
666 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
668 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
669 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
671 if (res->res_job.RegexWhere) {
672 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
674 if (res->res_job.RestoreBootstrap) {
675 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
677 if (res->res_job.WriteBootstrap) {
678 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
680 if (res->res_job.PluginOptions) {
681 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
683 if (res->res_job.MaxRunTime) {
684 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
686 if (res->res_job.MaxWaitTime) {
687 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
689 if (res->res_job.MaxStartDelay) {
690 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
692 if (res->res_job.storage) {
694 foreach_alist(store, res->res_job.storage) {
695 sendit(sock, _(" --> "));
696 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
699 if (res->res_job.RunScripts) {
701 foreach_alist(script, res->res_job.RunScripts) {
702 sendit(sock, _(" --> RunScript\n"));
703 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
704 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
705 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
706 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
707 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
708 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
711 if (res->res_job.pool) {
712 sendit(sock, _(" --> "));
713 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
715 if (res->res_job.full_pool) {
716 sendit(sock, _(" --> "));
717 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
719 if (res->res_job.inc_pool) {
720 sendit(sock, _(" --> "));
721 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
723 if (res->res_job.diff_pool) {
724 sendit(sock, _(" --> "));
725 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
727 if (res->res_job.verify_job) {
728 sendit(sock, _(" --> "));
729 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
731 if (res->res_job.run_cmds) {
733 foreach_alist(runcmd, res->res_job.run_cmds) {
734 sendit(sock, _(" --> Run=%s\n"), runcmd);
737 if (res->res_job.selection_pattern) {
738 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
740 if (res->res_job.messages) {
741 sendit(sock, _(" --> "));
742 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
749 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
750 for (i=0; i<res->res_fs.num_includes; i++) {
751 INCEXE *incexe = res->res_fs.include_items[i];
752 for (j=0; j<incexe->num_opts; j++) {
753 FOPTS *fo = incexe->opts_list[j];
754 sendit(sock, " O %s\n", fo->opts);
756 bool enhanced_wild = false;
757 for (k=0; fo->opts[k]!='\0'; k++) {
758 if (fo->opts[k]=='W') {
759 enhanced_wild = true;
764 for (k=0; k<fo->regex.size(); k++) {
765 sendit(sock, " R %s\n", fo->regex.get(k));
767 for (k=0; k<fo->regexdir.size(); k++) {
768 sendit(sock, " RD %s\n", fo->regexdir.get(k));
770 for (k=0; k<fo->regexfile.size(); k++) {
771 sendit(sock, " RF %s\n", fo->regexfile.get(k));
773 for (k=0; k<fo->wild.size(); k++) {
774 sendit(sock, " W %s\n", fo->wild.get(k));
776 for (k=0; k<fo->wilddir.size(); k++) {
777 sendit(sock, " WD %s\n", fo->wilddir.get(k));
779 for (k=0; k<fo->wildfile.size(); k++) {
780 sendit(sock, " WF %s\n", fo->wildfile.get(k));
782 for (k=0; k<fo->wildbase.size(); k++) {
783 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
785 for (k=0; k<fo->base.size(); k++) {
786 sendit(sock, " B %s\n", fo->base.get(k));
788 for (k=0; k<fo->fstype.size(); k++) {
789 sendit(sock, " X %s\n", fo->fstype.get(k));
791 for (k=0; k<fo->drivetype.size(); k++) {
792 sendit(sock, " XD %s\n", fo->drivetype.get(k));
795 sendit(sock, " G %s\n", fo->plugin);
798 sendit(sock, " D %s\n", fo->reader);
801 sendit(sock, " T %s\n", fo->writer);
803 sendit(sock, " N\n");
805 for (j=0; j<incexe->name_list.size(); j++) {
806 sendit(sock, " I %s\n", incexe->name_list.get(j));
808 if (incexe->name_list.size()) {
809 sendit(sock, " N\n");
811 for (j=0; j<incexe->plugin_list.size(); j++) {
812 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
814 if (incexe->plugin_list.size()) {
815 sendit(sock, " N\n");
820 for (i=0; i<res->res_fs.num_excludes; i++) {
821 INCEXE *incexe = res->res_fs.exclude_items[i];
822 for (j=0; j<incexe->name_list.size(); j++) {
823 sendit(sock, " E %s\n", incexe->name_list.get(j));
825 if (incexe->name_list.size()) {
826 sendit(sock, " N\n");
833 if (res->res_sch.run) {
835 RUN *run = res->res_sch.run;
836 char buf[1000], num[30];
837 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
842 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
843 bstrncpy(buf, _(" hour="), sizeof(buf));
844 for (i=0; i<24; i++) {
845 if (bit_is_set(i, run->hour)) {
846 bsnprintf(num, sizeof(num), "%d ", i);
847 bstrncat(buf, num, sizeof(buf));
850 bstrncat(buf, "\n", sizeof(buf));
852 bstrncpy(buf, _(" mday="), sizeof(buf));
853 for (i=0; i<31; i++) {
854 if (bit_is_set(i, run->mday)) {
855 bsnprintf(num, sizeof(num), "%d ", i);
856 bstrncat(buf, num, sizeof(buf));
859 bstrncat(buf, "\n", sizeof(buf));
861 bstrncpy(buf, _(" month="), sizeof(buf));
862 for (i=0; i<12; i++) {
863 if (bit_is_set(i, run->month)) {
864 bsnprintf(num, sizeof(num), "%d ", i);
865 bstrncat(buf, num, sizeof(buf));
868 bstrncat(buf, "\n", sizeof(buf));
870 bstrncpy(buf, _(" wday="), sizeof(buf));
871 for (i=0; i<7; i++) {
872 if (bit_is_set(i, run->wday)) {
873 bsnprintf(num, sizeof(num), "%d ", i);
874 bstrncat(buf, num, sizeof(buf));
877 bstrncat(buf, "\n", sizeof(buf));
879 bstrncpy(buf, _(" wom="), sizeof(buf));
880 for (i=0; i<5; i++) {
881 if (bit_is_set(i, run->wom)) {
882 bsnprintf(num, sizeof(num), "%d ", i);
883 bstrncat(buf, num, sizeof(buf));
886 bstrncat(buf, "\n", sizeof(buf));
888 bstrncpy(buf, _(" woy="), sizeof(buf));
889 for (i=0; i<54; i++) {
890 if (bit_is_set(i, run->woy)) {
891 bsnprintf(num, sizeof(num), "%d ", i);
892 bstrncat(buf, num, sizeof(buf));
895 bstrncat(buf, "\n", sizeof(buf));
897 sendit(sock, _(" mins=%d\n"), run->minute);
899 sendit(sock, _(" --> "));
900 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
903 sendit(sock, _(" --> "));
904 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
907 sendit(sock, _(" --> "));
908 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
910 /* If another Run record is chained in, go print it */
916 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
921 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
922 res->res_pool.pool_type);
923 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
924 res->res_pool.use_catalog, res->res_pool.use_volume_once,
925 res->res_pool.catalog_files);
926 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
927 res->res_pool.max_volumes, res->res_pool.AutoPrune,
928 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
929 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
930 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
931 res->res_pool.Recycle,
932 NPRT(res->res_pool.label_format));
933 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
934 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
935 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
936 res->res_pool.recycle_oldest_volume,
937 res->res_pool.purge_oldest_volume);
938 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
939 res->res_pool.MaxVolJobs,
940 res->res_pool.MaxVolFiles,
941 edit_uint64(res->res_pool.MaxVolFiles, ed1));
942 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
943 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
944 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
945 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
946 if (res->res_pool.NextPool) {
947 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
949 if (res->res_pool.RecyclePool) {
950 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
952 if (res->res_pool.catalog) {
953 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
955 if (res->res_pool.storage) {
957 foreach_alist(store, res->res_pool.storage) {
958 sendit(sock, _(" --> "));
959 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
962 if (res->res_pool.CopyPool) {
964 foreach_alist(copy, res->res_pool.CopyPool) {
965 sendit(sock, _(" --> "));
966 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
973 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
974 if (res->res_msgs.mail_cmd)
975 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
976 if (res->res_msgs.operator_cmd)
977 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
981 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
984 if (recurse && res->res_dir.hdr.next) {
985 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
990 * Free all the members of an INCEXE structure
992 static void free_incexe(INCEXE *incexe)
994 incexe->name_list.destroy();
995 incexe->plugin_list.destroy();
996 for (int i=0; i<incexe->num_opts; i++) {
997 FOPTS *fopt = incexe->opts_list[i];
998 fopt->regex.destroy();
999 fopt->regexdir.destroy();
1000 fopt->regexfile.destroy();
1001 fopt->wild.destroy();
1002 fopt->wilddir.destroy();
1003 fopt->wildfile.destroy();
1004 fopt->wildbase.destroy();
1005 fopt->base.destroy();
1006 fopt->fstype.destroy();
1007 fopt->drivetype.destroy();
1019 if (incexe->opts_list) {
1020 free(incexe->opts_list);
1026 * Free memory of resource -- called when daemon terminates.
1027 * NB, we don't need to worry about freeing any references
1028 * to other resources as they will be freed when that
1029 * resource chain is traversed. Mainly we worry about freeing
1030 * allocated strings (names).
1032 void free_resource(RES *sres, int type)
1035 RES *nres; /* next resource if linked */
1036 URES *res = (URES *)sres;
1041 /* common stuff -- free the resource name and description */
1042 nres = (RES *)res->res_dir.hdr.next;
1043 if (res->res_dir.hdr.name) {
1044 free(res->res_dir.hdr.name);
1046 if (res->res_dir.hdr.desc) {
1047 free(res->res_dir.hdr.desc);
1052 if (res->res_dir.working_directory) {
1053 free(res->res_dir.working_directory);
1055 if (res->res_dir.scripts_directory) {
1056 free((char *)res->res_dir.scripts_directory);
1058 if (res->res_dir.plugin_directory) {
1059 free((char *)res->res_dir.plugin_directory);
1061 if (res->res_dir.pid_directory) {
1062 free(res->res_dir.pid_directory);
1064 if (res->res_dir.subsys_directory) {
1065 free(res->res_dir.subsys_directory);
1067 if (res->res_dir.password) {
1068 free(res->res_dir.password);
1070 if (res->res_dir.query_file) {
1071 free(res->res_dir.query_file);
1073 if (res->res_dir.DIRaddrs) {
1074 free_addresses(res->res_dir.DIRaddrs);
1076 if (res->res_dir.tls_ctx) {
1077 free_tls_context(res->res_dir.tls_ctx);
1079 if (res->res_dir.tls_ca_certfile) {
1080 free(res->res_dir.tls_ca_certfile);
1082 if (res->res_dir.tls_ca_certdir) {
1083 free(res->res_dir.tls_ca_certdir);
1085 if (res->res_dir.tls_certfile) {
1086 free(res->res_dir.tls_certfile);
1088 if (res->res_dir.tls_keyfile) {
1089 free(res->res_dir.tls_keyfile);
1091 if (res->res_dir.tls_dhfile) {
1092 free(res->res_dir.tls_dhfile);
1094 if (res->res_dir.tls_allowed_cns) {
1095 delete res->res_dir.tls_allowed_cns;
1102 if (res->res_con.password) {
1103 free(res->res_con.password);
1105 if (res->res_con.tls_ctx) {
1106 free_tls_context(res->res_con.tls_ctx);
1108 if (res->res_con.tls_ca_certfile) {
1109 free(res->res_con.tls_ca_certfile);
1111 if (res->res_con.tls_ca_certdir) {
1112 free(res->res_con.tls_ca_certdir);
1114 if (res->res_con.tls_certfile) {
1115 free(res->res_con.tls_certfile);
1117 if (res->res_con.tls_keyfile) {
1118 free(res->res_con.tls_keyfile);
1120 if (res->res_con.tls_dhfile) {
1121 free(res->res_con.tls_dhfile);
1123 if (res->res_con.tls_allowed_cns) {
1124 delete res->res_con.tls_allowed_cns;
1126 for (int i=0; i<Num_ACL; i++) {
1127 if (res->res_con.ACL_lists[i]) {
1128 delete res->res_con.ACL_lists[i];
1129 res->res_con.ACL_lists[i] = NULL;
1134 if (res->res_client.address) {
1135 free(res->res_client.address);
1137 if (res->res_client.password) {
1138 free(res->res_client.password);
1140 if (res->res_client.tls_ctx) {
1141 free_tls_context(res->res_client.tls_ctx);
1143 if (res->res_client.tls_ca_certfile) {
1144 free(res->res_client.tls_ca_certfile);
1146 if (res->res_client.tls_ca_certdir) {
1147 free(res->res_client.tls_ca_certdir);
1149 if (res->res_client.tls_certfile) {
1150 free(res->res_client.tls_certfile);
1152 if (res->res_client.tls_keyfile) {
1153 free(res->res_client.tls_keyfile);
1155 if (res->res_client.tls_allowed_cns) {
1156 delete res->res_client.tls_allowed_cns;
1160 if (res->res_store.address) {
1161 free(res->res_store.address);
1163 if (res->res_store.password) {
1164 free(res->res_store.password);
1166 if (res->res_store.media_type) {
1167 free(res->res_store.media_type);
1169 if (res->res_store.device) {
1170 delete res->res_store.device;
1172 if (res->res_store.tls_ctx) {
1173 free_tls_context(res->res_store.tls_ctx);
1175 if (res->res_store.tls_ca_certfile) {
1176 free(res->res_store.tls_ca_certfile);
1178 if (res->res_store.tls_ca_certdir) {
1179 free(res->res_store.tls_ca_certdir);
1181 if (res->res_store.tls_certfile) {
1182 free(res->res_store.tls_certfile);
1184 if (res->res_store.tls_keyfile) {
1185 free(res->res_store.tls_keyfile);
1189 if (res->res_cat.db_address) {
1190 free(res->res_cat.db_address);
1192 if (res->res_cat.db_socket) {
1193 free(res->res_cat.db_socket);
1195 if (res->res_cat.db_user) {
1196 free(res->res_cat.db_user);
1198 if (res->res_cat.db_name) {
1199 free(res->res_cat.db_name);
1201 if (res->res_cat.db_driver) {
1202 free(res->res_cat.db_driver);
1204 if (res->res_cat.db_password) {
1205 free(res->res_cat.db_password);
1209 if ((num=res->res_fs.num_includes)) {
1210 while (--num >= 0) {
1211 free_incexe(res->res_fs.include_items[num]);
1213 free(res->res_fs.include_items);
1215 res->res_fs.num_includes = 0;
1216 if ((num=res->res_fs.num_excludes)) {
1217 while (--num >= 0) {
1218 free_incexe(res->res_fs.exclude_items[num]);
1220 free(res->res_fs.exclude_items);
1222 res->res_fs.num_excludes = 0;
1225 if (res->res_pool.pool_type) {
1226 free(res->res_pool.pool_type);
1228 if (res->res_pool.label_format) {
1229 free(res->res_pool.label_format);
1231 if (res->res_pool.cleaning_prefix) {
1232 free(res->res_pool.cleaning_prefix);
1234 if (res->res_pool.storage) {
1235 delete res->res_pool.storage;
1239 if (res->res_sch.run) {
1241 nrun = res->res_sch.run;
1251 if (res->res_job.RestoreWhere) {
1252 free(res->res_job.RestoreWhere);
1254 if (res->res_job.RegexWhere) {
1255 free(res->res_job.RegexWhere);
1257 if (res->res_job.strip_prefix) {
1258 free(res->res_job.strip_prefix);
1260 if (res->res_job.add_prefix) {
1261 free(res->res_job.add_prefix);
1263 if (res->res_job.add_suffix) {
1264 free(res->res_job.add_suffix);
1266 if (res->res_job.RestoreBootstrap) {
1267 free(res->res_job.RestoreBootstrap);
1269 if (res->res_job.WriteBootstrap) {
1270 free(res->res_job.WriteBootstrap);
1272 if (res->res_job.PluginOptions) {
1273 free(res->res_job.PluginOptions);
1275 if (res->res_job.selection_pattern) {
1276 free(res->res_job.selection_pattern);
1278 if (res->res_job.run_cmds) {
1279 delete res->res_job.run_cmds;
1281 if (res->res_job.storage) {
1282 delete res->res_job.storage;
1284 if (res->res_job.RunScripts) {
1285 free_runscripts(res->res_job.RunScripts);
1286 delete res->res_job.RunScripts;
1290 if (res->res_msgs.mail_cmd) {
1291 free(res->res_msgs.mail_cmd);
1293 if (res->res_msgs.operator_cmd) {
1294 free(res->res_msgs.operator_cmd);
1296 free_msgs_res((MSGS *)res); /* free message resource */
1300 printf(_("Unknown resource type %d in free_resource.\n"), type);
1302 /* Common stuff again -- free the resource, recurse to next one */
1307 free_resource(nres, type);
1312 * Save the new resource by chaining it into the head list for
1313 * the resource. If this is pass 2, we update any resource
1314 * pointers because they may not have been defined until
1317 void save_resource(int type, RES_ITEM *items, int pass)
1320 int rindex = type - r_first;
1324 /* Check Job requirements after applying JobDefs */
1325 if (type != R_JOB && type != R_JOBDEFS) {
1327 * Ensure that all required items are present
1329 for (i=0; items[i].name; i++) {
1330 if (items[i].flags & ITEM_REQUIRED) {
1331 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1332 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1333 items[i].name, resources[rindex]);
1336 /* If this triggers, take a look at lib/parse_conf.h */
1337 if (i >= MAX_RES_ITEMS) {
1338 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1341 } else if (type == R_JOB) {
1343 * Ensure that the name item is present
1345 if (items[0].flags & ITEM_REQUIRED) {
1346 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1347 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1348 items[0].name, resources[rindex]);
1354 * During pass 2 in each "store" routine, we looked up pointers
1355 * to all the resources referrenced in the current resource, now we
1356 * must copy their addresses from the static record to the allocated
1361 /* Resources not containing a resource */
1369 * Resources containing another resource or alist. First
1370 * look up the resource which contains another resource. It
1371 * was written during pass 1. Then stuff in the pointers to
1372 * the resources it contains, which were inserted this pass.
1373 * Finally, it will all be stored back.
1376 /* Find resource saved in pass 1 */
1377 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1378 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1380 /* Explicitly copy resource pointers from this pass (res_all) */
1381 res->res_pool.NextPool = res_all.res_pool.NextPool;
1382 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1383 res->res_pool.storage = res_all.res_pool.storage;
1384 res->res_pool.catalog = res_all.res_pool.catalog;
1387 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1388 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1390 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1393 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1394 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1396 res->res_dir.messages = res_all.res_dir.messages;
1397 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1400 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1401 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1402 res_all.res_dir.hdr.name);
1404 /* we must explicitly copy the device alist pointer */
1405 res->res_store.device = res_all.res_store.device;
1409 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1410 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1411 res_all.res_dir.hdr.name);
1413 res->res_job.messages = res_all.res_job.messages;
1414 res->res_job.schedule = res_all.res_job.schedule;
1415 res->res_job.client = res_all.res_job.client;
1416 res->res_job.fileset = res_all.res_job.fileset;
1417 res->res_job.storage = res_all.res_job.storage;
1418 res->res_job.pool = res_all.res_job.pool;
1419 res->res_job.full_pool = res_all.res_job.full_pool;
1420 res->res_job.inc_pool = res_all.res_job.inc_pool;
1421 res->res_job.diff_pool = res_all.res_job.diff_pool;
1422 res->res_job.verify_job = res_all.res_job.verify_job;
1423 res->res_job.jobdefs = res_all.res_job.jobdefs;
1424 res->res_job.run_cmds = res_all.res_job.run_cmds;
1425 res->res_job.RunScripts = res_all.res_job.RunScripts;
1427 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1428 * is not very useful)
1429 * We have to set_bit(index, res_all.hdr.item_present);
1430 * or something like that
1433 /* we take RegexWhere before all other options */
1434 if (!res->res_job.RegexWhere
1436 (res->res_job.strip_prefix ||
1437 res->res_job.add_suffix ||
1438 res->res_job.add_prefix))
1440 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1441 res->res_job.add_prefix,
1442 res->res_job.add_suffix);
1443 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1444 bregexp_build_where(res->res_job.RegexWhere, len,
1445 res->res_job.strip_prefix,
1446 res->res_job.add_prefix,
1447 res->res_job.add_suffix);
1448 /* TODO: test bregexp */
1451 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1452 free(res->res_job.RestoreWhere);
1453 res->res_job.RestoreWhere = NULL;
1458 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1459 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1461 res->res_counter.Catalog = res_all.res_counter.Catalog;
1462 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1466 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1467 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1469 res->res_client.catalog = res_all.res_client.catalog;
1470 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1474 * Schedule is a bit different in that it contains a RUN record
1475 * chain which isn't a "named" resource. This chain was linked
1476 * in by run_conf.c during pass 2, so here we jam the pointer
1477 * into the Schedule resource.
1479 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1480 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1482 res->res_sch.run = res_all.res_sch.run;
1485 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1489 /* Note, the resource name was already saved during pass 1,
1490 * so here, we can just release it.
1492 if (res_all.res_dir.hdr.name) {
1493 free(res_all.res_dir.hdr.name);
1494 res_all.res_dir.hdr.name = NULL;
1496 if (res_all.res_dir.hdr.desc) {
1497 free(res_all.res_dir.hdr.desc);
1498 res_all.res_dir.hdr.desc = NULL;
1504 * The following code is only executed during pass 1
1508 size = sizeof(DIRRES);
1511 size = sizeof(CONRES);
1514 size =sizeof(CLIENT);
1517 size = sizeof(STORE);
1527 size = sizeof(FILESET);
1530 size = sizeof(SCHED);
1533 size = sizeof(POOL);
1536 size = sizeof(MSGS);
1539 size = sizeof(COUNTER);
1545 printf(_("Unknown resource type %d in save_resource.\n"), type);
1551 res = (URES *)malloc(size);
1552 memcpy(res, &res_all, size);
1553 if (!res_head[rindex]) {
1554 res_head[rindex] = (RES *)res; /* store first entry */
1555 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1556 res->res_dir.hdr.name, rindex);
1559 if (res->res_dir.hdr.name == NULL) {
1560 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1563 /* Add new res to end of chain */
1564 for (last=next=res_head[rindex]; next; next=next->next) {
1566 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1567 Emsg2(M_ERROR_TERM, 0,
1568 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1569 resources[rindex].name, res->res_dir.hdr.name);
1572 last->next = (RES *)res;
1573 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1574 res->res_dir.hdr.name, rindex, pass);
1580 * Store Device. Note, the resource is created upon the
1581 * first reference. The details of the resource are obtained
1582 * later from the SD.
1584 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1588 int rindex = R_DEVICE - r_first;
1589 int size = sizeof(DEVICE);
1593 token = lex_get_token(lc, T_NAME);
1594 if (!res_head[rindex]) {
1595 res = (URES *)malloc(size);
1596 memset(res, 0, size);
1597 res->res_dev.hdr.name = bstrdup(lc->str);
1598 res_head[rindex] = (RES *)res; /* store first entry */
1599 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1600 res->res_dir.hdr.name, rindex);
1603 /* See if it is already defined */
1604 for (next=res_head[rindex]; next->next; next=next->next) {
1605 if (strcmp(next->name, lc->str) == 0) {
1611 res = (URES *)malloc(size);
1612 memset(res, 0, size);
1613 res->res_dev.hdr.name = bstrdup(lc->str);
1614 next->next = (RES *)res;
1615 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1616 res->res_dir.hdr.name, rindex, pass);
1621 set_bit(index, res_all.hdr.item_present);
1623 store_alist_res(lc, item, index, pass);
1628 * Store Migration/Copy type
1631 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1635 token = lex_get_token(lc, T_NAME);
1636 /* Store the type both pass 1 and pass 2 */
1637 for (i=0; migtypes[i].type_name; i++) {
1638 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1639 *(uint32_t *)(item->value) = migtypes[i].job_type;
1645 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1648 set_bit(index, res_all.hdr.item_present);
1654 * Store JobType (backup, verify, restore)
1657 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1661 token = lex_get_token(lc, T_NAME);
1662 /* Store the type both pass 1 and pass 2 */
1663 for (i=0; jobtypes[i].type_name; i++) {
1664 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1665 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1671 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1674 set_bit(index, res_all.hdr.item_present);
1678 * Store Job Level (Full, Incremental, ...)
1681 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1685 token = lex_get_token(lc, T_NAME);
1686 /* Store the level pass 2 so that type is defined */
1687 for (i=0; joblevels[i].level_name; i++) {
1688 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1689 *(uint32_t *)(item->value) = joblevels[i].level;
1695 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1698 set_bit(index, res_all.hdr.item_present);
1702 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1705 token = lex_get_token(lc, T_NAME);
1706 /* Scan Replacement options */
1707 for (i=0; ReplaceOptions[i].name; i++) {
1708 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1709 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1715 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1718 set_bit(index, res_all.hdr.item_present);
1722 * Store ACL (access control list)
1725 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1730 token = lex_get_token(lc, T_STRING);
1732 if (((alist **)item->value)[item->code] == NULL) {
1733 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1734 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1736 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1737 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1739 token = lex_get_token(lc, T_ALL);
1740 if (token == T_COMMA) {
1741 continue; /* get another ACL */
1745 set_bit(index, res_all.hdr.item_present);
1748 /* We build RunScripts items here */
1749 static RUNSCRIPT res_runscript;
1751 /* Store a runscript->when in a bit field */
1752 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1754 lex_get_token(lc, T_NAME);
1756 if (strcasecmp(lc->str, "before") == 0) {
1757 *(uint32_t *)(item->value) = SCRIPT_Before ;
1758 } else if (strcasecmp(lc->str, "after") == 0) {
1759 *(uint32_t *)(item->value) = SCRIPT_After;
1760 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1761 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1762 } else if (strcasecmp(lc->str, "always") == 0) {
1763 *(uint32_t *)(item->value) = SCRIPT_Any;
1765 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1770 /* Store a runscript->target
1773 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1775 lex_get_token(lc, T_STRING);
1778 if (strcmp(lc->str, "%c") == 0) {
1779 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1780 } else if (strcasecmp(lc->str, "yes") == 0) {
1781 ((RUNSCRIPT*) item->value)->set_target("%c");
1782 } else if (strcasecmp(lc->str, "no") == 0) {
1783 ((RUNSCRIPT*) item->value)->set_target("");
1785 RES *res = GetResWithName(R_CLIENT, lc->str);
1787 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1788 lc->str, lc->line_no, lc->line);
1791 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1798 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1800 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1802 lex_get_token(lc, T_STRING);
1805 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1806 POOLMEM *c = get_pool_memory(PM_FNAME);
1807 /* Each runscript command takes 2 entries in commands list */
1808 pm_strcpy(c, lc->str);
1809 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1810 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1815 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1817 lex_get_token(lc, T_STRING);
1818 alist **runscripts = (alist **)(item->value) ;
1821 RUNSCRIPT *script = new_runscript();
1822 script->set_job_code_callback(job_code_callback_filesetname);
1824 script->set_command(lc->str);
1826 /* TODO: remove all script->old_proto with bacula 1.42 */
1828 if (strcmp(item->name, "runbeforejob") == 0) {
1829 script->when = SCRIPT_Before;
1830 script->fail_on_error = true;
1831 script->set_target("");
1833 } else if (strcmp(item->name, "runafterjob") == 0) {
1834 script->when = SCRIPT_After;
1835 script->on_success = true;
1836 script->on_failure = false;
1837 script->set_target("");
1839 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1840 script->old_proto = true;
1841 script->when = SCRIPT_After;
1842 script->set_target("%c");
1843 script->on_success = true;
1844 script->on_failure = false;
1846 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1847 script->old_proto = true;
1848 script->when = SCRIPT_Before;
1849 script->set_target("%c");
1850 script->fail_on_error = true;
1852 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1853 script->when = SCRIPT_After;
1854 script->on_failure = true;
1855 script->on_success = false;
1856 script->set_target("");
1859 if (*runscripts == NULL) {
1860 *runscripts = New(alist(10, not_owned_by_alist));
1863 (*runscripts)->append(script);
1870 /* Store a bool in a bit field without modifing res_all.hdr
1871 * We can also add an option to store_bool to skip res_all.hdr
1873 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1875 lex_get_token(lc, T_NAME);
1876 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1877 *(bool *)(item->value) = true;
1878 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1879 *(bool *)(item->value) = false;
1881 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1887 * new RunScript items
1888 * name handler value code flags default_value
1890 static RES_ITEM runscript_items[] = {
1891 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1892 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1893 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1894 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1895 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1896 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1897 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1898 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1899 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1900 {NULL, NULL, {0}, 0, 0, 0}
1904 * Store RunScript info
1906 * Note, when this routine is called, we are inside a Job
1907 * resource. We treat the RunScript like a sort of
1908 * mini-resource within the Job resource.
1910 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1914 alist **runscripts = (alist **)(item->value) ;
1916 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1918 token = lex_get_token(lc, T_SKIP_EOL);
1920 if (token != T_BOB) {
1921 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1923 /* setting on_success, on_failure, fail_on_error */
1924 res_runscript.reset_default();
1927 res_runscript.commands = New(alist(10, not_owned_by_alist));
1930 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1931 if (token == T_EOB) {
1934 if (token != T_IDENTIFIER) {
1935 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1937 for (i=0; runscript_items[i].name; i++) {
1938 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1939 token = lex_get_token(lc, T_SKIP_EOL);
1940 if (token != T_EQUALS) {
1941 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1944 /* Call item handler */
1945 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1952 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1957 /* run on client by default */
1958 if (res_runscript.target == NULL) {
1959 res_runscript.set_target("%c");
1961 if (*runscripts == NULL) {
1962 *runscripts = New(alist(10, not_owned_by_alist));
1965 * commands list contains 2 values per command
1966 * - POOLMEM command string (ex: /bin/true)
1967 * - int command type (ex: SHELL_CMD)
1969 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1970 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1971 t = (long)res_runscript.commands->pop();
1972 RUNSCRIPT *script = new_runscript();
1973 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1974 script->command = c;
1975 script->cmd_type = t;
1976 /* target is taken from res_runscript, each runscript object have
1979 script->target = NULL;
1980 script->set_target(res_runscript.target);
1982 (*runscripts)->append(script);
1985 delete res_runscript.commands;
1986 /* setting on_success, on_failure... cleanup target field */
1987 res_runscript.reset_default(true);
1991 set_bit(index, res_all.hdr.item_present);
1994 /* callback function for edit_job_codes */
1995 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1997 if (param[0] == 'f') {
1998 return jcr->fileset->name();
2004 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2006 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2007 r_first, r_last, resources, res_head);
2008 return config->parse_config();