2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula Directors,
30 * some parts may be split into separate files such as
31 * the schedule configuration (run_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, January MM
56 /* Define the first and last resource ID record
57 * types. Note, these should be unique for each
58 * daemon though not a requirement.
60 int32_t r_first = R_FIRST;
61 int32_t r_last = R_LAST;
62 static RES *sres_head[R_LAST - R_FIRST + 1];
63 RES **res_head = sres_head;
65 /* Imported subroutines */
66 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
68 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
71 /* Forward referenced subroutines */
73 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
77 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
84 /* We build the current resource here as we are
85 * scanning the resource configuration definition,
86 * then move it to allocated memory when the resource
90 extern "C" { // work around visual compiler mangling variables
96 int32_t res_all_size = sizeof(res_all);
99 /* Definition of records permitted within each
100 * resource with the routine to process the record
101 * information. NOTE! quoted names must be in lower case.
106 * name handler value code flags default_value
108 static RES_ITEM dir_items[] = {
109 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
110 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
111 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
112 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
116 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
117 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
118 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
119 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
120 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
121 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
122 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
123 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
124 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
125 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
126 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
127 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
128 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
129 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
130 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
131 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
132 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
133 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
134 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
135 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
136 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
137 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
138 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
139 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
140 {NULL, NULL, {0}, 0, 0, 0}
146 * name handler value code flags default_value
148 static RES_ITEM con_items[] = {
149 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
150 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
151 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
152 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
153 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
154 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
155 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
156 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
157 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
158 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
159 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
160 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
161 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
162 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
163 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
164 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
165 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
166 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
167 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
168 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
169 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
170 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
171 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
172 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
173 {NULL, NULL, {0}, 0, 0, 0}
178 * Client or File daemon resource
180 * name handler value code flags default_value
183 static RES_ITEM cli_items[] = {
184 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
185 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
186 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
187 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
188 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
189 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
190 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
191 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
192 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
193 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
194 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
195 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
196 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
197 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
198 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
199 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
200 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
201 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
202 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
203 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
204 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
205 {NULL, NULL, {0}, 0, 0, 0}
208 /* Storage daemon resource
210 * name handler value code flags default_value
212 static RES_ITEM store_items[] = {
213 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
214 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
215 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
216 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
217 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
218 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
219 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
220 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
221 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
222 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
223 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
224 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
225 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
226 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
227 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
228 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
229 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
230 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
231 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
232 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
233 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
234 {NULL, NULL, {0}, 0, 0, 0}
238 * Catalog Resource Directives
240 * name handler value code flags default_value
242 static RES_ITEM cat_items[] = {
243 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
244 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
245 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
246 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
247 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
248 /* keep this password as store_str for the moment */
249 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
250 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
251 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
252 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
253 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
254 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
255 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
256 /* Turned off for the moment */
257 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
258 {NULL, NULL, {0}, 0, 0, 0}
262 * Job Resource Directives
264 * name handler value code flags default_value
266 RES_ITEM job_items[] = {
267 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
268 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
269 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
270 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
271 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
272 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
273 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
274 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
275 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
276 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
277 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
278 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
279 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
280 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
281 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
282 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
283 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
284 /* Root of where to restore files */
285 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
286 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
287 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
288 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
289 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
290 /* Where to find bootstrap during restore */
291 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
292 /* Where to write bootstrap file during backup */
293 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
294 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
295 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
296 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
297 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
298 /* xxxMaxWaitTime are deprecated */
299 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
300 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
301 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
302 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
303 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
304 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
305 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
306 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
307 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
308 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
309 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
310 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
311 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
312 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
313 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
314 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
315 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
316 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
317 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
318 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
319 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
320 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
326 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
327 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
328 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
329 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
330 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
331 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
332 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
333 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
334 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
335 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
336 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
337 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
338 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
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_size, 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_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
395 {"migrationlowbytes", store_size, 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 for (j=0; j<incexe->name_list.size(); j++) {
810 sendit(sock, " I %s\n", incexe->name_list.get(j));
812 if (incexe->name_list.size()) {
813 sendit(sock, " N\n");
815 for (j=0; j<incexe->plugin_list.size(); j++) {
816 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
818 if (incexe->plugin_list.size()) {
819 sendit(sock, " N\n");
824 for (i=0; i<res->res_fs.num_excludes; i++) {
825 INCEXE *incexe = res->res_fs.exclude_items[i];
826 for (j=0; j<incexe->name_list.size(); j++) {
827 sendit(sock, " E %s\n", incexe->name_list.get(j));
829 if (incexe->name_list.size()) {
830 sendit(sock, " N\n");
837 if (res->res_sch.run) {
839 RUN *run = res->res_sch.run;
840 char buf[1000], num[30];
841 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
846 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
847 bstrncpy(buf, _(" hour="), sizeof(buf));
848 for (i=0; i<24; i++) {
849 if (bit_is_set(i, run->hour)) {
850 bsnprintf(num, sizeof(num), "%d ", i);
851 bstrncat(buf, num, sizeof(buf));
854 bstrncat(buf, "\n", sizeof(buf));
856 bstrncpy(buf, _(" mday="), sizeof(buf));
857 for (i=0; i<31; i++) {
858 if (bit_is_set(i, run->mday)) {
859 bsnprintf(num, sizeof(num), "%d ", i);
860 bstrncat(buf, num, sizeof(buf));
863 bstrncat(buf, "\n", sizeof(buf));
865 bstrncpy(buf, _(" month="), sizeof(buf));
866 for (i=0; i<12; i++) {
867 if (bit_is_set(i, run->month)) {
868 bsnprintf(num, sizeof(num), "%d ", i);
869 bstrncat(buf, num, sizeof(buf));
872 bstrncat(buf, "\n", sizeof(buf));
874 bstrncpy(buf, _(" wday="), sizeof(buf));
875 for (i=0; i<7; i++) {
876 if (bit_is_set(i, run->wday)) {
877 bsnprintf(num, sizeof(num), "%d ", i);
878 bstrncat(buf, num, sizeof(buf));
881 bstrncat(buf, "\n", sizeof(buf));
883 bstrncpy(buf, _(" wom="), sizeof(buf));
884 for (i=0; i<5; i++) {
885 if (bit_is_set(i, run->wom)) {
886 bsnprintf(num, sizeof(num), "%d ", i);
887 bstrncat(buf, num, sizeof(buf));
890 bstrncat(buf, "\n", sizeof(buf));
892 bstrncpy(buf, _(" woy="), sizeof(buf));
893 for (i=0; i<54; i++) {
894 if (bit_is_set(i, run->woy)) {
895 bsnprintf(num, sizeof(num), "%d ", i);
896 bstrncat(buf, num, sizeof(buf));
899 bstrncat(buf, "\n", sizeof(buf));
901 sendit(sock, _(" mins=%d\n"), run->minute);
903 sendit(sock, _(" --> "));
904 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
907 sendit(sock, _(" --> "));
908 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
911 sendit(sock, _(" --> "));
912 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
914 /* If another Run record is chained in, go print it */
920 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
925 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
926 res->res_pool.pool_type);
927 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
928 res->res_pool.use_catalog, res->res_pool.use_volume_once,
929 res->res_pool.catalog_files);
930 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
931 res->res_pool.max_volumes, res->res_pool.AutoPrune,
932 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
933 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
934 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
935 res->res_pool.Recycle,
936 NPRT(res->res_pool.label_format));
937 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
938 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
939 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
940 res->res_pool.recycle_oldest_volume,
941 res->res_pool.purge_oldest_volume);
942 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
943 res->res_pool.MaxVolJobs,
944 res->res_pool.MaxVolFiles,
945 edit_uint64(res->res_pool.MaxVolFiles, ed1));
946 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
947 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
948 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
949 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
950 if (res->res_pool.NextPool) {
951 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
953 if (res->res_pool.RecyclePool) {
954 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
956 if (res->res_pool.ScratchPool) {
957 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
959 if (res->res_pool.catalog) {
960 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
962 if (res->res_pool.storage) {
964 foreach_alist(store, res->res_pool.storage) {
965 sendit(sock, _(" --> "));
966 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
969 if (res->res_pool.CopyPool) {
971 foreach_alist(copy, res->res_pool.CopyPool) {
972 sendit(sock, _(" --> "));
973 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
980 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
981 if (res->res_msgs.mail_cmd)
982 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
983 if (res->res_msgs.operator_cmd)
984 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
988 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
991 if (recurse && res->res_dir.hdr.next) {
992 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
997 * Free all the members of an INCEXE structure
999 static void free_incexe(INCEXE *incexe)
1001 incexe->name_list.destroy();
1002 incexe->plugin_list.destroy();
1003 for (int i=0; i<incexe->num_opts; i++) {
1004 FOPTS *fopt = incexe->opts_list[i];
1005 fopt->regex.destroy();
1006 fopt->regexdir.destroy();
1007 fopt->regexfile.destroy();
1008 fopt->wild.destroy();
1009 fopt->wilddir.destroy();
1010 fopt->wildfile.destroy();
1011 fopt->wildbase.destroy();
1012 fopt->base.destroy();
1013 fopt->fstype.destroy();
1014 fopt->drivetype.destroy();
1026 if (incexe->opts_list) {
1027 free(incexe->opts_list);
1033 * Free memory of resource -- called when daemon terminates.
1034 * NB, we don't need to worry about freeing any references
1035 * to other resources as they will be freed when that
1036 * resource chain is traversed. Mainly we worry about freeing
1037 * allocated strings (names).
1039 void free_resource(RES *sres, int type)
1042 RES *nres; /* next resource if linked */
1043 URES *res = (URES *)sres;
1048 /* common stuff -- free the resource name and description */
1049 nres = (RES *)res->res_dir.hdr.next;
1050 if (res->res_dir.hdr.name) {
1051 free(res->res_dir.hdr.name);
1053 if (res->res_dir.hdr.desc) {
1054 free(res->res_dir.hdr.desc);
1059 if (res->res_dir.working_directory) {
1060 free(res->res_dir.working_directory);
1062 if (res->res_dir.scripts_directory) {
1063 free((char *)res->res_dir.scripts_directory);
1065 if (res->res_dir.plugin_directory) {
1066 free((char *)res->res_dir.plugin_directory);
1068 if (res->res_dir.pid_directory) {
1069 free(res->res_dir.pid_directory);
1071 if (res->res_dir.subsys_directory) {
1072 free(res->res_dir.subsys_directory);
1074 if (res->res_dir.password) {
1075 free(res->res_dir.password);
1077 if (res->res_dir.query_file) {
1078 free(res->res_dir.query_file);
1080 if (res->res_dir.DIRaddrs) {
1081 free_addresses(res->res_dir.DIRaddrs);
1083 if (res->res_dir.DIRsrc_addr) {
1084 free_addresses(res->res_dir.DIRsrc_addr);
1086 if (res->res_dir.tls_ctx) {
1087 free_tls_context(res->res_dir.tls_ctx);
1089 if (res->res_dir.tls_ca_certfile) {
1090 free(res->res_dir.tls_ca_certfile);
1092 if (res->res_dir.tls_ca_certdir) {
1093 free(res->res_dir.tls_ca_certdir);
1095 if (res->res_dir.tls_certfile) {
1096 free(res->res_dir.tls_certfile);
1098 if (res->res_dir.tls_keyfile) {
1099 free(res->res_dir.tls_keyfile);
1101 if (res->res_dir.tls_dhfile) {
1102 free(res->res_dir.tls_dhfile);
1104 if (res->res_dir.tls_allowed_cns) {
1105 delete res->res_dir.tls_allowed_cns;
1107 if (res->res_dir.verid) {
1108 free(res->res_dir.verid);
1115 if (res->res_con.password) {
1116 free(res->res_con.password);
1118 if (res->res_con.tls_ctx) {
1119 free_tls_context(res->res_con.tls_ctx);
1121 if (res->res_con.tls_ca_certfile) {
1122 free(res->res_con.tls_ca_certfile);
1124 if (res->res_con.tls_ca_certdir) {
1125 free(res->res_con.tls_ca_certdir);
1127 if (res->res_con.tls_certfile) {
1128 free(res->res_con.tls_certfile);
1130 if (res->res_con.tls_keyfile) {
1131 free(res->res_con.tls_keyfile);
1133 if (res->res_con.tls_dhfile) {
1134 free(res->res_con.tls_dhfile);
1136 if (res->res_con.tls_allowed_cns) {
1137 delete res->res_con.tls_allowed_cns;
1139 for (int i=0; i<Num_ACL; i++) {
1140 if (res->res_con.ACL_lists[i]) {
1141 delete res->res_con.ACL_lists[i];
1142 res->res_con.ACL_lists[i] = NULL;
1147 if (res->res_client.address) {
1148 free(res->res_client.address);
1150 if (res->res_client.password) {
1151 free(res->res_client.password);
1153 if (res->res_client.tls_ctx) {
1154 free_tls_context(res->res_client.tls_ctx);
1156 if (res->res_client.tls_ca_certfile) {
1157 free(res->res_client.tls_ca_certfile);
1159 if (res->res_client.tls_ca_certdir) {
1160 free(res->res_client.tls_ca_certdir);
1162 if (res->res_client.tls_certfile) {
1163 free(res->res_client.tls_certfile);
1165 if (res->res_client.tls_keyfile) {
1166 free(res->res_client.tls_keyfile);
1168 if (res->res_client.tls_allowed_cns) {
1169 delete res->res_client.tls_allowed_cns;
1173 if (res->res_store.address) {
1174 free(res->res_store.address);
1176 if (res->res_store.password) {
1177 free(res->res_store.password);
1179 if (res->res_store.media_type) {
1180 free(res->res_store.media_type);
1182 if (res->res_store.device) {
1183 delete res->res_store.device;
1185 if (res->res_store.tls_ctx) {
1186 free_tls_context(res->res_store.tls_ctx);
1188 if (res->res_store.tls_ca_certfile) {
1189 free(res->res_store.tls_ca_certfile);
1191 if (res->res_store.tls_ca_certdir) {
1192 free(res->res_store.tls_ca_certdir);
1194 if (res->res_store.tls_certfile) {
1195 free(res->res_store.tls_certfile);
1197 if (res->res_store.tls_keyfile) {
1198 free(res->res_store.tls_keyfile);
1202 if (res->res_cat.db_address) {
1203 free(res->res_cat.db_address);
1205 if (res->res_cat.db_socket) {
1206 free(res->res_cat.db_socket);
1208 if (res->res_cat.db_user) {
1209 free(res->res_cat.db_user);
1211 if (res->res_cat.db_name) {
1212 free(res->res_cat.db_name);
1214 if (res->res_cat.db_driver) {
1215 free(res->res_cat.db_driver);
1217 if (res->res_cat.db_password) {
1218 free(res->res_cat.db_password);
1222 if ((num=res->res_fs.num_includes)) {
1223 while (--num >= 0) {
1224 free_incexe(res->res_fs.include_items[num]);
1226 free(res->res_fs.include_items);
1228 res->res_fs.num_includes = 0;
1229 if ((num=res->res_fs.num_excludes)) {
1230 while (--num >= 0) {
1231 free_incexe(res->res_fs.exclude_items[num]);
1233 free(res->res_fs.exclude_items);
1235 res->res_fs.num_excludes = 0;
1238 if (res->res_pool.pool_type) {
1239 free(res->res_pool.pool_type);
1241 if (res->res_pool.label_format) {
1242 free(res->res_pool.label_format);
1244 if (res->res_pool.cleaning_prefix) {
1245 free(res->res_pool.cleaning_prefix);
1247 if (res->res_pool.storage) {
1248 delete res->res_pool.storage;
1252 if (res->res_sch.run) {
1254 nrun = res->res_sch.run;
1264 if (res->res_job.RestoreWhere) {
1265 free(res->res_job.RestoreWhere);
1267 if (res->res_job.RegexWhere) {
1268 free(res->res_job.RegexWhere);
1270 if (res->res_job.strip_prefix) {
1271 free(res->res_job.strip_prefix);
1273 if (res->res_job.add_prefix) {
1274 free(res->res_job.add_prefix);
1276 if (res->res_job.add_suffix) {
1277 free(res->res_job.add_suffix);
1279 if (res->res_job.RestoreBootstrap) {
1280 free(res->res_job.RestoreBootstrap);
1282 if (res->res_job.WriteBootstrap) {
1283 free(res->res_job.WriteBootstrap);
1285 if (res->res_job.PluginOptions) {
1286 free(res->res_job.PluginOptions);
1288 if (res->res_job.selection_pattern) {
1289 free(res->res_job.selection_pattern);
1291 if (res->res_job.run_cmds) {
1292 delete res->res_job.run_cmds;
1294 if (res->res_job.storage) {
1295 delete res->res_job.storage;
1297 if (res->res_job.RunScripts) {
1298 free_runscripts(res->res_job.RunScripts);
1299 delete res->res_job.RunScripts;
1303 if (res->res_msgs.mail_cmd) {
1304 free(res->res_msgs.mail_cmd);
1306 if (res->res_msgs.operator_cmd) {
1307 free(res->res_msgs.operator_cmd);
1309 free_msgs_res((MSGS *)res); /* free message resource */
1313 printf(_("Unknown resource type %d in free_resource.\n"), type);
1315 /* Common stuff again -- free the resource, recurse to next one */
1320 free_resource(nres, type);
1325 * Save the new resource by chaining it into the head list for
1326 * the resource. If this is pass 2, we update any resource
1327 * pointers because they may not have been defined until
1330 void save_resource(int type, RES_ITEM *items, int pass)
1333 int rindex = type - r_first;
1337 /* Check Job requirements after applying JobDefs */
1338 if (type != R_JOB && type != R_JOBDEFS) {
1340 * Ensure that all required items are present
1342 for (i=0; items[i].name; i++) {
1343 if (items[i].flags & ITEM_REQUIRED) {
1344 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1345 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1346 items[i].name, resources[rindex]);
1349 /* If this triggers, take a look at lib/parse_conf.h */
1350 if (i >= MAX_RES_ITEMS) {
1351 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1354 } else if (type == R_JOB) {
1356 * Ensure that the name item is present
1358 if (items[0].flags & ITEM_REQUIRED) {
1359 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1360 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1361 items[0].name, resources[rindex]);
1367 * During pass 2 in each "store" routine, we looked up pointers
1368 * to all the resources referrenced in the current resource, now we
1369 * must copy their addresses from the static record to the allocated
1374 /* Resources not containing a resource */
1382 * Resources containing another resource or alist. First
1383 * look up the resource which contains another resource. It
1384 * was written during pass 1. Then stuff in the pointers to
1385 * the resources it contains, which were inserted this pass.
1386 * Finally, it will all be stored back.
1389 /* Find resource saved in pass 1 */
1390 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1391 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1393 /* Explicitly copy resource pointers from this pass (res_all) */
1394 res->res_pool.NextPool = res_all.res_pool.NextPool;
1395 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1396 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1397 res->res_pool.storage = res_all.res_pool.storage;
1398 res->res_pool.catalog = res_all.res_pool.catalog;
1401 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1402 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1404 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1407 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1408 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1410 res->res_dir.messages = res_all.res_dir.messages;
1411 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1414 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1415 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1416 res_all.res_dir.hdr.name);
1418 /* we must explicitly copy the device alist pointer */
1419 res->res_store.device = res_all.res_store.device;
1423 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1424 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1425 res_all.res_dir.hdr.name);
1427 res->res_job.messages = res_all.res_job.messages;
1428 res->res_job.schedule = res_all.res_job.schedule;
1429 res->res_job.client = res_all.res_job.client;
1430 res->res_job.fileset = res_all.res_job.fileset;
1431 res->res_job.storage = res_all.res_job.storage;
1432 res->res_job.pool = res_all.res_job.pool;
1433 res->res_job.full_pool = res_all.res_job.full_pool;
1434 res->res_job.inc_pool = res_all.res_job.inc_pool;
1435 res->res_job.diff_pool = res_all.res_job.diff_pool;
1436 res->res_job.verify_job = res_all.res_job.verify_job;
1437 res->res_job.jobdefs = res_all.res_job.jobdefs;
1438 res->res_job.run_cmds = res_all.res_job.run_cmds;
1439 res->res_job.RunScripts = res_all.res_job.RunScripts;
1441 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1442 * is not very useful)
1443 * We have to set_bit(index, res_all.hdr.item_present);
1444 * or something like that
1447 /* we take RegexWhere before all other options */
1448 if (!res->res_job.RegexWhere
1450 (res->res_job.strip_prefix ||
1451 res->res_job.add_suffix ||
1452 res->res_job.add_prefix))
1454 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1455 res->res_job.add_prefix,
1456 res->res_job.add_suffix);
1457 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1458 bregexp_build_where(res->res_job.RegexWhere, len,
1459 res->res_job.strip_prefix,
1460 res->res_job.add_prefix,
1461 res->res_job.add_suffix);
1462 /* TODO: test bregexp */
1465 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1466 free(res->res_job.RestoreWhere);
1467 res->res_job.RestoreWhere = NULL;
1472 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1473 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1475 res->res_counter.Catalog = res_all.res_counter.Catalog;
1476 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1480 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1481 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1483 res->res_client.catalog = res_all.res_client.catalog;
1484 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1488 * Schedule is a bit different in that it contains a RUN record
1489 * chain which isn't a "named" resource. This chain was linked
1490 * in by run_conf.c during pass 2, so here we jam the pointer
1491 * into the Schedule resource.
1493 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1494 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1496 res->res_sch.run = res_all.res_sch.run;
1499 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1503 /* Note, the resource name was already saved during pass 1,
1504 * so here, we can just release it.
1506 if (res_all.res_dir.hdr.name) {
1507 free(res_all.res_dir.hdr.name);
1508 res_all.res_dir.hdr.name = NULL;
1510 if (res_all.res_dir.hdr.desc) {
1511 free(res_all.res_dir.hdr.desc);
1512 res_all.res_dir.hdr.desc = NULL;
1518 * The following code is only executed during pass 1
1522 size = sizeof(DIRRES);
1525 size = sizeof(CONRES);
1528 size =sizeof(CLIENT);
1531 size = sizeof(STORE);
1541 size = sizeof(FILESET);
1544 size = sizeof(SCHED);
1547 size = sizeof(POOL);
1550 size = sizeof(MSGS);
1553 size = sizeof(COUNTER);
1559 printf(_("Unknown resource type %d in save_resource.\n"), type);
1565 res = (URES *)malloc(size);
1566 memcpy(res, &res_all, size);
1567 if (!res_head[rindex]) {
1568 res_head[rindex] = (RES *)res; /* store first entry */
1569 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1570 res->res_dir.hdr.name, rindex);
1573 if (res->res_dir.hdr.name == NULL) {
1574 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1577 /* Add new res to end of chain */
1578 for (last=next=res_head[rindex]; next; next=next->next) {
1580 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1581 Emsg2(M_ERROR_TERM, 0,
1582 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1583 resources[rindex].name, res->res_dir.hdr.name);
1586 last->next = (RES *)res;
1587 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1588 res->res_dir.hdr.name, rindex, pass);
1594 * Store Device. Note, the resource is created upon the
1595 * first reference. The details of the resource are obtained
1596 * later from the SD.
1598 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1602 int rindex = R_DEVICE - r_first;
1603 int size = sizeof(DEVICE);
1607 token = lex_get_token(lc, T_NAME);
1608 if (!res_head[rindex]) {
1609 res = (URES *)malloc(size);
1610 memset(res, 0, size);
1611 res->res_dev.hdr.name = bstrdup(lc->str);
1612 res_head[rindex] = (RES *)res; /* store first entry */
1613 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1614 res->res_dir.hdr.name, rindex);
1617 /* See if it is already defined */
1618 for (next=res_head[rindex]; next->next; next=next->next) {
1619 if (strcmp(next->name, lc->str) == 0) {
1625 res = (URES *)malloc(size);
1626 memset(res, 0, size);
1627 res->res_dev.hdr.name = bstrdup(lc->str);
1628 next->next = (RES *)res;
1629 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1630 res->res_dir.hdr.name, rindex, pass);
1635 set_bit(index, res_all.hdr.item_present);
1637 store_alist_res(lc, item, index, pass);
1642 * Store Migration/Copy type
1645 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1649 token = lex_get_token(lc, T_NAME);
1650 /* Store the type both pass 1 and pass 2 */
1651 for (i=0; migtypes[i].type_name; i++) {
1652 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1653 *(uint32_t *)(item->value) = migtypes[i].job_type;
1659 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1662 set_bit(index, res_all.hdr.item_present);
1668 * Store JobType (backup, verify, restore)
1671 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1675 token = lex_get_token(lc, T_NAME);
1676 /* Store the type both pass 1 and pass 2 */
1677 for (i=0; jobtypes[i].type_name; i++) {
1678 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1679 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1685 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1688 set_bit(index, res_all.hdr.item_present);
1692 * Store Job Level (Full, Incremental, ...)
1695 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1699 token = lex_get_token(lc, T_NAME);
1700 /* Store the level pass 2 so that type is defined */
1701 for (i=0; joblevels[i].level_name; i++) {
1702 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1703 *(uint32_t *)(item->value) = joblevels[i].level;
1709 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1712 set_bit(index, res_all.hdr.item_present);
1716 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1719 token = lex_get_token(lc, T_NAME);
1720 /* Scan Replacement options */
1721 for (i=0; ReplaceOptions[i].name; i++) {
1722 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1723 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1729 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1732 set_bit(index, res_all.hdr.item_present);
1736 * Store ACL (access control list)
1739 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1744 token = lex_get_token(lc, T_STRING);
1746 if (((alist **)item->value)[item->code] == NULL) {
1747 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1748 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1750 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1751 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1753 token = lex_get_token(lc, T_ALL);
1754 if (token == T_COMMA) {
1755 continue; /* get another ACL */
1759 set_bit(index, res_all.hdr.item_present);
1762 /* We build RunScripts items here */
1763 static RUNSCRIPT res_runscript;
1765 /* Store a runscript->when in a bit field */
1766 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1768 lex_get_token(lc, T_NAME);
1770 if (strcasecmp(lc->str, "before") == 0) {
1771 *(uint32_t *)(item->value) = SCRIPT_Before ;
1772 } else if (strcasecmp(lc->str, "after") == 0) {
1773 *(uint32_t *)(item->value) = SCRIPT_After;
1774 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1775 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1776 } else if (strcasecmp(lc->str, "always") == 0) {
1777 *(uint32_t *)(item->value) = SCRIPT_Any;
1779 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1784 /* Store a runscript->target
1787 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1789 lex_get_token(lc, T_STRING);
1792 if (strcmp(lc->str, "%c") == 0) {
1793 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1794 } else if (strcasecmp(lc->str, "yes") == 0) {
1795 ((RUNSCRIPT*) item->value)->set_target("%c");
1796 } else if (strcasecmp(lc->str, "no") == 0) {
1797 ((RUNSCRIPT*) item->value)->set_target("");
1799 RES *res = GetResWithName(R_CLIENT, lc->str);
1801 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1802 lc->str, lc->line_no, lc->line);
1805 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1812 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1814 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1816 lex_get_token(lc, T_STRING);
1819 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1820 POOLMEM *c = get_pool_memory(PM_FNAME);
1821 /* Each runscript command takes 2 entries in commands list */
1822 pm_strcpy(c, lc->str);
1823 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1824 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1829 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1831 lex_get_token(lc, T_STRING);
1832 alist **runscripts = (alist **)(item->value) ;
1835 RUNSCRIPT *script = new_runscript();
1836 script->set_job_code_callback(job_code_callback_filesetname);
1838 script->set_command(lc->str);
1840 /* TODO: remove all script->old_proto with bacula 1.42 */
1842 if (strcmp(item->name, "runbeforejob") == 0) {
1843 script->when = SCRIPT_Before;
1844 script->fail_on_error = true;
1845 script->set_target("");
1847 } else if (strcmp(item->name, "runafterjob") == 0) {
1848 script->when = SCRIPT_After;
1849 script->on_success = true;
1850 script->on_failure = false;
1851 script->set_target("");
1853 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1854 script->old_proto = true;
1855 script->when = SCRIPT_After;
1856 script->set_target("%c");
1857 script->on_success = true;
1858 script->on_failure = false;
1860 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1861 script->old_proto = true;
1862 script->when = SCRIPT_Before;
1863 script->set_target("%c");
1864 script->fail_on_error = true;
1866 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1867 script->when = SCRIPT_After;
1868 script->on_failure = true;
1869 script->on_success = false;
1870 script->set_target("");
1873 if (*runscripts == NULL) {
1874 *runscripts = New(alist(10, not_owned_by_alist));
1877 (*runscripts)->append(script);
1884 /* Store a bool in a bit field without modifing res_all.hdr
1885 * We can also add an option to store_bool to skip res_all.hdr
1887 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1889 lex_get_token(lc, T_NAME);
1890 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1891 *(bool *)(item->value) = true;
1892 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1893 *(bool *)(item->value) = false;
1895 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1901 * new RunScript items
1902 * name handler value code flags default_value
1904 static RES_ITEM runscript_items[] = {
1905 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1906 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1907 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1908 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1909 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1910 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1911 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1912 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1913 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1914 {NULL, NULL, {0}, 0, 0, 0}
1918 * Store RunScript info
1920 * Note, when this routine is called, we are inside a Job
1921 * resource. We treat the RunScript like a sort of
1922 * mini-resource within the Job resource.
1924 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1928 alist **runscripts = (alist **)(item->value) ;
1930 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1932 token = lex_get_token(lc, T_SKIP_EOL);
1934 if (token != T_BOB) {
1935 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1937 /* setting on_success, on_failure, fail_on_error */
1938 res_runscript.reset_default();
1941 res_runscript.commands = New(alist(10, not_owned_by_alist));
1944 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1945 if (token == T_EOB) {
1948 if (token != T_IDENTIFIER) {
1949 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1951 for (i=0; runscript_items[i].name; i++) {
1952 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1953 token = lex_get_token(lc, T_SKIP_EOL);
1954 if (token != T_EQUALS) {
1955 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1958 /* Call item handler */
1959 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1966 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1971 /* run on client by default */
1972 if (res_runscript.target == NULL) {
1973 res_runscript.set_target("%c");
1975 if (*runscripts == NULL) {
1976 *runscripts = New(alist(10, not_owned_by_alist));
1979 * commands list contains 2 values per command
1980 * - POOLMEM command string (ex: /bin/true)
1981 * - int command type (ex: SHELL_CMD)
1983 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1984 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1985 t = (intptr_t)res_runscript.commands->pop();
1986 RUNSCRIPT *script = new_runscript();
1987 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1988 script->command = c;
1989 script->cmd_type = t;
1990 /* target is taken from res_runscript, each runscript object have
1993 script->target = NULL;
1994 script->set_target(res_runscript.target);
1996 (*runscripts)->append(script);
1999 delete res_runscript.commands;
2000 /* setting on_success, on_failure... cleanup target field */
2001 res_runscript.reset_default(true);
2005 set_bit(index, res_all.hdr.item_present);
2008 /* callback function for edit_job_codes */
2009 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2011 if (param[0] == 'f') {
2012 return jcr->fileset->name();
2018 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2020 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2021 r_first, r_last, resources, res_head);
2022 return config->parse_config();