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 if (incexe->ignoredir) {
817 sendit(sock, " Z %s\n", incexe->ignoredir);
819 for (j=0; j<incexe->name_list.size(); j++) {
820 sendit(sock, " I %s\n", incexe->name_list.get(j));
822 if (incexe->name_list.size()) {
823 sendit(sock, " N\n");
825 for (j=0; j<incexe->plugin_list.size(); j++) {
826 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
828 if (incexe->plugin_list.size()) {
829 sendit(sock, " N\n");
834 for (i=0; i<res->res_fs.num_excludes; i++) {
835 INCEXE *incexe = res->res_fs.exclude_items[i];
836 for (j=0; j<incexe->name_list.size(); j++) {
837 sendit(sock, " E %s\n", incexe->name_list.get(j));
839 if (incexe->name_list.size()) {
840 sendit(sock, " N\n");
847 if (res->res_sch.run) {
849 RUN *run = res->res_sch.run;
850 char buf[1000], num[30];
851 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
856 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
857 bstrncpy(buf, _(" hour="), sizeof(buf));
858 for (i=0; i<24; i++) {
859 if (bit_is_set(i, run->hour)) {
860 bsnprintf(num, sizeof(num), "%d ", i);
861 bstrncat(buf, num, sizeof(buf));
864 bstrncat(buf, "\n", sizeof(buf));
866 bstrncpy(buf, _(" mday="), sizeof(buf));
867 for (i=0; i<31; i++) {
868 if (bit_is_set(i, run->mday)) {
869 bsnprintf(num, sizeof(num), "%d ", i);
870 bstrncat(buf, num, sizeof(buf));
873 bstrncat(buf, "\n", sizeof(buf));
875 bstrncpy(buf, _(" month="), sizeof(buf));
876 for (i=0; i<12; i++) {
877 if (bit_is_set(i, run->month)) {
878 bsnprintf(num, sizeof(num), "%d ", i);
879 bstrncat(buf, num, sizeof(buf));
882 bstrncat(buf, "\n", sizeof(buf));
884 bstrncpy(buf, _(" wday="), sizeof(buf));
885 for (i=0; i<7; i++) {
886 if (bit_is_set(i, run->wday)) {
887 bsnprintf(num, sizeof(num), "%d ", i);
888 bstrncat(buf, num, sizeof(buf));
891 bstrncat(buf, "\n", sizeof(buf));
893 bstrncpy(buf, _(" wom="), sizeof(buf));
894 for (i=0; i<5; i++) {
895 if (bit_is_set(i, run->wom)) {
896 bsnprintf(num, sizeof(num), "%d ", i);
897 bstrncat(buf, num, sizeof(buf));
900 bstrncat(buf, "\n", sizeof(buf));
902 bstrncpy(buf, _(" woy="), sizeof(buf));
903 for (i=0; i<54; i++) {
904 if (bit_is_set(i, run->woy)) {
905 bsnprintf(num, sizeof(num), "%d ", i);
906 bstrncat(buf, num, sizeof(buf));
909 bstrncat(buf, "\n", sizeof(buf));
911 sendit(sock, _(" mins=%d\n"), run->minute);
913 sendit(sock, _(" --> "));
914 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
917 sendit(sock, _(" --> "));
918 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
921 sendit(sock, _(" --> "));
922 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
924 /* If another Run record is chained in, go print it */
930 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
935 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
936 res->res_pool.pool_type);
937 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
938 res->res_pool.use_catalog, res->res_pool.use_volume_once,
939 res->res_pool.catalog_files);
940 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
941 res->res_pool.max_volumes, res->res_pool.AutoPrune,
942 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
943 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
944 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
945 res->res_pool.Recycle,
946 NPRT(res->res_pool.label_format));
947 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
948 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
949 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
950 res->res_pool.recycle_oldest_volume,
951 res->res_pool.purge_oldest_volume);
952 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
953 res->res_pool.MaxVolJobs,
954 res->res_pool.MaxVolFiles,
955 edit_uint64(res->res_pool.MaxVolBytes, ed1));
956 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
957 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
958 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
959 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
960 if (res->res_pool.NextPool) {
961 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
963 if (res->res_pool.RecyclePool) {
964 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
966 if (res->res_pool.ScratchPool) {
967 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
969 if (res->res_pool.catalog) {
970 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
972 if (res->res_pool.storage) {
974 foreach_alist(store, res->res_pool.storage) {
975 sendit(sock, _(" --> "));
976 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
979 if (res->res_pool.CopyPool) {
981 foreach_alist(copy, res->res_pool.CopyPool) {
982 sendit(sock, _(" --> "));
983 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
990 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
991 if (res->res_msgs.mail_cmd)
992 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
993 if (res->res_msgs.operator_cmd)
994 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
998 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1001 if (recurse && res->res_dir.hdr.next) {
1002 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1007 * Free all the members of an INCEXE structure
1009 static void free_incexe(INCEXE *incexe)
1011 incexe->name_list.destroy();
1012 incexe->plugin_list.destroy();
1013 for (int i=0; i<incexe->num_opts; i++) {
1014 FOPTS *fopt = incexe->opts_list[i];
1015 fopt->regex.destroy();
1016 fopt->regexdir.destroy();
1017 fopt->regexfile.destroy();
1018 fopt->wild.destroy();
1019 fopt->wilddir.destroy();
1020 fopt->wildfile.destroy();
1021 fopt->wildbase.destroy();
1022 fopt->base.destroy();
1023 fopt->fstype.destroy();
1024 fopt->drivetype.destroy();
1036 if (incexe->opts_list) {
1037 free(incexe->opts_list);
1039 if (incexe->ignoredir) {
1040 free(incexe->ignoredir);
1046 * Free memory of resource -- called when daemon terminates.
1047 * NB, we don't need to worry about freeing any references
1048 * to other resources as they will be freed when that
1049 * resource chain is traversed. Mainly we worry about freeing
1050 * allocated strings (names).
1052 void free_resource(RES *sres, int type)
1055 RES *nres; /* next resource if linked */
1056 URES *res = (URES *)sres;
1061 /* common stuff -- free the resource name and description */
1062 nres = (RES *)res->res_dir.hdr.next;
1063 if (res->res_dir.hdr.name) {
1064 free(res->res_dir.hdr.name);
1066 if (res->res_dir.hdr.desc) {
1067 free(res->res_dir.hdr.desc);
1072 if (res->res_dir.working_directory) {
1073 free(res->res_dir.working_directory);
1075 if (res->res_dir.scripts_directory) {
1076 free((char *)res->res_dir.scripts_directory);
1078 if (res->res_dir.plugin_directory) {
1079 free((char *)res->res_dir.plugin_directory);
1081 if (res->res_dir.pid_directory) {
1082 free(res->res_dir.pid_directory);
1084 if (res->res_dir.subsys_directory) {
1085 free(res->res_dir.subsys_directory);
1087 if (res->res_dir.password) {
1088 free(res->res_dir.password);
1090 if (res->res_dir.query_file) {
1091 free(res->res_dir.query_file);
1093 if (res->res_dir.DIRaddrs) {
1094 free_addresses(res->res_dir.DIRaddrs);
1096 if (res->res_dir.DIRsrc_addr) {
1097 free_addresses(res->res_dir.DIRsrc_addr);
1099 if (res->res_dir.tls_ctx) {
1100 free_tls_context(res->res_dir.tls_ctx);
1102 if (res->res_dir.tls_ca_certfile) {
1103 free(res->res_dir.tls_ca_certfile);
1105 if (res->res_dir.tls_ca_certdir) {
1106 free(res->res_dir.tls_ca_certdir);
1108 if (res->res_dir.tls_certfile) {
1109 free(res->res_dir.tls_certfile);
1111 if (res->res_dir.tls_keyfile) {
1112 free(res->res_dir.tls_keyfile);
1114 if (res->res_dir.tls_dhfile) {
1115 free(res->res_dir.tls_dhfile);
1117 if (res->res_dir.tls_allowed_cns) {
1118 delete res->res_dir.tls_allowed_cns;
1120 if (res->res_dir.verid) {
1121 free(res->res_dir.verid);
1128 if (res->res_con.password) {
1129 free(res->res_con.password);
1131 if (res->res_con.tls_ctx) {
1132 free_tls_context(res->res_con.tls_ctx);
1134 if (res->res_con.tls_ca_certfile) {
1135 free(res->res_con.tls_ca_certfile);
1137 if (res->res_con.tls_ca_certdir) {
1138 free(res->res_con.tls_ca_certdir);
1140 if (res->res_con.tls_certfile) {
1141 free(res->res_con.tls_certfile);
1143 if (res->res_con.tls_keyfile) {
1144 free(res->res_con.tls_keyfile);
1146 if (res->res_con.tls_dhfile) {
1147 free(res->res_con.tls_dhfile);
1149 if (res->res_con.tls_allowed_cns) {
1150 delete res->res_con.tls_allowed_cns;
1152 for (int i=0; i<Num_ACL; i++) {
1153 if (res->res_con.ACL_lists[i]) {
1154 delete res->res_con.ACL_lists[i];
1155 res->res_con.ACL_lists[i] = NULL;
1160 if (res->res_client.address) {
1161 free(res->res_client.address);
1163 if (res->res_client.password) {
1164 free(res->res_client.password);
1166 if (res->res_client.tls_ctx) {
1167 free_tls_context(res->res_client.tls_ctx);
1169 if (res->res_client.tls_ca_certfile) {
1170 free(res->res_client.tls_ca_certfile);
1172 if (res->res_client.tls_ca_certdir) {
1173 free(res->res_client.tls_ca_certdir);
1175 if (res->res_client.tls_certfile) {
1176 free(res->res_client.tls_certfile);
1178 if (res->res_client.tls_keyfile) {
1179 free(res->res_client.tls_keyfile);
1181 if (res->res_client.tls_allowed_cns) {
1182 delete res->res_client.tls_allowed_cns;
1186 if (res->res_store.address) {
1187 free(res->res_store.address);
1189 if (res->res_store.password) {
1190 free(res->res_store.password);
1192 if (res->res_store.media_type) {
1193 free(res->res_store.media_type);
1195 if (res->res_store.device) {
1196 delete res->res_store.device;
1198 if (res->res_store.tls_ctx) {
1199 free_tls_context(res->res_store.tls_ctx);
1201 if (res->res_store.tls_ca_certfile) {
1202 free(res->res_store.tls_ca_certfile);
1204 if (res->res_store.tls_ca_certdir) {
1205 free(res->res_store.tls_ca_certdir);
1207 if (res->res_store.tls_certfile) {
1208 free(res->res_store.tls_certfile);
1210 if (res->res_store.tls_keyfile) {
1211 free(res->res_store.tls_keyfile);
1215 if (res->res_cat.db_address) {
1216 free(res->res_cat.db_address);
1218 if (res->res_cat.db_socket) {
1219 free(res->res_cat.db_socket);
1221 if (res->res_cat.db_user) {
1222 free(res->res_cat.db_user);
1224 if (res->res_cat.db_name) {
1225 free(res->res_cat.db_name);
1227 if (res->res_cat.db_driver) {
1228 free(res->res_cat.db_driver);
1230 if (res->res_cat.db_password) {
1231 free(res->res_cat.db_password);
1235 if ((num=res->res_fs.num_includes)) {
1236 while (--num >= 0) {
1237 free_incexe(res->res_fs.include_items[num]);
1239 free(res->res_fs.include_items);
1241 res->res_fs.num_includes = 0;
1242 if ((num=res->res_fs.num_excludes)) {
1243 while (--num >= 0) {
1244 free_incexe(res->res_fs.exclude_items[num]);
1246 free(res->res_fs.exclude_items);
1248 res->res_fs.num_excludes = 0;
1251 if (res->res_pool.pool_type) {
1252 free(res->res_pool.pool_type);
1254 if (res->res_pool.label_format) {
1255 free(res->res_pool.label_format);
1257 if (res->res_pool.cleaning_prefix) {
1258 free(res->res_pool.cleaning_prefix);
1260 if (res->res_pool.storage) {
1261 delete res->res_pool.storage;
1265 if (res->res_sch.run) {
1267 nrun = res->res_sch.run;
1277 if (res->res_job.RestoreWhere) {
1278 free(res->res_job.RestoreWhere);
1280 if (res->res_job.RegexWhere) {
1281 free(res->res_job.RegexWhere);
1283 if (res->res_job.strip_prefix) {
1284 free(res->res_job.strip_prefix);
1286 if (res->res_job.add_prefix) {
1287 free(res->res_job.add_prefix);
1289 if (res->res_job.add_suffix) {
1290 free(res->res_job.add_suffix);
1292 if (res->res_job.RestoreBootstrap) {
1293 free(res->res_job.RestoreBootstrap);
1295 if (res->res_job.WriteBootstrap) {
1296 free(res->res_job.WriteBootstrap);
1298 if (res->res_job.PluginOptions) {
1299 free(res->res_job.PluginOptions);
1301 if (res->res_job.selection_pattern) {
1302 free(res->res_job.selection_pattern);
1304 if (res->res_job.run_cmds) {
1305 delete res->res_job.run_cmds;
1307 if (res->res_job.storage) {
1308 delete res->res_job.storage;
1310 if (res->res_job.base) {
1311 delete res->res_job.base;
1313 if (res->res_job.RunScripts) {
1314 free_runscripts(res->res_job.RunScripts);
1315 delete res->res_job.RunScripts;
1319 if (res->res_msgs.mail_cmd) {
1320 free(res->res_msgs.mail_cmd);
1322 if (res->res_msgs.operator_cmd) {
1323 free(res->res_msgs.operator_cmd);
1325 free_msgs_res((MSGS *)res); /* free message resource */
1329 printf(_("Unknown resource type %d in free_resource.\n"), type);
1331 /* Common stuff again -- free the resource, recurse to next one */
1336 free_resource(nres, type);
1341 * Save the new resource by chaining it into the head list for
1342 * the resource. If this is pass 2, we update any resource
1343 * pointers because they may not have been defined until
1346 void save_resource(int type, RES_ITEM *items, int pass)
1349 int rindex = type - r_first;
1353 /* Check Job requirements after applying JobDefs */
1354 if (type != R_JOB && type != R_JOBDEFS) {
1356 * Ensure that all required items are present
1358 for (i=0; items[i].name; i++) {
1359 if (items[i].flags & ITEM_REQUIRED) {
1360 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1361 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1362 items[i].name, resources[rindex]);
1365 /* If this triggers, take a look at lib/parse_conf.h */
1366 if (i >= MAX_RES_ITEMS) {
1367 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1370 } else if (type == R_JOB) {
1372 * Ensure that the name item is present
1374 if (items[0].flags & ITEM_REQUIRED) {
1375 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1376 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1377 items[0].name, resources[rindex]);
1383 * During pass 2 in each "store" routine, we looked up pointers
1384 * to all the resources referrenced in the current resource, now we
1385 * must copy their addresses from the static record to the allocated
1390 /* Resources not containing a resource */
1398 * Resources containing another resource or alist. First
1399 * look up the resource which contains another resource. It
1400 * was written during pass 1. Then stuff in the pointers to
1401 * the resources it contains, which were inserted this pass.
1402 * Finally, it will all be stored back.
1405 /* Find resource saved in pass 1 */
1406 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1407 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1409 /* Explicitly copy resource pointers from this pass (res_all) */
1410 res->res_pool.NextPool = res_all.res_pool.NextPool;
1411 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1412 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1413 res->res_pool.storage = res_all.res_pool.storage;
1414 res->res_pool.catalog = res_all.res_pool.catalog;
1417 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1418 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1420 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1423 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1424 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1426 res->res_dir.messages = res_all.res_dir.messages;
1427 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1430 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1431 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1432 res_all.res_dir.hdr.name);
1434 /* we must explicitly copy the device alist pointer */
1435 res->res_store.device = res_all.res_store.device;
1439 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1440 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1441 res_all.res_dir.hdr.name);
1443 res->res_job.messages = res_all.res_job.messages;
1444 res->res_job.schedule = res_all.res_job.schedule;
1445 res->res_job.client = res_all.res_job.client;
1446 res->res_job.fileset = res_all.res_job.fileset;
1447 res->res_job.storage = res_all.res_job.storage;
1448 res->res_job.base = res_all.res_job.base;
1449 res->res_job.pool = res_all.res_job.pool;
1450 res->res_job.full_pool = res_all.res_job.full_pool;
1451 res->res_job.inc_pool = res_all.res_job.inc_pool;
1452 res->res_job.diff_pool = res_all.res_job.diff_pool;
1453 res->res_job.verify_job = res_all.res_job.verify_job;
1454 res->res_job.jobdefs = res_all.res_job.jobdefs;
1455 res->res_job.run_cmds = res_all.res_job.run_cmds;
1456 res->res_job.RunScripts = res_all.res_job.RunScripts;
1458 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1459 * is not very useful)
1460 * We have to set_bit(index, res_all.hdr.item_present);
1461 * or something like that
1464 /* we take RegexWhere before all other options */
1465 if (!res->res_job.RegexWhere
1467 (res->res_job.strip_prefix ||
1468 res->res_job.add_suffix ||
1469 res->res_job.add_prefix))
1471 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1472 res->res_job.add_prefix,
1473 res->res_job.add_suffix);
1474 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1475 bregexp_build_where(res->res_job.RegexWhere, len,
1476 res->res_job.strip_prefix,
1477 res->res_job.add_prefix,
1478 res->res_job.add_suffix);
1479 /* TODO: test bregexp */
1482 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1483 free(res->res_job.RestoreWhere);
1484 res->res_job.RestoreWhere = NULL;
1489 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1490 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1492 res->res_counter.Catalog = res_all.res_counter.Catalog;
1493 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1497 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1498 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1500 res->res_client.catalog = res_all.res_client.catalog;
1501 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1505 * Schedule is a bit different in that it contains a RUN record
1506 * chain which isn't a "named" resource. This chain was linked
1507 * in by run_conf.c during pass 2, so here we jam the pointer
1508 * into the Schedule resource.
1510 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1511 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1513 res->res_sch.run = res_all.res_sch.run;
1516 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1520 /* Note, the resource name was already saved during pass 1,
1521 * so here, we can just release it.
1523 if (res_all.res_dir.hdr.name) {
1524 free(res_all.res_dir.hdr.name);
1525 res_all.res_dir.hdr.name = NULL;
1527 if (res_all.res_dir.hdr.desc) {
1528 free(res_all.res_dir.hdr.desc);
1529 res_all.res_dir.hdr.desc = NULL;
1535 * The following code is only executed during pass 1
1539 size = sizeof(DIRRES);
1542 size = sizeof(CONRES);
1545 size =sizeof(CLIENT);
1548 size = sizeof(STORE);
1558 size = sizeof(FILESET);
1561 size = sizeof(SCHED);
1564 size = sizeof(POOL);
1567 size = sizeof(MSGS);
1570 size = sizeof(COUNTER);
1576 printf(_("Unknown resource type %d in save_resource.\n"), type);
1582 res = (URES *)malloc(size);
1583 memcpy(res, &res_all, size);
1584 if (!res_head[rindex]) {
1585 res_head[rindex] = (RES *)res; /* store first entry */
1586 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1587 res->res_dir.hdr.name, rindex);
1590 if (res->res_dir.hdr.name == NULL) {
1591 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1594 /* Add new res to end of chain */
1595 for (last=next=res_head[rindex]; next; next=next->next) {
1597 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1598 Emsg2(M_ERROR_TERM, 0,
1599 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1600 resources[rindex].name, res->res_dir.hdr.name);
1603 last->next = (RES *)res;
1604 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1605 res->res_dir.hdr.name, rindex, pass);
1611 * Store Device. Note, the resource is created upon the
1612 * first reference. The details of the resource are obtained
1613 * later from the SD.
1615 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1619 int rindex = R_DEVICE - r_first;
1620 int size = sizeof(DEVICE);
1624 token = lex_get_token(lc, T_NAME);
1625 if (!res_head[rindex]) {
1626 res = (URES *)malloc(size);
1627 memset(res, 0, size);
1628 res->res_dev.hdr.name = bstrdup(lc->str);
1629 res_head[rindex] = (RES *)res; /* store first entry */
1630 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1631 res->res_dir.hdr.name, rindex);
1634 /* See if it is already defined */
1635 for (next=res_head[rindex]; next->next; next=next->next) {
1636 if (strcmp(next->name, lc->str) == 0) {
1642 res = (URES *)malloc(size);
1643 memset(res, 0, size);
1644 res->res_dev.hdr.name = bstrdup(lc->str);
1645 next->next = (RES *)res;
1646 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1647 res->res_dir.hdr.name, rindex, pass);
1652 set_bit(index, res_all.hdr.item_present);
1654 store_alist_res(lc, item, index, pass);
1659 * Store Migration/Copy type
1662 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1666 token = lex_get_token(lc, T_NAME);
1667 /* Store the type both pass 1 and pass 2 */
1668 for (i=0; migtypes[i].type_name; i++) {
1669 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1670 *(uint32_t *)(item->value) = migtypes[i].job_type;
1676 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1679 set_bit(index, res_all.hdr.item_present);
1685 * Store JobType (backup, verify, restore)
1688 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1692 token = lex_get_token(lc, T_NAME);
1693 /* Store the type both pass 1 and pass 2 */
1694 for (i=0; jobtypes[i].type_name; i++) {
1695 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1696 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1702 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1705 set_bit(index, res_all.hdr.item_present);
1709 * Store Job Level (Full, Incremental, ...)
1712 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1716 token = lex_get_token(lc, T_NAME);
1717 /* Store the level pass 2 so that type is defined */
1718 for (i=0; joblevels[i].level_name; i++) {
1719 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1720 *(uint32_t *)(item->value) = joblevels[i].level;
1726 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1729 set_bit(index, res_all.hdr.item_present);
1733 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1736 token = lex_get_token(lc, T_NAME);
1737 /* Scan Replacement options */
1738 for (i=0; ReplaceOptions[i].name; i++) {
1739 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1740 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1746 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1749 set_bit(index, res_all.hdr.item_present);
1753 * Store ACL (access control list)
1756 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1761 token = lex_get_token(lc, T_STRING);
1763 if (((alist **)item->value)[item->code] == NULL) {
1764 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1765 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1767 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1768 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1770 token = lex_get_token(lc, T_ALL);
1771 if (token == T_COMMA) {
1772 continue; /* get another ACL */
1776 set_bit(index, res_all.hdr.item_present);
1779 /* We build RunScripts items here */
1780 static RUNSCRIPT res_runscript;
1782 /* Store a runscript->when in a bit field */
1783 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1785 lex_get_token(lc, T_NAME);
1787 if (strcasecmp(lc->str, "before") == 0) {
1788 *(uint32_t *)(item->value) = SCRIPT_Before ;
1789 } else if (strcasecmp(lc->str, "after") == 0) {
1790 *(uint32_t *)(item->value) = SCRIPT_After;
1791 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1792 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1793 } else if (strcasecmp(lc->str, "always") == 0) {
1794 *(uint32_t *)(item->value) = SCRIPT_Any;
1796 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1801 /* Store a runscript->target
1804 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1806 lex_get_token(lc, T_STRING);
1809 if (strcmp(lc->str, "%c") == 0) {
1810 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1811 } else if (strcasecmp(lc->str, "yes") == 0) {
1812 ((RUNSCRIPT*) item->value)->set_target("%c");
1813 } else if (strcasecmp(lc->str, "no") == 0) {
1814 ((RUNSCRIPT*) item->value)->set_target("");
1816 RES *res = GetResWithName(R_CLIENT, lc->str);
1818 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1819 lc->str, lc->line_no, lc->line);
1822 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1829 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1831 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1833 lex_get_token(lc, T_STRING);
1836 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1837 POOLMEM *c = get_pool_memory(PM_FNAME);
1838 /* Each runscript command takes 2 entries in commands list */
1839 pm_strcpy(c, lc->str);
1840 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1841 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1846 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1848 lex_get_token(lc, T_STRING);
1849 alist **runscripts = (alist **)(item->value) ;
1852 RUNSCRIPT *script = new_runscript();
1853 script->set_job_code_callback(job_code_callback_filesetname);
1855 script->set_command(lc->str);
1857 /* TODO: remove all script->old_proto with bacula 1.42 */
1859 if (strcmp(item->name, "runbeforejob") == 0) {
1860 script->when = SCRIPT_Before;
1861 script->fail_on_error = true;
1862 script->set_target("");
1864 } else if (strcmp(item->name, "runafterjob") == 0) {
1865 script->when = SCRIPT_After;
1866 script->on_success = true;
1867 script->on_failure = false;
1868 script->set_target("");
1870 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1871 script->old_proto = true;
1872 script->when = SCRIPT_After;
1873 script->set_target("%c");
1874 script->on_success = true;
1875 script->on_failure = false;
1877 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1878 script->old_proto = true;
1879 script->when = SCRIPT_Before;
1880 script->set_target("%c");
1881 script->fail_on_error = true;
1883 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1884 script->when = SCRIPT_After;
1885 script->on_failure = true;
1886 script->on_success = false;
1887 script->set_target("");
1890 if (*runscripts == NULL) {
1891 *runscripts = New(alist(10, not_owned_by_alist));
1894 (*runscripts)->append(script);
1901 /* Store a bool in a bit field without modifing res_all.hdr
1902 * We can also add an option to store_bool to skip res_all.hdr
1904 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1906 lex_get_token(lc, T_NAME);
1907 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1908 *(bool *)(item->value) = true;
1909 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1910 *(bool *)(item->value) = false;
1912 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1918 * new RunScript items
1919 * name handler value code flags default_value
1921 static RES_ITEM runscript_items[] = {
1922 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1923 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1924 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1925 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1926 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1927 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1928 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1929 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1930 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1931 {NULL, NULL, {0}, 0, 0, 0}
1935 * Store RunScript info
1937 * Note, when this routine is called, we are inside a Job
1938 * resource. We treat the RunScript like a sort of
1939 * mini-resource within the Job resource.
1941 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1945 alist **runscripts = (alist **)(item->value) ;
1947 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1949 token = lex_get_token(lc, T_SKIP_EOL);
1951 if (token != T_BOB) {
1952 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1954 /* setting on_success, on_failure, fail_on_error */
1955 res_runscript.reset_default();
1958 res_runscript.commands = New(alist(10, not_owned_by_alist));
1961 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1962 if (token == T_EOB) {
1965 if (token != T_IDENTIFIER) {
1966 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1968 for (i=0; runscript_items[i].name; i++) {
1969 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1970 token = lex_get_token(lc, T_SKIP_EOL);
1971 if (token != T_EQUALS) {
1972 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1975 /* Call item handler */
1976 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1983 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1988 /* run on client by default */
1989 if (res_runscript.target == NULL) {
1990 res_runscript.set_target("%c");
1992 if (*runscripts == NULL) {
1993 *runscripts = New(alist(10, not_owned_by_alist));
1996 * commands list contains 2 values per command
1997 * - POOLMEM command string (ex: /bin/true)
1998 * - int command type (ex: SHELL_CMD)
2000 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2001 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2002 t = (intptr_t)res_runscript.commands->pop();
2003 RUNSCRIPT *script = new_runscript();
2004 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2005 script->command = c;
2006 script->cmd_type = t;
2007 /* target is taken from res_runscript, each runscript object have
2010 script->target = NULL;
2011 script->set_target(res_runscript.target);
2013 (*runscripts)->append(script);
2016 delete res_runscript.commands;
2017 /* setting on_success, on_failure... cleanup target field */
2018 res_runscript.reset_default(true);
2022 set_bit(index, res_all.hdr.item_present);
2025 /* callback function for edit_job_codes */
2026 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2028 if (param[0] == 'f') {
2029 return jcr->fileset->name();
2035 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2037 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2038 r_first, r_last, resources, res_head);
2039 return config->parse_config();