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 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
123 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
124 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
125 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
126 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
127 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
128 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
129 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
130 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
131 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
132 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
133 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
134 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
135 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
136 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
137 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
138 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
139 {NULL, NULL, {0}, 0, 0, 0}
145 * name handler value code flags default_value
147 static RES_ITEM con_items[] = {
148 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
149 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
150 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
151 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
152 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
153 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
154 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
155 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
156 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
157 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
158 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
159 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
160 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
161 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
162 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
163 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
164 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
165 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
166 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
167 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
168 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
169 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
170 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
171 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
172 {NULL, NULL, {0}, 0, 0, 0}
177 * Client or File daemon resource
179 * name handler value code flags default_value
182 static RES_ITEM cli_items[] = {
183 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
184 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
185 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
186 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
187 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
188 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
189 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
190 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
191 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
192 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
193 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
194 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
195 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
196 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
197 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
198 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
199 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
200 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
201 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
202 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
203 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
204 {NULL, NULL, {0}, 0, 0, 0}
207 /* Storage daemon resource
209 * name handler value code flags default_value
211 static RES_ITEM store_items[] = {
212 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
213 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
214 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
215 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
216 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
217 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
218 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
219 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
220 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
221 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
222 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
223 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
224 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
225 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
226 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
227 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
228 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
229 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
230 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
231 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
232 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
233 {NULL, NULL, {0}, 0, 0, 0}
237 * Catalog Resource Directives
239 * name handler value code flags default_value
241 static RES_ITEM cat_items[] = {
242 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
243 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
244 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
245 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
246 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
247 /* keep this password as store_str for the moment */
248 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
249 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
250 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
251 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
252 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
253 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
254 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
255 /* Turned off for the moment */
256 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
257 {NULL, NULL, {0}, 0, 0, 0}
261 * Job Resource Directives
263 * name handler value code flags default_value
265 RES_ITEM job_items[] = {
266 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
267 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
268 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
269 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
270 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
271 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
272 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
273 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
274 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
275 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
276 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
277 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
278 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
279 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
280 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
281 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
282 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
283 /* Root of where to restore files */
284 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
285 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
286 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
287 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
288 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
289 /* Where to find bootstrap during restore */
290 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
291 /* Where to write bootstrap file during backup */
292 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
293 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
294 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
295 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
296 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
297 /* xxxMaxWaitTime are deprecated */
298 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
299 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
300 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
301 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
302 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
303 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
304 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
305 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
306 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
307 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
308 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
309 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
310 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
311 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
312 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
313 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
314 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
315 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
316 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
317 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
318 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
319 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
320 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
325 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
326 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
327 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
328 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
329 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
330 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
331 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
332 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
333 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
334 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
335 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
336 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
337 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
338 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
339 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
340 {NULL, NULL, {0}, 0, 0, 0}
345 * name handler value code flags default_value
347 static RES_ITEM fs_items[] = {
348 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
349 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
350 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
351 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
352 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
353 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
354 {NULL, NULL, {0}, 0, 0, 0}
357 /* Schedule -- see run_conf.c */
360 * name handler value code flags default_value
362 static RES_ITEM sch_items[] = {
363 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
364 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
365 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
366 {NULL, NULL, {0}, 0, 0, 0}
371 * name handler value code flags default_value
373 static RES_ITEM pool_items[] = {
374 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
375 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
376 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
377 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
378 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
379 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
380 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
381 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
382 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
383 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
384 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
385 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
386 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
387 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
388 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
389 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
390 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
391 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
392 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
393 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
394 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
395 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
396 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
397 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
398 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
399 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
400 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
401 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
402 {NULL, NULL, {0}, 0, 0, 0}
407 * name handler value code flags default_value
409 static RES_ITEM counter_items[] = {
410 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
411 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
412 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
413 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
414 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
415 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
416 {NULL, NULL, {0}, 0, 0, 0}
420 /* Message resource */
421 extern RES_ITEM msgs_items[];
424 * This is the master resource definition.
425 * It must have one item for each of the resources.
427 * NOTE!!! keep it in the same order as the R_codes
428 * or eliminate all resources[rindex].name
430 * name items rcode res_head
432 RES_TABLE resources[] = {
433 {"director", dir_items, R_DIRECTOR},
434 {"client", cli_items, R_CLIENT},
435 {"job", job_items, R_JOB},
436 {"storage", store_items, R_STORAGE},
437 {"catalog", cat_items, R_CATALOG},
438 {"schedule", sch_items, R_SCHEDULE},
439 {"fileset", fs_items, R_FILESET},
440 {"pool", pool_items, R_POOL},
441 {"messages", msgs_items, R_MSGS},
442 {"counter", counter_items, R_COUNTER},
443 {"console", con_items, R_CONSOLE},
444 {"jobdefs", job_items, R_JOBDEFS},
445 {"device", NULL, R_DEVICE}, /* info obtained from SD */
450 /* Keywords (RHS) permitted in Job Level records
452 * level_name level job_type
454 struct s_jl joblevels[] = {
455 {"Full", L_FULL, JT_BACKUP},
456 {"Base", L_BASE, JT_BACKUP},
457 {"Incremental", L_INCREMENTAL, JT_BACKUP},
458 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
459 {"Since", L_SINCE, JT_BACKUP},
460 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
461 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
462 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
463 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
464 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
465 {"Data", L_VERIFY_DATA, JT_VERIFY},
466 {" ", L_NONE, JT_ADMIN},
467 {" ", L_NONE, JT_RESTORE},
471 /* Keywords (RHS) permitted in Job type records
475 struct s_jt jobtypes[] = {
476 {"backup", JT_BACKUP},
478 {"verify", JT_VERIFY},
479 {"restore", JT_RESTORE},
480 {"migrate", JT_MIGRATE},
486 /* Keywords (RHS) permitted in Selection type records
490 struct s_jt migtypes[] = {
491 {"smallestvolume", MT_SMALLEST_VOL},
492 {"oldestvolume", MT_OLDEST_VOL},
493 {"pooloccupancy", MT_POOL_OCCUPANCY},
494 {"pooltime", MT_POOL_TIME},
495 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
496 {"client", MT_CLIENT},
497 {"volume", MT_VOLUME},
499 {"sqlquery", MT_SQLQUERY},
505 /* Options permitted in Restore replace= */
506 struct s_kw ReplaceOptions[] = {
507 {"always", REPLACE_ALWAYS},
508 {"ifnewer", REPLACE_IFNEWER},
509 {"ifolder", REPLACE_IFOLDER},
510 {"never", REPLACE_NEVER},
514 char *CAT::display(POOLMEM *dst) {
515 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
516 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
518 name(), NPRTB(db_name),
519 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
520 NPRTB(db_address), db_port, NPRTB(db_socket));
524 const char *level_to_str(int level)
527 static char level_no[30];
528 const char *str = level_no;
530 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
531 for (i=0; joblevels[i].level_name; i++) {
532 if (level == (int)joblevels[i].level) {
533 str = joblevels[i].level_name;
540 /* Dump contents of resource */
541 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
543 URES *res = (URES *)reshdr;
545 char ed1[100], ed2[100], ed3[100];
549 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
552 if (type < 0) { /* no recursion */
558 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
559 reshdr->name, res->res_dir.MaxConcurrentJobs,
560 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
561 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
562 if (res->res_dir.query_file) {
563 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
565 if (res->res_dir.messages) {
566 sendit(sock, _(" --> "));
567 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
571 sendit(sock, _("Console: name=%s SSL=%d\n"),
572 res->res_con.hdr.name, res->res_con.tls_enable);
575 if (res->res_counter.WrapCounter) {
576 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
577 res->res_counter.hdr.name, res->res_counter.MinValue,
578 res->res_counter.MaxValue, res->res_counter.CurrentValue,
579 res->res_counter.WrapCounter->hdr.name);
581 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
582 res->res_counter.hdr.name, res->res_counter.MinValue,
583 res->res_counter.MaxValue);
585 if (res->res_counter.Catalog) {
586 sendit(sock, _(" --> "));
587 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
592 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
593 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
594 res->res_client.MaxConcurrentJobs);
595 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
596 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
597 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
598 res->res_client.AutoPrune);
599 if (res->res_client.catalog) {
600 sendit(sock, _(" --> "));
601 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
608 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
609 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
610 " poolid=%s volname=%s MediaType=%s\n"),
611 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
612 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
613 dev->offline, dev->autochanger,
614 edit_uint64(dev->PoolId, ed1),
615 dev->VolumeName, dev->MediaType);
619 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
620 " DeviceName=%s MediaType=%s StorageId=%s\n"),
621 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
622 res->res_store.MaxConcurrentJobs,
623 res->res_store.dev_name(),
624 res->res_store.media_type,
625 edit_int64(res->res_store.StorageId, ed1));
629 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
630 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
631 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
632 res->res_cat.db_port, res->res_cat.db_name,
633 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
634 res->res_cat.mult_db_connections);
639 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
640 type == R_JOB ? _("Job") : _("JobDefs"),
641 res->res_job.hdr.name, res->res_job.JobType,
642 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
643 res->res_job.enabled);
644 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
645 res->res_job.MaxConcurrentJobs,
646 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
647 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
648 res->res_job.spool_data, res->res_job.write_part_after_job);
649 if (res->res_job.spool_size) {
650 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
652 if (res->res_job.JobType == JT_BACKUP) {
653 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
655 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
656 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
658 if (res->res_job.client) {
659 sendit(sock, _(" --> "));
660 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
662 if (res->res_job.fileset) {
663 sendit(sock, _(" --> "));
664 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
666 if (res->res_job.schedule) {
667 sendit(sock, _(" --> "));
668 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
670 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
671 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
673 if (res->res_job.RegexWhere) {
674 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
676 if (res->res_job.RestoreBootstrap) {
677 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
679 if (res->res_job.WriteBootstrap) {
680 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
682 if (res->res_job.PluginOptions) {
683 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
685 if (res->res_job.MaxRunTime) {
686 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
688 if (res->res_job.MaxWaitTime) {
689 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
691 if (res->res_job.MaxStartDelay) {
692 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
694 if (res->res_job.storage) {
696 foreach_alist(store, res->res_job.storage) {
697 sendit(sock, _(" --> "));
698 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
701 if (res->res_job.RunScripts) {
703 foreach_alist(script, res->res_job.RunScripts) {
704 sendit(sock, _(" --> RunScript\n"));
705 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
706 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
707 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
708 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
709 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
710 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
713 if (res->res_job.pool) {
714 sendit(sock, _(" --> "));
715 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
717 if (res->res_job.full_pool) {
718 sendit(sock, _(" --> "));
719 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
721 if (res->res_job.inc_pool) {
722 sendit(sock, _(" --> "));
723 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
725 if (res->res_job.diff_pool) {
726 sendit(sock, _(" --> "));
727 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
729 if (res->res_job.verify_job) {
730 sendit(sock, _(" --> "));
731 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
733 if (res->res_job.run_cmds) {
735 foreach_alist(runcmd, res->res_job.run_cmds) {
736 sendit(sock, _(" --> Run=%s\n"), runcmd);
739 if (res->res_job.selection_pattern) {
740 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
742 if (res->res_job.messages) {
743 sendit(sock, _(" --> "));
744 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
751 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
752 for (i=0; i<res->res_fs.num_includes; i++) {
753 INCEXE *incexe = res->res_fs.include_items[i];
754 for (j=0; j<incexe->num_opts; j++) {
755 FOPTS *fo = incexe->opts_list[j];
756 sendit(sock, " O %s\n", fo->opts);
758 bool enhanced_wild = false;
759 for (k=0; fo->opts[k]!='\0'; k++) {
760 if (fo->opts[k]=='W') {
761 enhanced_wild = true;
766 for (k=0; k<fo->regex.size(); k++) {
767 sendit(sock, " R %s\n", fo->regex.get(k));
769 for (k=0; k<fo->regexdir.size(); k++) {
770 sendit(sock, " RD %s\n", fo->regexdir.get(k));
772 for (k=0; k<fo->regexfile.size(); k++) {
773 sendit(sock, " RF %s\n", fo->regexfile.get(k));
775 for (k=0; k<fo->wild.size(); k++) {
776 sendit(sock, " W %s\n", fo->wild.get(k));
778 for (k=0; k<fo->wilddir.size(); k++) {
779 sendit(sock, " WD %s\n", fo->wilddir.get(k));
781 for (k=0; k<fo->wildfile.size(); k++) {
782 sendit(sock, " WF %s\n", fo->wildfile.get(k));
784 for (k=0; k<fo->wildbase.size(); k++) {
785 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
787 for (k=0; k<fo->base.size(); k++) {
788 sendit(sock, " B %s\n", fo->base.get(k));
790 for (k=0; k<fo->fstype.size(); k++) {
791 sendit(sock, " X %s\n", fo->fstype.get(k));
793 for (k=0; k<fo->drivetype.size(); k++) {
794 sendit(sock, " XD %s\n", fo->drivetype.get(k));
797 sendit(sock, " G %s\n", fo->plugin);
800 sendit(sock, " D %s\n", fo->reader);
803 sendit(sock, " T %s\n", fo->writer);
805 sendit(sock, " N\n");
807 for (j=0; j<incexe->name_list.size(); j++) {
808 sendit(sock, " I %s\n", incexe->name_list.get(j));
810 if (incexe->name_list.size()) {
811 sendit(sock, " N\n");
813 for (j=0; j<incexe->plugin_list.size(); j++) {
814 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
816 if (incexe->plugin_list.size()) {
817 sendit(sock, " N\n");
822 for (i=0; i<res->res_fs.num_excludes; i++) {
823 INCEXE *incexe = res->res_fs.exclude_items[i];
824 for (j=0; j<incexe->name_list.size(); j++) {
825 sendit(sock, " E %s\n", incexe->name_list.get(j));
827 if (incexe->name_list.size()) {
828 sendit(sock, " N\n");
835 if (res->res_sch.run) {
837 RUN *run = res->res_sch.run;
838 char buf[1000], num[30];
839 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
844 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
845 bstrncpy(buf, _(" hour="), sizeof(buf));
846 for (i=0; i<24; i++) {
847 if (bit_is_set(i, run->hour)) {
848 bsnprintf(num, sizeof(num), "%d ", i);
849 bstrncat(buf, num, sizeof(buf));
852 bstrncat(buf, "\n", sizeof(buf));
854 bstrncpy(buf, _(" mday="), sizeof(buf));
855 for (i=0; i<31; i++) {
856 if (bit_is_set(i, run->mday)) {
857 bsnprintf(num, sizeof(num), "%d ", i);
858 bstrncat(buf, num, sizeof(buf));
861 bstrncat(buf, "\n", sizeof(buf));
863 bstrncpy(buf, _(" month="), sizeof(buf));
864 for (i=0; i<12; i++) {
865 if (bit_is_set(i, run->month)) {
866 bsnprintf(num, sizeof(num), "%d ", i);
867 bstrncat(buf, num, sizeof(buf));
870 bstrncat(buf, "\n", sizeof(buf));
872 bstrncpy(buf, _(" wday="), sizeof(buf));
873 for (i=0; i<7; i++) {
874 if (bit_is_set(i, run->wday)) {
875 bsnprintf(num, sizeof(num), "%d ", i);
876 bstrncat(buf, num, sizeof(buf));
879 bstrncat(buf, "\n", sizeof(buf));
881 bstrncpy(buf, _(" wom="), sizeof(buf));
882 for (i=0; i<5; i++) {
883 if (bit_is_set(i, run->wom)) {
884 bsnprintf(num, sizeof(num), "%d ", i);
885 bstrncat(buf, num, sizeof(buf));
888 bstrncat(buf, "\n", sizeof(buf));
890 bstrncpy(buf, _(" woy="), sizeof(buf));
891 for (i=0; i<54; i++) {
892 if (bit_is_set(i, run->woy)) {
893 bsnprintf(num, sizeof(num), "%d ", i);
894 bstrncat(buf, num, sizeof(buf));
897 bstrncat(buf, "\n", sizeof(buf));
899 sendit(sock, _(" mins=%d\n"), run->minute);
901 sendit(sock, _(" --> "));
902 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
905 sendit(sock, _(" --> "));
906 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
909 sendit(sock, _(" --> "));
910 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
912 /* If another Run record is chained in, go print it */
918 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
923 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
924 res->res_pool.pool_type);
925 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
926 res->res_pool.use_catalog, res->res_pool.use_volume_once,
927 res->res_pool.catalog_files);
928 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
929 res->res_pool.max_volumes, res->res_pool.AutoPrune,
930 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
931 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
932 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
933 res->res_pool.Recycle,
934 NPRT(res->res_pool.label_format));
935 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
936 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
937 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
938 res->res_pool.recycle_oldest_volume,
939 res->res_pool.purge_oldest_volume);
940 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
941 res->res_pool.MaxVolJobs,
942 res->res_pool.MaxVolFiles,
943 edit_uint64(res->res_pool.MaxVolFiles, ed1));
944 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
945 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
946 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
947 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
948 if (res->res_pool.NextPool) {
949 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
951 if (res->res_pool.RecyclePool) {
952 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
954 if (res->res_pool.catalog) {
955 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
957 if (res->res_pool.storage) {
959 foreach_alist(store, res->res_pool.storage) {
960 sendit(sock, _(" --> "));
961 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
964 if (res->res_pool.CopyPool) {
966 foreach_alist(copy, res->res_pool.CopyPool) {
967 sendit(sock, _(" --> "));
968 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
975 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
976 if (res->res_msgs.mail_cmd)
977 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
978 if (res->res_msgs.operator_cmd)
979 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
983 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
986 if (recurse && res->res_dir.hdr.next) {
987 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
992 * Free all the members of an INCEXE structure
994 static void free_incexe(INCEXE *incexe)
996 incexe->name_list.destroy();
997 incexe->plugin_list.destroy();
998 for (int i=0; i<incexe->num_opts; i++) {
999 FOPTS *fopt = incexe->opts_list[i];
1000 fopt->regex.destroy();
1001 fopt->regexdir.destroy();
1002 fopt->regexfile.destroy();
1003 fopt->wild.destroy();
1004 fopt->wilddir.destroy();
1005 fopt->wildfile.destroy();
1006 fopt->wildbase.destroy();
1007 fopt->base.destroy();
1008 fopt->fstype.destroy();
1009 fopt->drivetype.destroy();
1021 if (incexe->opts_list) {
1022 free(incexe->opts_list);
1028 * Free memory of resource -- called when daemon terminates.
1029 * NB, we don't need to worry about freeing any references
1030 * to other resources as they will be freed when that
1031 * resource chain is traversed. Mainly we worry about freeing
1032 * allocated strings (names).
1034 void free_resource(RES *sres, int type)
1037 RES *nres; /* next resource if linked */
1038 URES *res = (URES *)sres;
1043 /* common stuff -- free the resource name and description */
1044 nres = (RES *)res->res_dir.hdr.next;
1045 if (res->res_dir.hdr.name) {
1046 free(res->res_dir.hdr.name);
1048 if (res->res_dir.hdr.desc) {
1049 free(res->res_dir.hdr.desc);
1054 if (res->res_dir.working_directory) {
1055 free(res->res_dir.working_directory);
1057 if (res->res_dir.scripts_directory) {
1058 free((char *)res->res_dir.scripts_directory);
1060 if (res->res_dir.plugin_directory) {
1061 free((char *)res->res_dir.plugin_directory);
1063 if (res->res_dir.pid_directory) {
1064 free(res->res_dir.pid_directory);
1066 if (res->res_dir.subsys_directory) {
1067 free(res->res_dir.subsys_directory);
1069 if (res->res_dir.password) {
1070 free(res->res_dir.password);
1072 if (res->res_dir.query_file) {
1073 free(res->res_dir.query_file);
1075 if (res->res_dir.DIRaddrs) {
1076 free_addresses(res->res_dir.DIRaddrs);
1078 if (res->res_dir.tls_ctx) {
1079 free_tls_context(res->res_dir.tls_ctx);
1081 if (res->res_dir.tls_ca_certfile) {
1082 free(res->res_dir.tls_ca_certfile);
1084 if (res->res_dir.tls_ca_certdir) {
1085 free(res->res_dir.tls_ca_certdir);
1087 if (res->res_dir.tls_certfile) {
1088 free(res->res_dir.tls_certfile);
1090 if (res->res_dir.tls_keyfile) {
1091 free(res->res_dir.tls_keyfile);
1093 if (res->res_dir.tls_dhfile) {
1094 free(res->res_dir.tls_dhfile);
1096 if (res->res_dir.tls_allowed_cns) {
1097 delete res->res_dir.tls_allowed_cns;
1099 if (res->res_dir.verid) {
1100 free(res->res_dir.verid);
1107 if (res->res_con.password) {
1108 free(res->res_con.password);
1110 if (res->res_con.tls_ctx) {
1111 free_tls_context(res->res_con.tls_ctx);
1113 if (res->res_con.tls_ca_certfile) {
1114 free(res->res_con.tls_ca_certfile);
1116 if (res->res_con.tls_ca_certdir) {
1117 free(res->res_con.tls_ca_certdir);
1119 if (res->res_con.tls_certfile) {
1120 free(res->res_con.tls_certfile);
1122 if (res->res_con.tls_keyfile) {
1123 free(res->res_con.tls_keyfile);
1125 if (res->res_con.tls_dhfile) {
1126 free(res->res_con.tls_dhfile);
1128 if (res->res_con.tls_allowed_cns) {
1129 delete res->res_con.tls_allowed_cns;
1131 for (int i=0; i<Num_ACL; i++) {
1132 if (res->res_con.ACL_lists[i]) {
1133 delete res->res_con.ACL_lists[i];
1134 res->res_con.ACL_lists[i] = NULL;
1139 if (res->res_client.address) {
1140 free(res->res_client.address);
1142 if (res->res_client.password) {
1143 free(res->res_client.password);
1145 if (res->res_client.tls_ctx) {
1146 free_tls_context(res->res_client.tls_ctx);
1148 if (res->res_client.tls_ca_certfile) {
1149 free(res->res_client.tls_ca_certfile);
1151 if (res->res_client.tls_ca_certdir) {
1152 free(res->res_client.tls_ca_certdir);
1154 if (res->res_client.tls_certfile) {
1155 free(res->res_client.tls_certfile);
1157 if (res->res_client.tls_keyfile) {
1158 free(res->res_client.tls_keyfile);
1160 if (res->res_client.tls_allowed_cns) {
1161 delete res->res_client.tls_allowed_cns;
1165 if (res->res_store.address) {
1166 free(res->res_store.address);
1168 if (res->res_store.password) {
1169 free(res->res_store.password);
1171 if (res->res_store.media_type) {
1172 free(res->res_store.media_type);
1174 if (res->res_store.device) {
1175 delete res->res_store.device;
1177 if (res->res_store.tls_ctx) {
1178 free_tls_context(res->res_store.tls_ctx);
1180 if (res->res_store.tls_ca_certfile) {
1181 free(res->res_store.tls_ca_certfile);
1183 if (res->res_store.tls_ca_certdir) {
1184 free(res->res_store.tls_ca_certdir);
1186 if (res->res_store.tls_certfile) {
1187 free(res->res_store.tls_certfile);
1189 if (res->res_store.tls_keyfile) {
1190 free(res->res_store.tls_keyfile);
1194 if (res->res_cat.db_address) {
1195 free(res->res_cat.db_address);
1197 if (res->res_cat.db_socket) {
1198 free(res->res_cat.db_socket);
1200 if (res->res_cat.db_user) {
1201 free(res->res_cat.db_user);
1203 if (res->res_cat.db_name) {
1204 free(res->res_cat.db_name);
1206 if (res->res_cat.db_driver) {
1207 free(res->res_cat.db_driver);
1209 if (res->res_cat.db_password) {
1210 free(res->res_cat.db_password);
1214 if ((num=res->res_fs.num_includes)) {
1215 while (--num >= 0) {
1216 free_incexe(res->res_fs.include_items[num]);
1218 free(res->res_fs.include_items);
1220 res->res_fs.num_includes = 0;
1221 if ((num=res->res_fs.num_excludes)) {
1222 while (--num >= 0) {
1223 free_incexe(res->res_fs.exclude_items[num]);
1225 free(res->res_fs.exclude_items);
1227 res->res_fs.num_excludes = 0;
1230 if (res->res_pool.pool_type) {
1231 free(res->res_pool.pool_type);
1233 if (res->res_pool.label_format) {
1234 free(res->res_pool.label_format);
1236 if (res->res_pool.cleaning_prefix) {
1237 free(res->res_pool.cleaning_prefix);
1239 if (res->res_pool.storage) {
1240 delete res->res_pool.storage;
1244 if (res->res_sch.run) {
1246 nrun = res->res_sch.run;
1256 if (res->res_job.RestoreWhere) {
1257 free(res->res_job.RestoreWhere);
1259 if (res->res_job.RegexWhere) {
1260 free(res->res_job.RegexWhere);
1262 if (res->res_job.strip_prefix) {
1263 free(res->res_job.strip_prefix);
1265 if (res->res_job.add_prefix) {
1266 free(res->res_job.add_prefix);
1268 if (res->res_job.add_suffix) {
1269 free(res->res_job.add_suffix);
1271 if (res->res_job.RestoreBootstrap) {
1272 free(res->res_job.RestoreBootstrap);
1274 if (res->res_job.WriteBootstrap) {
1275 free(res->res_job.WriteBootstrap);
1277 if (res->res_job.PluginOptions) {
1278 free(res->res_job.PluginOptions);
1280 if (res->res_job.selection_pattern) {
1281 free(res->res_job.selection_pattern);
1283 if (res->res_job.run_cmds) {
1284 delete res->res_job.run_cmds;
1286 if (res->res_job.storage) {
1287 delete res->res_job.storage;
1289 if (res->res_job.RunScripts) {
1290 free_runscripts(res->res_job.RunScripts);
1291 delete res->res_job.RunScripts;
1295 if (res->res_msgs.mail_cmd) {
1296 free(res->res_msgs.mail_cmd);
1298 if (res->res_msgs.operator_cmd) {
1299 free(res->res_msgs.operator_cmd);
1301 free_msgs_res((MSGS *)res); /* free message resource */
1305 printf(_("Unknown resource type %d in free_resource.\n"), type);
1307 /* Common stuff again -- free the resource, recurse to next one */
1312 free_resource(nres, type);
1317 * Save the new resource by chaining it into the head list for
1318 * the resource. If this is pass 2, we update any resource
1319 * pointers because they may not have been defined until
1322 void save_resource(int type, RES_ITEM *items, int pass)
1325 int rindex = type - r_first;
1329 /* Check Job requirements after applying JobDefs */
1330 if (type != R_JOB && type != R_JOBDEFS) {
1332 * Ensure that all required items are present
1334 for (i=0; items[i].name; i++) {
1335 if (items[i].flags & ITEM_REQUIRED) {
1336 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1337 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1338 items[i].name, resources[rindex]);
1341 /* If this triggers, take a look at lib/parse_conf.h */
1342 if (i >= MAX_RES_ITEMS) {
1343 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1346 } else if (type == R_JOB) {
1348 * Ensure that the name item is present
1350 if (items[0].flags & ITEM_REQUIRED) {
1351 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1352 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1353 items[0].name, resources[rindex]);
1359 * During pass 2 in each "store" routine, we looked up pointers
1360 * to all the resources referrenced in the current resource, now we
1361 * must copy their addresses from the static record to the allocated
1366 /* Resources not containing a resource */
1374 * Resources containing another resource or alist. First
1375 * look up the resource which contains another resource. It
1376 * was written during pass 1. Then stuff in the pointers to
1377 * the resources it contains, which were inserted this pass.
1378 * Finally, it will all be stored back.
1381 /* Find resource saved in pass 1 */
1382 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1383 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1385 /* Explicitly copy resource pointers from this pass (res_all) */
1386 res->res_pool.NextPool = res_all.res_pool.NextPool;
1387 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1388 res->res_pool.storage = res_all.res_pool.storage;
1389 res->res_pool.catalog = res_all.res_pool.catalog;
1392 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1393 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1395 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1398 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1399 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1401 res->res_dir.messages = res_all.res_dir.messages;
1402 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1405 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1406 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1407 res_all.res_dir.hdr.name);
1409 /* we must explicitly copy the device alist pointer */
1410 res->res_store.device = res_all.res_store.device;
1414 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1415 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1416 res_all.res_dir.hdr.name);
1418 res->res_job.messages = res_all.res_job.messages;
1419 res->res_job.schedule = res_all.res_job.schedule;
1420 res->res_job.client = res_all.res_job.client;
1421 res->res_job.fileset = res_all.res_job.fileset;
1422 res->res_job.storage = res_all.res_job.storage;
1423 res->res_job.pool = res_all.res_job.pool;
1424 res->res_job.full_pool = res_all.res_job.full_pool;
1425 res->res_job.inc_pool = res_all.res_job.inc_pool;
1426 res->res_job.diff_pool = res_all.res_job.diff_pool;
1427 res->res_job.verify_job = res_all.res_job.verify_job;
1428 res->res_job.jobdefs = res_all.res_job.jobdefs;
1429 res->res_job.run_cmds = res_all.res_job.run_cmds;
1430 res->res_job.RunScripts = res_all.res_job.RunScripts;
1432 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1433 * is not very useful)
1434 * We have to set_bit(index, res_all.hdr.item_present);
1435 * or something like that
1438 /* we take RegexWhere before all other options */
1439 if (!res->res_job.RegexWhere
1441 (res->res_job.strip_prefix ||
1442 res->res_job.add_suffix ||
1443 res->res_job.add_prefix))
1445 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1446 res->res_job.add_prefix,
1447 res->res_job.add_suffix);
1448 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1449 bregexp_build_where(res->res_job.RegexWhere, len,
1450 res->res_job.strip_prefix,
1451 res->res_job.add_prefix,
1452 res->res_job.add_suffix);
1453 /* TODO: test bregexp */
1456 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1457 free(res->res_job.RestoreWhere);
1458 res->res_job.RestoreWhere = NULL;
1463 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1464 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1466 res->res_counter.Catalog = res_all.res_counter.Catalog;
1467 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1471 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1472 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1474 res->res_client.catalog = res_all.res_client.catalog;
1475 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1479 * Schedule is a bit different in that it contains a RUN record
1480 * chain which isn't a "named" resource. This chain was linked
1481 * in by run_conf.c during pass 2, so here we jam the pointer
1482 * into the Schedule resource.
1484 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1485 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1487 res->res_sch.run = res_all.res_sch.run;
1490 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1494 /* Note, the resource name was already saved during pass 1,
1495 * so here, we can just release it.
1497 if (res_all.res_dir.hdr.name) {
1498 free(res_all.res_dir.hdr.name);
1499 res_all.res_dir.hdr.name = NULL;
1501 if (res_all.res_dir.hdr.desc) {
1502 free(res_all.res_dir.hdr.desc);
1503 res_all.res_dir.hdr.desc = NULL;
1509 * The following code is only executed during pass 1
1513 size = sizeof(DIRRES);
1516 size = sizeof(CONRES);
1519 size =sizeof(CLIENT);
1522 size = sizeof(STORE);
1532 size = sizeof(FILESET);
1535 size = sizeof(SCHED);
1538 size = sizeof(POOL);
1541 size = sizeof(MSGS);
1544 size = sizeof(COUNTER);
1550 printf(_("Unknown resource type %d in save_resource.\n"), type);
1556 res = (URES *)malloc(size);
1557 memcpy(res, &res_all, size);
1558 if (!res_head[rindex]) {
1559 res_head[rindex] = (RES *)res; /* store first entry */
1560 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1561 res->res_dir.hdr.name, rindex);
1564 if (res->res_dir.hdr.name == NULL) {
1565 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1568 /* Add new res to end of chain */
1569 for (last=next=res_head[rindex]; next; next=next->next) {
1571 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1572 Emsg2(M_ERROR_TERM, 0,
1573 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1574 resources[rindex].name, res->res_dir.hdr.name);
1577 last->next = (RES *)res;
1578 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1579 res->res_dir.hdr.name, rindex, pass);
1585 * Store Device. Note, the resource is created upon the
1586 * first reference. The details of the resource are obtained
1587 * later from the SD.
1589 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1593 int rindex = R_DEVICE - r_first;
1594 int size = sizeof(DEVICE);
1598 token = lex_get_token(lc, T_NAME);
1599 if (!res_head[rindex]) {
1600 res = (URES *)malloc(size);
1601 memset(res, 0, size);
1602 res->res_dev.hdr.name = bstrdup(lc->str);
1603 res_head[rindex] = (RES *)res; /* store first entry */
1604 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1605 res->res_dir.hdr.name, rindex);
1608 /* See if it is already defined */
1609 for (next=res_head[rindex]; next->next; next=next->next) {
1610 if (strcmp(next->name, lc->str) == 0) {
1616 res = (URES *)malloc(size);
1617 memset(res, 0, size);
1618 res->res_dev.hdr.name = bstrdup(lc->str);
1619 next->next = (RES *)res;
1620 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1621 res->res_dir.hdr.name, rindex, pass);
1626 set_bit(index, res_all.hdr.item_present);
1628 store_alist_res(lc, item, index, pass);
1633 * Store Migration/Copy type
1636 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1640 token = lex_get_token(lc, T_NAME);
1641 /* Store the type both pass 1 and pass 2 */
1642 for (i=0; migtypes[i].type_name; i++) {
1643 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1644 *(uint32_t *)(item->value) = migtypes[i].job_type;
1650 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1653 set_bit(index, res_all.hdr.item_present);
1659 * Store JobType (backup, verify, restore)
1662 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1666 token = lex_get_token(lc, T_NAME);
1667 /* Store the type both pass 1 and pass 2 */
1668 for (i=0; jobtypes[i].type_name; i++) {
1669 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1670 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1676 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1679 set_bit(index, res_all.hdr.item_present);
1683 * Store Job Level (Full, Incremental, ...)
1686 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1690 token = lex_get_token(lc, T_NAME);
1691 /* Store the level pass 2 so that type is defined */
1692 for (i=0; joblevels[i].level_name; i++) {
1693 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1694 *(uint32_t *)(item->value) = joblevels[i].level;
1700 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1703 set_bit(index, res_all.hdr.item_present);
1707 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1710 token = lex_get_token(lc, T_NAME);
1711 /* Scan Replacement options */
1712 for (i=0; ReplaceOptions[i].name; i++) {
1713 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1714 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1720 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1723 set_bit(index, res_all.hdr.item_present);
1727 * Store ACL (access control list)
1730 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1735 token = lex_get_token(lc, T_STRING);
1737 if (((alist **)item->value)[item->code] == NULL) {
1738 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1739 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1741 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1742 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1744 token = lex_get_token(lc, T_ALL);
1745 if (token == T_COMMA) {
1746 continue; /* get another ACL */
1750 set_bit(index, res_all.hdr.item_present);
1753 /* We build RunScripts items here */
1754 static RUNSCRIPT res_runscript;
1756 /* Store a runscript->when in a bit field */
1757 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1759 lex_get_token(lc, T_NAME);
1761 if (strcasecmp(lc->str, "before") == 0) {
1762 *(uint32_t *)(item->value) = SCRIPT_Before ;
1763 } else if (strcasecmp(lc->str, "after") == 0) {
1764 *(uint32_t *)(item->value) = SCRIPT_After;
1765 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1766 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1767 } else if (strcasecmp(lc->str, "always") == 0) {
1768 *(uint32_t *)(item->value) = SCRIPT_Any;
1770 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1775 /* Store a runscript->target
1778 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1780 lex_get_token(lc, T_STRING);
1783 if (strcmp(lc->str, "%c") == 0) {
1784 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1785 } else if (strcasecmp(lc->str, "yes") == 0) {
1786 ((RUNSCRIPT*) item->value)->set_target("%c");
1787 } else if (strcasecmp(lc->str, "no") == 0) {
1788 ((RUNSCRIPT*) item->value)->set_target("");
1790 RES *res = GetResWithName(R_CLIENT, lc->str);
1792 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1793 lc->str, lc->line_no, lc->line);
1796 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1803 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1805 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1807 lex_get_token(lc, T_STRING);
1810 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1811 POOLMEM *c = get_pool_memory(PM_FNAME);
1812 /* Each runscript command takes 2 entries in commands list */
1813 pm_strcpy(c, lc->str);
1814 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1815 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1820 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1822 lex_get_token(lc, T_STRING);
1823 alist **runscripts = (alist **)(item->value) ;
1826 RUNSCRIPT *script = new_runscript();
1827 script->set_job_code_callback(job_code_callback_filesetname);
1829 script->set_command(lc->str);
1831 /* TODO: remove all script->old_proto with bacula 1.42 */
1833 if (strcmp(item->name, "runbeforejob") == 0) {
1834 script->when = SCRIPT_Before;
1835 script->fail_on_error = true;
1836 script->set_target("");
1838 } else if (strcmp(item->name, "runafterjob") == 0) {
1839 script->when = SCRIPT_After;
1840 script->on_success = true;
1841 script->on_failure = false;
1842 script->set_target("");
1844 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1845 script->old_proto = true;
1846 script->when = SCRIPT_After;
1847 script->set_target("%c");
1848 script->on_success = true;
1849 script->on_failure = false;
1851 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1852 script->old_proto = true;
1853 script->when = SCRIPT_Before;
1854 script->set_target("%c");
1855 script->fail_on_error = true;
1857 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1858 script->when = SCRIPT_After;
1859 script->on_failure = true;
1860 script->on_success = false;
1861 script->set_target("");
1864 if (*runscripts == NULL) {
1865 *runscripts = New(alist(10, not_owned_by_alist));
1868 (*runscripts)->append(script);
1875 /* Store a bool in a bit field without modifing res_all.hdr
1876 * We can also add an option to store_bool to skip res_all.hdr
1878 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1880 lex_get_token(lc, T_NAME);
1881 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1882 *(bool *)(item->value) = true;
1883 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1884 *(bool *)(item->value) = false;
1886 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1892 * new RunScript items
1893 * name handler value code flags default_value
1895 static RES_ITEM runscript_items[] = {
1896 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1897 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1898 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1899 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1900 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1901 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1902 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1903 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1904 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1905 {NULL, NULL, {0}, 0, 0, 0}
1909 * Store RunScript info
1911 * Note, when this routine is called, we are inside a Job
1912 * resource. We treat the RunScript like a sort of
1913 * mini-resource within the Job resource.
1915 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1919 alist **runscripts = (alist **)(item->value) ;
1921 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1923 token = lex_get_token(lc, T_SKIP_EOL);
1925 if (token != T_BOB) {
1926 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1928 /* setting on_success, on_failure, fail_on_error */
1929 res_runscript.reset_default();
1932 res_runscript.commands = New(alist(10, not_owned_by_alist));
1935 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1936 if (token == T_EOB) {
1939 if (token != T_IDENTIFIER) {
1940 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1942 for (i=0; runscript_items[i].name; i++) {
1943 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1944 token = lex_get_token(lc, T_SKIP_EOL);
1945 if (token != T_EQUALS) {
1946 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1949 /* Call item handler */
1950 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1957 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1962 /* run on client by default */
1963 if (res_runscript.target == NULL) {
1964 res_runscript.set_target("%c");
1966 if (*runscripts == NULL) {
1967 *runscripts = New(alist(10, not_owned_by_alist));
1970 * commands list contains 2 values per command
1971 * - POOLMEM command string (ex: /bin/true)
1972 * - int command type (ex: SHELL_CMD)
1974 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1975 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1976 t = (long)res_runscript.commands->pop();
1977 RUNSCRIPT *script = new_runscript();
1978 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1979 script->command = c;
1980 script->cmd_type = t;
1981 /* target is taken from res_runscript, each runscript object have
1984 script->target = NULL;
1985 script->set_target(res_runscript.target);
1987 (*runscripts)->append(script);
1990 delete res_runscript.commands;
1991 /* setting on_success, on_failure... cleanup target field */
1992 res_runscript.reset_default(true);
1996 set_bit(index, res_all.hdr.item_present);
1999 /* callback function for edit_job_codes */
2000 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2002 if (param[0] == 'f') {
2003 return jcr->fileset->name();
2009 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2011 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2012 r_first, r_last, resources, res_head);
2013 return config->parse_config();