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 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
116 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
117 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
118 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
119 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
120 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
121 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
122 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
123 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
124 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
125 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
126 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
127 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
128 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
129 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
130 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
131 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
132 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
133 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
134 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
135 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
136 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
137 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
138 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
139 {NULL, NULL, {0}, 0, 0, 0}
145 * name handler value code flags default_value
147 static RES_ITEM con_items[] = {
148 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
149 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
150 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
151 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
152 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
153 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
154 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
155 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
156 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
157 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
158 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
159 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
160 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
161 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
162 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
163 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
164 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
165 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
166 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
167 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
168 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
169 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
170 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
171 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
172 {NULL, NULL, {0}, 0, 0, 0}
177 * Client or File daemon resource
179 * name handler value code flags default_value
182 static RES_ITEM cli_items[] = {
183 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
184 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
185 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
186 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
187 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
188 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
189 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
190 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
191 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
192 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
193 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
194 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
195 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
196 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
197 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
198 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
199 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
200 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
201 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
202 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
203 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
204 {NULL, NULL, {0}, 0, 0, 0}
207 /* Storage daemon resource
209 * name handler value code flags default_value
211 static RES_ITEM store_items[] = {
212 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
213 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
214 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
215 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
216 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
217 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
218 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
219 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
220 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
221 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
222 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
223 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
224 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
225 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
226 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
227 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
228 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
229 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
230 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
231 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
232 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
233 {NULL, NULL, {0}, 0, 0, 0}
237 * Catalog Resource Directives
239 * name handler value code flags default_value
241 static RES_ITEM cat_items[] = {
242 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
243 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
244 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
245 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
246 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
247 /* keep this password as store_str for the moment */
248 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
249 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
250 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
251 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
252 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
253 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
254 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
255 /* Turned off for the moment */
256 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
257 {NULL, NULL, {0}, 0, 0, 0}
261 * Job Resource Directives
263 * name handler value code flags default_value
265 RES_ITEM job_items[] = {
266 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
267 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
268 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
269 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
270 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
271 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
272 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
273 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
274 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
275 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
276 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
277 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
278 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
279 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
280 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
281 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
282 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
283 /* Root of where to restore files */
284 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
285 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
286 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
287 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
288 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
289 /* Where to find bootstrap during restore */
290 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
291 /* Where to write bootstrap file during backup */
292 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
293 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
294 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
295 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
296 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
297 /* xxxMaxWaitTime are deprecated */
298 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
299 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
300 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
301 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
302 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
303 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
304 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
305 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
306 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
307 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
308 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
309 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
310 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
311 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
312 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
313 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
314 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
315 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
316 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
317 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
318 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
319 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
320 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
325 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
326 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
327 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
328 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
329 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
330 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
331 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
332 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
333 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
334 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
335 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
336 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
337 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
338 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
339 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
340 {NULL, NULL, {0}, 0, 0, 0}
345 * name handler value code flags default_value
347 static RES_ITEM fs_items[] = {
348 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
349 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
350 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
351 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
352 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
353 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
354 {NULL, NULL, {0}, 0, 0, 0}
357 /* Schedule -- see run_conf.c */
360 * name handler value code flags default_value
362 static RES_ITEM sch_items[] = {
363 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
364 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
365 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
366 {NULL, NULL, {0}, 0, 0, 0}
371 * name handler value code flags default_value
373 static RES_ITEM pool_items[] = {
374 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
375 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
376 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
377 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
378 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
379 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
380 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
381 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
382 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
383 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
384 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
385 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
386 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
387 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
388 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
389 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
390 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
391 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
392 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
393 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
394 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
395 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
396 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
397 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
398 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
399 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
400 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
401 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
402 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
403 {NULL, NULL, {0}, 0, 0, 0}
408 * name handler value code flags default_value
410 static RES_ITEM counter_items[] = {
411 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
412 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
413 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
414 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
415 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
416 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
417 {NULL, NULL, {0}, 0, 0, 0}
421 /* Message resource */
422 extern RES_ITEM msgs_items[];
425 * This is the master resource definition.
426 * It must have one item for each of the resources.
428 * NOTE!!! keep it in the same order as the R_codes
429 * or eliminate all resources[rindex].name
431 * name items rcode res_head
433 RES_TABLE resources[] = {
434 {"director", dir_items, R_DIRECTOR},
435 {"client", cli_items, R_CLIENT},
436 {"job", job_items, R_JOB},
437 {"storage", store_items, R_STORAGE},
438 {"catalog", cat_items, R_CATALOG},
439 {"schedule", sch_items, R_SCHEDULE},
440 {"fileset", fs_items, R_FILESET},
441 {"pool", pool_items, R_POOL},
442 {"messages", msgs_items, R_MSGS},
443 {"counter", counter_items, R_COUNTER},
444 {"console", con_items, R_CONSOLE},
445 {"jobdefs", job_items, R_JOBDEFS},
446 {"device", NULL, R_DEVICE}, /* info obtained from SD */
451 /* Keywords (RHS) permitted in Job Level records
453 * level_name level job_type
455 struct s_jl joblevels[] = {
456 {"Full", L_FULL, JT_BACKUP},
457 {"Base", L_BASE, JT_BACKUP},
458 {"Incremental", L_INCREMENTAL, JT_BACKUP},
459 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
460 {"Since", L_SINCE, JT_BACKUP},
461 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
462 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
463 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
464 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
465 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
466 {"Data", L_VERIFY_DATA, JT_VERIFY},
467 {" ", L_NONE, JT_ADMIN},
468 {" ", L_NONE, JT_RESTORE},
472 /* Keywords (RHS) permitted in Job type records
476 struct s_jt jobtypes[] = {
477 {"backup", JT_BACKUP},
479 {"verify", JT_VERIFY},
480 {"restore", JT_RESTORE},
481 {"migrate", JT_MIGRATE},
487 /* Keywords (RHS) permitted in Selection type records
491 struct s_jt migtypes[] = {
492 {"smallestvolume", MT_SMALLEST_VOL},
493 {"oldestvolume", MT_OLDEST_VOL},
494 {"pooloccupancy", MT_POOL_OCCUPANCY},
495 {"pooltime", MT_POOL_TIME},
496 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
497 {"client", MT_CLIENT},
498 {"volume", MT_VOLUME},
500 {"sqlquery", MT_SQLQUERY},
506 /* Options permitted in Restore replace= */
507 struct s_kw ReplaceOptions[] = {
508 {"always", REPLACE_ALWAYS},
509 {"ifnewer", REPLACE_IFNEWER},
510 {"ifolder", REPLACE_IFOLDER},
511 {"never", REPLACE_NEVER},
515 char *CAT::display(POOLMEM *dst) {
516 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
517 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
519 name(), NPRTB(db_name),
520 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
521 NPRTB(db_address), db_port, NPRTB(db_socket));
525 const char *level_to_str(int level)
528 static char level_no[30];
529 const char *str = level_no;
531 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
532 for (i=0; joblevels[i].level_name; i++) {
533 if (level == (int)joblevels[i].level) {
534 str = joblevels[i].level_name;
541 /* Dump contents of resource */
542 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
544 URES *res = (URES *)reshdr;
546 char ed1[100], ed2[100], ed3[100];
550 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
553 if (type < 0) { /* no recursion */
559 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
560 reshdr->name, res->res_dir.MaxConcurrentJobs,
561 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
562 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
563 if (res->res_dir.query_file) {
564 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
566 if (res->res_dir.messages) {
567 sendit(sock, _(" --> "));
568 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
572 sendit(sock, _("Console: name=%s SSL=%d\n"),
573 res->res_con.hdr.name, res->res_con.tls_enable);
576 if (res->res_counter.WrapCounter) {
577 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
578 res->res_counter.hdr.name, res->res_counter.MinValue,
579 res->res_counter.MaxValue, res->res_counter.CurrentValue,
580 res->res_counter.WrapCounter->hdr.name);
582 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
583 res->res_counter.hdr.name, res->res_counter.MinValue,
584 res->res_counter.MaxValue);
586 if (res->res_counter.Catalog) {
587 sendit(sock, _(" --> "));
588 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
593 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
594 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
595 res->res_client.MaxConcurrentJobs);
596 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
597 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
598 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
599 res->res_client.AutoPrune);
600 if (res->res_client.catalog) {
601 sendit(sock, _(" --> "));
602 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
609 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
610 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
611 " poolid=%s volname=%s MediaType=%s\n"),
612 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
613 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
614 dev->offline, dev->autochanger,
615 edit_uint64(dev->PoolId, ed1),
616 dev->VolumeName, dev->MediaType);
620 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
621 " DeviceName=%s MediaType=%s StorageId=%s\n"),
622 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
623 res->res_store.MaxConcurrentJobs,
624 res->res_store.dev_name(),
625 res->res_store.media_type,
626 edit_int64(res->res_store.StorageId, ed1));
630 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
631 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
632 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
633 res->res_cat.db_port, res->res_cat.db_name,
634 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
635 res->res_cat.mult_db_connections);
640 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
641 type == R_JOB ? _("Job") : _("JobDefs"),
642 res->res_job.hdr.name, res->res_job.JobType,
643 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
644 res->res_job.enabled);
645 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
646 res->res_job.MaxConcurrentJobs,
647 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
648 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
649 res->res_job.spool_data, res->res_job.write_part_after_job);
650 if (res->res_job.spool_size) {
651 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
653 if (res->res_job.JobType == JT_BACKUP) {
654 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
656 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
657 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
659 if (res->res_job.client) {
660 sendit(sock, _(" --> "));
661 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
663 if (res->res_job.fileset) {
664 sendit(sock, _(" --> "));
665 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
667 if (res->res_job.schedule) {
668 sendit(sock, _(" --> "));
669 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
671 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
672 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
674 if (res->res_job.RegexWhere) {
675 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
677 if (res->res_job.RestoreBootstrap) {
678 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
680 if (res->res_job.WriteBootstrap) {
681 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
683 if (res->res_job.PluginOptions) {
684 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
686 if (res->res_job.MaxRunTime) {
687 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
689 if (res->res_job.MaxWaitTime) {
690 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
692 if (res->res_job.MaxStartDelay) {
693 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
695 if (res->res_job.storage) {
697 foreach_alist(store, res->res_job.storage) {
698 sendit(sock, _(" --> "));
699 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
702 if (res->res_job.RunScripts) {
704 foreach_alist(script, res->res_job.RunScripts) {
705 sendit(sock, _(" --> RunScript\n"));
706 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
707 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
708 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
709 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
710 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
711 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
714 if (res->res_job.pool) {
715 sendit(sock, _(" --> "));
716 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
718 if (res->res_job.full_pool) {
719 sendit(sock, _(" --> "));
720 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
722 if (res->res_job.inc_pool) {
723 sendit(sock, _(" --> "));
724 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
726 if (res->res_job.diff_pool) {
727 sendit(sock, _(" --> "));
728 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
730 if (res->res_job.verify_job) {
731 sendit(sock, _(" --> "));
732 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
734 if (res->res_job.run_cmds) {
736 foreach_alist(runcmd, res->res_job.run_cmds) {
737 sendit(sock, _(" --> Run=%s\n"), runcmd);
740 if (res->res_job.selection_pattern) {
741 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
743 if (res->res_job.messages) {
744 sendit(sock, _(" --> "));
745 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
752 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
753 for (i=0; i<res->res_fs.num_includes; i++) {
754 INCEXE *incexe = res->res_fs.include_items[i];
755 for (j=0; j<incexe->num_opts; j++) {
756 FOPTS *fo = incexe->opts_list[j];
757 sendit(sock, " O %s\n", fo->opts);
759 bool enhanced_wild = false;
760 for (k=0; fo->opts[k]!='\0'; k++) {
761 if (fo->opts[k]=='W') {
762 enhanced_wild = true;
767 for (k=0; k<fo->regex.size(); k++) {
768 sendit(sock, " R %s\n", fo->regex.get(k));
770 for (k=0; k<fo->regexdir.size(); k++) {
771 sendit(sock, " RD %s\n", fo->regexdir.get(k));
773 for (k=0; k<fo->regexfile.size(); k++) {
774 sendit(sock, " RF %s\n", fo->regexfile.get(k));
776 for (k=0; k<fo->wild.size(); k++) {
777 sendit(sock, " W %s\n", fo->wild.get(k));
779 for (k=0; k<fo->wilddir.size(); k++) {
780 sendit(sock, " WD %s\n", fo->wilddir.get(k));
782 for (k=0; k<fo->wildfile.size(); k++) {
783 sendit(sock, " WF %s\n", fo->wildfile.get(k));
785 for (k=0; k<fo->wildbase.size(); k++) {
786 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
788 for (k=0; k<fo->base.size(); k++) {
789 sendit(sock, " B %s\n", fo->base.get(k));
791 for (k=0; k<fo->fstype.size(); k++) {
792 sendit(sock, " X %s\n", fo->fstype.get(k));
794 for (k=0; k<fo->drivetype.size(); k++) {
795 sendit(sock, " XD %s\n", fo->drivetype.get(k));
798 sendit(sock, " G %s\n", fo->plugin);
801 sendit(sock, " D %s\n", fo->reader);
804 sendit(sock, " T %s\n", fo->writer);
806 sendit(sock, " N\n");
808 for (j=0; j<incexe->name_list.size(); j++) {
809 sendit(sock, " I %s\n", incexe->name_list.get(j));
811 if (incexe->name_list.size()) {
812 sendit(sock, " N\n");
814 for (j=0; j<incexe->plugin_list.size(); j++) {
815 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
817 if (incexe->plugin_list.size()) {
818 sendit(sock, " N\n");
823 for (i=0; i<res->res_fs.num_excludes; i++) {
824 INCEXE *incexe = res->res_fs.exclude_items[i];
825 for (j=0; j<incexe->name_list.size(); j++) {
826 sendit(sock, " E %s\n", incexe->name_list.get(j));
828 if (incexe->name_list.size()) {
829 sendit(sock, " N\n");
836 if (res->res_sch.run) {
838 RUN *run = res->res_sch.run;
839 char buf[1000], num[30];
840 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
845 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
846 bstrncpy(buf, _(" hour="), sizeof(buf));
847 for (i=0; i<24; i++) {
848 if (bit_is_set(i, run->hour)) {
849 bsnprintf(num, sizeof(num), "%d ", i);
850 bstrncat(buf, num, sizeof(buf));
853 bstrncat(buf, "\n", sizeof(buf));
855 bstrncpy(buf, _(" mday="), sizeof(buf));
856 for (i=0; i<31; i++) {
857 if (bit_is_set(i, run->mday)) {
858 bsnprintf(num, sizeof(num), "%d ", i);
859 bstrncat(buf, num, sizeof(buf));
862 bstrncat(buf, "\n", sizeof(buf));
864 bstrncpy(buf, _(" month="), sizeof(buf));
865 for (i=0; i<12; i++) {
866 if (bit_is_set(i, run->month)) {
867 bsnprintf(num, sizeof(num), "%d ", i);
868 bstrncat(buf, num, sizeof(buf));
871 bstrncat(buf, "\n", sizeof(buf));
873 bstrncpy(buf, _(" wday="), sizeof(buf));
874 for (i=0; i<7; i++) {
875 if (bit_is_set(i, run->wday)) {
876 bsnprintf(num, sizeof(num), "%d ", i);
877 bstrncat(buf, num, sizeof(buf));
880 bstrncat(buf, "\n", sizeof(buf));
882 bstrncpy(buf, _(" wom="), sizeof(buf));
883 for (i=0; i<5; i++) {
884 if (bit_is_set(i, run->wom)) {
885 bsnprintf(num, sizeof(num), "%d ", i);
886 bstrncat(buf, num, sizeof(buf));
889 bstrncat(buf, "\n", sizeof(buf));
891 bstrncpy(buf, _(" woy="), sizeof(buf));
892 for (i=0; i<54; i++) {
893 if (bit_is_set(i, run->woy)) {
894 bsnprintf(num, sizeof(num), "%d ", i);
895 bstrncat(buf, num, sizeof(buf));
898 bstrncat(buf, "\n", sizeof(buf));
900 sendit(sock, _(" mins=%d\n"), run->minute);
902 sendit(sock, _(" --> "));
903 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
906 sendit(sock, _(" --> "));
907 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
910 sendit(sock, _(" --> "));
911 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
913 /* If another Run record is chained in, go print it */
919 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
924 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
925 res->res_pool.pool_type);
926 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
927 res->res_pool.use_catalog, res->res_pool.use_volume_once,
928 res->res_pool.catalog_files);
929 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
930 res->res_pool.max_volumes, res->res_pool.AutoPrune,
931 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
932 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
933 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
934 res->res_pool.Recycle,
935 NPRT(res->res_pool.label_format));
936 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
937 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
938 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
939 res->res_pool.recycle_oldest_volume,
940 res->res_pool.purge_oldest_volume);
941 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
942 res->res_pool.MaxVolJobs,
943 res->res_pool.MaxVolFiles,
944 edit_uint64(res->res_pool.MaxVolFiles, ed1));
945 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
946 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
947 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
948 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
949 if (res->res_pool.NextPool) {
950 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
952 if (res->res_pool.RecyclePool) {
953 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
955 if (res->res_pool.ScratchPool) {
956 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
958 if (res->res_pool.catalog) {
959 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
961 if (res->res_pool.storage) {
963 foreach_alist(store, res->res_pool.storage) {
964 sendit(sock, _(" --> "));
965 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
968 if (res->res_pool.CopyPool) {
970 foreach_alist(copy, res->res_pool.CopyPool) {
971 sendit(sock, _(" --> "));
972 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
979 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
980 if (res->res_msgs.mail_cmd)
981 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
982 if (res->res_msgs.operator_cmd)
983 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
987 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
990 if (recurse && res->res_dir.hdr.next) {
991 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
996 * Free all the members of an INCEXE structure
998 static void free_incexe(INCEXE *incexe)
1000 incexe->name_list.destroy();
1001 incexe->plugin_list.destroy();
1002 for (int i=0; i<incexe->num_opts; i++) {
1003 FOPTS *fopt = incexe->opts_list[i];
1004 fopt->regex.destroy();
1005 fopt->regexdir.destroy();
1006 fopt->regexfile.destroy();
1007 fopt->wild.destroy();
1008 fopt->wilddir.destroy();
1009 fopt->wildfile.destroy();
1010 fopt->wildbase.destroy();
1011 fopt->base.destroy();
1012 fopt->fstype.destroy();
1013 fopt->drivetype.destroy();
1025 if (incexe->opts_list) {
1026 free(incexe->opts_list);
1032 * Free memory of resource -- called when daemon terminates.
1033 * NB, we don't need to worry about freeing any references
1034 * to other resources as they will be freed when that
1035 * resource chain is traversed. Mainly we worry about freeing
1036 * allocated strings (names).
1038 void free_resource(RES *sres, int type)
1041 RES *nres; /* next resource if linked */
1042 URES *res = (URES *)sres;
1047 /* common stuff -- free the resource name and description */
1048 nres = (RES *)res->res_dir.hdr.next;
1049 if (res->res_dir.hdr.name) {
1050 free(res->res_dir.hdr.name);
1052 if (res->res_dir.hdr.desc) {
1053 free(res->res_dir.hdr.desc);
1058 if (res->res_dir.working_directory) {
1059 free(res->res_dir.working_directory);
1061 if (res->res_dir.scripts_directory) {
1062 free((char *)res->res_dir.scripts_directory);
1064 if (res->res_dir.plugin_directory) {
1065 free((char *)res->res_dir.plugin_directory);
1067 if (res->res_dir.pid_directory) {
1068 free(res->res_dir.pid_directory);
1070 if (res->res_dir.subsys_directory) {
1071 free(res->res_dir.subsys_directory);
1073 if (res->res_dir.password) {
1074 free(res->res_dir.password);
1076 if (res->res_dir.query_file) {
1077 free(res->res_dir.query_file);
1079 if (res->res_dir.DIRaddrs) {
1080 free_addresses(res->res_dir.DIRaddrs);
1082 if (res->res_dir.tls_ctx) {
1083 free_tls_context(res->res_dir.tls_ctx);
1085 if (res->res_dir.tls_ca_certfile) {
1086 free(res->res_dir.tls_ca_certfile);
1088 if (res->res_dir.tls_ca_certdir) {
1089 free(res->res_dir.tls_ca_certdir);
1091 if (res->res_dir.tls_certfile) {
1092 free(res->res_dir.tls_certfile);
1094 if (res->res_dir.tls_keyfile) {
1095 free(res->res_dir.tls_keyfile);
1097 if (res->res_dir.tls_dhfile) {
1098 free(res->res_dir.tls_dhfile);
1100 if (res->res_dir.tls_allowed_cns) {
1101 delete res->res_dir.tls_allowed_cns;
1103 if (res->res_dir.verid) {
1104 free(res->res_dir.verid);
1111 if (res->res_con.password) {
1112 free(res->res_con.password);
1114 if (res->res_con.tls_ctx) {
1115 free_tls_context(res->res_con.tls_ctx);
1117 if (res->res_con.tls_ca_certfile) {
1118 free(res->res_con.tls_ca_certfile);
1120 if (res->res_con.tls_ca_certdir) {
1121 free(res->res_con.tls_ca_certdir);
1123 if (res->res_con.tls_certfile) {
1124 free(res->res_con.tls_certfile);
1126 if (res->res_con.tls_keyfile) {
1127 free(res->res_con.tls_keyfile);
1129 if (res->res_con.tls_dhfile) {
1130 free(res->res_con.tls_dhfile);
1132 if (res->res_con.tls_allowed_cns) {
1133 delete res->res_con.tls_allowed_cns;
1135 for (int i=0; i<Num_ACL; i++) {
1136 if (res->res_con.ACL_lists[i]) {
1137 delete res->res_con.ACL_lists[i];
1138 res->res_con.ACL_lists[i] = NULL;
1143 if (res->res_client.address) {
1144 free(res->res_client.address);
1146 if (res->res_client.password) {
1147 free(res->res_client.password);
1149 if (res->res_client.tls_ctx) {
1150 free_tls_context(res->res_client.tls_ctx);
1152 if (res->res_client.tls_ca_certfile) {
1153 free(res->res_client.tls_ca_certfile);
1155 if (res->res_client.tls_ca_certdir) {
1156 free(res->res_client.tls_ca_certdir);
1158 if (res->res_client.tls_certfile) {
1159 free(res->res_client.tls_certfile);
1161 if (res->res_client.tls_keyfile) {
1162 free(res->res_client.tls_keyfile);
1164 if (res->res_client.tls_allowed_cns) {
1165 delete res->res_client.tls_allowed_cns;
1169 if (res->res_store.address) {
1170 free(res->res_store.address);
1172 if (res->res_store.password) {
1173 free(res->res_store.password);
1175 if (res->res_store.media_type) {
1176 free(res->res_store.media_type);
1178 if (res->res_store.device) {
1179 delete res->res_store.device;
1181 if (res->res_store.tls_ctx) {
1182 free_tls_context(res->res_store.tls_ctx);
1184 if (res->res_store.tls_ca_certfile) {
1185 free(res->res_store.tls_ca_certfile);
1187 if (res->res_store.tls_ca_certdir) {
1188 free(res->res_store.tls_ca_certdir);
1190 if (res->res_store.tls_certfile) {
1191 free(res->res_store.tls_certfile);
1193 if (res->res_store.tls_keyfile) {
1194 free(res->res_store.tls_keyfile);
1198 if (res->res_cat.db_address) {
1199 free(res->res_cat.db_address);
1201 if (res->res_cat.db_socket) {
1202 free(res->res_cat.db_socket);
1204 if (res->res_cat.db_user) {
1205 free(res->res_cat.db_user);
1207 if (res->res_cat.db_name) {
1208 free(res->res_cat.db_name);
1210 if (res->res_cat.db_driver) {
1211 free(res->res_cat.db_driver);
1213 if (res->res_cat.db_password) {
1214 free(res->res_cat.db_password);
1218 if ((num=res->res_fs.num_includes)) {
1219 while (--num >= 0) {
1220 free_incexe(res->res_fs.include_items[num]);
1222 free(res->res_fs.include_items);
1224 res->res_fs.num_includes = 0;
1225 if ((num=res->res_fs.num_excludes)) {
1226 while (--num >= 0) {
1227 free_incexe(res->res_fs.exclude_items[num]);
1229 free(res->res_fs.exclude_items);
1231 res->res_fs.num_excludes = 0;
1234 if (res->res_pool.pool_type) {
1235 free(res->res_pool.pool_type);
1237 if (res->res_pool.label_format) {
1238 free(res->res_pool.label_format);
1240 if (res->res_pool.cleaning_prefix) {
1241 free(res->res_pool.cleaning_prefix);
1243 if (res->res_pool.storage) {
1244 delete res->res_pool.storage;
1248 if (res->res_sch.run) {
1250 nrun = res->res_sch.run;
1260 if (res->res_job.RestoreWhere) {
1261 free(res->res_job.RestoreWhere);
1263 if (res->res_job.RegexWhere) {
1264 free(res->res_job.RegexWhere);
1266 if (res->res_job.strip_prefix) {
1267 free(res->res_job.strip_prefix);
1269 if (res->res_job.add_prefix) {
1270 free(res->res_job.add_prefix);
1272 if (res->res_job.add_suffix) {
1273 free(res->res_job.add_suffix);
1275 if (res->res_job.RestoreBootstrap) {
1276 free(res->res_job.RestoreBootstrap);
1278 if (res->res_job.WriteBootstrap) {
1279 free(res->res_job.WriteBootstrap);
1281 if (res->res_job.PluginOptions) {
1282 free(res->res_job.PluginOptions);
1284 if (res->res_job.selection_pattern) {
1285 free(res->res_job.selection_pattern);
1287 if (res->res_job.run_cmds) {
1288 delete res->res_job.run_cmds;
1290 if (res->res_job.storage) {
1291 delete res->res_job.storage;
1293 if (res->res_job.RunScripts) {
1294 free_runscripts(res->res_job.RunScripts);
1295 delete res->res_job.RunScripts;
1299 if (res->res_msgs.mail_cmd) {
1300 free(res->res_msgs.mail_cmd);
1302 if (res->res_msgs.operator_cmd) {
1303 free(res->res_msgs.operator_cmd);
1305 free_msgs_res((MSGS *)res); /* free message resource */
1309 printf(_("Unknown resource type %d in free_resource.\n"), type);
1311 /* Common stuff again -- free the resource, recurse to next one */
1316 free_resource(nres, type);
1321 * Save the new resource by chaining it into the head list for
1322 * the resource. If this is pass 2, we update any resource
1323 * pointers because they may not have been defined until
1326 void save_resource(int type, RES_ITEM *items, int pass)
1329 int rindex = type - r_first;
1333 /* Check Job requirements after applying JobDefs */
1334 if (type != R_JOB && type != R_JOBDEFS) {
1336 * Ensure that all required items are present
1338 for (i=0; items[i].name; i++) {
1339 if (items[i].flags & ITEM_REQUIRED) {
1340 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1341 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1342 items[i].name, resources[rindex]);
1345 /* If this triggers, take a look at lib/parse_conf.h */
1346 if (i >= MAX_RES_ITEMS) {
1347 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1350 } else if (type == R_JOB) {
1352 * Ensure that the name item is present
1354 if (items[0].flags & ITEM_REQUIRED) {
1355 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1356 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1357 items[0].name, resources[rindex]);
1363 * During pass 2 in each "store" routine, we looked up pointers
1364 * to all the resources referrenced in the current resource, now we
1365 * must copy their addresses from the static record to the allocated
1370 /* Resources not containing a resource */
1378 * Resources containing another resource or alist. First
1379 * look up the resource which contains another resource. It
1380 * was written during pass 1. Then stuff in the pointers to
1381 * the resources it contains, which were inserted this pass.
1382 * Finally, it will all be stored back.
1385 /* Find resource saved in pass 1 */
1386 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1387 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1389 /* Explicitly copy resource pointers from this pass (res_all) */
1390 res->res_pool.NextPool = res_all.res_pool.NextPool;
1391 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1392 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1393 res->res_pool.storage = res_all.res_pool.storage;
1394 res->res_pool.catalog = res_all.res_pool.catalog;
1397 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1398 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1400 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1403 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1404 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1406 res->res_dir.messages = res_all.res_dir.messages;
1407 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1410 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1411 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1412 res_all.res_dir.hdr.name);
1414 /* we must explicitly copy the device alist pointer */
1415 res->res_store.device = res_all.res_store.device;
1419 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1420 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1421 res_all.res_dir.hdr.name);
1423 res->res_job.messages = res_all.res_job.messages;
1424 res->res_job.schedule = res_all.res_job.schedule;
1425 res->res_job.client = res_all.res_job.client;
1426 res->res_job.fileset = res_all.res_job.fileset;
1427 res->res_job.storage = res_all.res_job.storage;
1428 res->res_job.pool = res_all.res_job.pool;
1429 res->res_job.full_pool = res_all.res_job.full_pool;
1430 res->res_job.inc_pool = res_all.res_job.inc_pool;
1431 res->res_job.diff_pool = res_all.res_job.diff_pool;
1432 res->res_job.verify_job = res_all.res_job.verify_job;
1433 res->res_job.jobdefs = res_all.res_job.jobdefs;
1434 res->res_job.run_cmds = res_all.res_job.run_cmds;
1435 res->res_job.RunScripts = res_all.res_job.RunScripts;
1437 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1438 * is not very useful)
1439 * We have to set_bit(index, res_all.hdr.item_present);
1440 * or something like that
1443 /* we take RegexWhere before all other options */
1444 if (!res->res_job.RegexWhere
1446 (res->res_job.strip_prefix ||
1447 res->res_job.add_suffix ||
1448 res->res_job.add_prefix))
1450 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1451 res->res_job.add_prefix,
1452 res->res_job.add_suffix);
1453 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1454 bregexp_build_where(res->res_job.RegexWhere, len,
1455 res->res_job.strip_prefix,
1456 res->res_job.add_prefix,
1457 res->res_job.add_suffix);
1458 /* TODO: test bregexp */
1461 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1462 free(res->res_job.RestoreWhere);
1463 res->res_job.RestoreWhere = NULL;
1468 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1469 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1471 res->res_counter.Catalog = res_all.res_counter.Catalog;
1472 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1476 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1477 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1479 res->res_client.catalog = res_all.res_client.catalog;
1480 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1484 * Schedule is a bit different in that it contains a RUN record
1485 * chain which isn't a "named" resource. This chain was linked
1486 * in by run_conf.c during pass 2, so here we jam the pointer
1487 * into the Schedule resource.
1489 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1490 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1492 res->res_sch.run = res_all.res_sch.run;
1495 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1499 /* Note, the resource name was already saved during pass 1,
1500 * so here, we can just release it.
1502 if (res_all.res_dir.hdr.name) {
1503 free(res_all.res_dir.hdr.name);
1504 res_all.res_dir.hdr.name = NULL;
1506 if (res_all.res_dir.hdr.desc) {
1507 free(res_all.res_dir.hdr.desc);
1508 res_all.res_dir.hdr.desc = NULL;
1514 * The following code is only executed during pass 1
1518 size = sizeof(DIRRES);
1521 size = sizeof(CONRES);
1524 size =sizeof(CLIENT);
1527 size = sizeof(STORE);
1537 size = sizeof(FILESET);
1540 size = sizeof(SCHED);
1543 size = sizeof(POOL);
1546 size = sizeof(MSGS);
1549 size = sizeof(COUNTER);
1555 printf(_("Unknown resource type %d in save_resource.\n"), type);
1561 res = (URES *)malloc(size);
1562 memcpy(res, &res_all, size);
1563 if (!res_head[rindex]) {
1564 res_head[rindex] = (RES *)res; /* store first entry */
1565 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1566 res->res_dir.hdr.name, rindex);
1569 if (res->res_dir.hdr.name == NULL) {
1570 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1573 /* Add new res to end of chain */
1574 for (last=next=res_head[rindex]; next; next=next->next) {
1576 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1577 Emsg2(M_ERROR_TERM, 0,
1578 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1579 resources[rindex].name, res->res_dir.hdr.name);
1582 last->next = (RES *)res;
1583 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1584 res->res_dir.hdr.name, rindex, pass);
1590 * Store Device. Note, the resource is created upon the
1591 * first reference. The details of the resource are obtained
1592 * later from the SD.
1594 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1598 int rindex = R_DEVICE - r_first;
1599 int size = sizeof(DEVICE);
1603 token = lex_get_token(lc, T_NAME);
1604 if (!res_head[rindex]) {
1605 res = (URES *)malloc(size);
1606 memset(res, 0, size);
1607 res->res_dev.hdr.name = bstrdup(lc->str);
1608 res_head[rindex] = (RES *)res; /* store first entry */
1609 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1610 res->res_dir.hdr.name, rindex);
1613 /* See if it is already defined */
1614 for (next=res_head[rindex]; next->next; next=next->next) {
1615 if (strcmp(next->name, lc->str) == 0) {
1621 res = (URES *)malloc(size);
1622 memset(res, 0, size);
1623 res->res_dev.hdr.name = bstrdup(lc->str);
1624 next->next = (RES *)res;
1625 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1626 res->res_dir.hdr.name, rindex, pass);
1631 set_bit(index, res_all.hdr.item_present);
1633 store_alist_res(lc, item, index, pass);
1638 * Store Migration/Copy type
1641 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1645 token = lex_get_token(lc, T_NAME);
1646 /* Store the type both pass 1 and pass 2 */
1647 for (i=0; migtypes[i].type_name; i++) {
1648 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1649 *(uint32_t *)(item->value) = migtypes[i].job_type;
1655 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1658 set_bit(index, res_all.hdr.item_present);
1664 * Store JobType (backup, verify, restore)
1667 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1671 token = lex_get_token(lc, T_NAME);
1672 /* Store the type both pass 1 and pass 2 */
1673 for (i=0; jobtypes[i].type_name; i++) {
1674 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1675 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1681 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1684 set_bit(index, res_all.hdr.item_present);
1688 * Store Job Level (Full, Incremental, ...)
1691 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1695 token = lex_get_token(lc, T_NAME);
1696 /* Store the level pass 2 so that type is defined */
1697 for (i=0; joblevels[i].level_name; i++) {
1698 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1699 *(uint32_t *)(item->value) = joblevels[i].level;
1705 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1708 set_bit(index, res_all.hdr.item_present);
1712 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1715 token = lex_get_token(lc, T_NAME);
1716 /* Scan Replacement options */
1717 for (i=0; ReplaceOptions[i].name; i++) {
1718 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1719 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1725 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1728 set_bit(index, res_all.hdr.item_present);
1732 * Store ACL (access control list)
1735 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1740 token = lex_get_token(lc, T_STRING);
1742 if (((alist **)item->value)[item->code] == NULL) {
1743 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1744 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1746 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1747 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1749 token = lex_get_token(lc, T_ALL);
1750 if (token == T_COMMA) {
1751 continue; /* get another ACL */
1755 set_bit(index, res_all.hdr.item_present);
1758 /* We build RunScripts items here */
1759 static RUNSCRIPT res_runscript;
1761 /* Store a runscript->when in a bit field */
1762 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1764 lex_get_token(lc, T_NAME);
1766 if (strcasecmp(lc->str, "before") == 0) {
1767 *(uint32_t *)(item->value) = SCRIPT_Before ;
1768 } else if (strcasecmp(lc->str, "after") == 0) {
1769 *(uint32_t *)(item->value) = SCRIPT_After;
1770 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1771 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1772 } else if (strcasecmp(lc->str, "always") == 0) {
1773 *(uint32_t *)(item->value) = SCRIPT_Any;
1775 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1780 /* Store a runscript->target
1783 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1785 lex_get_token(lc, T_STRING);
1788 if (strcmp(lc->str, "%c") == 0) {
1789 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1790 } else if (strcasecmp(lc->str, "yes") == 0) {
1791 ((RUNSCRIPT*) item->value)->set_target("%c");
1792 } else if (strcasecmp(lc->str, "no") == 0) {
1793 ((RUNSCRIPT*) item->value)->set_target("");
1795 RES *res = GetResWithName(R_CLIENT, lc->str);
1797 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1798 lc->str, lc->line_no, lc->line);
1801 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1808 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1810 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1812 lex_get_token(lc, T_STRING);
1815 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1816 POOLMEM *c = get_pool_memory(PM_FNAME);
1817 /* Each runscript command takes 2 entries in commands list */
1818 pm_strcpy(c, lc->str);
1819 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1820 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1825 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1827 lex_get_token(lc, T_STRING);
1828 alist **runscripts = (alist **)(item->value) ;
1831 RUNSCRIPT *script = new_runscript();
1832 script->set_job_code_callback(job_code_callback_filesetname);
1834 script->set_command(lc->str);
1836 /* TODO: remove all script->old_proto with bacula 1.42 */
1838 if (strcmp(item->name, "runbeforejob") == 0) {
1839 script->when = SCRIPT_Before;
1840 script->fail_on_error = true;
1841 script->set_target("");
1843 } else if (strcmp(item->name, "runafterjob") == 0) {
1844 script->when = SCRIPT_After;
1845 script->on_success = true;
1846 script->on_failure = false;
1847 script->set_target("");
1849 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1850 script->old_proto = true;
1851 script->when = SCRIPT_After;
1852 script->set_target("%c");
1853 script->on_success = true;
1854 script->on_failure = false;
1856 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1857 script->old_proto = true;
1858 script->when = SCRIPT_Before;
1859 script->set_target("%c");
1860 script->fail_on_error = true;
1862 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1863 script->when = SCRIPT_After;
1864 script->on_failure = true;
1865 script->on_success = false;
1866 script->set_target("");
1869 if (*runscripts == NULL) {
1870 *runscripts = New(alist(10, not_owned_by_alist));
1873 (*runscripts)->append(script);
1880 /* Store a bool in a bit field without modifing res_all.hdr
1881 * We can also add an option to store_bool to skip res_all.hdr
1883 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1885 lex_get_token(lc, T_NAME);
1886 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1887 *(bool *)(item->value) = true;
1888 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1889 *(bool *)(item->value) = false;
1891 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1897 * new RunScript items
1898 * name handler value code flags default_value
1900 static RES_ITEM runscript_items[] = {
1901 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1902 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1903 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1904 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1905 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1906 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1907 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1908 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1909 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1910 {NULL, NULL, {0}, 0, 0, 0}
1914 * Store RunScript info
1916 * Note, when this routine is called, we are inside a Job
1917 * resource. We treat the RunScript like a sort of
1918 * mini-resource within the Job resource.
1920 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1924 alist **runscripts = (alist **)(item->value) ;
1926 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1928 token = lex_get_token(lc, T_SKIP_EOL);
1930 if (token != T_BOB) {
1931 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1933 /* setting on_success, on_failure, fail_on_error */
1934 res_runscript.reset_default();
1937 res_runscript.commands = New(alist(10, not_owned_by_alist));
1940 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1941 if (token == T_EOB) {
1944 if (token != T_IDENTIFIER) {
1945 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1947 for (i=0; runscript_items[i].name; i++) {
1948 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1949 token = lex_get_token(lc, T_SKIP_EOL);
1950 if (token != T_EQUALS) {
1951 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1954 /* Call item handler */
1955 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1962 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1967 /* run on client by default */
1968 if (res_runscript.target == NULL) {
1969 res_runscript.set_target("%c");
1971 if (*runscripts == NULL) {
1972 *runscripts = New(alist(10, not_owned_by_alist));
1975 * commands list contains 2 values per command
1976 * - POOLMEM command string (ex: /bin/true)
1977 * - int command type (ex: SHELL_CMD)
1979 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1980 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1981 t = (long)res_runscript.commands->pop();
1982 RUNSCRIPT *script = new_runscript();
1983 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1984 script->command = c;
1985 script->cmd_type = t;
1986 /* target is taken from res_runscript, each runscript object have
1989 script->target = NULL;
1990 script->set_target(res_runscript.target);
1992 (*runscripts)->append(script);
1995 delete res_runscript.commands;
1996 /* setting on_success, on_failure... cleanup target field */
1997 res_runscript.reset_default(true);
2001 set_bit(index, res_all.hdr.item_present);
2004 /* callback function for edit_job_codes */
2005 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2007 if (param[0] == 'f') {
2008 return jcr->fileset->name();
2014 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2016 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2017 r_first, r_last, resources, res_head);
2018 return config->parse_config();