2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
116 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
117 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
118 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
119 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
120 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
121 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
122 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
123 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
124 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
125 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
126 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
127 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
128 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
129 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
130 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
131 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
132 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
133 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
134 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
135 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
136 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
137 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
138 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
139 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
140 {NULL, NULL, {0}, 0, 0, 0}
146 * name handler value code flags default_value
148 static RES_ITEM con_items[] = {
149 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
150 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
151 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
152 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
153 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
154 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
155 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
156 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
157 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
158 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
159 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
160 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
161 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
162 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
163 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
164 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
165 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
166 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
167 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
168 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
169 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
170 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
171 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
172 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
173 {NULL, NULL, {0}, 0, 0, 0}
178 * Client or File daemon resource
180 * name handler value code flags default_value
183 static RES_ITEM cli_items[] = {
184 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
185 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
186 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
187 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
188 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
189 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
190 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
191 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
192 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
193 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
194 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
195 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
196 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
197 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
198 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
199 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
200 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
201 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
202 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
203 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
204 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
205 {NULL, NULL, {0}, 0, 0, 0}
208 /* Storage daemon resource
210 * name handler value code flags default_value
212 static RES_ITEM store_items[] = {
213 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
214 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
215 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
216 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
217 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
218 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
219 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
220 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
221 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
222 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
223 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
224 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
225 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
226 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
227 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
228 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
229 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
230 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
231 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
232 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
233 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
234 {NULL, NULL, {0}, 0, 0, 0}
238 * Catalog Resource Directives
240 * name handler value code flags default_value
242 static RES_ITEM cat_items[] = {
243 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
244 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
245 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
246 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
247 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
248 /* keep this password as store_str for the moment */
249 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
250 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
251 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
252 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
253 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
254 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
255 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
256 /* Turned off for the moment */
257 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
258 {NULL, NULL, {0}, 0, 0, 0}
262 * Job Resource Directives
264 * name handler value code flags default_value
266 RES_ITEM job_items[] = {
267 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
268 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
269 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
270 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
271 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
272 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
273 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
274 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
275 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
276 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
277 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
278 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
279 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
280 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
281 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
282 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
283 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
284 /* Root of where to restore files */
285 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
286 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
287 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
288 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
289 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
290 /* Where to find bootstrap during restore */
291 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
292 /* Where to write bootstrap file during backup */
293 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
294 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
295 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
296 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
297 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
298 /* xxxMaxWaitTime are deprecated */
299 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
300 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
301 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
302 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
303 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
304 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
305 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
306 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
307 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
308 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
309 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
310 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
311 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
312 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
313 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
314 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
315 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
316 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
317 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
318 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
319 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
320 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
326 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
327 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
328 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
329 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
330 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
331 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
332 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
333 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
334 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
335 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
336 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
337 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
338 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
339 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
340 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
341 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
342 {NULL, NULL, {0}, 0, 0, 0}
347 * name handler value code flags default_value
349 static RES_ITEM fs_items[] = {
350 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
351 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
352 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
353 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
354 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
355 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
356 {NULL, NULL, {0}, 0, 0, 0}
359 /* Schedule -- see run_conf.c */
362 * name handler value code flags default_value
364 static RES_ITEM sch_items[] = {
365 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
366 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
367 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
368 {NULL, NULL, {0}, 0, 0, 0}
373 * name handler value code flags default_value
375 static RES_ITEM pool_items[] = {
376 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
377 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
378 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
379 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
380 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
381 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
382 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
383 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
384 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
385 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
386 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
387 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
388 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
389 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
390 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
391 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
392 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
393 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
394 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
395 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
396 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
397 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
398 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
399 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
400 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
401 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
402 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
403 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
404 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
405 {NULL, NULL, {0}, 0, 0, 0}
410 * name handler value code flags default_value
412 static RES_ITEM counter_items[] = {
413 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
414 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
415 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
416 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
417 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
418 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
419 {NULL, NULL, {0}, 0, 0, 0}
423 /* Message resource */
424 extern RES_ITEM msgs_items[];
427 * This is the master resource definition.
428 * It must have one item for each of the resources.
430 * NOTE!!! keep it in the same order as the R_codes
431 * or eliminate all resources[rindex].name
433 * name items rcode res_head
435 RES_TABLE resources[] = {
436 {"director", dir_items, R_DIRECTOR},
437 {"client", cli_items, R_CLIENT},
438 {"job", job_items, R_JOB},
439 {"storage", store_items, R_STORAGE},
440 {"catalog", cat_items, R_CATALOG},
441 {"schedule", sch_items, R_SCHEDULE},
442 {"fileset", fs_items, R_FILESET},
443 {"pool", pool_items, R_POOL},
444 {"messages", msgs_items, R_MSGS},
445 {"counter", counter_items, R_COUNTER},
446 {"console", con_items, R_CONSOLE},
447 {"jobdefs", job_items, R_JOBDEFS},
448 {"device", NULL, R_DEVICE}, /* info obtained from SD */
453 /* Keywords (RHS) permitted in Job Level records
455 * level_name level job_type
457 struct s_jl joblevels[] = {
458 {"Full", L_FULL, JT_BACKUP},
459 {"Base", L_BASE, JT_BACKUP},
460 {"Incremental", L_INCREMENTAL, JT_BACKUP},
461 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
462 {"Since", L_SINCE, JT_BACKUP},
463 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
464 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
465 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
466 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
467 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
468 {"Data", L_VERIFY_DATA, JT_VERIFY},
469 {" ", L_NONE, JT_ADMIN},
470 {" ", L_NONE, JT_RESTORE},
474 /* Keywords (RHS) permitted in Job type records
478 struct s_jt jobtypes[] = {
479 {"backup", JT_BACKUP},
481 {"verify", JT_VERIFY},
482 {"restore", JT_RESTORE},
483 {"migrate", JT_MIGRATE},
489 /* Keywords (RHS) permitted in Selection type records
493 struct s_jt migtypes[] = {
494 {"smallestvolume", MT_SMALLEST_VOL},
495 {"oldestvolume", MT_OLDEST_VOL},
496 {"pooloccupancy", MT_POOL_OCCUPANCY},
497 {"pooltime", MT_POOL_TIME},
498 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
499 {"client", MT_CLIENT},
500 {"volume", MT_VOLUME},
502 {"sqlquery", MT_SQLQUERY},
508 /* Options permitted in Restore replace= */
509 struct s_kw ReplaceOptions[] = {
510 {"always", REPLACE_ALWAYS},
511 {"ifnewer", REPLACE_IFNEWER},
512 {"ifolder", REPLACE_IFOLDER},
513 {"never", REPLACE_NEVER},
517 char *CAT::display(POOLMEM *dst) {
518 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
519 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
521 name(), NPRTB(db_name),
522 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
523 NPRTB(db_address), db_port, NPRTB(db_socket));
527 const char *level_to_str(int level)
530 static char level_no[30];
531 const char *str = level_no;
533 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
534 for (i=0; joblevels[i].level_name; i++) {
535 if (level == (int)joblevels[i].level) {
536 str = joblevels[i].level_name;
543 /* Dump contents of resource */
544 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
546 URES *res = (URES *)reshdr;
548 char ed1[100], ed2[100], ed3[100];
552 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
555 if (type < 0) { /* no recursion */
561 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
562 reshdr->name, res->res_dir.MaxConcurrentJobs,
563 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
564 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
565 if (res->res_dir.query_file) {
566 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
568 if (res->res_dir.messages) {
569 sendit(sock, _(" --> "));
570 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
574 sendit(sock, _("Console: name=%s SSL=%d\n"),
575 res->res_con.hdr.name, res->res_con.tls_enable);
578 if (res->res_counter.WrapCounter) {
579 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
580 res->res_counter.hdr.name, res->res_counter.MinValue,
581 res->res_counter.MaxValue, res->res_counter.CurrentValue,
582 res->res_counter.WrapCounter->hdr.name);
584 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
585 res->res_counter.hdr.name, res->res_counter.MinValue,
586 res->res_counter.MaxValue);
588 if (res->res_counter.Catalog) {
589 sendit(sock, _(" --> "));
590 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
595 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
596 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
597 res->res_client.MaxConcurrentJobs);
598 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
599 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
600 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
601 res->res_client.AutoPrune);
602 if (res->res_client.catalog) {
603 sendit(sock, _(" --> "));
604 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
611 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
612 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
613 " poolid=%s volname=%s MediaType=%s\n"),
614 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
615 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
616 dev->offline, dev->autochanger,
617 edit_uint64(dev->PoolId, ed1),
618 dev->VolumeName, dev->MediaType);
622 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
623 " DeviceName=%s MediaType=%s StorageId=%s\n"),
624 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
625 res->res_store.MaxConcurrentJobs,
626 res->res_store.dev_name(),
627 res->res_store.media_type,
628 edit_int64(res->res_store.StorageId, ed1));
632 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
633 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
634 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
635 res->res_cat.db_port, res->res_cat.db_name,
636 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
637 res->res_cat.mult_db_connections);
642 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
643 type == R_JOB ? _("Job") : _("JobDefs"),
644 res->res_job.hdr.name, res->res_job.JobType,
645 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
646 res->res_job.enabled);
647 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
648 res->res_job.MaxConcurrentJobs,
649 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
650 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
651 res->res_job.spool_data, res->res_job.write_part_after_job);
652 if (res->res_job.spool_size) {
653 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
655 if (res->res_job.JobType == JT_BACKUP) {
656 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
658 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
659 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
661 if (res->res_job.client) {
662 sendit(sock, _(" --> "));
663 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
665 if (res->res_job.fileset) {
666 sendit(sock, _(" --> "));
667 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
669 if (res->res_job.schedule) {
670 sendit(sock, _(" --> "));
671 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
673 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
674 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
676 if (res->res_job.RegexWhere) {
677 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
679 if (res->res_job.RestoreBootstrap) {
680 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
682 if (res->res_job.WriteBootstrap) {
683 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
685 if (res->res_job.PluginOptions) {
686 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
688 if (res->res_job.MaxRunTime) {
689 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
691 if (res->res_job.MaxWaitTime) {
692 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
694 if (res->res_job.MaxStartDelay) {
695 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
697 if (res->res_job.storage) {
699 foreach_alist(store, res->res_job.storage) {
700 sendit(sock, _(" --> "));
701 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
704 if (res->res_job.base) {
706 foreach_alist(job, res->res_job.base) {
707 sendit(sock, _(" --> Base %s\n"), job->name());
710 if (res->res_job.RunScripts) {
712 foreach_alist(script, res->res_job.RunScripts) {
713 sendit(sock, _(" --> RunScript\n"));
714 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
715 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
716 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
717 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
718 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
719 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
722 if (res->res_job.pool) {
723 sendit(sock, _(" --> "));
724 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
726 if (res->res_job.full_pool) {
727 sendit(sock, _(" --> "));
728 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
730 if (res->res_job.inc_pool) {
731 sendit(sock, _(" --> "));
732 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
734 if (res->res_job.diff_pool) {
735 sendit(sock, _(" --> "));
736 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
738 if (res->res_job.verify_job) {
739 sendit(sock, _(" --> "));
740 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
742 if (res->res_job.run_cmds) {
744 foreach_alist(runcmd, res->res_job.run_cmds) {
745 sendit(sock, _(" --> Run=%s\n"), runcmd);
748 if (res->res_job.selection_pattern) {
749 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
751 if (res->res_job.messages) {
752 sendit(sock, _(" --> "));
753 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
760 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
761 for (i=0; i<res->res_fs.num_includes; i++) {
762 INCEXE *incexe = res->res_fs.include_items[i];
763 for (j=0; j<incexe->num_opts; j++) {
764 FOPTS *fo = incexe->opts_list[j];
765 sendit(sock, " O %s\n", fo->opts);
767 bool enhanced_wild = false;
768 for (k=0; fo->opts[k]!='\0'; k++) {
769 if (fo->opts[k]=='W') {
770 enhanced_wild = true;
775 for (k=0; k<fo->regex.size(); k++) {
776 sendit(sock, " R %s\n", fo->regex.get(k));
778 for (k=0; k<fo->regexdir.size(); k++) {
779 sendit(sock, " RD %s\n", fo->regexdir.get(k));
781 for (k=0; k<fo->regexfile.size(); k++) {
782 sendit(sock, " RF %s\n", fo->regexfile.get(k));
784 for (k=0; k<fo->wild.size(); k++) {
785 sendit(sock, " W %s\n", fo->wild.get(k));
787 for (k=0; k<fo->wilddir.size(); k++) {
788 sendit(sock, " WD %s\n", fo->wilddir.get(k));
790 for (k=0; k<fo->wildfile.size(); k++) {
791 sendit(sock, " WF %s\n", fo->wildfile.get(k));
793 for (k=0; k<fo->wildbase.size(); k++) {
794 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
796 for (k=0; k<fo->base.size(); k++) {
797 sendit(sock, " B %s\n", fo->base.get(k));
799 for (k=0; k<fo->fstype.size(); k++) {
800 sendit(sock, " X %s\n", fo->fstype.get(k));
802 for (k=0; k<fo->drivetype.size(); k++) {
803 sendit(sock, " XD %s\n", fo->drivetype.get(k));
806 sendit(sock, " G %s\n", fo->plugin);
809 sendit(sock, " D %s\n", fo->reader);
812 sendit(sock, " T %s\n", fo->writer);
814 sendit(sock, " N\n");
816 for (j=0; j<incexe->name_list.size(); j++) {
817 sendit(sock, " I %s\n", incexe->name_list.get(j));
819 if (incexe->name_list.size()) {
820 sendit(sock, " N\n");
822 for (j=0; j<incexe->plugin_list.size(); j++) {
823 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
825 if (incexe->plugin_list.size()) {
826 sendit(sock, " N\n");
831 for (i=0; i<res->res_fs.num_excludes; i++) {
832 INCEXE *incexe = res->res_fs.exclude_items[i];
833 for (j=0; j<incexe->name_list.size(); j++) {
834 sendit(sock, " E %s\n", incexe->name_list.get(j));
836 if (incexe->name_list.size()) {
837 sendit(sock, " N\n");
844 if (res->res_sch.run) {
846 RUN *run = res->res_sch.run;
847 char buf[1000], num[30];
848 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
853 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
854 bstrncpy(buf, _(" hour="), sizeof(buf));
855 for (i=0; i<24; i++) {
856 if (bit_is_set(i, run->hour)) {
857 bsnprintf(num, sizeof(num), "%d ", i);
858 bstrncat(buf, num, sizeof(buf));
861 bstrncat(buf, "\n", sizeof(buf));
863 bstrncpy(buf, _(" mday="), sizeof(buf));
864 for (i=0; i<31; i++) {
865 if (bit_is_set(i, run->mday)) {
866 bsnprintf(num, sizeof(num), "%d ", i);
867 bstrncat(buf, num, sizeof(buf));
870 bstrncat(buf, "\n", sizeof(buf));
872 bstrncpy(buf, _(" month="), sizeof(buf));
873 for (i=0; i<12; i++) {
874 if (bit_is_set(i, run->month)) {
875 bsnprintf(num, sizeof(num), "%d ", i);
876 bstrncat(buf, num, sizeof(buf));
879 bstrncat(buf, "\n", sizeof(buf));
881 bstrncpy(buf, _(" wday="), sizeof(buf));
882 for (i=0; i<7; i++) {
883 if (bit_is_set(i, run->wday)) {
884 bsnprintf(num, sizeof(num), "%d ", i);
885 bstrncat(buf, num, sizeof(buf));
888 bstrncat(buf, "\n", sizeof(buf));
890 bstrncpy(buf, _(" wom="), sizeof(buf));
891 for (i=0; i<5; i++) {
892 if (bit_is_set(i, run->wom)) {
893 bsnprintf(num, sizeof(num), "%d ", i);
894 bstrncat(buf, num, sizeof(buf));
897 bstrncat(buf, "\n", sizeof(buf));
899 bstrncpy(buf, _(" woy="), sizeof(buf));
900 for (i=0; i<54; i++) {
901 if (bit_is_set(i, run->woy)) {
902 bsnprintf(num, sizeof(num), "%d ", i);
903 bstrncat(buf, num, sizeof(buf));
906 bstrncat(buf, "\n", sizeof(buf));
908 sendit(sock, _(" mins=%d\n"), run->minute);
910 sendit(sock, _(" --> "));
911 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
914 sendit(sock, _(" --> "));
915 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
918 sendit(sock, _(" --> "));
919 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
921 /* If another Run record is chained in, go print it */
927 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
932 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
933 res->res_pool.pool_type);
934 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
935 res->res_pool.use_catalog, res->res_pool.use_volume_once,
936 res->res_pool.catalog_files);
937 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
938 res->res_pool.max_volumes, res->res_pool.AutoPrune,
939 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
940 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
941 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
942 res->res_pool.Recycle,
943 NPRT(res->res_pool.label_format));
944 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
945 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
946 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
947 res->res_pool.recycle_oldest_volume,
948 res->res_pool.purge_oldest_volume);
949 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
950 res->res_pool.MaxVolJobs,
951 res->res_pool.MaxVolFiles,
952 edit_uint64(res->res_pool.MaxVolBytes, ed1));
953 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
954 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
955 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
956 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
957 if (res->res_pool.NextPool) {
958 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
960 if (res->res_pool.RecyclePool) {
961 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
963 if (res->res_pool.ScratchPool) {
964 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
966 if (res->res_pool.catalog) {
967 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
969 if (res->res_pool.storage) {
971 foreach_alist(store, res->res_pool.storage) {
972 sendit(sock, _(" --> "));
973 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
976 if (res->res_pool.CopyPool) {
978 foreach_alist(copy, res->res_pool.CopyPool) {
979 sendit(sock, _(" --> "));
980 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
987 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
988 if (res->res_msgs.mail_cmd)
989 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
990 if (res->res_msgs.operator_cmd)
991 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
995 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
998 if (recurse && res->res_dir.hdr.next) {
999 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1004 * Free all the members of an INCEXE structure
1006 static void free_incexe(INCEXE *incexe)
1008 incexe->name_list.destroy();
1009 incexe->plugin_list.destroy();
1010 for (int i=0; i<incexe->num_opts; i++) {
1011 FOPTS *fopt = incexe->opts_list[i];
1012 fopt->regex.destroy();
1013 fopt->regexdir.destroy();
1014 fopt->regexfile.destroy();
1015 fopt->wild.destroy();
1016 fopt->wilddir.destroy();
1017 fopt->wildfile.destroy();
1018 fopt->wildbase.destroy();
1019 fopt->base.destroy();
1020 fopt->fstype.destroy();
1021 fopt->drivetype.destroy();
1033 if (incexe->opts_list) {
1034 free(incexe->opts_list);
1040 * Free memory of resource -- called when daemon terminates.
1041 * NB, we don't need to worry about freeing any references
1042 * to other resources as they will be freed when that
1043 * resource chain is traversed. Mainly we worry about freeing
1044 * allocated strings (names).
1046 void free_resource(RES *sres, int type)
1049 RES *nres; /* next resource if linked */
1050 URES *res = (URES *)sres;
1055 /* common stuff -- free the resource name and description */
1056 nres = (RES *)res->res_dir.hdr.next;
1057 if (res->res_dir.hdr.name) {
1058 free(res->res_dir.hdr.name);
1060 if (res->res_dir.hdr.desc) {
1061 free(res->res_dir.hdr.desc);
1066 if (res->res_dir.working_directory) {
1067 free(res->res_dir.working_directory);
1069 if (res->res_dir.scripts_directory) {
1070 free((char *)res->res_dir.scripts_directory);
1072 if (res->res_dir.plugin_directory) {
1073 free((char *)res->res_dir.plugin_directory);
1075 if (res->res_dir.pid_directory) {
1076 free(res->res_dir.pid_directory);
1078 if (res->res_dir.subsys_directory) {
1079 free(res->res_dir.subsys_directory);
1081 if (res->res_dir.password) {
1082 free(res->res_dir.password);
1084 if (res->res_dir.query_file) {
1085 free(res->res_dir.query_file);
1087 if (res->res_dir.DIRaddrs) {
1088 free_addresses(res->res_dir.DIRaddrs);
1090 if (res->res_dir.DIRsrc_addr) {
1091 free_addresses(res->res_dir.DIRsrc_addr);
1093 if (res->res_dir.tls_ctx) {
1094 free_tls_context(res->res_dir.tls_ctx);
1096 if (res->res_dir.tls_ca_certfile) {
1097 free(res->res_dir.tls_ca_certfile);
1099 if (res->res_dir.tls_ca_certdir) {
1100 free(res->res_dir.tls_ca_certdir);
1102 if (res->res_dir.tls_certfile) {
1103 free(res->res_dir.tls_certfile);
1105 if (res->res_dir.tls_keyfile) {
1106 free(res->res_dir.tls_keyfile);
1108 if (res->res_dir.tls_dhfile) {
1109 free(res->res_dir.tls_dhfile);
1111 if (res->res_dir.tls_allowed_cns) {
1112 delete res->res_dir.tls_allowed_cns;
1114 if (res->res_dir.verid) {
1115 free(res->res_dir.verid);
1122 if (res->res_con.password) {
1123 free(res->res_con.password);
1125 if (res->res_con.tls_ctx) {
1126 free_tls_context(res->res_con.tls_ctx);
1128 if (res->res_con.tls_ca_certfile) {
1129 free(res->res_con.tls_ca_certfile);
1131 if (res->res_con.tls_ca_certdir) {
1132 free(res->res_con.tls_ca_certdir);
1134 if (res->res_con.tls_certfile) {
1135 free(res->res_con.tls_certfile);
1137 if (res->res_con.tls_keyfile) {
1138 free(res->res_con.tls_keyfile);
1140 if (res->res_con.tls_dhfile) {
1141 free(res->res_con.tls_dhfile);
1143 if (res->res_con.tls_allowed_cns) {
1144 delete res->res_con.tls_allowed_cns;
1146 for (int i=0; i<Num_ACL; i++) {
1147 if (res->res_con.ACL_lists[i]) {
1148 delete res->res_con.ACL_lists[i];
1149 res->res_con.ACL_lists[i] = NULL;
1154 if (res->res_client.address) {
1155 free(res->res_client.address);
1157 if (res->res_client.password) {
1158 free(res->res_client.password);
1160 if (res->res_client.tls_ctx) {
1161 free_tls_context(res->res_client.tls_ctx);
1163 if (res->res_client.tls_ca_certfile) {
1164 free(res->res_client.tls_ca_certfile);
1166 if (res->res_client.tls_ca_certdir) {
1167 free(res->res_client.tls_ca_certdir);
1169 if (res->res_client.tls_certfile) {
1170 free(res->res_client.tls_certfile);
1172 if (res->res_client.tls_keyfile) {
1173 free(res->res_client.tls_keyfile);
1175 if (res->res_client.tls_allowed_cns) {
1176 delete res->res_client.tls_allowed_cns;
1180 if (res->res_store.address) {
1181 free(res->res_store.address);
1183 if (res->res_store.password) {
1184 free(res->res_store.password);
1186 if (res->res_store.media_type) {
1187 free(res->res_store.media_type);
1189 if (res->res_store.device) {
1190 delete res->res_store.device;
1192 if (res->res_store.tls_ctx) {
1193 free_tls_context(res->res_store.tls_ctx);
1195 if (res->res_store.tls_ca_certfile) {
1196 free(res->res_store.tls_ca_certfile);
1198 if (res->res_store.tls_ca_certdir) {
1199 free(res->res_store.tls_ca_certdir);
1201 if (res->res_store.tls_certfile) {
1202 free(res->res_store.tls_certfile);
1204 if (res->res_store.tls_keyfile) {
1205 free(res->res_store.tls_keyfile);
1209 if (res->res_cat.db_address) {
1210 free(res->res_cat.db_address);
1212 if (res->res_cat.db_socket) {
1213 free(res->res_cat.db_socket);
1215 if (res->res_cat.db_user) {
1216 free(res->res_cat.db_user);
1218 if (res->res_cat.db_name) {
1219 free(res->res_cat.db_name);
1221 if (res->res_cat.db_driver) {
1222 free(res->res_cat.db_driver);
1224 if (res->res_cat.db_password) {
1225 free(res->res_cat.db_password);
1229 if ((num=res->res_fs.num_includes)) {
1230 while (--num >= 0) {
1231 free_incexe(res->res_fs.include_items[num]);
1233 free(res->res_fs.include_items);
1235 res->res_fs.num_includes = 0;
1236 if ((num=res->res_fs.num_excludes)) {
1237 while (--num >= 0) {
1238 free_incexe(res->res_fs.exclude_items[num]);
1240 free(res->res_fs.exclude_items);
1242 res->res_fs.num_excludes = 0;
1245 if (res->res_pool.pool_type) {
1246 free(res->res_pool.pool_type);
1248 if (res->res_pool.label_format) {
1249 free(res->res_pool.label_format);
1251 if (res->res_pool.cleaning_prefix) {
1252 free(res->res_pool.cleaning_prefix);
1254 if (res->res_pool.storage) {
1255 delete res->res_pool.storage;
1259 if (res->res_sch.run) {
1261 nrun = res->res_sch.run;
1271 if (res->res_job.RestoreWhere) {
1272 free(res->res_job.RestoreWhere);
1274 if (res->res_job.RegexWhere) {
1275 free(res->res_job.RegexWhere);
1277 if (res->res_job.strip_prefix) {
1278 free(res->res_job.strip_prefix);
1280 if (res->res_job.add_prefix) {
1281 free(res->res_job.add_prefix);
1283 if (res->res_job.add_suffix) {
1284 free(res->res_job.add_suffix);
1286 if (res->res_job.RestoreBootstrap) {
1287 free(res->res_job.RestoreBootstrap);
1289 if (res->res_job.WriteBootstrap) {
1290 free(res->res_job.WriteBootstrap);
1292 if (res->res_job.PluginOptions) {
1293 free(res->res_job.PluginOptions);
1295 if (res->res_job.selection_pattern) {
1296 free(res->res_job.selection_pattern);
1298 if (res->res_job.run_cmds) {
1299 delete res->res_job.run_cmds;
1301 if (res->res_job.storage) {
1302 delete res->res_job.storage;
1304 if (res->res_job.base) {
1305 delete res->res_job.base;
1307 if (res->res_job.RunScripts) {
1308 free_runscripts(res->res_job.RunScripts);
1309 delete res->res_job.RunScripts;
1313 if (res->res_msgs.mail_cmd) {
1314 free(res->res_msgs.mail_cmd);
1316 if (res->res_msgs.operator_cmd) {
1317 free(res->res_msgs.operator_cmd);
1319 free_msgs_res((MSGS *)res); /* free message resource */
1323 printf(_("Unknown resource type %d in free_resource.\n"), type);
1325 /* Common stuff again -- free the resource, recurse to next one */
1330 free_resource(nres, type);
1335 * Save the new resource by chaining it into the head list for
1336 * the resource. If this is pass 2, we update any resource
1337 * pointers because they may not have been defined until
1340 void save_resource(int type, RES_ITEM *items, int pass)
1343 int rindex = type - r_first;
1347 /* Check Job requirements after applying JobDefs */
1348 if (type != R_JOB && type != R_JOBDEFS) {
1350 * Ensure that all required items are present
1352 for (i=0; items[i].name; i++) {
1353 if (items[i].flags & ITEM_REQUIRED) {
1354 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1355 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1356 items[i].name, resources[rindex]);
1359 /* If this triggers, take a look at lib/parse_conf.h */
1360 if (i >= MAX_RES_ITEMS) {
1361 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1364 } else if (type == R_JOB) {
1366 * Ensure that the name item is present
1368 if (items[0].flags & ITEM_REQUIRED) {
1369 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1370 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1371 items[0].name, resources[rindex]);
1377 * During pass 2 in each "store" routine, we looked up pointers
1378 * to all the resources referrenced in the current resource, now we
1379 * must copy their addresses from the static record to the allocated
1384 /* Resources not containing a resource */
1392 * Resources containing another resource or alist. First
1393 * look up the resource which contains another resource. It
1394 * was written during pass 1. Then stuff in the pointers to
1395 * the resources it contains, which were inserted this pass.
1396 * Finally, it will all be stored back.
1399 /* Find resource saved in pass 1 */
1400 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1401 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1403 /* Explicitly copy resource pointers from this pass (res_all) */
1404 res->res_pool.NextPool = res_all.res_pool.NextPool;
1405 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1406 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1407 res->res_pool.storage = res_all.res_pool.storage;
1408 res->res_pool.catalog = res_all.res_pool.catalog;
1411 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1412 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1414 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1417 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1418 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1420 res->res_dir.messages = res_all.res_dir.messages;
1421 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1424 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1425 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1426 res_all.res_dir.hdr.name);
1428 /* we must explicitly copy the device alist pointer */
1429 res->res_store.device = res_all.res_store.device;
1433 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1434 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1435 res_all.res_dir.hdr.name);
1437 res->res_job.messages = res_all.res_job.messages;
1438 res->res_job.schedule = res_all.res_job.schedule;
1439 res->res_job.client = res_all.res_job.client;
1440 res->res_job.fileset = res_all.res_job.fileset;
1441 res->res_job.storage = res_all.res_job.storage;
1442 res->res_job.base = res_all.res_job.base;
1443 res->res_job.pool = res_all.res_job.pool;
1444 res->res_job.full_pool = res_all.res_job.full_pool;
1445 res->res_job.inc_pool = res_all.res_job.inc_pool;
1446 res->res_job.diff_pool = res_all.res_job.diff_pool;
1447 res->res_job.verify_job = res_all.res_job.verify_job;
1448 res->res_job.jobdefs = res_all.res_job.jobdefs;
1449 res->res_job.run_cmds = res_all.res_job.run_cmds;
1450 res->res_job.RunScripts = res_all.res_job.RunScripts;
1452 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1453 * is not very useful)
1454 * We have to set_bit(index, res_all.hdr.item_present);
1455 * or something like that
1458 /* we take RegexWhere before all other options */
1459 if (!res->res_job.RegexWhere
1461 (res->res_job.strip_prefix ||
1462 res->res_job.add_suffix ||
1463 res->res_job.add_prefix))
1465 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1466 res->res_job.add_prefix,
1467 res->res_job.add_suffix);
1468 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1469 bregexp_build_where(res->res_job.RegexWhere, len,
1470 res->res_job.strip_prefix,
1471 res->res_job.add_prefix,
1472 res->res_job.add_suffix);
1473 /* TODO: test bregexp */
1476 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1477 free(res->res_job.RestoreWhere);
1478 res->res_job.RestoreWhere = NULL;
1483 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1484 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1486 res->res_counter.Catalog = res_all.res_counter.Catalog;
1487 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1491 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1492 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1494 res->res_client.catalog = res_all.res_client.catalog;
1495 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1499 * Schedule is a bit different in that it contains a RUN record
1500 * chain which isn't a "named" resource. This chain was linked
1501 * in by run_conf.c during pass 2, so here we jam the pointer
1502 * into the Schedule resource.
1504 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1505 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1507 res->res_sch.run = res_all.res_sch.run;
1510 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1514 /* Note, the resource name was already saved during pass 1,
1515 * so here, we can just release it.
1517 if (res_all.res_dir.hdr.name) {
1518 free(res_all.res_dir.hdr.name);
1519 res_all.res_dir.hdr.name = NULL;
1521 if (res_all.res_dir.hdr.desc) {
1522 free(res_all.res_dir.hdr.desc);
1523 res_all.res_dir.hdr.desc = NULL;
1529 * The following code is only executed during pass 1
1533 size = sizeof(DIRRES);
1536 size = sizeof(CONRES);
1539 size =sizeof(CLIENT);
1542 size = sizeof(STORE);
1552 size = sizeof(FILESET);
1555 size = sizeof(SCHED);
1558 size = sizeof(POOL);
1561 size = sizeof(MSGS);
1564 size = sizeof(COUNTER);
1570 printf(_("Unknown resource type %d in save_resource.\n"), type);
1576 res = (URES *)malloc(size);
1577 memcpy(res, &res_all, size);
1578 if (!res_head[rindex]) {
1579 res_head[rindex] = (RES *)res; /* store first entry */
1580 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1581 res->res_dir.hdr.name, rindex);
1584 if (res->res_dir.hdr.name == NULL) {
1585 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1588 /* Add new res to end of chain */
1589 for (last=next=res_head[rindex]; next; next=next->next) {
1591 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1592 Emsg2(M_ERROR_TERM, 0,
1593 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1594 resources[rindex].name, res->res_dir.hdr.name);
1597 last->next = (RES *)res;
1598 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1599 res->res_dir.hdr.name, rindex, pass);
1605 * Store Device. Note, the resource is created upon the
1606 * first reference. The details of the resource are obtained
1607 * later from the SD.
1609 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1613 int rindex = R_DEVICE - r_first;
1614 int size = sizeof(DEVICE);
1618 token = lex_get_token(lc, T_NAME);
1619 if (!res_head[rindex]) {
1620 res = (URES *)malloc(size);
1621 memset(res, 0, size);
1622 res->res_dev.hdr.name = bstrdup(lc->str);
1623 res_head[rindex] = (RES *)res; /* store first entry */
1624 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1625 res->res_dir.hdr.name, rindex);
1628 /* See if it is already defined */
1629 for (next=res_head[rindex]; next->next; next=next->next) {
1630 if (strcmp(next->name, lc->str) == 0) {
1636 res = (URES *)malloc(size);
1637 memset(res, 0, size);
1638 res->res_dev.hdr.name = bstrdup(lc->str);
1639 next->next = (RES *)res;
1640 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1641 res->res_dir.hdr.name, rindex, pass);
1646 set_bit(index, res_all.hdr.item_present);
1648 store_alist_res(lc, item, index, pass);
1653 * Store Migration/Copy type
1656 void store_migtype(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; migtypes[i].type_name; i++) {
1663 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1664 *(uint32_t *)(item->value) = migtypes[i].job_type;
1670 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1673 set_bit(index, res_all.hdr.item_present);
1679 * Store JobType (backup, verify, restore)
1682 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1686 token = lex_get_token(lc, T_NAME);
1687 /* Store the type both pass 1 and pass 2 */
1688 for (i=0; jobtypes[i].type_name; i++) {
1689 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1690 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1696 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1699 set_bit(index, res_all.hdr.item_present);
1703 * Store Job Level (Full, Incremental, ...)
1706 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1710 token = lex_get_token(lc, T_NAME);
1711 /* Store the level pass 2 so that type is defined */
1712 for (i=0; joblevels[i].level_name; i++) {
1713 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1714 *(uint32_t *)(item->value) = joblevels[i].level;
1720 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1723 set_bit(index, res_all.hdr.item_present);
1727 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1730 token = lex_get_token(lc, T_NAME);
1731 /* Scan Replacement options */
1732 for (i=0; ReplaceOptions[i].name; i++) {
1733 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1734 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1740 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1743 set_bit(index, res_all.hdr.item_present);
1747 * Store ACL (access control list)
1750 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1755 token = lex_get_token(lc, T_STRING);
1757 if (((alist **)item->value)[item->code] == NULL) {
1758 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1759 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1761 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1762 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1764 token = lex_get_token(lc, T_ALL);
1765 if (token == T_COMMA) {
1766 continue; /* get another ACL */
1770 set_bit(index, res_all.hdr.item_present);
1773 /* We build RunScripts items here */
1774 static RUNSCRIPT res_runscript;
1776 /* Store a runscript->when in a bit field */
1777 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1779 lex_get_token(lc, T_NAME);
1781 if (strcasecmp(lc->str, "before") == 0) {
1782 *(uint32_t *)(item->value) = SCRIPT_Before ;
1783 } else if (strcasecmp(lc->str, "after") == 0) {
1784 *(uint32_t *)(item->value) = SCRIPT_After;
1785 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1786 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1787 } else if (strcasecmp(lc->str, "always") == 0) {
1788 *(uint32_t *)(item->value) = SCRIPT_Any;
1790 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1795 /* Store a runscript->target
1798 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1800 lex_get_token(lc, T_STRING);
1803 if (strcmp(lc->str, "%c") == 0) {
1804 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1805 } else if (strcasecmp(lc->str, "yes") == 0) {
1806 ((RUNSCRIPT*) item->value)->set_target("%c");
1807 } else if (strcasecmp(lc->str, "no") == 0) {
1808 ((RUNSCRIPT*) item->value)->set_target("");
1810 RES *res = GetResWithName(R_CLIENT, lc->str);
1812 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1813 lc->str, lc->line_no, lc->line);
1816 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1823 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1825 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1827 lex_get_token(lc, T_STRING);
1830 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1831 POOLMEM *c = get_pool_memory(PM_FNAME);
1832 /* Each runscript command takes 2 entries in commands list */
1833 pm_strcpy(c, lc->str);
1834 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1835 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1840 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1842 lex_get_token(lc, T_STRING);
1843 alist **runscripts = (alist **)(item->value) ;
1846 RUNSCRIPT *script = new_runscript();
1847 script->set_job_code_callback(job_code_callback_filesetname);
1849 script->set_command(lc->str);
1851 /* TODO: remove all script->old_proto with bacula 1.42 */
1853 if (strcmp(item->name, "runbeforejob") == 0) {
1854 script->when = SCRIPT_Before;
1855 script->fail_on_error = true;
1856 script->set_target("");
1858 } else if (strcmp(item->name, "runafterjob") == 0) {
1859 script->when = SCRIPT_After;
1860 script->on_success = true;
1861 script->on_failure = false;
1862 script->set_target("");
1864 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1865 script->old_proto = true;
1866 script->when = SCRIPT_After;
1867 script->set_target("%c");
1868 script->on_success = true;
1869 script->on_failure = false;
1871 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1872 script->old_proto = true;
1873 script->when = SCRIPT_Before;
1874 script->set_target("%c");
1875 script->fail_on_error = true;
1877 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1878 script->when = SCRIPT_After;
1879 script->on_failure = true;
1880 script->on_success = false;
1881 script->set_target("");
1884 if (*runscripts == NULL) {
1885 *runscripts = New(alist(10, not_owned_by_alist));
1888 (*runscripts)->append(script);
1895 /* Store a bool in a bit field without modifing res_all.hdr
1896 * We can also add an option to store_bool to skip res_all.hdr
1898 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1900 lex_get_token(lc, T_NAME);
1901 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1902 *(bool *)(item->value) = true;
1903 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1904 *(bool *)(item->value) = false;
1906 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1912 * new RunScript items
1913 * name handler value code flags default_value
1915 static RES_ITEM runscript_items[] = {
1916 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1917 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1918 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1919 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1920 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1921 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1922 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1923 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1924 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1925 {NULL, NULL, {0}, 0, 0, 0}
1929 * Store RunScript info
1931 * Note, when this routine is called, we are inside a Job
1932 * resource. We treat the RunScript like a sort of
1933 * mini-resource within the Job resource.
1935 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1939 alist **runscripts = (alist **)(item->value) ;
1941 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1943 token = lex_get_token(lc, T_SKIP_EOL);
1945 if (token != T_BOB) {
1946 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1948 /* setting on_success, on_failure, fail_on_error */
1949 res_runscript.reset_default();
1952 res_runscript.commands = New(alist(10, not_owned_by_alist));
1955 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1956 if (token == T_EOB) {
1959 if (token != T_IDENTIFIER) {
1960 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1962 for (i=0; runscript_items[i].name; i++) {
1963 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1964 token = lex_get_token(lc, T_SKIP_EOL);
1965 if (token != T_EQUALS) {
1966 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1969 /* Call item handler */
1970 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1977 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1982 /* run on client by default */
1983 if (res_runscript.target == NULL) {
1984 res_runscript.set_target("%c");
1986 if (*runscripts == NULL) {
1987 *runscripts = New(alist(10, not_owned_by_alist));
1990 * commands list contains 2 values per command
1991 * - POOLMEM command string (ex: /bin/true)
1992 * - int command type (ex: SHELL_CMD)
1994 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1995 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1996 t = (intptr_t)res_runscript.commands->pop();
1997 RUNSCRIPT *script = new_runscript();
1998 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1999 script->command = c;
2000 script->cmd_type = t;
2001 /* target is taken from res_runscript, each runscript object have
2004 script->target = NULL;
2005 script->set_target(res_runscript.target);
2007 (*runscripts)->append(script);
2010 delete res_runscript.commands;
2011 /* setting on_success, on_failure... cleanup target field */
2012 res_runscript.reset_default(true);
2016 set_bit(index, res_all.hdr.item_present);
2019 /* callback function for edit_job_codes */
2020 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2022 if (param[0] == 'f') {
2023 return jcr->fileset->name();
2029 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2031 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2032 r_first, r_last, resources, res_head);
2033 return config->parse_config();