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_size64, 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 {NULL, NULL, {0}, 0, 0, 0}
346 * name handler value code flags default_value
348 static RES_ITEM fs_items[] = {
349 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
350 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
351 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
352 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
353 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
354 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
355 {NULL, NULL, {0}, 0, 0, 0}
358 /* Schedule -- see run_conf.c */
361 * name handler value code flags default_value
363 static RES_ITEM sch_items[] = {
364 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
365 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
366 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
367 {NULL, NULL, {0}, 0, 0, 0}
372 * name handler value code flags default_value
374 static RES_ITEM pool_items[] = {
375 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
376 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
377 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
378 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
379 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
380 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
381 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
382 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
383 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
384 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
385 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
386 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
387 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
388 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
389 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
390 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
391 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
392 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
393 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
394 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
395 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
396 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
397 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
398 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
399 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
400 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
401 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
402 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
403 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
404 {NULL, NULL, {0}, 0, 0, 0}
409 * name handler value code flags default_value
411 static RES_ITEM counter_items[] = {
412 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
413 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
414 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
415 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
416 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
417 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
418 {NULL, NULL, {0}, 0, 0, 0}
422 /* Message resource */
423 extern RES_ITEM msgs_items[];
426 * This is the master resource definition.
427 * It must have one item for each of the resources.
429 * NOTE!!! keep it in the same order as the R_codes
430 * or eliminate all resources[rindex].name
432 * name items rcode res_head
434 RES_TABLE resources[] = {
435 {"director", dir_items, R_DIRECTOR},
436 {"client", cli_items, R_CLIENT},
437 {"job", job_items, R_JOB},
438 {"storage", store_items, R_STORAGE},
439 {"catalog", cat_items, R_CATALOG},
440 {"schedule", sch_items, R_SCHEDULE},
441 {"fileset", fs_items, R_FILESET},
442 {"pool", pool_items, R_POOL},
443 {"messages", msgs_items, R_MSGS},
444 {"counter", counter_items, R_COUNTER},
445 {"console", con_items, R_CONSOLE},
446 {"jobdefs", job_items, R_JOBDEFS},
447 {"device", NULL, R_DEVICE}, /* info obtained from SD */
452 /* Keywords (RHS) permitted in Job Level records
454 * level_name level job_type
456 struct s_jl joblevels[] = {
457 {"Full", L_FULL, JT_BACKUP},
458 {"Base", L_BASE, JT_BACKUP},
459 {"Incremental", L_INCREMENTAL, JT_BACKUP},
460 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
461 {"Since", L_SINCE, JT_BACKUP},
462 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
463 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
464 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
465 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
466 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
467 {"Data", L_VERIFY_DATA, JT_VERIFY},
468 {" ", L_NONE, JT_ADMIN},
469 {" ", L_NONE, JT_RESTORE},
473 /* Keywords (RHS) permitted in Job type records
477 struct s_jt jobtypes[] = {
478 {"backup", JT_BACKUP},
480 {"verify", JT_VERIFY},
481 {"restore", JT_RESTORE},
482 {"migrate", JT_MIGRATE},
488 /* Keywords (RHS) permitted in Selection type records
492 struct s_jt migtypes[] = {
493 {"smallestvolume", MT_SMALLEST_VOL},
494 {"oldestvolume", MT_OLDEST_VOL},
495 {"pooloccupancy", MT_POOL_OCCUPANCY},
496 {"pooltime", MT_POOL_TIME},
497 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
498 {"client", MT_CLIENT},
499 {"volume", MT_VOLUME},
501 {"sqlquery", MT_SQLQUERY},
507 /* Options permitted in Restore replace= */
508 struct s_kw ReplaceOptions[] = {
509 {"always", REPLACE_ALWAYS},
510 {"ifnewer", REPLACE_IFNEWER},
511 {"ifolder", REPLACE_IFOLDER},
512 {"never", REPLACE_NEVER},
516 char *CAT::display(POOLMEM *dst) {
517 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
518 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
520 name(), NPRTB(db_name),
521 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
522 NPRTB(db_address), db_port, NPRTB(db_socket));
526 const char *level_to_str(int level)
529 static char level_no[30];
530 const char *str = level_no;
532 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
533 for (i=0; joblevels[i].level_name; i++) {
534 if (level == (int)joblevels[i].level) {
535 str = joblevels[i].level_name;
542 /* Dump contents of resource */
543 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
545 URES *res = (URES *)reshdr;
547 char ed1[100], ed2[100], ed3[100];
551 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
554 if (type < 0) { /* no recursion */
560 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
561 reshdr->name, res->res_dir.MaxConcurrentJobs,
562 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
563 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
564 if (res->res_dir.query_file) {
565 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
567 if (res->res_dir.messages) {
568 sendit(sock, _(" --> "));
569 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
573 sendit(sock, _("Console: name=%s SSL=%d\n"),
574 res->res_con.hdr.name, res->res_con.tls_enable);
577 if (res->res_counter.WrapCounter) {
578 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
579 res->res_counter.hdr.name, res->res_counter.MinValue,
580 res->res_counter.MaxValue, res->res_counter.CurrentValue,
581 res->res_counter.WrapCounter->hdr.name);
583 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
584 res->res_counter.hdr.name, res->res_counter.MinValue,
585 res->res_counter.MaxValue);
587 if (res->res_counter.Catalog) {
588 sendit(sock, _(" --> "));
589 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
594 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
595 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
596 res->res_client.MaxConcurrentJobs);
597 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
598 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
599 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
600 res->res_client.AutoPrune);
601 if (res->res_client.catalog) {
602 sendit(sock, _(" --> "));
603 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
610 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
611 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
612 " poolid=%s volname=%s MediaType=%s\n"),
613 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
614 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
615 dev->offline, dev->autochanger,
616 edit_uint64(dev->PoolId, ed1),
617 dev->VolumeName, dev->MediaType);
621 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
622 " DeviceName=%s MediaType=%s StorageId=%s\n"),
623 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
624 res->res_store.MaxConcurrentJobs,
625 res->res_store.dev_name(),
626 res->res_store.media_type,
627 edit_int64(res->res_store.StorageId, ed1));
631 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
632 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
633 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
634 res->res_cat.db_port, res->res_cat.db_name,
635 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
636 res->res_cat.mult_db_connections);
641 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
642 type == R_JOB ? _("Job") : _("JobDefs"),
643 res->res_job.hdr.name, res->res_job.JobType,
644 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
645 res->res_job.enabled);
646 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
647 res->res_job.MaxConcurrentJobs,
648 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
649 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
650 res->res_job.spool_data, res->res_job.write_part_after_job);
651 if (res->res_job.spool_size) {
652 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
654 if (res->res_job.JobType == JT_BACKUP) {
655 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
657 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
658 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
660 if (res->res_job.client) {
661 sendit(sock, _(" --> "));
662 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
664 if (res->res_job.fileset) {
665 sendit(sock, _(" --> "));
666 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
668 if (res->res_job.schedule) {
669 sendit(sock, _(" --> "));
670 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
672 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
673 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
675 if (res->res_job.RegexWhere) {
676 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
678 if (res->res_job.RestoreBootstrap) {
679 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
681 if (res->res_job.WriteBootstrap) {
682 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
684 if (res->res_job.PluginOptions) {
685 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
687 if (res->res_job.MaxRunTime) {
688 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
690 if (res->res_job.MaxWaitTime) {
691 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
693 if (res->res_job.MaxStartDelay) {
694 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
696 if (res->res_job.storage) {
698 foreach_alist(store, res->res_job.storage) {
699 sendit(sock, _(" --> "));
700 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
703 if (res->res_job.RunScripts) {
705 foreach_alist(script, res->res_job.RunScripts) {
706 sendit(sock, _(" --> RunScript\n"));
707 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
708 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
709 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
710 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
711 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
712 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
715 if (res->res_job.pool) {
716 sendit(sock, _(" --> "));
717 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
719 if (res->res_job.full_pool) {
720 sendit(sock, _(" --> "));
721 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
723 if (res->res_job.inc_pool) {
724 sendit(sock, _(" --> "));
725 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
727 if (res->res_job.diff_pool) {
728 sendit(sock, _(" --> "));
729 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
731 if (res->res_job.verify_job) {
732 sendit(sock, _(" --> "));
733 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
735 if (res->res_job.run_cmds) {
737 foreach_alist(runcmd, res->res_job.run_cmds) {
738 sendit(sock, _(" --> Run=%s\n"), runcmd);
741 if (res->res_job.selection_pattern) {
742 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
744 if (res->res_job.messages) {
745 sendit(sock, _(" --> "));
746 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
753 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
754 for (i=0; i<res->res_fs.num_includes; i++) {
755 INCEXE *incexe = res->res_fs.include_items[i];
756 for (j=0; j<incexe->num_opts; j++) {
757 FOPTS *fo = incexe->opts_list[j];
758 sendit(sock, " O %s\n", fo->opts);
760 bool enhanced_wild = false;
761 for (k=0; fo->opts[k]!='\0'; k++) {
762 if (fo->opts[k]=='W') {
763 enhanced_wild = true;
768 for (k=0; k<fo->regex.size(); k++) {
769 sendit(sock, " R %s\n", fo->regex.get(k));
771 for (k=0; k<fo->regexdir.size(); k++) {
772 sendit(sock, " RD %s\n", fo->regexdir.get(k));
774 for (k=0; k<fo->regexfile.size(); k++) {
775 sendit(sock, " RF %s\n", fo->regexfile.get(k));
777 for (k=0; k<fo->wild.size(); k++) {
778 sendit(sock, " W %s\n", fo->wild.get(k));
780 for (k=0; k<fo->wilddir.size(); k++) {
781 sendit(sock, " WD %s\n", fo->wilddir.get(k));
783 for (k=0; k<fo->wildfile.size(); k++) {
784 sendit(sock, " WF %s\n", fo->wildfile.get(k));
786 for (k=0; k<fo->wildbase.size(); k++) {
787 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
789 for (k=0; k<fo->base.size(); k++) {
790 sendit(sock, " B %s\n", fo->base.get(k));
792 for (k=0; k<fo->fstype.size(); k++) {
793 sendit(sock, " X %s\n", fo->fstype.get(k));
795 for (k=0; k<fo->drivetype.size(); k++) {
796 sendit(sock, " XD %s\n", fo->drivetype.get(k));
799 sendit(sock, " G %s\n", fo->plugin);
802 sendit(sock, " D %s\n", fo->reader);
805 sendit(sock, " T %s\n", fo->writer);
807 sendit(sock, " N\n");
809 if (incexe->ignoredir) {
810 sendit(sock, " Z %s\n", incexe->ignoredir);
812 for (j=0; j<incexe->name_list.size(); j++) {
813 sendit(sock, " I %s\n", incexe->name_list.get(j));
815 if (incexe->name_list.size()) {
816 sendit(sock, " N\n");
818 for (j=0; j<incexe->plugin_list.size(); j++) {
819 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
821 if (incexe->plugin_list.size()) {
822 sendit(sock, " N\n");
827 for (i=0; i<res->res_fs.num_excludes; i++) {
828 INCEXE *incexe = res->res_fs.exclude_items[i];
829 for (j=0; j<incexe->name_list.size(); j++) {
830 sendit(sock, " E %s\n", incexe->name_list.get(j));
832 if (incexe->name_list.size()) {
833 sendit(sock, " N\n");
840 if (res->res_sch.run) {
842 RUN *run = res->res_sch.run;
843 char buf[1000], num[30];
844 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
849 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
850 bstrncpy(buf, _(" hour="), sizeof(buf));
851 for (i=0; i<24; i++) {
852 if (bit_is_set(i, run->hour)) {
853 bsnprintf(num, sizeof(num), "%d ", i);
854 bstrncat(buf, num, sizeof(buf));
857 bstrncat(buf, "\n", sizeof(buf));
859 bstrncpy(buf, _(" mday="), sizeof(buf));
860 for (i=0; i<31; i++) {
861 if (bit_is_set(i, run->mday)) {
862 bsnprintf(num, sizeof(num), "%d ", i);
863 bstrncat(buf, num, sizeof(buf));
866 bstrncat(buf, "\n", sizeof(buf));
868 bstrncpy(buf, _(" month="), sizeof(buf));
869 for (i=0; i<12; i++) {
870 if (bit_is_set(i, run->month)) {
871 bsnprintf(num, sizeof(num), "%d ", i);
872 bstrncat(buf, num, sizeof(buf));
875 bstrncat(buf, "\n", sizeof(buf));
877 bstrncpy(buf, _(" wday="), sizeof(buf));
878 for (i=0; i<7; i++) {
879 if (bit_is_set(i, run->wday)) {
880 bsnprintf(num, sizeof(num), "%d ", i);
881 bstrncat(buf, num, sizeof(buf));
884 bstrncat(buf, "\n", sizeof(buf));
886 bstrncpy(buf, _(" wom="), sizeof(buf));
887 for (i=0; i<5; i++) {
888 if (bit_is_set(i, run->wom)) {
889 bsnprintf(num, sizeof(num), "%d ", i);
890 bstrncat(buf, num, sizeof(buf));
893 bstrncat(buf, "\n", sizeof(buf));
895 bstrncpy(buf, _(" woy="), sizeof(buf));
896 for (i=0; i<54; i++) {
897 if (bit_is_set(i, run->woy)) {
898 bsnprintf(num, sizeof(num), "%d ", i);
899 bstrncat(buf, num, sizeof(buf));
902 bstrncat(buf, "\n", sizeof(buf));
904 sendit(sock, _(" mins=%d\n"), run->minute);
906 sendit(sock, _(" --> "));
907 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
910 sendit(sock, _(" --> "));
911 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
914 sendit(sock, _(" --> "));
915 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
917 /* If another Run record is chained in, go print it */
923 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
928 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
929 res->res_pool.pool_type);
930 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
931 res->res_pool.use_catalog, res->res_pool.use_volume_once,
932 res->res_pool.catalog_files);
933 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
934 res->res_pool.max_volumes, res->res_pool.AutoPrune,
935 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
936 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
937 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
938 res->res_pool.Recycle,
939 NPRT(res->res_pool.label_format));
940 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
941 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
942 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
943 res->res_pool.recycle_oldest_volume,
944 res->res_pool.purge_oldest_volume);
945 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
946 res->res_pool.MaxVolJobs,
947 res->res_pool.MaxVolFiles,
948 edit_uint64(res->res_pool.MaxVolBytes, ed1));
949 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
950 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
951 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
952 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
953 if (res->res_pool.NextPool) {
954 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
956 if (res->res_pool.RecyclePool) {
957 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
959 if (res->res_pool.ScratchPool) {
960 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
962 if (res->res_pool.catalog) {
963 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
965 if (res->res_pool.storage) {
967 foreach_alist(store, res->res_pool.storage) {
968 sendit(sock, _(" --> "));
969 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
972 if (res->res_pool.CopyPool) {
974 foreach_alist(copy, res->res_pool.CopyPool) {
975 sendit(sock, _(" --> "));
976 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
983 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
984 if (res->res_msgs.mail_cmd)
985 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
986 if (res->res_msgs.operator_cmd)
987 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
991 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
994 if (recurse && res->res_dir.hdr.next) {
995 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1000 * Free all the members of an INCEXE structure
1002 static void free_incexe(INCEXE *incexe)
1004 incexe->name_list.destroy();
1005 incexe->plugin_list.destroy();
1006 for (int i=0; i<incexe->num_opts; i++) {
1007 FOPTS *fopt = incexe->opts_list[i];
1008 fopt->regex.destroy();
1009 fopt->regexdir.destroy();
1010 fopt->regexfile.destroy();
1011 fopt->wild.destroy();
1012 fopt->wilddir.destroy();
1013 fopt->wildfile.destroy();
1014 fopt->wildbase.destroy();
1015 fopt->base.destroy();
1016 fopt->fstype.destroy();
1017 fopt->drivetype.destroy();
1029 if (incexe->opts_list) {
1030 free(incexe->opts_list);
1032 if (incexe->ignoredir) {
1033 free(incexe->ignoredir);
1039 * Free memory of resource -- called when daemon terminates.
1040 * NB, we don't need to worry about freeing any references
1041 * to other resources as they will be freed when that
1042 * resource chain is traversed. Mainly we worry about freeing
1043 * allocated strings (names).
1045 void free_resource(RES *sres, int type)
1048 RES *nres; /* next resource if linked */
1049 URES *res = (URES *)sres;
1054 /* common stuff -- free the resource name and description */
1055 nres = (RES *)res->res_dir.hdr.next;
1056 if (res->res_dir.hdr.name) {
1057 free(res->res_dir.hdr.name);
1059 if (res->res_dir.hdr.desc) {
1060 free(res->res_dir.hdr.desc);
1065 if (res->res_dir.working_directory) {
1066 free(res->res_dir.working_directory);
1068 if (res->res_dir.scripts_directory) {
1069 free((char *)res->res_dir.scripts_directory);
1071 if (res->res_dir.plugin_directory) {
1072 free((char *)res->res_dir.plugin_directory);
1074 if (res->res_dir.pid_directory) {
1075 free(res->res_dir.pid_directory);
1077 if (res->res_dir.subsys_directory) {
1078 free(res->res_dir.subsys_directory);
1080 if (res->res_dir.password) {
1081 free(res->res_dir.password);
1083 if (res->res_dir.query_file) {
1084 free(res->res_dir.query_file);
1086 if (res->res_dir.DIRaddrs) {
1087 free_addresses(res->res_dir.DIRaddrs);
1089 if (res->res_dir.DIRsrc_addr) {
1090 free_addresses(res->res_dir.DIRsrc_addr);
1092 if (res->res_dir.tls_ctx) {
1093 free_tls_context(res->res_dir.tls_ctx);
1095 if (res->res_dir.tls_ca_certfile) {
1096 free(res->res_dir.tls_ca_certfile);
1098 if (res->res_dir.tls_ca_certdir) {
1099 free(res->res_dir.tls_ca_certdir);
1101 if (res->res_dir.tls_certfile) {
1102 free(res->res_dir.tls_certfile);
1104 if (res->res_dir.tls_keyfile) {
1105 free(res->res_dir.tls_keyfile);
1107 if (res->res_dir.tls_dhfile) {
1108 free(res->res_dir.tls_dhfile);
1110 if (res->res_dir.tls_allowed_cns) {
1111 delete res->res_dir.tls_allowed_cns;
1113 if (res->res_dir.verid) {
1114 free(res->res_dir.verid);
1121 if (res->res_con.password) {
1122 free(res->res_con.password);
1124 if (res->res_con.tls_ctx) {
1125 free_tls_context(res->res_con.tls_ctx);
1127 if (res->res_con.tls_ca_certfile) {
1128 free(res->res_con.tls_ca_certfile);
1130 if (res->res_con.tls_ca_certdir) {
1131 free(res->res_con.tls_ca_certdir);
1133 if (res->res_con.tls_certfile) {
1134 free(res->res_con.tls_certfile);
1136 if (res->res_con.tls_keyfile) {
1137 free(res->res_con.tls_keyfile);
1139 if (res->res_con.tls_dhfile) {
1140 free(res->res_con.tls_dhfile);
1142 if (res->res_con.tls_allowed_cns) {
1143 delete res->res_con.tls_allowed_cns;
1145 for (int i=0; i<Num_ACL; i++) {
1146 if (res->res_con.ACL_lists[i]) {
1147 delete res->res_con.ACL_lists[i];
1148 res->res_con.ACL_lists[i] = NULL;
1153 if (res->res_client.address) {
1154 free(res->res_client.address);
1156 if (res->res_client.password) {
1157 free(res->res_client.password);
1159 if (res->res_client.tls_ctx) {
1160 free_tls_context(res->res_client.tls_ctx);
1162 if (res->res_client.tls_ca_certfile) {
1163 free(res->res_client.tls_ca_certfile);
1165 if (res->res_client.tls_ca_certdir) {
1166 free(res->res_client.tls_ca_certdir);
1168 if (res->res_client.tls_certfile) {
1169 free(res->res_client.tls_certfile);
1171 if (res->res_client.tls_keyfile) {
1172 free(res->res_client.tls_keyfile);
1174 if (res->res_client.tls_allowed_cns) {
1175 delete res->res_client.tls_allowed_cns;
1179 if (res->res_store.address) {
1180 free(res->res_store.address);
1182 if (res->res_store.password) {
1183 free(res->res_store.password);
1185 if (res->res_store.media_type) {
1186 free(res->res_store.media_type);
1188 if (res->res_store.device) {
1189 delete res->res_store.device;
1191 if (res->res_store.tls_ctx) {
1192 free_tls_context(res->res_store.tls_ctx);
1194 if (res->res_store.tls_ca_certfile) {
1195 free(res->res_store.tls_ca_certfile);
1197 if (res->res_store.tls_ca_certdir) {
1198 free(res->res_store.tls_ca_certdir);
1200 if (res->res_store.tls_certfile) {
1201 free(res->res_store.tls_certfile);
1203 if (res->res_store.tls_keyfile) {
1204 free(res->res_store.tls_keyfile);
1208 if (res->res_cat.db_address) {
1209 free(res->res_cat.db_address);
1211 if (res->res_cat.db_socket) {
1212 free(res->res_cat.db_socket);
1214 if (res->res_cat.db_user) {
1215 free(res->res_cat.db_user);
1217 if (res->res_cat.db_name) {
1218 free(res->res_cat.db_name);
1220 if (res->res_cat.db_driver) {
1221 free(res->res_cat.db_driver);
1223 if (res->res_cat.db_password) {
1224 free(res->res_cat.db_password);
1228 if ((num=res->res_fs.num_includes)) {
1229 while (--num >= 0) {
1230 free_incexe(res->res_fs.include_items[num]);
1232 free(res->res_fs.include_items);
1234 res->res_fs.num_includes = 0;
1235 if ((num=res->res_fs.num_excludes)) {
1236 while (--num >= 0) {
1237 free_incexe(res->res_fs.exclude_items[num]);
1239 free(res->res_fs.exclude_items);
1241 res->res_fs.num_excludes = 0;
1244 if (res->res_pool.pool_type) {
1245 free(res->res_pool.pool_type);
1247 if (res->res_pool.label_format) {
1248 free(res->res_pool.label_format);
1250 if (res->res_pool.cleaning_prefix) {
1251 free(res->res_pool.cleaning_prefix);
1253 if (res->res_pool.storage) {
1254 delete res->res_pool.storage;
1258 if (res->res_sch.run) {
1260 nrun = res->res_sch.run;
1270 if (res->res_job.RestoreWhere) {
1271 free(res->res_job.RestoreWhere);
1273 if (res->res_job.RegexWhere) {
1274 free(res->res_job.RegexWhere);
1276 if (res->res_job.strip_prefix) {
1277 free(res->res_job.strip_prefix);
1279 if (res->res_job.add_prefix) {
1280 free(res->res_job.add_prefix);
1282 if (res->res_job.add_suffix) {
1283 free(res->res_job.add_suffix);
1285 if (res->res_job.RestoreBootstrap) {
1286 free(res->res_job.RestoreBootstrap);
1288 if (res->res_job.WriteBootstrap) {
1289 free(res->res_job.WriteBootstrap);
1291 if (res->res_job.PluginOptions) {
1292 free(res->res_job.PluginOptions);
1294 if (res->res_job.selection_pattern) {
1295 free(res->res_job.selection_pattern);
1297 if (res->res_job.run_cmds) {
1298 delete res->res_job.run_cmds;
1300 if (res->res_job.storage) {
1301 delete res->res_job.storage;
1303 if (res->res_job.RunScripts) {
1304 free_runscripts(res->res_job.RunScripts);
1305 delete res->res_job.RunScripts;
1309 if (res->res_msgs.mail_cmd) {
1310 free(res->res_msgs.mail_cmd);
1312 if (res->res_msgs.operator_cmd) {
1313 free(res->res_msgs.operator_cmd);
1315 free_msgs_res((MSGS *)res); /* free message resource */
1319 printf(_("Unknown resource type %d in free_resource.\n"), type);
1321 /* Common stuff again -- free the resource, recurse to next one */
1326 free_resource(nres, type);
1331 * Save the new resource by chaining it into the head list for
1332 * the resource. If this is pass 2, we update any resource
1333 * pointers because they may not have been defined until
1336 void save_resource(int type, RES_ITEM *items, int pass)
1339 int rindex = type - r_first;
1343 /* Check Job requirements after applying JobDefs */
1344 if (type != R_JOB && type != R_JOBDEFS) {
1346 * Ensure that all required items are present
1348 for (i=0; items[i].name; i++) {
1349 if (items[i].flags & ITEM_REQUIRED) {
1350 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1351 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1352 items[i].name, resources[rindex]);
1355 /* If this triggers, take a look at lib/parse_conf.h */
1356 if (i >= MAX_RES_ITEMS) {
1357 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1360 } else if (type == R_JOB) {
1362 * Ensure that the name item is present
1364 if (items[0].flags & ITEM_REQUIRED) {
1365 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1366 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1367 items[0].name, resources[rindex]);
1373 * During pass 2 in each "store" routine, we looked up pointers
1374 * to all the resources referrenced in the current resource, now we
1375 * must copy their addresses from the static record to the allocated
1380 /* Resources not containing a resource */
1388 * Resources containing another resource or alist. First
1389 * look up the resource which contains another resource. It
1390 * was written during pass 1. Then stuff in the pointers to
1391 * the resources it contains, which were inserted this pass.
1392 * Finally, it will all be stored back.
1395 /* Find resource saved in pass 1 */
1396 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1397 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1399 /* Explicitly copy resource pointers from this pass (res_all) */
1400 res->res_pool.NextPool = res_all.res_pool.NextPool;
1401 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1402 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1403 res->res_pool.storage = res_all.res_pool.storage;
1404 res->res_pool.catalog = res_all.res_pool.catalog;
1407 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1408 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1410 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1413 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1414 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1416 res->res_dir.messages = res_all.res_dir.messages;
1417 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1420 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1421 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1422 res_all.res_dir.hdr.name);
1424 /* we must explicitly copy the device alist pointer */
1425 res->res_store.device = res_all.res_store.device;
1429 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1430 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1431 res_all.res_dir.hdr.name);
1433 res->res_job.messages = res_all.res_job.messages;
1434 res->res_job.schedule = res_all.res_job.schedule;
1435 res->res_job.client = res_all.res_job.client;
1436 res->res_job.fileset = res_all.res_job.fileset;
1437 res->res_job.storage = res_all.res_job.storage;
1438 res->res_job.pool = res_all.res_job.pool;
1439 res->res_job.full_pool = res_all.res_job.full_pool;
1440 res->res_job.inc_pool = res_all.res_job.inc_pool;
1441 res->res_job.diff_pool = res_all.res_job.diff_pool;
1442 res->res_job.verify_job = res_all.res_job.verify_job;
1443 res->res_job.jobdefs = res_all.res_job.jobdefs;
1444 res->res_job.run_cmds = res_all.res_job.run_cmds;
1445 res->res_job.RunScripts = res_all.res_job.RunScripts;
1447 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1448 * is not very useful)
1449 * We have to set_bit(index, res_all.hdr.item_present);
1450 * or something like that
1453 /* we take RegexWhere before all other options */
1454 if (!res->res_job.RegexWhere
1456 (res->res_job.strip_prefix ||
1457 res->res_job.add_suffix ||
1458 res->res_job.add_prefix))
1460 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1461 res->res_job.add_prefix,
1462 res->res_job.add_suffix);
1463 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1464 bregexp_build_where(res->res_job.RegexWhere, len,
1465 res->res_job.strip_prefix,
1466 res->res_job.add_prefix,
1467 res->res_job.add_suffix);
1468 /* TODO: test bregexp */
1471 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1472 free(res->res_job.RestoreWhere);
1473 res->res_job.RestoreWhere = NULL;
1478 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1479 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1481 res->res_counter.Catalog = res_all.res_counter.Catalog;
1482 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1486 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1487 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1489 res->res_client.catalog = res_all.res_client.catalog;
1490 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1494 * Schedule is a bit different in that it contains a RUN record
1495 * chain which isn't a "named" resource. This chain was linked
1496 * in by run_conf.c during pass 2, so here we jam the pointer
1497 * into the Schedule resource.
1499 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1500 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1502 res->res_sch.run = res_all.res_sch.run;
1505 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1509 /* Note, the resource name was already saved during pass 1,
1510 * so here, we can just release it.
1512 if (res_all.res_dir.hdr.name) {
1513 free(res_all.res_dir.hdr.name);
1514 res_all.res_dir.hdr.name = NULL;
1516 if (res_all.res_dir.hdr.desc) {
1517 free(res_all.res_dir.hdr.desc);
1518 res_all.res_dir.hdr.desc = NULL;
1524 * The following code is only executed during pass 1
1528 size = sizeof(DIRRES);
1531 size = sizeof(CONRES);
1534 size =sizeof(CLIENT);
1537 size = sizeof(STORE);
1547 size = sizeof(FILESET);
1550 size = sizeof(SCHED);
1553 size = sizeof(POOL);
1556 size = sizeof(MSGS);
1559 size = sizeof(COUNTER);
1565 printf(_("Unknown resource type %d in save_resource.\n"), type);
1571 res = (URES *)malloc(size);
1572 memcpy(res, &res_all, size);
1573 if (!res_head[rindex]) {
1574 res_head[rindex] = (RES *)res; /* store first entry */
1575 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1576 res->res_dir.hdr.name, rindex);
1579 if (res->res_dir.hdr.name == NULL) {
1580 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1583 /* Add new res to end of chain */
1584 for (last=next=res_head[rindex]; next; next=next->next) {
1586 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1587 Emsg2(M_ERROR_TERM, 0,
1588 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1589 resources[rindex].name, res->res_dir.hdr.name);
1592 last->next = (RES *)res;
1593 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1594 res->res_dir.hdr.name, rindex, pass);
1600 * Store Device. Note, the resource is created upon the
1601 * first reference. The details of the resource are obtained
1602 * later from the SD.
1604 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1608 int rindex = R_DEVICE - r_first;
1609 int size = sizeof(DEVICE);
1613 token = lex_get_token(lc, T_NAME);
1614 if (!res_head[rindex]) {
1615 res = (URES *)malloc(size);
1616 memset(res, 0, size);
1617 res->res_dev.hdr.name = bstrdup(lc->str);
1618 res_head[rindex] = (RES *)res; /* store first entry */
1619 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1620 res->res_dir.hdr.name, rindex);
1623 /* See if it is already defined */
1624 for (next=res_head[rindex]; next->next; next=next->next) {
1625 if (strcmp(next->name, lc->str) == 0) {
1631 res = (URES *)malloc(size);
1632 memset(res, 0, size);
1633 res->res_dev.hdr.name = bstrdup(lc->str);
1634 next->next = (RES *)res;
1635 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1636 res->res_dir.hdr.name, rindex, pass);
1641 set_bit(index, res_all.hdr.item_present);
1643 store_alist_res(lc, item, index, pass);
1648 * Store Migration/Copy type
1651 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1655 token = lex_get_token(lc, T_NAME);
1656 /* Store the type both pass 1 and pass 2 */
1657 for (i=0; migtypes[i].type_name; i++) {
1658 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1659 *(uint32_t *)(item->value) = migtypes[i].job_type;
1665 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1668 set_bit(index, res_all.hdr.item_present);
1674 * Store JobType (backup, verify, restore)
1677 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1681 token = lex_get_token(lc, T_NAME);
1682 /* Store the type both pass 1 and pass 2 */
1683 for (i=0; jobtypes[i].type_name; i++) {
1684 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1685 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1691 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1694 set_bit(index, res_all.hdr.item_present);
1698 * Store Job Level (Full, Incremental, ...)
1701 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1705 token = lex_get_token(lc, T_NAME);
1706 /* Store the level pass 2 so that type is defined */
1707 for (i=0; joblevels[i].level_name; i++) {
1708 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1709 *(uint32_t *)(item->value) = joblevels[i].level;
1715 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1718 set_bit(index, res_all.hdr.item_present);
1722 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1725 token = lex_get_token(lc, T_NAME);
1726 /* Scan Replacement options */
1727 for (i=0; ReplaceOptions[i].name; i++) {
1728 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1729 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1735 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1738 set_bit(index, res_all.hdr.item_present);
1742 * Store ACL (access control list)
1745 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1750 token = lex_get_token(lc, T_STRING);
1752 if (((alist **)item->value)[item->code] == NULL) {
1753 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1754 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1756 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1757 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1759 token = lex_get_token(lc, T_ALL);
1760 if (token == T_COMMA) {
1761 continue; /* get another ACL */
1765 set_bit(index, res_all.hdr.item_present);
1768 /* We build RunScripts items here */
1769 static RUNSCRIPT res_runscript;
1771 /* Store a runscript->when in a bit field */
1772 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1774 lex_get_token(lc, T_NAME);
1776 if (strcasecmp(lc->str, "before") == 0) {
1777 *(uint32_t *)(item->value) = SCRIPT_Before ;
1778 } else if (strcasecmp(lc->str, "after") == 0) {
1779 *(uint32_t *)(item->value) = SCRIPT_After;
1780 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1781 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1782 } else if (strcasecmp(lc->str, "always") == 0) {
1783 *(uint32_t *)(item->value) = SCRIPT_Any;
1785 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1790 /* Store a runscript->target
1793 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1795 lex_get_token(lc, T_STRING);
1798 if (strcmp(lc->str, "%c") == 0) {
1799 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1800 } else if (strcasecmp(lc->str, "yes") == 0) {
1801 ((RUNSCRIPT*) item->value)->set_target("%c");
1802 } else if (strcasecmp(lc->str, "no") == 0) {
1803 ((RUNSCRIPT*) item->value)->set_target("");
1805 RES *res = GetResWithName(R_CLIENT, lc->str);
1807 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1808 lc->str, lc->line_no, lc->line);
1811 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1818 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1820 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1822 lex_get_token(lc, T_STRING);
1825 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1826 POOLMEM *c = get_pool_memory(PM_FNAME);
1827 /* Each runscript command takes 2 entries in commands list */
1828 pm_strcpy(c, lc->str);
1829 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1830 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1835 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1837 lex_get_token(lc, T_STRING);
1838 alist **runscripts = (alist **)(item->value) ;
1841 RUNSCRIPT *script = new_runscript();
1842 script->set_job_code_callback(job_code_callback_filesetname);
1844 script->set_command(lc->str);
1846 /* TODO: remove all script->old_proto with bacula 1.42 */
1848 if (strcmp(item->name, "runbeforejob") == 0) {
1849 script->when = SCRIPT_Before;
1850 script->fail_on_error = true;
1851 script->set_target("");
1853 } else if (strcmp(item->name, "runafterjob") == 0) {
1854 script->when = SCRIPT_After;
1855 script->on_success = true;
1856 script->on_failure = false;
1857 script->set_target("");
1859 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1860 script->old_proto = true;
1861 script->when = SCRIPT_After;
1862 script->set_target("%c");
1863 script->on_success = true;
1864 script->on_failure = false;
1866 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1867 script->old_proto = true;
1868 script->when = SCRIPT_Before;
1869 script->set_target("%c");
1870 script->fail_on_error = true;
1872 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1873 script->when = SCRIPT_After;
1874 script->on_failure = true;
1875 script->on_success = false;
1876 script->set_target("");
1879 if (*runscripts == NULL) {
1880 *runscripts = New(alist(10, not_owned_by_alist));
1883 (*runscripts)->append(script);
1890 /* Store a bool in a bit field without modifing res_all.hdr
1891 * We can also add an option to store_bool to skip res_all.hdr
1893 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1895 lex_get_token(lc, T_NAME);
1896 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1897 *(bool *)(item->value) = true;
1898 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1899 *(bool *)(item->value) = false;
1901 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1907 * new RunScript items
1908 * name handler value code flags default_value
1910 static RES_ITEM runscript_items[] = {
1911 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1912 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1913 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1914 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1915 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1916 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1917 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1918 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1919 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1920 {NULL, NULL, {0}, 0, 0, 0}
1924 * Store RunScript info
1926 * Note, when this routine is called, we are inside a Job
1927 * resource. We treat the RunScript like a sort of
1928 * mini-resource within the Job resource.
1930 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1934 alist **runscripts = (alist **)(item->value) ;
1936 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1938 token = lex_get_token(lc, T_SKIP_EOL);
1940 if (token != T_BOB) {
1941 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1943 /* setting on_success, on_failure, fail_on_error */
1944 res_runscript.reset_default();
1947 res_runscript.commands = New(alist(10, not_owned_by_alist));
1950 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1951 if (token == T_EOB) {
1954 if (token != T_IDENTIFIER) {
1955 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1957 for (i=0; runscript_items[i].name; i++) {
1958 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1959 token = lex_get_token(lc, T_SKIP_EOL);
1960 if (token != T_EQUALS) {
1961 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1964 /* Call item handler */
1965 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1972 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1977 /* run on client by default */
1978 if (res_runscript.target == NULL) {
1979 res_runscript.set_target("%c");
1981 if (*runscripts == NULL) {
1982 *runscripts = New(alist(10, not_owned_by_alist));
1985 * commands list contains 2 values per command
1986 * - POOLMEM command string (ex: /bin/true)
1987 * - int command type (ex: SHELL_CMD)
1989 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1990 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1991 t = (intptr_t)res_runscript.commands->pop();
1992 RUNSCRIPT *script = new_runscript();
1993 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1994 script->command = c;
1995 script->cmd_type = t;
1996 /* target is taken from res_runscript, each runscript object have
1999 script->target = NULL;
2000 script->set_target(res_runscript.target);
2002 (*runscripts)->append(script);
2005 delete res_runscript.commands;
2006 /* setting on_success, on_failure... cleanup target field */
2007 res_runscript.reset_default(true);
2011 set_bit(index, res_all.hdr.item_present);
2014 /* callback function for edit_job_codes */
2015 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2017 if (param[0] == 'f') {
2018 return jcr->fileset->name();
2024 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2026 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2027 r_first, r_last, resources, res_head);
2028 return config->parse_config();