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_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
83 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
85 /* We build the current resource here as we are
86 * scanning the resource configuration definition,
87 * then move it to allocated memory when the resource
91 extern "C" { // work around visual compiler mangling variables
97 int32_t res_all_size = sizeof(res_all);
100 /* Definition of records permitted within each
101 * resource with the routine to process the record
102 * information. NOTE! quoted names must be in lower case.
107 * name handler value code flags default_value
109 static RES_ITEM dir_items[] = {
110 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
111 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
112 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
113 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
116 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
117 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
118 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
119 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
120 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
121 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
122 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
123 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
124 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
125 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
126 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
127 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
128 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
129 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
130 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
131 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
132 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
133 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
134 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
135 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
136 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
137 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
138 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
139 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
140 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
141 {NULL, NULL, {0}, 0, 0, 0}
147 * name handler value code flags default_value
149 static RES_ITEM con_items[] = {
150 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
151 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
152 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
153 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
154 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
155 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
156 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
157 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
158 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
159 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
160 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
161 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
162 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
163 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
164 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
165 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
166 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
167 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
168 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
169 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
170 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
171 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
172 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
173 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
174 {NULL, NULL, {0}, 0, 0, 0}
179 * Client or File daemon resource
181 * name handler value code flags default_value
184 static RES_ITEM cli_items[] = {
185 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
186 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
187 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
188 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
189 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
190 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
191 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
192 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
193 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
194 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
195 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
196 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
197 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
198 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
199 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
200 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
201 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
202 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
203 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
204 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
205 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
206 {NULL, NULL, {0}, 0, 0, 0}
209 /* Storage daemon resource
211 * name handler value code flags default_value
213 static RES_ITEM store_items[] = {
214 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
215 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
216 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
217 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
218 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
219 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
220 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
221 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
222 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
223 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
224 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
225 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
226 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
227 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
228 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
229 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
230 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
231 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
232 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
233 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
234 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
235 {NULL, NULL, {0}, 0, 0, 0}
239 * Catalog Resource Directives
241 * name handler value code flags default_value
243 static RES_ITEM cat_items[] = {
244 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
245 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
246 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
247 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
248 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
249 /* keep this password as store_str for the moment */
250 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
251 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
252 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
253 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
254 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
255 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
256 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
257 /* Turned off for the moment */
258 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
259 {NULL, NULL, {0}, 0, 0, 0}
263 * Job Resource Directives
265 * name handler value code flags default_value
267 RES_ITEM job_items[] = {
268 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
269 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
270 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
271 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
272 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
273 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
274 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
275 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
276 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
277 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
278 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
279 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
280 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
281 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
282 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
283 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
284 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
285 /* Root of where to restore files */
286 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
287 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
288 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
289 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
290 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
291 /* Where to find bootstrap during restore */
292 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
293 /* Where to write bootstrap file during backup */
294 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
295 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
296 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
297 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
298 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
299 /* xxxMaxWaitTime are deprecated */
300 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
301 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
302 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
303 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
304 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
305 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
306 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
307 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
308 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
309 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
310 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
311 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
312 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
313 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
314 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
315 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
316 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
317 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
318 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
319 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
320 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
321 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
327 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
328 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
329 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
330 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
331 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
332 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
333 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
334 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
335 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
336 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
337 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
338 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
339 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
340 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
341 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 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 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
386 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
387 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
388 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
389 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
390 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
391 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
392 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
393 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
394 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
395 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
396 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
397 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
398 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
399 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
400 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
401 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
402 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
403 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
404 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
405 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
406 {NULL, NULL, {0}, 0, 0, 0}
411 * name handler value code flags default_value
413 static RES_ITEM counter_items[] = {
414 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
415 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
416 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
417 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
418 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
419 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
420 {NULL, NULL, {0}, 0, 0, 0}
424 /* Message resource */
425 extern RES_ITEM msgs_items[];
428 * This is the master resource definition.
429 * It must have one item for each of the resources.
431 * NOTE!!! keep it in the same order as the R_codes
432 * or eliminate all resources[rindex].name
434 * name items rcode res_head
436 RES_TABLE resources[] = {
437 {"director", dir_items, R_DIRECTOR},
438 {"client", cli_items, R_CLIENT},
439 {"job", job_items, R_JOB},
440 {"storage", store_items, R_STORAGE},
441 {"catalog", cat_items, R_CATALOG},
442 {"schedule", sch_items, R_SCHEDULE},
443 {"fileset", fs_items, R_FILESET},
444 {"pool", pool_items, R_POOL},
445 {"messages", msgs_items, R_MSGS},
446 {"counter", counter_items, R_COUNTER},
447 {"console", con_items, R_CONSOLE},
448 {"jobdefs", job_items, R_JOBDEFS},
449 {"device", NULL, R_DEVICE}, /* info obtained from SD */
454 /* Keywords (RHS) permitted in Job Level records
456 * level_name level job_type
458 struct s_jl joblevels[] = {
459 {"Full", L_FULL, JT_BACKUP},
460 {"Base", L_BASE, JT_BACKUP},
461 {"Incremental", L_INCREMENTAL, JT_BACKUP},
462 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
463 {"Since", L_SINCE, JT_BACKUP},
464 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
465 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
466 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
467 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
468 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
469 {"Data", L_VERIFY_DATA, JT_VERIFY},
470 {" ", L_NONE, JT_ADMIN},
471 {" ", L_NONE, JT_RESTORE},
475 /* Keywords (RHS) permitted in Job type records
479 struct s_jt jobtypes[] = {
480 {"backup", JT_BACKUP},
482 {"verify", JT_VERIFY},
483 {"restore", JT_RESTORE},
484 {"migrate", JT_MIGRATE},
490 /* Keywords (RHS) permitted in Selection type records
494 struct s_jt migtypes[] = {
495 {"smallestvolume", MT_SMALLEST_VOL},
496 {"oldestvolume", MT_OLDEST_VOL},
497 {"pooloccupancy", MT_POOL_OCCUPANCY},
498 {"pooltime", MT_POOL_TIME},
499 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
500 {"client", MT_CLIENT},
501 {"volume", MT_VOLUME},
503 {"sqlquery", MT_SQLQUERY},
509 /* Options permitted in Restore replace= */
510 struct s_kw ReplaceOptions[] = {
511 {"always", REPLACE_ALWAYS},
512 {"ifnewer", REPLACE_IFNEWER},
513 {"ifolder", REPLACE_IFOLDER},
514 {"never", REPLACE_NEVER},
518 char *CAT::display(POOLMEM *dst) {
519 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
520 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
522 name(), NPRTB(db_name),
523 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
524 NPRTB(db_address), db_port, NPRTB(db_socket));
528 const char *level_to_str(int level)
531 static char level_no[30];
532 const char *str = level_no;
534 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
535 for (i=0; joblevels[i].level_name; i++) {
536 if (level == (int)joblevels[i].level) {
537 str = joblevels[i].level_name;
544 /* Dump contents of resource */
545 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
547 URES *res = (URES *)reshdr;
549 char ed1[100], ed2[100], ed3[100];
553 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
556 if (type < 0) { /* no recursion */
562 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
563 reshdr->name, res->res_dir.MaxConcurrentJobs,
564 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
565 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
566 if (res->res_dir.query_file) {
567 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
569 if (res->res_dir.messages) {
570 sendit(sock, _(" --> "));
571 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
575 sendit(sock, _("Console: name=%s SSL=%d\n"),
576 res->res_con.hdr.name, res->res_con.tls_enable);
579 if (res->res_counter.WrapCounter) {
580 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
581 res->res_counter.hdr.name, res->res_counter.MinValue,
582 res->res_counter.MaxValue, res->res_counter.CurrentValue,
583 res->res_counter.WrapCounter->hdr.name);
585 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
586 res->res_counter.hdr.name, res->res_counter.MinValue,
587 res->res_counter.MaxValue);
589 if (res->res_counter.Catalog) {
590 sendit(sock, _(" --> "));
591 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
596 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
597 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
598 res->res_client.MaxConcurrentJobs);
599 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
600 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
601 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
602 res->res_client.AutoPrune);
603 if (res->res_client.catalog) {
604 sendit(sock, _(" --> "));
605 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
612 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
613 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
614 " poolid=%s volname=%s MediaType=%s\n"),
615 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
616 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
617 dev->offline, dev->autochanger,
618 edit_uint64(dev->PoolId, ed1),
619 dev->VolumeName, dev->MediaType);
623 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
624 " DeviceName=%s MediaType=%s StorageId=%s\n"),
625 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
626 res->res_store.MaxConcurrentJobs,
627 res->res_store.dev_name(),
628 res->res_store.media_type,
629 edit_int64(res->res_store.StorageId, ed1));
633 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
634 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
635 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
636 res->res_cat.db_port, res->res_cat.db_name,
637 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
638 res->res_cat.mult_db_connections);
643 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
644 type == R_JOB ? _("Job") : _("JobDefs"),
645 res->res_job.hdr.name, res->res_job.JobType,
646 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
647 res->res_job.enabled);
648 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
649 res->res_job.MaxConcurrentJobs,
650 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
651 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
652 res->res_job.spool_data, res->res_job.write_part_after_job);
653 if (res->res_job.spool_size) {
654 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
656 if (res->res_job.JobType == JT_BACKUP) {
657 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
659 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
660 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
662 if (res->res_job.client) {
663 sendit(sock, _(" --> "));
664 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
666 if (res->res_job.fileset) {
667 sendit(sock, _(" --> "));
668 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
670 if (res->res_job.schedule) {
671 sendit(sock, _(" --> "));
672 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
674 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
675 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
677 if (res->res_job.RegexWhere) {
678 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
680 if (res->res_job.RestoreBootstrap) {
681 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
683 if (res->res_job.WriteBootstrap) {
684 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
686 if (res->res_job.PluginOptions) {
687 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
689 if (res->res_job.MaxRunTime) {
690 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
692 if (res->res_job.MaxWaitTime) {
693 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
695 if (res->res_job.MaxStartDelay) {
696 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
698 if (res->res_job.storage) {
700 foreach_alist(store, res->res_job.storage) {
701 sendit(sock, _(" --> "));
702 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
705 if (res->res_job.RunScripts) {
707 foreach_alist(script, res->res_job.RunScripts) {
708 sendit(sock, _(" --> RunScript\n"));
709 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
710 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
711 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
712 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
713 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
714 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
717 if (res->res_job.pool) {
718 sendit(sock, _(" --> "));
719 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
721 if (res->res_job.full_pool) {
722 sendit(sock, _(" --> "));
723 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
725 if (res->res_job.inc_pool) {
726 sendit(sock, _(" --> "));
727 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
729 if (res->res_job.diff_pool) {
730 sendit(sock, _(" --> "));
731 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
733 if (res->res_job.verify_job) {
734 sendit(sock, _(" --> "));
735 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
737 if (res->res_job.run_cmds) {
739 foreach_alist(runcmd, res->res_job.run_cmds) {
740 sendit(sock, _(" --> Run=%s\n"), runcmd);
743 if (res->res_job.selection_pattern) {
744 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
746 if (res->res_job.messages) {
747 sendit(sock, _(" --> "));
748 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
755 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
756 for (i=0; i<res->res_fs.num_includes; i++) {
757 INCEXE *incexe = res->res_fs.include_items[i];
758 for (j=0; j<incexe->num_opts; j++) {
759 FOPTS *fo = incexe->opts_list[j];
760 sendit(sock, " O %s\n", fo->opts);
762 bool enhanced_wild = false;
763 for (k=0; fo->opts[k]!='\0'; k++) {
764 if (fo->opts[k]=='W') {
765 enhanced_wild = true;
770 for (k=0; k<fo->regex.size(); k++) {
771 sendit(sock, " R %s\n", fo->regex.get(k));
773 for (k=0; k<fo->regexdir.size(); k++) {
774 sendit(sock, " RD %s\n", fo->regexdir.get(k));
776 for (k=0; k<fo->regexfile.size(); k++) {
777 sendit(sock, " RF %s\n", fo->regexfile.get(k));
779 for (k=0; k<fo->wild.size(); k++) {
780 sendit(sock, " W %s\n", fo->wild.get(k));
782 for (k=0; k<fo->wilddir.size(); k++) {
783 sendit(sock, " WD %s\n", fo->wilddir.get(k));
785 for (k=0; k<fo->wildfile.size(); k++) {
786 sendit(sock, " WF %s\n", fo->wildfile.get(k));
788 for (k=0; k<fo->wildbase.size(); k++) {
789 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
791 for (k=0; k<fo->base.size(); k++) {
792 sendit(sock, " B %s\n", fo->base.get(k));
794 for (k=0; k<fo->fstype.size(); k++) {
795 sendit(sock, " X %s\n", fo->fstype.get(k));
797 for (k=0; k<fo->drivetype.size(); k++) {
798 sendit(sock, " XD %s\n", fo->drivetype.get(k));
801 sendit(sock, " G %s\n", fo->plugin);
804 sendit(sock, " D %s\n", fo->reader);
807 sendit(sock, " T %s\n", fo->writer);
809 sendit(sock, " N\n");
811 if (incexe->ignoredir) {
812 sendit(sock, " Z %s\n", incexe->ignoredir);
814 for (j=0; j<incexe->name_list.size(); j++) {
815 sendit(sock, " I %s\n", incexe->name_list.get(j));
817 if (incexe->name_list.size()) {
818 sendit(sock, " N\n");
820 for (j=0; j<incexe->plugin_list.size(); j++) {
821 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
823 if (incexe->plugin_list.size()) {
824 sendit(sock, " N\n");
829 for (i=0; i<res->res_fs.num_excludes; i++) {
830 INCEXE *incexe = res->res_fs.exclude_items[i];
831 for (j=0; j<incexe->name_list.size(); j++) {
832 sendit(sock, " E %s\n", incexe->name_list.get(j));
834 if (incexe->name_list.size()) {
835 sendit(sock, " N\n");
842 if (res->res_sch.run) {
844 RUN *run = res->res_sch.run;
845 char buf[1000], num[30];
846 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
851 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
852 bstrncpy(buf, _(" hour="), sizeof(buf));
853 for (i=0; i<24; i++) {
854 if (bit_is_set(i, run->hour)) {
855 bsnprintf(num, sizeof(num), "%d ", i);
856 bstrncat(buf, num, sizeof(buf));
859 bstrncat(buf, "\n", sizeof(buf));
861 bstrncpy(buf, _(" mday="), sizeof(buf));
862 for (i=0; i<31; i++) {
863 if (bit_is_set(i, run->mday)) {
864 bsnprintf(num, sizeof(num), "%d ", i);
865 bstrncat(buf, num, sizeof(buf));
868 bstrncat(buf, "\n", sizeof(buf));
870 bstrncpy(buf, _(" month="), sizeof(buf));
871 for (i=0; i<12; i++) {
872 if (bit_is_set(i, run->month)) {
873 bsnprintf(num, sizeof(num), "%d ", i);
874 bstrncat(buf, num, sizeof(buf));
877 bstrncat(buf, "\n", sizeof(buf));
879 bstrncpy(buf, _(" wday="), sizeof(buf));
880 for (i=0; i<7; i++) {
881 if (bit_is_set(i, run->wday)) {
882 bsnprintf(num, sizeof(num), "%d ", i);
883 bstrncat(buf, num, sizeof(buf));
886 bstrncat(buf, "\n", sizeof(buf));
888 bstrncpy(buf, _(" wom="), sizeof(buf));
889 for (i=0; i<5; i++) {
890 if (bit_is_set(i, run->wom)) {
891 bsnprintf(num, sizeof(num), "%d ", i);
892 bstrncat(buf, num, sizeof(buf));
895 bstrncat(buf, "\n", sizeof(buf));
897 bstrncpy(buf, _(" woy="), sizeof(buf));
898 for (i=0; i<54; i++) {
899 if (bit_is_set(i, run->woy)) {
900 bsnprintf(num, sizeof(num), "%d ", i);
901 bstrncat(buf, num, sizeof(buf));
904 bstrncat(buf, "\n", sizeof(buf));
906 sendit(sock, _(" mins=%d\n"), run->minute);
908 sendit(sock, _(" --> "));
909 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
912 sendit(sock, _(" --> "));
913 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
916 sendit(sock, _(" --> "));
917 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
919 /* If another Run record is chained in, go print it */
925 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
930 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
931 res->res_pool.pool_type);
932 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
933 res->res_pool.use_catalog, res->res_pool.use_volume_once,
934 res->res_pool.catalog_files);
935 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
936 res->res_pool.max_volumes, res->res_pool.AutoPrune,
937 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
938 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
939 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
940 res->res_pool.Recycle,
941 NPRT(res->res_pool.label_format));
942 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
943 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
944 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
945 res->res_pool.recycle_oldest_volume,
946 res->res_pool.purge_oldest_volume,
947 res->res_pool.action_on_purge);
948 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
949 res->res_pool.MaxVolJobs,
950 res->res_pool.MaxVolFiles,
951 edit_uint64(res->res_pool.MaxVolBytes, ed1));
952 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
953 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
954 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
955 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
956 if (res->res_pool.NextPool) {
957 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
959 if (res->res_pool.RecyclePool) {
960 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
962 if (res->res_pool.ScratchPool) {
963 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
965 if (res->res_pool.catalog) {
966 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
968 if (res->res_pool.storage) {
970 foreach_alist(store, res->res_pool.storage) {
971 sendit(sock, _(" --> "));
972 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
975 if (res->res_pool.CopyPool) {
977 foreach_alist(copy, res->res_pool.CopyPool) {
978 sendit(sock, _(" --> "));
979 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
986 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
987 if (res->res_msgs.mail_cmd)
988 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
989 if (res->res_msgs.operator_cmd)
990 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
994 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
997 if (recurse && res->res_dir.hdr.next) {
998 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1003 * Free all the members of an INCEXE structure
1005 static void free_incexe(INCEXE *incexe)
1007 incexe->name_list.destroy();
1008 incexe->plugin_list.destroy();
1009 for (int i=0; i<incexe->num_opts; i++) {
1010 FOPTS *fopt = incexe->opts_list[i];
1011 fopt->regex.destroy();
1012 fopt->regexdir.destroy();
1013 fopt->regexfile.destroy();
1014 fopt->wild.destroy();
1015 fopt->wilddir.destroy();
1016 fopt->wildfile.destroy();
1017 fopt->wildbase.destroy();
1018 fopt->base.destroy();
1019 fopt->fstype.destroy();
1020 fopt->drivetype.destroy();
1032 if (incexe->opts_list) {
1033 free(incexe->opts_list);
1035 if (incexe->ignoredir) {
1036 free(incexe->ignoredir);
1042 * Free memory of resource -- called when daemon terminates.
1043 * NB, we don't need to worry about freeing any references
1044 * to other resources as they will be freed when that
1045 * resource chain is traversed. Mainly we worry about freeing
1046 * allocated strings (names).
1048 void free_resource(RES *sres, int type)
1051 RES *nres; /* next resource if linked */
1052 URES *res = (URES *)sres;
1057 /* common stuff -- free the resource name and description */
1058 nres = (RES *)res->res_dir.hdr.next;
1059 if (res->res_dir.hdr.name) {
1060 free(res->res_dir.hdr.name);
1062 if (res->res_dir.hdr.desc) {
1063 free(res->res_dir.hdr.desc);
1068 if (res->res_dir.working_directory) {
1069 free(res->res_dir.working_directory);
1071 if (res->res_dir.scripts_directory) {
1072 free((char *)res->res_dir.scripts_directory);
1074 if (res->res_dir.plugin_directory) {
1075 free((char *)res->res_dir.plugin_directory);
1077 if (res->res_dir.pid_directory) {
1078 free(res->res_dir.pid_directory);
1080 if (res->res_dir.subsys_directory) {
1081 free(res->res_dir.subsys_directory);
1083 if (res->res_dir.password) {
1084 free(res->res_dir.password);
1086 if (res->res_dir.query_file) {
1087 free(res->res_dir.query_file);
1089 if (res->res_dir.DIRaddrs) {
1090 free_addresses(res->res_dir.DIRaddrs);
1092 if (res->res_dir.DIRsrc_addr) {
1093 free_addresses(res->res_dir.DIRsrc_addr);
1095 if (res->res_dir.tls_ctx) {
1096 free_tls_context(res->res_dir.tls_ctx);
1098 if (res->res_dir.tls_ca_certfile) {
1099 free(res->res_dir.tls_ca_certfile);
1101 if (res->res_dir.tls_ca_certdir) {
1102 free(res->res_dir.tls_ca_certdir);
1104 if (res->res_dir.tls_certfile) {
1105 free(res->res_dir.tls_certfile);
1107 if (res->res_dir.tls_keyfile) {
1108 free(res->res_dir.tls_keyfile);
1110 if (res->res_dir.tls_dhfile) {
1111 free(res->res_dir.tls_dhfile);
1113 if (res->res_dir.tls_allowed_cns) {
1114 delete res->res_dir.tls_allowed_cns;
1116 if (res->res_dir.verid) {
1117 free(res->res_dir.verid);
1124 if (res->res_con.password) {
1125 free(res->res_con.password);
1127 if (res->res_con.tls_ctx) {
1128 free_tls_context(res->res_con.tls_ctx);
1130 if (res->res_con.tls_ca_certfile) {
1131 free(res->res_con.tls_ca_certfile);
1133 if (res->res_con.tls_ca_certdir) {
1134 free(res->res_con.tls_ca_certdir);
1136 if (res->res_con.tls_certfile) {
1137 free(res->res_con.tls_certfile);
1139 if (res->res_con.tls_keyfile) {
1140 free(res->res_con.tls_keyfile);
1142 if (res->res_con.tls_dhfile) {
1143 free(res->res_con.tls_dhfile);
1145 if (res->res_con.tls_allowed_cns) {
1146 delete res->res_con.tls_allowed_cns;
1148 for (int i=0; i<Num_ACL; i++) {
1149 if (res->res_con.ACL_lists[i]) {
1150 delete res->res_con.ACL_lists[i];
1151 res->res_con.ACL_lists[i] = NULL;
1156 if (res->res_client.address) {
1157 free(res->res_client.address);
1159 if (res->res_client.password) {
1160 free(res->res_client.password);
1162 if (res->res_client.tls_ctx) {
1163 free_tls_context(res->res_client.tls_ctx);
1165 if (res->res_client.tls_ca_certfile) {
1166 free(res->res_client.tls_ca_certfile);
1168 if (res->res_client.tls_ca_certdir) {
1169 free(res->res_client.tls_ca_certdir);
1171 if (res->res_client.tls_certfile) {
1172 free(res->res_client.tls_certfile);
1174 if (res->res_client.tls_keyfile) {
1175 free(res->res_client.tls_keyfile);
1177 if (res->res_client.tls_allowed_cns) {
1178 delete res->res_client.tls_allowed_cns;
1182 if (res->res_store.address) {
1183 free(res->res_store.address);
1185 if (res->res_store.password) {
1186 free(res->res_store.password);
1188 if (res->res_store.media_type) {
1189 free(res->res_store.media_type);
1191 if (res->res_store.device) {
1192 delete res->res_store.device;
1194 if (res->res_store.tls_ctx) {
1195 free_tls_context(res->res_store.tls_ctx);
1197 if (res->res_store.tls_ca_certfile) {
1198 free(res->res_store.tls_ca_certfile);
1200 if (res->res_store.tls_ca_certdir) {
1201 free(res->res_store.tls_ca_certdir);
1203 if (res->res_store.tls_certfile) {
1204 free(res->res_store.tls_certfile);
1206 if (res->res_store.tls_keyfile) {
1207 free(res->res_store.tls_keyfile);
1211 if (res->res_cat.db_address) {
1212 free(res->res_cat.db_address);
1214 if (res->res_cat.db_socket) {
1215 free(res->res_cat.db_socket);
1217 if (res->res_cat.db_user) {
1218 free(res->res_cat.db_user);
1220 if (res->res_cat.db_name) {
1221 free(res->res_cat.db_name);
1223 if (res->res_cat.db_driver) {
1224 free(res->res_cat.db_driver);
1226 if (res->res_cat.db_password) {
1227 free(res->res_cat.db_password);
1231 if ((num=res->res_fs.num_includes)) {
1232 while (--num >= 0) {
1233 free_incexe(res->res_fs.include_items[num]);
1235 free(res->res_fs.include_items);
1237 res->res_fs.num_includes = 0;
1238 if ((num=res->res_fs.num_excludes)) {
1239 while (--num >= 0) {
1240 free_incexe(res->res_fs.exclude_items[num]);
1242 free(res->res_fs.exclude_items);
1244 res->res_fs.num_excludes = 0;
1247 if (res->res_pool.pool_type) {
1248 free(res->res_pool.pool_type);
1250 if (res->res_pool.label_format) {
1251 free(res->res_pool.label_format);
1253 if (res->res_pool.cleaning_prefix) {
1254 free(res->res_pool.cleaning_prefix);
1256 if (res->res_pool.storage) {
1257 delete res->res_pool.storage;
1261 if (res->res_sch.run) {
1263 nrun = res->res_sch.run;
1273 if (res->res_job.RestoreWhere) {
1274 free(res->res_job.RestoreWhere);
1276 if (res->res_job.RegexWhere) {
1277 free(res->res_job.RegexWhere);
1279 if (res->res_job.strip_prefix) {
1280 free(res->res_job.strip_prefix);
1282 if (res->res_job.add_prefix) {
1283 free(res->res_job.add_prefix);
1285 if (res->res_job.add_suffix) {
1286 free(res->res_job.add_suffix);
1288 if (res->res_job.RestoreBootstrap) {
1289 free(res->res_job.RestoreBootstrap);
1291 if (res->res_job.WriteBootstrap) {
1292 free(res->res_job.WriteBootstrap);
1294 if (res->res_job.PluginOptions) {
1295 free(res->res_job.PluginOptions);
1297 if (res->res_job.selection_pattern) {
1298 free(res->res_job.selection_pattern);
1300 if (res->res_job.run_cmds) {
1301 delete res->res_job.run_cmds;
1303 if (res->res_job.storage) {
1304 delete res->res_job.storage;
1306 if (res->res_job.RunScripts) {
1307 free_runscripts(res->res_job.RunScripts);
1308 delete res->res_job.RunScripts;
1312 if (res->res_msgs.mail_cmd) {
1313 free(res->res_msgs.mail_cmd);
1315 if (res->res_msgs.operator_cmd) {
1316 free(res->res_msgs.operator_cmd);
1318 free_msgs_res((MSGS *)res); /* free message resource */
1322 printf(_("Unknown resource type %d in free_resource.\n"), type);
1324 /* Common stuff again -- free the resource, recurse to next one */
1329 free_resource(nres, type);
1334 * Save the new resource by chaining it into the head list for
1335 * the resource. If this is pass 2, we update any resource
1336 * pointers because they may not have been defined until
1339 void save_resource(int type, RES_ITEM *items, int pass)
1342 int rindex = type - r_first;
1346 /* Check Job requirements after applying JobDefs */
1347 if (type != R_JOB && type != R_JOBDEFS) {
1349 * Ensure that all required items are present
1351 for (i=0; items[i].name; i++) {
1352 if (items[i].flags & ITEM_REQUIRED) {
1353 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1354 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1355 items[i].name, resources[rindex]);
1358 /* If this triggers, take a look at lib/parse_conf.h */
1359 if (i >= MAX_RES_ITEMS) {
1360 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1363 } else if (type == R_JOB) {
1365 * Ensure that the name item is present
1367 if (items[0].flags & ITEM_REQUIRED) {
1368 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1369 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1370 items[0].name, resources[rindex]);
1376 * During pass 2 in each "store" routine, we looked up pointers
1377 * to all the resources referrenced in the current resource, now we
1378 * must copy their addresses from the static record to the allocated
1383 /* Resources not containing a resource */
1391 * Resources containing another resource or alist. First
1392 * look up the resource which contains another resource. It
1393 * was written during pass 1. Then stuff in the pointers to
1394 * the resources it contains, which were inserted this pass.
1395 * Finally, it will all be stored back.
1398 /* Find resource saved in pass 1 */
1399 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1400 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1402 /* Explicitly copy resource pointers from this pass (res_all) */
1403 res->res_pool.NextPool = res_all.res_pool.NextPool;
1404 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1405 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1406 res->res_pool.storage = res_all.res_pool.storage;
1407 res->res_pool.catalog = res_all.res_pool.catalog;
1410 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1411 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1413 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1416 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1417 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1419 res->res_dir.messages = res_all.res_dir.messages;
1420 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1423 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1424 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1425 res_all.res_dir.hdr.name);
1427 /* we must explicitly copy the device alist pointer */
1428 res->res_store.device = res_all.res_store.device;
1432 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1433 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1434 res_all.res_dir.hdr.name);
1436 res->res_job.messages = res_all.res_job.messages;
1437 res->res_job.schedule = res_all.res_job.schedule;
1438 res->res_job.client = res_all.res_job.client;
1439 res->res_job.fileset = res_all.res_job.fileset;
1440 res->res_job.storage = res_all.res_job.storage;
1441 res->res_job.pool = res_all.res_job.pool;
1442 res->res_job.full_pool = res_all.res_job.full_pool;
1443 res->res_job.inc_pool = res_all.res_job.inc_pool;
1444 res->res_job.diff_pool = res_all.res_job.diff_pool;
1445 res->res_job.verify_job = res_all.res_job.verify_job;
1446 res->res_job.jobdefs = res_all.res_job.jobdefs;
1447 res->res_job.run_cmds = res_all.res_job.run_cmds;
1448 res->res_job.RunScripts = res_all.res_job.RunScripts;
1450 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1451 * is not very useful)
1452 * We have to set_bit(index, res_all.hdr.item_present);
1453 * or something like that
1456 /* we take RegexWhere before all other options */
1457 if (!res->res_job.RegexWhere
1459 (res->res_job.strip_prefix ||
1460 res->res_job.add_suffix ||
1461 res->res_job.add_prefix))
1463 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1464 res->res_job.add_prefix,
1465 res->res_job.add_suffix);
1466 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1467 bregexp_build_where(res->res_job.RegexWhere, len,
1468 res->res_job.strip_prefix,
1469 res->res_job.add_prefix,
1470 res->res_job.add_suffix);
1471 /* TODO: test bregexp */
1474 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1475 free(res->res_job.RestoreWhere);
1476 res->res_job.RestoreWhere = NULL;
1481 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1482 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1484 res->res_counter.Catalog = res_all.res_counter.Catalog;
1485 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1489 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1490 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1492 res->res_client.catalog = res_all.res_client.catalog;
1493 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1497 * Schedule is a bit different in that it contains a RUN record
1498 * chain which isn't a "named" resource. This chain was linked
1499 * in by run_conf.c during pass 2, so here we jam the pointer
1500 * into the Schedule resource.
1502 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1503 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1505 res->res_sch.run = res_all.res_sch.run;
1508 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1512 /* Note, the resource name was already saved during pass 1,
1513 * so here, we can just release it.
1515 if (res_all.res_dir.hdr.name) {
1516 free(res_all.res_dir.hdr.name);
1517 res_all.res_dir.hdr.name = NULL;
1519 if (res_all.res_dir.hdr.desc) {
1520 free(res_all.res_dir.hdr.desc);
1521 res_all.res_dir.hdr.desc = NULL;
1527 * The following code is only executed during pass 1
1531 size = sizeof(DIRRES);
1534 size = sizeof(CONRES);
1537 size =sizeof(CLIENT);
1540 size = sizeof(STORE);
1550 size = sizeof(FILESET);
1553 size = sizeof(SCHED);
1556 size = sizeof(POOL);
1559 size = sizeof(MSGS);
1562 size = sizeof(COUNTER);
1568 printf(_("Unknown resource type %d in save_resource.\n"), type);
1574 res = (URES *)malloc(size);
1575 memcpy(res, &res_all, size);
1576 if (!res_head[rindex]) {
1577 res_head[rindex] = (RES *)res; /* store first entry */
1578 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1579 res->res_dir.hdr.name, rindex);
1582 if (res->res_dir.hdr.name == NULL) {
1583 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1586 /* Add new res to end of chain */
1587 for (last=next=res_head[rindex]; next; next=next->next) {
1589 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1590 Emsg2(M_ERROR_TERM, 0,
1591 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1592 resources[rindex].name, res->res_dir.hdr.name);
1595 last->next = (RES *)res;
1596 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1597 res->res_dir.hdr.name, rindex, pass);
1602 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1604 uint32_t *destination = (uint32_t*)item->value;
1605 lex_get_token(lc, T_NAME);
1606 if (strcasecmp(lc->str, "truncate") == 0) {
1607 *destination = (*destination) | AOP_TRUNCATE;
1609 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1613 set_bit(index, res_all.hdr.item_present);
1617 * Store Device. Note, the resource is created upon the
1618 * first reference. The details of the resource are obtained
1619 * later from the SD.
1621 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1625 int rindex = R_DEVICE - r_first;
1626 int size = sizeof(DEVICE);
1630 token = lex_get_token(lc, T_NAME);
1631 if (!res_head[rindex]) {
1632 res = (URES *)malloc(size);
1633 memset(res, 0, size);
1634 res->res_dev.hdr.name = bstrdup(lc->str);
1635 res_head[rindex] = (RES *)res; /* store first entry */
1636 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1637 res->res_dir.hdr.name, rindex);
1640 /* See if it is already defined */
1641 for (next=res_head[rindex]; next->next; next=next->next) {
1642 if (strcmp(next->name, lc->str) == 0) {
1648 res = (URES *)malloc(size);
1649 memset(res, 0, size);
1650 res->res_dev.hdr.name = bstrdup(lc->str);
1651 next->next = (RES *)res;
1652 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1653 res->res_dir.hdr.name, rindex, pass);
1658 set_bit(index, res_all.hdr.item_present);
1660 store_alist_res(lc, item, index, pass);
1665 * Store Migration/Copy type
1668 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1672 token = lex_get_token(lc, T_NAME);
1673 /* Store the type both pass 1 and pass 2 */
1674 for (i=0; migtypes[i].type_name; i++) {
1675 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1676 *(uint32_t *)(item->value) = migtypes[i].job_type;
1682 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1685 set_bit(index, res_all.hdr.item_present);
1691 * Store JobType (backup, verify, restore)
1694 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1698 token = lex_get_token(lc, T_NAME);
1699 /* Store the type both pass 1 and pass 2 */
1700 for (i=0; jobtypes[i].type_name; i++) {
1701 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1702 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1708 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1711 set_bit(index, res_all.hdr.item_present);
1715 * Store Job Level (Full, Incremental, ...)
1718 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1722 token = lex_get_token(lc, T_NAME);
1723 /* Store the level pass 2 so that type is defined */
1724 for (i=0; joblevels[i].level_name; i++) {
1725 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1726 *(uint32_t *)(item->value) = joblevels[i].level;
1732 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1735 set_bit(index, res_all.hdr.item_present);
1739 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1742 token = lex_get_token(lc, T_NAME);
1743 /* Scan Replacement options */
1744 for (i=0; ReplaceOptions[i].name; i++) {
1745 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1746 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1752 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1755 set_bit(index, res_all.hdr.item_present);
1759 * Store ACL (access control list)
1762 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1767 token = lex_get_token(lc, T_STRING);
1769 if (((alist **)item->value)[item->code] == NULL) {
1770 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1771 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1773 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1774 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1776 token = lex_get_token(lc, T_ALL);
1777 if (token == T_COMMA) {
1778 continue; /* get another ACL */
1782 set_bit(index, res_all.hdr.item_present);
1785 /* We build RunScripts items here */
1786 static RUNSCRIPT res_runscript;
1788 /* Store a runscript->when in a bit field */
1789 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1791 lex_get_token(lc, T_NAME);
1793 if (strcasecmp(lc->str, "before") == 0) {
1794 *(uint32_t *)(item->value) = SCRIPT_Before ;
1795 } else if (strcasecmp(lc->str, "after") == 0) {
1796 *(uint32_t *)(item->value) = SCRIPT_After;
1797 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1798 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1799 } else if (strcasecmp(lc->str, "always") == 0) {
1800 *(uint32_t *)(item->value) = SCRIPT_Any;
1802 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1807 /* Store a runscript->target
1810 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1812 lex_get_token(lc, T_STRING);
1815 if (strcmp(lc->str, "%c") == 0) {
1816 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1817 } else if (strcasecmp(lc->str, "yes") == 0) {
1818 ((RUNSCRIPT*) item->value)->set_target("%c");
1819 } else if (strcasecmp(lc->str, "no") == 0) {
1820 ((RUNSCRIPT*) item->value)->set_target("");
1822 RES *res = GetResWithName(R_CLIENT, lc->str);
1824 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1825 lc->str, lc->line_no, lc->line);
1828 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1835 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1837 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1839 lex_get_token(lc, T_STRING);
1842 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1843 POOLMEM *c = get_pool_memory(PM_FNAME);
1844 /* Each runscript command takes 2 entries in commands list */
1845 pm_strcpy(c, lc->str);
1846 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1847 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1852 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1854 lex_get_token(lc, T_STRING);
1855 alist **runscripts = (alist **)(item->value) ;
1858 RUNSCRIPT *script = new_runscript();
1859 script->set_job_code_callback(job_code_callback_filesetname);
1861 script->set_command(lc->str);
1863 /* TODO: remove all script->old_proto with bacula 1.42 */
1865 if (strcmp(item->name, "runbeforejob") == 0) {
1866 script->when = SCRIPT_Before;
1867 script->fail_on_error = true;
1868 script->set_target("");
1870 } else if (strcmp(item->name, "runafterjob") == 0) {
1871 script->when = SCRIPT_After;
1872 script->on_success = true;
1873 script->on_failure = false;
1874 script->set_target("");
1876 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1877 script->old_proto = true;
1878 script->when = SCRIPT_After;
1879 script->set_target("%c");
1880 script->on_success = true;
1881 script->on_failure = false;
1883 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1884 script->old_proto = true;
1885 script->when = SCRIPT_Before;
1886 script->set_target("%c");
1887 script->fail_on_error = true;
1889 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1890 script->when = SCRIPT_After;
1891 script->on_failure = true;
1892 script->on_success = false;
1893 script->set_target("");
1896 if (*runscripts == NULL) {
1897 *runscripts = New(alist(10, not_owned_by_alist));
1900 (*runscripts)->append(script);
1907 /* Store a bool in a bit field without modifing res_all.hdr
1908 * We can also add an option to store_bool to skip res_all.hdr
1910 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1912 lex_get_token(lc, T_NAME);
1913 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1914 *(bool *)(item->value) = true;
1915 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1916 *(bool *)(item->value) = false;
1918 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1924 * new RunScript items
1925 * name handler value code flags default_value
1927 static RES_ITEM runscript_items[] = {
1928 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1929 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1930 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1931 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1932 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1933 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1934 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1935 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1936 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1937 {NULL, NULL, {0}, 0, 0, 0}
1941 * Store RunScript info
1943 * Note, when this routine is called, we are inside a Job
1944 * resource. We treat the RunScript like a sort of
1945 * mini-resource within the Job resource.
1947 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1951 alist **runscripts = (alist **)(item->value) ;
1953 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1955 token = lex_get_token(lc, T_SKIP_EOL);
1957 if (token != T_BOB) {
1958 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1960 /* setting on_success, on_failure, fail_on_error */
1961 res_runscript.reset_default();
1964 res_runscript.commands = New(alist(10, not_owned_by_alist));
1967 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1968 if (token == T_EOB) {
1971 if (token != T_IDENTIFIER) {
1972 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1974 for (i=0; runscript_items[i].name; i++) {
1975 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1976 token = lex_get_token(lc, T_SKIP_EOL);
1977 if (token != T_EQUALS) {
1978 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1981 /* Call item handler */
1982 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1989 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1994 /* run on client by default */
1995 if (res_runscript.target == NULL) {
1996 res_runscript.set_target("%c");
1998 if (*runscripts == NULL) {
1999 *runscripts = New(alist(10, not_owned_by_alist));
2002 * commands list contains 2 values per command
2003 * - POOLMEM command string (ex: /bin/true)
2004 * - int command type (ex: SHELL_CMD)
2006 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2007 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2008 t = (intptr_t)res_runscript.commands->pop();
2009 RUNSCRIPT *script = new_runscript();
2010 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2011 script->command = c;
2012 script->cmd_type = t;
2013 /* target is taken from res_runscript, each runscript object have
2016 script->target = NULL;
2017 script->set_target(res_runscript.target);
2019 (*runscripts)->append(script);
2022 delete res_runscript.commands;
2023 /* setting on_success, on_failure... cleanup target field */
2024 res_runscript.reset_default(true);
2028 set_bit(index, res_all.hdr.item_present);
2031 /* callback function for edit_job_codes */
2032 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2034 if (param[0] == 'f') {
2035 return jcr->fileset->name();
2041 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2043 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2044 r_first, r_last, resources, res_head);
2045 return config->parse_config();