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 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
493 {"client", MT_CLIENT},
494 {"volume", MT_VOLUME},
496 {"sqlquery", MT_SQLQUERY},
502 /* Options permitted in Restore replace= */
503 struct s_kw ReplaceOptions[] = {
504 {"always", REPLACE_ALWAYS},
505 {"ifnewer", REPLACE_IFNEWER},
506 {"ifolder", REPLACE_IFOLDER},
507 {"never", REPLACE_NEVER},
511 char *CAT::display(POOLMEM *dst) {
512 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
513 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
515 name(), NPRTB(db_name),
516 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
517 NPRTB(db_address), db_port, NPRTB(db_socket));
521 const char *level_to_str(int level)
524 static char level_no[30];
525 const char *str = level_no;
527 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
528 for (i=0; joblevels[i].level_name; i++) {
529 if (level == (int)joblevels[i].level) {
530 str = joblevels[i].level_name;
537 /* Dump contents of resource */
538 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
540 URES *res = (URES *)reshdr;
542 char ed1[100], ed2[100], ed3[100];
546 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
549 if (type < 0) { /* no recursion */
555 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
556 reshdr->name, res->res_dir.MaxConcurrentJobs,
557 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
558 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
559 if (res->res_dir.query_file) {
560 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
562 if (res->res_dir.messages) {
563 sendit(sock, _(" --> "));
564 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
568 sendit(sock, _("Console: name=%s SSL=%d\n"),
569 res->res_con.hdr.name, res->res_con.tls_enable);
572 if (res->res_counter.WrapCounter) {
573 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
574 res->res_counter.hdr.name, res->res_counter.MinValue,
575 res->res_counter.MaxValue, res->res_counter.CurrentValue,
576 res->res_counter.WrapCounter->hdr.name);
578 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
579 res->res_counter.hdr.name, res->res_counter.MinValue,
580 res->res_counter.MaxValue);
582 if (res->res_counter.Catalog) {
583 sendit(sock, _(" --> "));
584 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
589 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
590 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
591 res->res_client.MaxConcurrentJobs);
592 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
593 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
594 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
595 res->res_client.AutoPrune);
596 if (res->res_client.catalog) {
597 sendit(sock, _(" --> "));
598 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
605 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
606 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
607 " poolid=%s volname=%s MediaType=%s\n"),
608 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
609 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
610 dev->offline, dev->autochanger,
611 edit_uint64(dev->PoolId, ed1),
612 dev->VolumeName, dev->MediaType);
616 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
617 " DeviceName=%s MediaType=%s StorageId=%s\n"),
618 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
619 res->res_store.MaxConcurrentJobs,
620 res->res_store.dev_name(),
621 res->res_store.media_type,
622 edit_int64(res->res_store.StorageId, ed1));
626 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
627 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
628 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
629 res->res_cat.db_port, res->res_cat.db_name,
630 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
631 res->res_cat.mult_db_connections);
636 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
637 type == R_JOB ? _("Job") : _("JobDefs"),
638 res->res_job.hdr.name, res->res_job.JobType,
639 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
640 res->res_job.enabled);
641 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
642 res->res_job.MaxConcurrentJobs,
643 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
644 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
645 res->res_job.spool_data, res->res_job.write_part_after_job);
646 if (res->res_job.spool_size) {
647 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
649 if (res->res_job.JobType == JT_BACKUP) {
650 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
652 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
653 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
655 if (res->res_job.client) {
656 sendit(sock, _(" --> "));
657 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
659 if (res->res_job.fileset) {
660 sendit(sock, _(" --> "));
661 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
663 if (res->res_job.schedule) {
664 sendit(sock, _(" --> "));
665 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
667 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
668 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
670 if (res->res_job.RegexWhere) {
671 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
673 if (res->res_job.RestoreBootstrap) {
674 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
676 if (res->res_job.WriteBootstrap) {
677 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
679 if (res->res_job.PluginOptions) {
680 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
682 if (res->res_job.MaxRunTime) {
683 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
685 if (res->res_job.MaxWaitTime) {
686 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
688 if (res->res_job.MaxStartDelay) {
689 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
691 if (res->res_job.storage) {
693 foreach_alist(store, res->res_job.storage) {
694 sendit(sock, _(" --> "));
695 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
698 if (res->res_job.RunScripts) {
700 foreach_alist(script, res->res_job.RunScripts) {
701 sendit(sock, _(" --> RunScript\n"));
702 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
703 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
704 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
705 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
706 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
707 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
710 if (res->res_job.pool) {
711 sendit(sock, _(" --> "));
712 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
714 if (res->res_job.full_pool) {
715 sendit(sock, _(" --> "));
716 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
718 if (res->res_job.inc_pool) {
719 sendit(sock, _(" --> "));
720 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
722 if (res->res_job.diff_pool) {
723 sendit(sock, _(" --> "));
724 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
726 if (res->res_job.verify_job) {
727 sendit(sock, _(" --> "));
728 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
730 if (res->res_job.run_cmds) {
732 foreach_alist(runcmd, res->res_job.run_cmds) {
733 sendit(sock, _(" --> Run=%s\n"), runcmd);
736 if (res->res_job.selection_pattern) {
737 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
739 if (res->res_job.messages) {
740 sendit(sock, _(" --> "));
741 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
748 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
749 for (i=0; i<res->res_fs.num_includes; i++) {
750 INCEXE *incexe = res->res_fs.include_items[i];
751 for (j=0; j<incexe->num_opts; j++) {
752 FOPTS *fo = incexe->opts_list[j];
753 sendit(sock, " O %s\n", fo->opts);
755 bool enhanced_wild = false;
756 for (k=0; fo->opts[k]!='\0'; k++) {
757 if (fo->opts[k]=='W') {
758 enhanced_wild = true;
763 for (k=0; k<fo->regex.size(); k++) {
764 sendit(sock, " R %s\n", fo->regex.get(k));
766 for (k=0; k<fo->regexdir.size(); k++) {
767 sendit(sock, " RD %s\n", fo->regexdir.get(k));
769 for (k=0; k<fo->regexfile.size(); k++) {
770 sendit(sock, " RF %s\n", fo->regexfile.get(k));
772 for (k=0; k<fo->wild.size(); k++) {
773 sendit(sock, " W %s\n", fo->wild.get(k));
775 for (k=0; k<fo->wilddir.size(); k++) {
776 sendit(sock, " WD %s\n", fo->wilddir.get(k));
778 for (k=0; k<fo->wildfile.size(); k++) {
779 sendit(sock, " WF %s\n", fo->wildfile.get(k));
781 for (k=0; k<fo->wildbase.size(); k++) {
782 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
784 for (k=0; k<fo->base.size(); k++) {
785 sendit(sock, " B %s\n", fo->base.get(k));
787 for (k=0; k<fo->fstype.size(); k++) {
788 sendit(sock, " X %s\n", fo->fstype.get(k));
790 for (k=0; k<fo->drivetype.size(); k++) {
791 sendit(sock, " XD %s\n", fo->drivetype.get(k));
794 sendit(sock, " G %s\n", fo->plugin);
797 sendit(sock, " D %s\n", fo->reader);
800 sendit(sock, " T %s\n", fo->writer);
802 sendit(sock, " N\n");
804 for (j=0; j<incexe->name_list.size(); j++) {
805 sendit(sock, " I %s\n", incexe->name_list.get(j));
807 if (incexe->name_list.size()) {
808 sendit(sock, " N\n");
810 for (j=0; j<incexe->plugin_list.size(); j++) {
811 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
813 if (incexe->plugin_list.size()) {
814 sendit(sock, " N\n");
819 for (i=0; i<res->res_fs.num_excludes; i++) {
820 INCEXE *incexe = res->res_fs.exclude_items[i];
821 for (j=0; j<incexe->name_list.size(); j++) {
822 sendit(sock, " E %s\n", incexe->name_list.get(j));
824 if (incexe->name_list.size()) {
825 sendit(sock, " N\n");
832 if (res->res_sch.run) {
834 RUN *run = res->res_sch.run;
835 char buf[1000], num[30];
836 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
841 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
842 bstrncpy(buf, _(" hour="), sizeof(buf));
843 for (i=0; i<24; i++) {
844 if (bit_is_set(i, run->hour)) {
845 bsnprintf(num, sizeof(num), "%d ", i);
846 bstrncat(buf, num, sizeof(buf));
849 bstrncat(buf, "\n", sizeof(buf));
851 bstrncpy(buf, _(" mday="), sizeof(buf));
852 for (i=0; i<31; i++) {
853 if (bit_is_set(i, run->mday)) {
854 bsnprintf(num, sizeof(num), "%d ", i);
855 bstrncat(buf, num, sizeof(buf));
858 bstrncat(buf, "\n", sizeof(buf));
860 bstrncpy(buf, _(" month="), sizeof(buf));
861 for (i=0; i<12; i++) {
862 if (bit_is_set(i, run->month)) {
863 bsnprintf(num, sizeof(num), "%d ", i);
864 bstrncat(buf, num, sizeof(buf));
867 bstrncat(buf, "\n", sizeof(buf));
869 bstrncpy(buf, _(" wday="), sizeof(buf));
870 for (i=0; i<7; i++) {
871 if (bit_is_set(i, run->wday)) {
872 bsnprintf(num, sizeof(num), "%d ", i);
873 bstrncat(buf, num, sizeof(buf));
876 bstrncat(buf, "\n", sizeof(buf));
878 bstrncpy(buf, _(" wom="), sizeof(buf));
879 for (i=0; i<5; i++) {
880 if (bit_is_set(i, run->wom)) {
881 bsnprintf(num, sizeof(num), "%d ", i);
882 bstrncat(buf, num, sizeof(buf));
885 bstrncat(buf, "\n", sizeof(buf));
887 bstrncpy(buf, _(" woy="), sizeof(buf));
888 for (i=0; i<54; i++) {
889 if (bit_is_set(i, run->woy)) {
890 bsnprintf(num, sizeof(num), "%d ", i);
891 bstrncat(buf, num, sizeof(buf));
894 bstrncat(buf, "\n", sizeof(buf));
896 sendit(sock, _(" mins=%d\n"), run->minute);
898 sendit(sock, _(" --> "));
899 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
902 sendit(sock, _(" --> "));
903 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
906 sendit(sock, _(" --> "));
907 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
909 /* If another Run record is chained in, go print it */
915 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
920 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
921 res->res_pool.pool_type);
922 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
923 res->res_pool.use_catalog, res->res_pool.use_volume_once,
924 res->res_pool.catalog_files);
925 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
926 res->res_pool.max_volumes, res->res_pool.AutoPrune,
927 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
928 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
929 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
930 res->res_pool.Recycle,
931 NPRT(res->res_pool.label_format));
932 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
933 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
934 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
935 res->res_pool.recycle_oldest_volume,
936 res->res_pool.purge_oldest_volume);
937 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
938 res->res_pool.MaxVolJobs,
939 res->res_pool.MaxVolFiles,
940 edit_uint64(res->res_pool.MaxVolFiles, ed1));
941 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
942 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
943 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
944 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
945 if (res->res_pool.NextPool) {
946 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
948 if (res->res_pool.RecyclePool) {
949 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
951 if (res->res_pool.catalog) {
952 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
954 if (res->res_pool.storage) {
956 foreach_alist(store, res->res_pool.storage) {
957 sendit(sock, _(" --> "));
958 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
961 if (res->res_pool.CopyPool) {
963 foreach_alist(copy, res->res_pool.CopyPool) {
964 sendit(sock, _(" --> "));
965 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
972 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
973 if (res->res_msgs.mail_cmd)
974 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
975 if (res->res_msgs.operator_cmd)
976 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
980 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
983 if (recurse && res->res_dir.hdr.next) {
984 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
989 * Free all the members of an INCEXE structure
991 static void free_incexe(INCEXE *incexe)
993 incexe->name_list.destroy();
994 incexe->plugin_list.destroy();
995 for (int i=0; i<incexe->num_opts; i++) {
996 FOPTS *fopt = incexe->opts_list[i];
997 fopt->regex.destroy();
998 fopt->regexdir.destroy();
999 fopt->regexfile.destroy();
1000 fopt->wild.destroy();
1001 fopt->wilddir.destroy();
1002 fopt->wildfile.destroy();
1003 fopt->wildbase.destroy();
1004 fopt->base.destroy();
1005 fopt->fstype.destroy();
1006 fopt->drivetype.destroy();
1018 if (incexe->opts_list) {
1019 free(incexe->opts_list);
1025 * Free memory of resource -- called when daemon terminates.
1026 * NB, we don't need to worry about freeing any references
1027 * to other resources as they will be freed when that
1028 * resource chain is traversed. Mainly we worry about freeing
1029 * allocated strings (names).
1031 void free_resource(RES *sres, int type)
1034 RES *nres; /* next resource if linked */
1035 URES *res = (URES *)sres;
1040 /* common stuff -- free the resource name and description */
1041 nres = (RES *)res->res_dir.hdr.next;
1042 if (res->res_dir.hdr.name) {
1043 free(res->res_dir.hdr.name);
1045 if (res->res_dir.hdr.desc) {
1046 free(res->res_dir.hdr.desc);
1051 if (res->res_dir.working_directory) {
1052 free(res->res_dir.working_directory);
1054 if (res->res_dir.scripts_directory) {
1055 free((char *)res->res_dir.scripts_directory);
1057 if (res->res_dir.plugin_directory) {
1058 free((char *)res->res_dir.plugin_directory);
1060 if (res->res_dir.pid_directory) {
1061 free(res->res_dir.pid_directory);
1063 if (res->res_dir.subsys_directory) {
1064 free(res->res_dir.subsys_directory);
1066 if (res->res_dir.password) {
1067 free(res->res_dir.password);
1069 if (res->res_dir.query_file) {
1070 free(res->res_dir.query_file);
1072 if (res->res_dir.DIRaddrs) {
1073 free_addresses(res->res_dir.DIRaddrs);
1075 if (res->res_dir.tls_ctx) {
1076 free_tls_context(res->res_dir.tls_ctx);
1078 if (res->res_dir.tls_ca_certfile) {
1079 free(res->res_dir.tls_ca_certfile);
1081 if (res->res_dir.tls_ca_certdir) {
1082 free(res->res_dir.tls_ca_certdir);
1084 if (res->res_dir.tls_certfile) {
1085 free(res->res_dir.tls_certfile);
1087 if (res->res_dir.tls_keyfile) {
1088 free(res->res_dir.tls_keyfile);
1090 if (res->res_dir.tls_dhfile) {
1091 free(res->res_dir.tls_dhfile);
1093 if (res->res_dir.tls_allowed_cns) {
1094 delete res->res_dir.tls_allowed_cns;
1101 if (res->res_con.password) {
1102 free(res->res_con.password);
1104 if (res->res_con.tls_ctx) {
1105 free_tls_context(res->res_con.tls_ctx);
1107 if (res->res_con.tls_ca_certfile) {
1108 free(res->res_con.tls_ca_certfile);
1110 if (res->res_con.tls_ca_certdir) {
1111 free(res->res_con.tls_ca_certdir);
1113 if (res->res_con.tls_certfile) {
1114 free(res->res_con.tls_certfile);
1116 if (res->res_con.tls_keyfile) {
1117 free(res->res_con.tls_keyfile);
1119 if (res->res_con.tls_dhfile) {
1120 free(res->res_con.tls_dhfile);
1122 if (res->res_con.tls_allowed_cns) {
1123 delete res->res_con.tls_allowed_cns;
1125 for (int i=0; i<Num_ACL; i++) {
1126 if (res->res_con.ACL_lists[i]) {
1127 delete res->res_con.ACL_lists[i];
1128 res->res_con.ACL_lists[i] = NULL;
1133 if (res->res_client.address) {
1134 free(res->res_client.address);
1136 if (res->res_client.password) {
1137 free(res->res_client.password);
1139 if (res->res_client.tls_ctx) {
1140 free_tls_context(res->res_client.tls_ctx);
1142 if (res->res_client.tls_ca_certfile) {
1143 free(res->res_client.tls_ca_certfile);
1145 if (res->res_client.tls_ca_certdir) {
1146 free(res->res_client.tls_ca_certdir);
1148 if (res->res_client.tls_certfile) {
1149 free(res->res_client.tls_certfile);
1151 if (res->res_client.tls_keyfile) {
1152 free(res->res_client.tls_keyfile);
1154 if (res->res_client.tls_allowed_cns) {
1155 delete res->res_client.tls_allowed_cns;
1159 if (res->res_store.address) {
1160 free(res->res_store.address);
1162 if (res->res_store.password) {
1163 free(res->res_store.password);
1165 if (res->res_store.media_type) {
1166 free(res->res_store.media_type);
1168 if (res->res_store.device) {
1169 delete res->res_store.device;
1171 if (res->res_store.tls_ctx) {
1172 free_tls_context(res->res_store.tls_ctx);
1174 if (res->res_store.tls_ca_certfile) {
1175 free(res->res_store.tls_ca_certfile);
1177 if (res->res_store.tls_ca_certdir) {
1178 free(res->res_store.tls_ca_certdir);
1180 if (res->res_store.tls_certfile) {
1181 free(res->res_store.tls_certfile);
1183 if (res->res_store.tls_keyfile) {
1184 free(res->res_store.tls_keyfile);
1188 if (res->res_cat.db_address) {
1189 free(res->res_cat.db_address);
1191 if (res->res_cat.db_socket) {
1192 free(res->res_cat.db_socket);
1194 if (res->res_cat.db_user) {
1195 free(res->res_cat.db_user);
1197 if (res->res_cat.db_name) {
1198 free(res->res_cat.db_name);
1200 if (res->res_cat.db_driver) {
1201 free(res->res_cat.db_driver);
1203 if (res->res_cat.db_password) {
1204 free(res->res_cat.db_password);
1208 if ((num=res->res_fs.num_includes)) {
1209 while (--num >= 0) {
1210 free_incexe(res->res_fs.include_items[num]);
1212 free(res->res_fs.include_items);
1214 res->res_fs.num_includes = 0;
1215 if ((num=res->res_fs.num_excludes)) {
1216 while (--num >= 0) {
1217 free_incexe(res->res_fs.exclude_items[num]);
1219 free(res->res_fs.exclude_items);
1221 res->res_fs.num_excludes = 0;
1224 if (res->res_pool.pool_type) {
1225 free(res->res_pool.pool_type);
1227 if (res->res_pool.label_format) {
1228 free(res->res_pool.label_format);
1230 if (res->res_pool.cleaning_prefix) {
1231 free(res->res_pool.cleaning_prefix);
1233 if (res->res_pool.storage) {
1234 delete res->res_pool.storage;
1238 if (res->res_sch.run) {
1240 nrun = res->res_sch.run;
1250 if (res->res_job.RestoreWhere) {
1251 free(res->res_job.RestoreWhere);
1253 if (res->res_job.RegexWhere) {
1254 free(res->res_job.RegexWhere);
1256 if (res->res_job.strip_prefix) {
1257 free(res->res_job.strip_prefix);
1259 if (res->res_job.add_prefix) {
1260 free(res->res_job.add_prefix);
1262 if (res->res_job.add_suffix) {
1263 free(res->res_job.add_suffix);
1265 if (res->res_job.RestoreBootstrap) {
1266 free(res->res_job.RestoreBootstrap);
1268 if (res->res_job.WriteBootstrap) {
1269 free(res->res_job.WriteBootstrap);
1271 if (res->res_job.PluginOptions) {
1272 free(res->res_job.PluginOptions);
1274 if (res->res_job.selection_pattern) {
1275 free(res->res_job.selection_pattern);
1277 if (res->res_job.run_cmds) {
1278 delete res->res_job.run_cmds;
1280 if (res->res_job.storage) {
1281 delete res->res_job.storage;
1283 if (res->res_job.RunScripts) {
1284 free_runscripts(res->res_job.RunScripts);
1285 delete res->res_job.RunScripts;
1289 if (res->res_msgs.mail_cmd) {
1290 free(res->res_msgs.mail_cmd);
1292 if (res->res_msgs.operator_cmd) {
1293 free(res->res_msgs.operator_cmd);
1295 free_msgs_res((MSGS *)res); /* free message resource */
1299 printf(_("Unknown resource type %d in free_resource.\n"), type);
1301 /* Common stuff again -- free the resource, recurse to next one */
1306 free_resource(nres, type);
1311 * Save the new resource by chaining it into the head list for
1312 * the resource. If this is pass 2, we update any resource
1313 * pointers because they may not have been defined until
1316 void save_resource(int type, RES_ITEM *items, int pass)
1319 int rindex = type - r_first;
1323 /* Check Job requirements after applying JobDefs */
1324 if (type != R_JOB && type != R_JOBDEFS) {
1326 * Ensure that all required items are present
1328 for (i=0; items[i].name; i++) {
1329 if (items[i].flags & ITEM_REQUIRED) {
1330 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1331 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1332 items[i].name, resources[rindex]);
1335 /* If this triggers, take a look at lib/parse_conf.h */
1336 if (i >= MAX_RES_ITEMS) {
1337 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1340 } else if (type == R_JOB) {
1342 * Ensure that the name item is present
1344 if (items[0].flags & ITEM_REQUIRED) {
1345 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1346 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1347 items[0].name, resources[rindex]);
1353 * During pass 2 in each "store" routine, we looked up pointers
1354 * to all the resources referrenced in the current resource, now we
1355 * must copy their addresses from the static record to the allocated
1360 /* Resources not containing a resource */
1368 * Resources containing another resource or alist. First
1369 * look up the resource which contains another resource. It
1370 * was written during pass 1. Then stuff in the pointers to
1371 * the resources it contains, which were inserted this pass.
1372 * Finally, it will all be stored back.
1375 /* Find resource saved in pass 1 */
1376 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1377 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1379 /* Explicitly copy resource pointers from this pass (res_all) */
1380 res->res_pool.NextPool = res_all.res_pool.NextPool;
1381 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1382 res->res_pool.storage = res_all.res_pool.storage;
1383 res->res_pool.catalog = res_all.res_pool.catalog;
1386 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1387 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1389 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1392 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1393 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1395 res->res_dir.messages = res_all.res_dir.messages;
1396 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1399 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1400 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1401 res_all.res_dir.hdr.name);
1403 /* we must explicitly copy the device alist pointer */
1404 res->res_store.device = res_all.res_store.device;
1408 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1409 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1410 res_all.res_dir.hdr.name);
1412 res->res_job.messages = res_all.res_job.messages;
1413 res->res_job.schedule = res_all.res_job.schedule;
1414 res->res_job.client = res_all.res_job.client;
1415 res->res_job.fileset = res_all.res_job.fileset;
1416 res->res_job.storage = res_all.res_job.storage;
1417 res->res_job.pool = res_all.res_job.pool;
1418 res->res_job.full_pool = res_all.res_job.full_pool;
1419 res->res_job.inc_pool = res_all.res_job.inc_pool;
1420 res->res_job.diff_pool = res_all.res_job.diff_pool;
1421 res->res_job.verify_job = res_all.res_job.verify_job;
1422 res->res_job.jobdefs = res_all.res_job.jobdefs;
1423 res->res_job.run_cmds = res_all.res_job.run_cmds;
1424 res->res_job.RunScripts = res_all.res_job.RunScripts;
1426 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1427 * is not very useful)
1428 * We have to set_bit(index, res_all.hdr.item_present);
1429 * or something like that
1432 /* we take RegexWhere before all other options */
1433 if (!res->res_job.RegexWhere
1435 (res->res_job.strip_prefix ||
1436 res->res_job.add_suffix ||
1437 res->res_job.add_prefix))
1439 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1440 res->res_job.add_prefix,
1441 res->res_job.add_suffix);
1442 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1443 bregexp_build_where(res->res_job.RegexWhere, len,
1444 res->res_job.strip_prefix,
1445 res->res_job.add_prefix,
1446 res->res_job.add_suffix);
1447 /* TODO: test bregexp */
1450 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1451 free(res->res_job.RestoreWhere);
1452 res->res_job.RestoreWhere = NULL;
1457 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1458 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1460 res->res_counter.Catalog = res_all.res_counter.Catalog;
1461 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1465 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1466 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1468 res->res_client.catalog = res_all.res_client.catalog;
1469 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1473 * Schedule is a bit different in that it contains a RUN record
1474 * chain which isn't a "named" resource. This chain was linked
1475 * in by run_conf.c during pass 2, so here we jam the pointer
1476 * into the Schedule resource.
1478 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1479 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1481 res->res_sch.run = res_all.res_sch.run;
1484 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1488 /* Note, the resource name was already saved during pass 1,
1489 * so here, we can just release it.
1491 if (res_all.res_dir.hdr.name) {
1492 free(res_all.res_dir.hdr.name);
1493 res_all.res_dir.hdr.name = NULL;
1495 if (res_all.res_dir.hdr.desc) {
1496 free(res_all.res_dir.hdr.desc);
1497 res_all.res_dir.hdr.desc = NULL;
1503 * The following code is only executed during pass 1
1507 size = sizeof(DIRRES);
1510 size = sizeof(CONRES);
1513 size =sizeof(CLIENT);
1516 size = sizeof(STORE);
1526 size = sizeof(FILESET);
1529 size = sizeof(SCHED);
1532 size = sizeof(POOL);
1535 size = sizeof(MSGS);
1538 size = sizeof(COUNTER);
1544 printf(_("Unknown resource type %d in save_resource.\n"), type);
1550 res = (URES *)malloc(size);
1551 memcpy(res, &res_all, size);
1552 if (!res_head[rindex]) {
1553 res_head[rindex] = (RES *)res; /* store first entry */
1554 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1555 res->res_dir.hdr.name, rindex);
1558 if (res->res_dir.hdr.name == NULL) {
1559 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1562 /* Add new res to end of chain */
1563 for (last=next=res_head[rindex]; next; next=next->next) {
1565 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1566 Emsg2(M_ERROR_TERM, 0,
1567 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1568 resources[rindex].name, res->res_dir.hdr.name);
1571 last->next = (RES *)res;
1572 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1573 res->res_dir.hdr.name, rindex, pass);
1579 * Store Device. Note, the resource is created upon the
1580 * first reference. The details of the resource are obtained
1581 * later from the SD.
1583 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1587 int rindex = R_DEVICE - r_first;
1588 int size = sizeof(DEVICE);
1592 token = lex_get_token(lc, T_NAME);
1593 if (!res_head[rindex]) {
1594 res = (URES *)malloc(size);
1595 memset(res, 0, size);
1596 res->res_dev.hdr.name = bstrdup(lc->str);
1597 res_head[rindex] = (RES *)res; /* store first entry */
1598 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1599 res->res_dir.hdr.name, rindex);
1602 /* See if it is already defined */
1603 for (next=res_head[rindex]; next->next; next=next->next) {
1604 if (strcmp(next->name, lc->str) == 0) {
1610 res = (URES *)malloc(size);
1611 memset(res, 0, size);
1612 res->res_dev.hdr.name = bstrdup(lc->str);
1613 next->next = (RES *)res;
1614 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1615 res->res_dir.hdr.name, rindex, pass);
1620 set_bit(index, res_all.hdr.item_present);
1622 store_alist_res(lc, item, index, pass);
1627 * Store Migration/Copy type
1630 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1634 token = lex_get_token(lc, T_NAME);
1635 /* Store the type both pass 1 and pass 2 */
1636 for (i=0; migtypes[i].type_name; i++) {
1637 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1638 *(uint32_t *)(item->value) = migtypes[i].job_type;
1644 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1647 set_bit(index, res_all.hdr.item_present);
1653 * Store JobType (backup, verify, restore)
1656 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1660 token = lex_get_token(lc, T_NAME);
1661 /* Store the type both pass 1 and pass 2 */
1662 for (i=0; jobtypes[i].type_name; i++) {
1663 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1664 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1670 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1673 set_bit(index, res_all.hdr.item_present);
1677 * Store Job Level (Full, Incremental, ...)
1680 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1684 token = lex_get_token(lc, T_NAME);
1685 /* Store the level pass 2 so that type is defined */
1686 for (i=0; joblevels[i].level_name; i++) {
1687 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1688 *(uint32_t *)(item->value) = joblevels[i].level;
1694 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1697 set_bit(index, res_all.hdr.item_present);
1701 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1704 token = lex_get_token(lc, T_NAME);
1705 /* Scan Replacement options */
1706 for (i=0; ReplaceOptions[i].name; i++) {
1707 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1708 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1714 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1717 set_bit(index, res_all.hdr.item_present);
1721 * Store ACL (access control list)
1724 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1729 token = lex_get_token(lc, T_STRING);
1731 if (((alist **)item->value)[item->code] == NULL) {
1732 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1733 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1735 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1736 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1738 token = lex_get_token(lc, T_ALL);
1739 if (token == T_COMMA) {
1740 continue; /* get another ACL */
1744 set_bit(index, res_all.hdr.item_present);
1747 /* We build RunScripts items here */
1748 static RUNSCRIPT res_runscript;
1750 /* Store a runscript->when in a bit field */
1751 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1753 lex_get_token(lc, T_NAME);
1755 if (strcasecmp(lc->str, "before") == 0) {
1756 *(uint32_t *)(item->value) = SCRIPT_Before ;
1757 } else if (strcasecmp(lc->str, "after") == 0) {
1758 *(uint32_t *)(item->value) = SCRIPT_After;
1759 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1760 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1761 } else if (strcasecmp(lc->str, "always") == 0) {
1762 *(uint32_t *)(item->value) = SCRIPT_Any;
1764 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1769 /* Store a runscript->target
1772 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1774 lex_get_token(lc, T_STRING);
1777 if (strcmp(lc->str, "%c") == 0) {
1778 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1779 } else if (strcasecmp(lc->str, "yes") == 0) {
1780 ((RUNSCRIPT*) item->value)->set_target("%c");
1781 } else if (strcasecmp(lc->str, "no") == 0) {
1782 ((RUNSCRIPT*) item->value)->set_target("");
1784 RES *res = GetResWithName(R_CLIENT, lc->str);
1786 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1787 lc->str, lc->line_no, lc->line);
1790 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1797 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1799 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1801 lex_get_token(lc, T_STRING);
1804 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1805 POOLMEM *c = get_pool_memory(PM_FNAME);
1806 /* Each runscript command takes 2 entries in commands list */
1807 pm_strcpy(c, lc->str);
1808 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1809 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1814 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1816 lex_get_token(lc, T_STRING);
1817 alist **runscripts = (alist **)(item->value) ;
1820 RUNSCRIPT *script = new_runscript();
1821 script->set_job_code_callback(job_code_callback_filesetname);
1823 script->set_command(lc->str);
1825 /* TODO: remove all script->old_proto with bacula 1.42 */
1827 if (strcmp(item->name, "runbeforejob") == 0) {
1828 script->when = SCRIPT_Before;
1829 script->fail_on_error = true;
1830 script->set_target("");
1832 } else if (strcmp(item->name, "runafterjob") == 0) {
1833 script->when = SCRIPT_After;
1834 script->on_success = true;
1835 script->on_failure = false;
1836 script->set_target("");
1838 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1839 script->old_proto = true;
1840 script->when = SCRIPT_After;
1841 script->set_target("%c");
1842 script->on_success = true;
1843 script->on_failure = false;
1845 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1846 script->old_proto = true;
1847 script->when = SCRIPT_Before;
1848 script->set_target("%c");
1849 script->fail_on_error = true;
1851 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1852 script->when = SCRIPT_After;
1853 script->on_failure = true;
1854 script->on_success = false;
1855 script->set_target("");
1858 if (*runscripts == NULL) {
1859 *runscripts = New(alist(10, not_owned_by_alist));
1862 (*runscripts)->append(script);
1869 /* Store a bool in a bit field without modifing res_all.hdr
1870 * We can also add an option to store_bool to skip res_all.hdr
1872 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1874 lex_get_token(lc, T_NAME);
1875 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1876 *(bool *)(item->value) = true;
1877 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1878 *(bool *)(item->value) = false;
1880 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1886 * new RunScript items
1887 * name handler value code flags default_value
1889 static RES_ITEM runscript_items[] = {
1890 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1891 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1892 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1893 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1894 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1895 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1896 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1897 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1898 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1899 {NULL, NULL, {0}, 0, 0, 0}
1903 * Store RunScript info
1905 * Note, when this routine is called, we are inside a Job
1906 * resource. We treat the RunScript like a sort of
1907 * mini-resource within the Job resource.
1909 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1913 alist **runscripts = (alist **)(item->value) ;
1915 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1917 token = lex_get_token(lc, T_SKIP_EOL);
1919 if (token != T_BOB) {
1920 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1922 /* setting on_success, on_failure, fail_on_error */
1923 res_runscript.reset_default();
1926 res_runscript.commands = New(alist(10, not_owned_by_alist));
1929 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1930 if (token == T_EOB) {
1933 if (token != T_IDENTIFIER) {
1934 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1936 for (i=0; runscript_items[i].name; i++) {
1937 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1938 token = lex_get_token(lc, T_SKIP_EOL);
1939 if (token != T_EQUALS) {
1940 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1943 /* Call item handler */
1944 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1951 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1956 /* run on client by default */
1957 if (res_runscript.target == NULL) {
1958 res_runscript.set_target("%c");
1960 if (*runscripts == NULL) {
1961 *runscripts = New(alist(10, not_owned_by_alist));
1964 * commands list contains 2 values per command
1965 * - POOLMEM command string (ex: /bin/true)
1966 * - int command type (ex: SHELL_CMD)
1968 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1969 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1970 t = (long)res_runscript.commands->pop();
1971 RUNSCRIPT *script = new_runscript();
1972 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1973 script->command = c;
1974 script->cmd_type = t;
1975 /* target is taken from res_runscript, each runscript object have
1978 script->target = NULL;
1979 script->set_target(res_runscript.target);
1981 (*runscripts)->append(script);
1984 delete res_runscript.commands;
1985 /* setting on_success, on_failure... cleanup target field */
1986 res_runscript.reset_default(true);
1990 set_bit(index, res_all.hdr.item_present);
1993 /* callback function for edit_job_codes */
1994 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
1996 if (param[0] == 'f') {
1997 return jcr->fileset->name();
2003 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2005 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2006 r_first, r_last, resources, res_head);
2007 return config->parse_config();