2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula Directors,
30 * some parts may be split into separate files such as
31 * the schedule configuration (run_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, January MM
56 /* Define the first and last resource ID record
57 * types. Note, these should be unique for each
58 * daemon though not a requirement.
60 int32_t r_first = R_FIRST;
61 int32_t r_last = R_LAST;
62 static RES *sres_head[R_LAST - R_FIRST + 1];
63 RES **res_head = sres_head;
65 /* Imported subroutines */
66 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
68 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
71 /* Forward referenced subroutines */
73 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
77 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
83 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
85 /* We build the current resource here as we are
86 * scanning the resource configuration definition,
87 * then move it to allocated memory when the resource
91 extern "C" { // work around visual compiler mangling variables
97 int32_t res_all_size = sizeof(res_all);
100 /* Definition of records permitted within each
101 * resource with the routine to process the record
102 * information. NOTE! quoted names must be in lower case.
107 * name handler value code flags default_value
109 static RES_ITEM dir_items[] = {
110 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
111 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
112 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
113 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
116 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
117 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
118 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
119 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
120 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
121 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
122 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
123 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
124 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
125 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
126 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
127 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
128 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
129 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
130 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
131 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
132 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
133 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
134 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
135 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
136 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
137 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
138 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
139 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
140 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
141 {NULL, NULL, {0}, 0, 0, 0}
147 * name handler value code flags default_value
149 static RES_ITEM con_items[] = {
150 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
151 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
152 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
153 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
154 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
155 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
156 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
157 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
158 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
159 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
160 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
161 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
162 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
163 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
164 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
165 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
166 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
167 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
168 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
169 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
170 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
171 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
172 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
173 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
174 {NULL, NULL, {0}, 0, 0, 0}
179 * Client or File daemon resource
181 * name handler value code flags default_value
184 static RES_ITEM cli_items[] = {
185 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
186 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
187 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
188 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
189 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
190 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
191 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
192 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
193 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
194 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
195 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
196 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
197 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
198 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
199 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
200 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
201 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
202 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
203 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
204 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
205 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
206 {NULL, NULL, {0}, 0, 0, 0}
209 /* Storage daemon resource
211 * name handler value code flags default_value
213 static RES_ITEM store_items[] = {
214 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
215 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
216 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
217 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
218 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
219 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
220 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
221 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
222 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
223 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
224 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
225 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
226 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
227 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
228 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
229 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
230 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
231 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
232 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
233 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
234 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
235 {NULL, NULL, {0}, 0, 0, 0}
239 * Catalog Resource Directives
241 * name handler value code flags default_value
243 static RES_ITEM cat_items[] = {
244 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
245 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
246 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
247 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
248 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
249 /* keep this password as store_str for the moment */
250 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
251 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
252 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
253 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
254 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
255 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
256 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
257 /* Turned off for the moment */
258 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
259 {NULL, NULL, {0}, 0, 0, 0}
263 * Job Resource Directives
265 * name handler value code flags default_value
267 RES_ITEM job_items[] = {
268 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
269 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
270 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
271 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
272 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
273 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
274 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
275 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
276 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
277 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
278 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
279 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
280 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
281 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
282 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
283 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
284 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
285 /* Root of where to restore files */
286 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
287 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
288 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
289 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
290 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
291 /* Where to find bootstrap during restore */
292 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
293 /* Where to write bootstrap file during backup */
294 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
295 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
296 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
297 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
298 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
299 /* xxxMaxWaitTime are deprecated */
300 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
301 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
302 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
303 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
304 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
305 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
306 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
307 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
308 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
309 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
310 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
311 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
312 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
313 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
314 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
315 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
316 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
317 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
318 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
319 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
320 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
326 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
327 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
328 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
329 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
330 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
331 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
332 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
333 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
334 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
335 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
336 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
337 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
338 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
339 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
340 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
341 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
342 {NULL, NULL, {0}, 0, 0, 0}
347 * name handler value code flags default_value
349 static RES_ITEM fs_items[] = {
350 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
351 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
352 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
353 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
354 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
355 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
356 {NULL, NULL, {0}, 0, 0, 0}
359 /* Schedule -- see run_conf.c */
362 * name handler value code flags default_value
364 static RES_ITEM sch_items[] = {
365 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
366 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
367 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
368 {NULL, NULL, {0}, 0, 0, 0}
373 * name handler value code flags default_value
375 static RES_ITEM pool_items[] = {
376 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
377 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
378 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
379 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
380 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
381 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
382 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
383 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
384 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
385 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
386 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
387 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
388 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
389 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
390 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
391 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
392 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
393 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
394 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
395 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
396 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
397 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
398 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
399 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
400 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
401 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
402 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
403 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
404 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
405 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
406 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
407 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
409 {NULL, NULL, {0}, 0, 0, 0}
414 * name handler value code flags default_value
416 static RES_ITEM counter_items[] = {
417 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
418 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
419 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
420 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
421 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
422 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
423 {NULL, NULL, {0}, 0, 0, 0}
427 /* Message resource */
428 extern RES_ITEM msgs_items[];
431 * This is the master resource definition.
432 * It must have one item for each of the resources.
434 * NOTE!!! keep it in the same order as the R_codes
435 * or eliminate all resources[rindex].name
437 * name items rcode res_head
439 RES_TABLE resources[] = {
440 {"director", dir_items, R_DIRECTOR},
441 {"client", cli_items, R_CLIENT},
442 {"job", job_items, R_JOB},
443 {"storage", store_items, R_STORAGE},
444 {"catalog", cat_items, R_CATALOG},
445 {"schedule", sch_items, R_SCHEDULE},
446 {"fileset", fs_items, R_FILESET},
447 {"pool", pool_items, R_POOL},
448 {"messages", msgs_items, R_MSGS},
449 {"counter", counter_items, R_COUNTER},
450 {"console", con_items, R_CONSOLE},
451 {"jobdefs", job_items, R_JOBDEFS},
452 {"device", NULL, R_DEVICE}, /* info obtained from SD */
457 /* Keywords (RHS) permitted in Job Level records
459 * level_name level job_type
461 struct s_jl joblevels[] = {
462 {"Full", L_FULL, JT_BACKUP},
463 {"Base", L_BASE, JT_BACKUP},
464 {"Incremental", L_INCREMENTAL, JT_BACKUP},
465 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
466 {"Since", L_SINCE, JT_BACKUP},
467 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
468 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
469 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
470 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
471 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
472 {"Data", L_VERIFY_DATA, JT_VERIFY},
473 {" ", L_NONE, JT_ADMIN},
474 {" ", L_NONE, JT_RESTORE},
478 /* Keywords (RHS) permitted in Job type records
482 struct s_jt jobtypes[] = {
483 {"backup", JT_BACKUP},
485 {"verify", JT_VERIFY},
486 {"restore", JT_RESTORE},
487 {"migrate", JT_MIGRATE},
493 /* Keywords (RHS) permitted in Selection type records
497 struct s_jt migtypes[] = {
498 {"smallestvolume", MT_SMALLEST_VOL},
499 {"oldestvolume", MT_OLDEST_VOL},
500 {"pooloccupancy", MT_POOL_OCCUPANCY},
501 {"pooltime", MT_POOL_TIME},
502 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
503 {"client", MT_CLIENT},
504 {"volume", MT_VOLUME},
506 {"sqlquery", MT_SQLQUERY},
512 /* Options permitted in Restore replace= */
513 struct s_kw ReplaceOptions[] = {
514 {"always", REPLACE_ALWAYS},
515 {"ifnewer", REPLACE_IFNEWER},
516 {"ifolder", REPLACE_IFOLDER},
517 {"never", REPLACE_NEVER},
521 char *CAT::display(POOLMEM *dst) {
522 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
523 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
525 name(), NPRTB(db_name),
526 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
527 NPRTB(db_address), db_port, NPRTB(db_socket));
531 const char *level_to_str(int level)
534 static char level_no[30];
535 const char *str = level_no;
537 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
538 for (i=0; joblevels[i].level_name; i++) {
539 if (level == (int)joblevels[i].level) {
540 str = joblevels[i].level_name;
547 /* Dump contents of resource */
548 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
550 URES *res = (URES *)reshdr;
552 char ed1[100], ed2[100], ed3[100];
556 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
559 if (type < 0) { /* no recursion */
565 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
566 reshdr->name, res->res_dir.MaxConcurrentJobs,
567 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
568 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
569 if (res->res_dir.query_file) {
570 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
572 if (res->res_dir.messages) {
573 sendit(sock, _(" --> "));
574 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
578 sendit(sock, _("Console: name=%s SSL=%d\n"),
579 res->res_con.hdr.name, res->res_con.tls_enable);
582 if (res->res_counter.WrapCounter) {
583 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
584 res->res_counter.hdr.name, res->res_counter.MinValue,
585 res->res_counter.MaxValue, res->res_counter.CurrentValue,
586 res->res_counter.WrapCounter->hdr.name);
588 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
589 res->res_counter.hdr.name, res->res_counter.MinValue,
590 res->res_counter.MaxValue);
592 if (res->res_counter.Catalog) {
593 sendit(sock, _(" --> "));
594 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
599 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
600 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
601 res->res_client.MaxConcurrentJobs);
602 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
603 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
604 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
605 res->res_client.AutoPrune);
606 if (res->res_client.catalog) {
607 sendit(sock, _(" --> "));
608 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
615 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
616 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
617 " poolid=%s volname=%s MediaType=%s\n"),
618 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
619 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
620 dev->offline, dev->autochanger,
621 edit_uint64(dev->PoolId, ed1),
622 dev->VolumeName, dev->MediaType);
626 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
627 " DeviceName=%s MediaType=%s StorageId=%s\n"),
628 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
629 res->res_store.MaxConcurrentJobs,
630 res->res_store.dev_name(),
631 res->res_store.media_type,
632 edit_int64(res->res_store.StorageId, ed1));
636 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
637 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
638 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
639 res->res_cat.db_port, res->res_cat.db_name,
640 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
641 res->res_cat.mult_db_connections);
646 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
647 type == R_JOB ? _("Job") : _("JobDefs"),
648 res->res_job.hdr.name, res->res_job.JobType,
649 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
650 res->res_job.enabled);
651 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
652 res->res_job.MaxConcurrentJobs,
653 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
654 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
655 res->res_job.spool_data, res->res_job.write_part_after_job);
656 if (res->res_job.spool_size) {
657 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
659 if (res->res_job.JobType == JT_BACKUP) {
660 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
662 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
663 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
665 if (res->res_job.client) {
666 sendit(sock, _(" --> "));
667 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
669 if (res->res_job.fileset) {
670 sendit(sock, _(" --> "));
671 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
673 if (res->res_job.schedule) {
674 sendit(sock, _(" --> "));
675 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
677 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
678 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
680 if (res->res_job.RegexWhere) {
681 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
683 if (res->res_job.RestoreBootstrap) {
684 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
686 if (res->res_job.WriteBootstrap) {
687 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
689 if (res->res_job.PluginOptions) {
690 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
692 if (res->res_job.MaxRunTime) {
693 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
695 if (res->res_job.MaxWaitTime) {
696 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
698 if (res->res_job.MaxStartDelay) {
699 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
701 if (res->res_job.storage) {
703 foreach_alist(store, res->res_job.storage) {
704 sendit(sock, _(" --> "));
705 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
708 if (res->res_job.base) {
710 foreach_alist(job, res->res_job.base) {
711 sendit(sock, _(" --> Base %s\n"), job->name());
714 if (res->res_job.RunScripts) {
716 foreach_alist(script, res->res_job.RunScripts) {
717 sendit(sock, _(" --> RunScript\n"));
718 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
719 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
720 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
721 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
722 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
723 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
726 if (res->res_job.pool) {
727 sendit(sock, _(" --> "));
728 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
730 if (res->res_job.full_pool) {
731 sendit(sock, _(" --> "));
732 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
734 if (res->res_job.inc_pool) {
735 sendit(sock, _(" --> "));
736 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
738 if (res->res_job.diff_pool) {
739 sendit(sock, _(" --> "));
740 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
742 if (res->res_job.verify_job) {
743 sendit(sock, _(" --> "));
744 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
746 if (res->res_job.run_cmds) {
748 foreach_alist(runcmd, res->res_job.run_cmds) {
749 sendit(sock, _(" --> Run=%s\n"), runcmd);
752 if (res->res_job.selection_pattern) {
753 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
755 if (res->res_job.messages) {
756 sendit(sock, _(" --> "));
757 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
764 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
765 for (i=0; i<res->res_fs.num_includes; i++) {
766 INCEXE *incexe = res->res_fs.include_items[i];
767 for (j=0; j<incexe->num_opts; j++) {
768 FOPTS *fo = incexe->opts_list[j];
769 sendit(sock, " O %s\n", fo->opts);
771 bool enhanced_wild = false;
772 for (k=0; fo->opts[k]!='\0'; k++) {
773 if (fo->opts[k]=='W') {
774 enhanced_wild = true;
779 for (k=0; k<fo->regex.size(); k++) {
780 sendit(sock, " R %s\n", fo->regex.get(k));
782 for (k=0; k<fo->regexdir.size(); k++) {
783 sendit(sock, " RD %s\n", fo->regexdir.get(k));
785 for (k=0; k<fo->regexfile.size(); k++) {
786 sendit(sock, " RF %s\n", fo->regexfile.get(k));
788 for (k=0; k<fo->wild.size(); k++) {
789 sendit(sock, " W %s\n", fo->wild.get(k));
791 for (k=0; k<fo->wilddir.size(); k++) {
792 sendit(sock, " WD %s\n", fo->wilddir.get(k));
794 for (k=0; k<fo->wildfile.size(); k++) {
795 sendit(sock, " WF %s\n", fo->wildfile.get(k));
797 for (k=0; k<fo->wildbase.size(); k++) {
798 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
800 for (k=0; k<fo->base.size(); k++) {
801 sendit(sock, " B %s\n", fo->base.get(k));
803 for (k=0; k<fo->fstype.size(); k++) {
804 sendit(sock, " X %s\n", fo->fstype.get(k));
806 for (k=0; k<fo->drivetype.size(); k++) {
807 sendit(sock, " XD %s\n", fo->drivetype.get(k));
810 sendit(sock, " G %s\n", fo->plugin);
813 sendit(sock, " D %s\n", fo->reader);
816 sendit(sock, " T %s\n", fo->writer);
818 sendit(sock, " N\n");
820 if (incexe->ignoredir) {
821 sendit(sock, " Z %s\n", incexe->ignoredir);
823 for (j=0; j<incexe->name_list.size(); j++) {
824 sendit(sock, " I %s\n", incexe->name_list.get(j));
826 if (incexe->name_list.size()) {
827 sendit(sock, " N\n");
829 for (j=0; j<incexe->plugin_list.size(); j++) {
830 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
832 if (incexe->plugin_list.size()) {
833 sendit(sock, " N\n");
838 for (i=0; i<res->res_fs.num_excludes; i++) {
839 INCEXE *incexe = res->res_fs.exclude_items[i];
840 for (j=0; j<incexe->name_list.size(); j++) {
841 sendit(sock, " E %s\n", incexe->name_list.get(j));
843 if (incexe->name_list.size()) {
844 sendit(sock, " N\n");
851 if (res->res_sch.run) {
853 RUN *run = res->res_sch.run;
854 char buf[1000], num[30];
855 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
860 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
861 bstrncpy(buf, _(" hour="), sizeof(buf));
862 for (i=0; i<24; i++) {
863 if (bit_is_set(i, run->hour)) {
864 bsnprintf(num, sizeof(num), "%d ", i);
865 bstrncat(buf, num, sizeof(buf));
868 bstrncat(buf, "\n", sizeof(buf));
870 bstrncpy(buf, _(" mday="), sizeof(buf));
871 for (i=0; i<31; i++) {
872 if (bit_is_set(i, run->mday)) {
873 bsnprintf(num, sizeof(num), "%d ", i);
874 bstrncat(buf, num, sizeof(buf));
877 bstrncat(buf, "\n", sizeof(buf));
879 bstrncpy(buf, _(" month="), sizeof(buf));
880 for (i=0; i<12; i++) {
881 if (bit_is_set(i, run->month)) {
882 bsnprintf(num, sizeof(num), "%d ", i);
883 bstrncat(buf, num, sizeof(buf));
886 bstrncat(buf, "\n", sizeof(buf));
888 bstrncpy(buf, _(" wday="), sizeof(buf));
889 for (i=0; i<7; i++) {
890 if (bit_is_set(i, run->wday)) {
891 bsnprintf(num, sizeof(num), "%d ", i);
892 bstrncat(buf, num, sizeof(buf));
895 bstrncat(buf, "\n", sizeof(buf));
897 bstrncpy(buf, _(" wom="), sizeof(buf));
898 for (i=0; i<5; i++) {
899 if (bit_is_set(i, run->wom)) {
900 bsnprintf(num, sizeof(num), "%d ", i);
901 bstrncat(buf, num, sizeof(buf));
904 bstrncat(buf, "\n", sizeof(buf));
906 bstrncpy(buf, _(" woy="), sizeof(buf));
907 for (i=0; i<54; i++) {
908 if (bit_is_set(i, run->woy)) {
909 bsnprintf(num, sizeof(num), "%d ", i);
910 bstrncat(buf, num, sizeof(buf));
913 bstrncat(buf, "\n", sizeof(buf));
915 sendit(sock, _(" mins=%d\n"), run->minute);
917 sendit(sock, _(" --> "));
918 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
921 sendit(sock, _(" --> "));
922 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
925 sendit(sock, _(" --> "));
926 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
928 /* If another Run record is chained in, go print it */
934 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
939 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
940 res->res_pool.pool_type);
941 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
942 res->res_pool.use_catalog, res->res_pool.use_volume_once,
943 res->res_pool.catalog_files);
944 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
945 res->res_pool.max_volumes, res->res_pool.AutoPrune,
946 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
947 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
948 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
949 res->res_pool.Recycle,
950 NPRT(res->res_pool.label_format));
951 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
952 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
953 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
954 res->res_pool.recycle_oldest_volume,
955 res->res_pool.purge_oldest_volume,
956 res->res_pool.action_on_purge);
957 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
958 res->res_pool.MaxVolJobs,
959 res->res_pool.MaxVolFiles,
960 edit_uint64(res->res_pool.MaxVolBytes, ed1));
961 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
962 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
963 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
964 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
965 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
966 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
967 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)));
968 if (res->res_pool.NextPool) {
969 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
971 if (res->res_pool.RecyclePool) {
972 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
974 if (res->res_pool.ScratchPool) {
975 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
977 if (res->res_pool.catalog) {
978 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
980 if (res->res_pool.storage) {
982 foreach_alist(store, res->res_pool.storage) {
983 sendit(sock, _(" --> "));
984 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
987 if (res->res_pool.CopyPool) {
989 foreach_alist(copy, res->res_pool.CopyPool) {
990 sendit(sock, _(" --> "));
991 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
998 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
999 if (res->res_msgs.mail_cmd)
1000 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1001 if (res->res_msgs.operator_cmd)
1002 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1006 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1009 if (recurse && res->res_dir.hdr.next) {
1010 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1015 * Free all the members of an INCEXE structure
1017 static void free_incexe(INCEXE *incexe)
1019 incexe->name_list.destroy();
1020 incexe->plugin_list.destroy();
1021 for (int i=0; i<incexe->num_opts; i++) {
1022 FOPTS *fopt = incexe->opts_list[i];
1023 fopt->regex.destroy();
1024 fopt->regexdir.destroy();
1025 fopt->regexfile.destroy();
1026 fopt->wild.destroy();
1027 fopt->wilddir.destroy();
1028 fopt->wildfile.destroy();
1029 fopt->wildbase.destroy();
1030 fopt->base.destroy();
1031 fopt->fstype.destroy();
1032 fopt->drivetype.destroy();
1044 if (incexe->opts_list) {
1045 free(incexe->opts_list);
1047 if (incexe->ignoredir) {
1048 free(incexe->ignoredir);
1054 * Free memory of resource -- called when daemon terminates.
1055 * NB, we don't need to worry about freeing any references
1056 * to other resources as they will be freed when that
1057 * resource chain is traversed. Mainly we worry about freeing
1058 * allocated strings (names).
1060 void free_resource(RES *sres, int type)
1063 RES *nres; /* next resource if linked */
1064 URES *res = (URES *)sres;
1069 /* common stuff -- free the resource name and description */
1070 nres = (RES *)res->res_dir.hdr.next;
1071 if (res->res_dir.hdr.name) {
1072 free(res->res_dir.hdr.name);
1074 if (res->res_dir.hdr.desc) {
1075 free(res->res_dir.hdr.desc);
1080 if (res->res_dir.working_directory) {
1081 free(res->res_dir.working_directory);
1083 if (res->res_dir.scripts_directory) {
1084 free((char *)res->res_dir.scripts_directory);
1086 if (res->res_dir.plugin_directory) {
1087 free((char *)res->res_dir.plugin_directory);
1089 if (res->res_dir.pid_directory) {
1090 free(res->res_dir.pid_directory);
1092 if (res->res_dir.subsys_directory) {
1093 free(res->res_dir.subsys_directory);
1095 if (res->res_dir.password) {
1096 free(res->res_dir.password);
1098 if (res->res_dir.query_file) {
1099 free(res->res_dir.query_file);
1101 if (res->res_dir.DIRaddrs) {
1102 free_addresses(res->res_dir.DIRaddrs);
1104 if (res->res_dir.DIRsrc_addr) {
1105 free_addresses(res->res_dir.DIRsrc_addr);
1107 if (res->res_dir.tls_ctx) {
1108 free_tls_context(res->res_dir.tls_ctx);
1110 if (res->res_dir.tls_ca_certfile) {
1111 free(res->res_dir.tls_ca_certfile);
1113 if (res->res_dir.tls_ca_certdir) {
1114 free(res->res_dir.tls_ca_certdir);
1116 if (res->res_dir.tls_certfile) {
1117 free(res->res_dir.tls_certfile);
1119 if (res->res_dir.tls_keyfile) {
1120 free(res->res_dir.tls_keyfile);
1122 if (res->res_dir.tls_dhfile) {
1123 free(res->res_dir.tls_dhfile);
1125 if (res->res_dir.tls_allowed_cns) {
1126 delete res->res_dir.tls_allowed_cns;
1128 if (res->res_dir.verid) {
1129 free(res->res_dir.verid);
1136 if (res->res_con.password) {
1137 free(res->res_con.password);
1139 if (res->res_con.tls_ctx) {
1140 free_tls_context(res->res_con.tls_ctx);
1142 if (res->res_con.tls_ca_certfile) {
1143 free(res->res_con.tls_ca_certfile);
1145 if (res->res_con.tls_ca_certdir) {
1146 free(res->res_con.tls_ca_certdir);
1148 if (res->res_con.tls_certfile) {
1149 free(res->res_con.tls_certfile);
1151 if (res->res_con.tls_keyfile) {
1152 free(res->res_con.tls_keyfile);
1154 if (res->res_con.tls_dhfile) {
1155 free(res->res_con.tls_dhfile);
1157 if (res->res_con.tls_allowed_cns) {
1158 delete res->res_con.tls_allowed_cns;
1160 for (int i=0; i<Num_ACL; i++) {
1161 if (res->res_con.ACL_lists[i]) {
1162 delete res->res_con.ACL_lists[i];
1163 res->res_con.ACL_lists[i] = NULL;
1168 if (res->res_client.address) {
1169 free(res->res_client.address);
1171 if (res->res_client.password) {
1172 free(res->res_client.password);
1174 if (res->res_client.tls_ctx) {
1175 free_tls_context(res->res_client.tls_ctx);
1177 if (res->res_client.tls_ca_certfile) {
1178 free(res->res_client.tls_ca_certfile);
1180 if (res->res_client.tls_ca_certdir) {
1181 free(res->res_client.tls_ca_certdir);
1183 if (res->res_client.tls_certfile) {
1184 free(res->res_client.tls_certfile);
1186 if (res->res_client.tls_keyfile) {
1187 free(res->res_client.tls_keyfile);
1189 if (res->res_client.tls_allowed_cns) {
1190 delete res->res_client.tls_allowed_cns;
1194 if (res->res_store.address) {
1195 free(res->res_store.address);
1197 if (res->res_store.password) {
1198 free(res->res_store.password);
1200 if (res->res_store.media_type) {
1201 free(res->res_store.media_type);
1203 if (res->res_store.device) {
1204 delete res->res_store.device;
1206 if (res->res_store.tls_ctx) {
1207 free_tls_context(res->res_store.tls_ctx);
1209 if (res->res_store.tls_ca_certfile) {
1210 free(res->res_store.tls_ca_certfile);
1212 if (res->res_store.tls_ca_certdir) {
1213 free(res->res_store.tls_ca_certdir);
1215 if (res->res_store.tls_certfile) {
1216 free(res->res_store.tls_certfile);
1218 if (res->res_store.tls_keyfile) {
1219 free(res->res_store.tls_keyfile);
1223 if (res->res_cat.db_address) {
1224 free(res->res_cat.db_address);
1226 if (res->res_cat.db_socket) {
1227 free(res->res_cat.db_socket);
1229 if (res->res_cat.db_user) {
1230 free(res->res_cat.db_user);
1232 if (res->res_cat.db_name) {
1233 free(res->res_cat.db_name);
1235 if (res->res_cat.db_driver) {
1236 free(res->res_cat.db_driver);
1238 if (res->res_cat.db_password) {
1239 free(res->res_cat.db_password);
1243 if ((num=res->res_fs.num_includes)) {
1244 while (--num >= 0) {
1245 free_incexe(res->res_fs.include_items[num]);
1247 free(res->res_fs.include_items);
1249 res->res_fs.num_includes = 0;
1250 if ((num=res->res_fs.num_excludes)) {
1251 while (--num >= 0) {
1252 free_incexe(res->res_fs.exclude_items[num]);
1254 free(res->res_fs.exclude_items);
1256 res->res_fs.num_excludes = 0;
1259 if (res->res_pool.pool_type) {
1260 free(res->res_pool.pool_type);
1262 if (res->res_pool.label_format) {
1263 free(res->res_pool.label_format);
1265 if (res->res_pool.cleaning_prefix) {
1266 free(res->res_pool.cleaning_prefix);
1268 if (res->res_pool.storage) {
1269 delete res->res_pool.storage;
1273 if (res->res_sch.run) {
1275 nrun = res->res_sch.run;
1285 if (res->res_job.RestoreWhere) {
1286 free(res->res_job.RestoreWhere);
1288 if (res->res_job.RegexWhere) {
1289 free(res->res_job.RegexWhere);
1291 if (res->res_job.strip_prefix) {
1292 free(res->res_job.strip_prefix);
1294 if (res->res_job.add_prefix) {
1295 free(res->res_job.add_prefix);
1297 if (res->res_job.add_suffix) {
1298 free(res->res_job.add_suffix);
1300 if (res->res_job.RestoreBootstrap) {
1301 free(res->res_job.RestoreBootstrap);
1303 if (res->res_job.WriteBootstrap) {
1304 free(res->res_job.WriteBootstrap);
1306 if (res->res_job.PluginOptions) {
1307 free(res->res_job.PluginOptions);
1309 if (res->res_job.selection_pattern) {
1310 free(res->res_job.selection_pattern);
1312 if (res->res_job.run_cmds) {
1313 delete res->res_job.run_cmds;
1315 if (res->res_job.storage) {
1316 delete res->res_job.storage;
1318 if (res->res_job.base) {
1319 delete res->res_job.base;
1321 if (res->res_job.RunScripts) {
1322 free_runscripts(res->res_job.RunScripts);
1323 delete res->res_job.RunScripts;
1327 if (res->res_msgs.mail_cmd) {
1328 free(res->res_msgs.mail_cmd);
1330 if (res->res_msgs.operator_cmd) {
1331 free(res->res_msgs.operator_cmd);
1333 free_msgs_res((MSGS *)res); /* free message resource */
1337 printf(_("Unknown resource type %d in free_resource.\n"), type);
1339 /* Common stuff again -- free the resource, recurse to next one */
1344 free_resource(nres, type);
1349 * Save the new resource by chaining it into the head list for
1350 * the resource. If this is pass 2, we update any resource
1351 * pointers because they may not have been defined until
1354 void save_resource(int type, RES_ITEM *items, int pass)
1357 int rindex = type - r_first;
1361 /* Check Job requirements after applying JobDefs */
1362 if (type != R_JOB && type != R_JOBDEFS) {
1364 * Ensure that all required items are present
1366 for (i=0; items[i].name; i++) {
1367 if (items[i].flags & ITEM_REQUIRED) {
1368 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1369 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1370 items[i].name, resources[rindex]);
1373 /* If this triggers, take a look at lib/parse_conf.h */
1374 if (i >= MAX_RES_ITEMS) {
1375 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1378 } else if (type == R_JOB) {
1380 * Ensure that the name item is present
1382 if (items[0].flags & ITEM_REQUIRED) {
1383 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1384 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1385 items[0].name, resources[rindex]);
1391 * During pass 2 in each "store" routine, we looked up pointers
1392 * to all the resources referrenced in the current resource, now we
1393 * must copy their addresses from the static record to the allocated
1398 /* Resources not containing a resource */
1406 * Resources containing another resource or alist. First
1407 * look up the resource which contains another resource. It
1408 * was written during pass 1. Then stuff in the pointers to
1409 * the resources it contains, which were inserted this pass.
1410 * Finally, it will all be stored back.
1413 /* Find resource saved in pass 1 */
1414 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1415 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1417 /* Explicitly copy resource pointers from this pass (res_all) */
1418 res->res_pool.NextPool = res_all.res_pool.NextPool;
1419 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1420 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1421 res->res_pool.storage = res_all.res_pool.storage;
1422 res->res_pool.catalog = res_all.res_pool.catalog;
1425 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1426 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1428 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1431 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1432 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1434 res->res_dir.messages = res_all.res_dir.messages;
1435 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1438 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1439 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1440 res_all.res_dir.hdr.name);
1442 /* we must explicitly copy the device alist pointer */
1443 res->res_store.device = res_all.res_store.device;
1447 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1448 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1449 res_all.res_dir.hdr.name);
1451 res->res_job.messages = res_all.res_job.messages;
1452 res->res_job.schedule = res_all.res_job.schedule;
1453 res->res_job.client = res_all.res_job.client;
1454 res->res_job.fileset = res_all.res_job.fileset;
1455 res->res_job.storage = res_all.res_job.storage;
1456 res->res_job.base = res_all.res_job.base;
1457 res->res_job.pool = res_all.res_job.pool;
1458 res->res_job.full_pool = res_all.res_job.full_pool;
1459 res->res_job.inc_pool = res_all.res_job.inc_pool;
1460 res->res_job.diff_pool = res_all.res_job.diff_pool;
1461 res->res_job.verify_job = res_all.res_job.verify_job;
1462 res->res_job.jobdefs = res_all.res_job.jobdefs;
1463 res->res_job.run_cmds = res_all.res_job.run_cmds;
1464 res->res_job.RunScripts = res_all.res_job.RunScripts;
1466 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1467 * is not very useful)
1468 * We have to set_bit(index, res_all.hdr.item_present);
1469 * or something like that
1472 /* we take RegexWhere before all other options */
1473 if (!res->res_job.RegexWhere
1475 (res->res_job.strip_prefix ||
1476 res->res_job.add_suffix ||
1477 res->res_job.add_prefix))
1479 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1480 res->res_job.add_prefix,
1481 res->res_job.add_suffix);
1482 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1483 bregexp_build_where(res->res_job.RegexWhere, len,
1484 res->res_job.strip_prefix,
1485 res->res_job.add_prefix,
1486 res->res_job.add_suffix);
1487 /* TODO: test bregexp */
1490 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1491 free(res->res_job.RestoreWhere);
1492 res->res_job.RestoreWhere = NULL;
1497 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1498 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1500 res->res_counter.Catalog = res_all.res_counter.Catalog;
1501 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1505 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1506 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1508 res->res_client.catalog = res_all.res_client.catalog;
1509 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1513 * Schedule is a bit different in that it contains a RUN record
1514 * chain which isn't a "named" resource. This chain was linked
1515 * in by run_conf.c during pass 2, so here we jam the pointer
1516 * into the Schedule resource.
1518 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1519 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1521 res->res_sch.run = res_all.res_sch.run;
1524 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1528 /* Note, the resource name was already saved during pass 1,
1529 * so here, we can just release it.
1531 if (res_all.res_dir.hdr.name) {
1532 free(res_all.res_dir.hdr.name);
1533 res_all.res_dir.hdr.name = NULL;
1535 if (res_all.res_dir.hdr.desc) {
1536 free(res_all.res_dir.hdr.desc);
1537 res_all.res_dir.hdr.desc = NULL;
1543 * The following code is only executed during pass 1
1547 size = sizeof(DIRRES);
1550 size = sizeof(CONRES);
1553 size =sizeof(CLIENT);
1556 size = sizeof(STORE);
1566 size = sizeof(FILESET);
1569 size = sizeof(SCHED);
1572 size = sizeof(POOL);
1575 size = sizeof(MSGS);
1578 size = sizeof(COUNTER);
1584 printf(_("Unknown resource type %d in save_resource.\n"), type);
1590 res = (URES *)malloc(size);
1591 memcpy(res, &res_all, size);
1592 if (!res_head[rindex]) {
1593 res_head[rindex] = (RES *)res; /* store first entry */
1594 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1595 res->res_dir.hdr.name, rindex);
1598 if (res->res_dir.hdr.name == NULL) {
1599 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1602 /* Add new res to end of chain */
1603 for (last=next=res_head[rindex]; next; next=next->next) {
1605 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1606 Emsg2(M_ERROR_TERM, 0,
1607 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1608 resources[rindex].name, res->res_dir.hdr.name);
1611 last->next = (RES *)res;
1612 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1613 res->res_dir.hdr.name, rindex, pass);
1618 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1620 uint32_t *destination = (uint32_t*)item->value;
1621 lex_get_token(lc, T_NAME);
1622 if (strcasecmp(lc->str, "truncate") == 0) {
1623 *destination = (*destination) | AOP_TRUNCATE;
1625 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1629 set_bit(index, res_all.hdr.item_present);
1633 * Store Device. Note, the resource is created upon the
1634 * first reference. The details of the resource are obtained
1635 * later from the SD.
1637 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1641 int rindex = R_DEVICE - r_first;
1642 int size = sizeof(DEVICE);
1646 token = lex_get_token(lc, T_NAME);
1647 if (!res_head[rindex]) {
1648 res = (URES *)malloc(size);
1649 memset(res, 0, size);
1650 res->res_dev.hdr.name = bstrdup(lc->str);
1651 res_head[rindex] = (RES *)res; /* store first entry */
1652 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1653 res->res_dir.hdr.name, rindex);
1656 /* See if it is already defined */
1657 for (next=res_head[rindex]; next->next; next=next->next) {
1658 if (strcmp(next->name, lc->str) == 0) {
1664 res = (URES *)malloc(size);
1665 memset(res, 0, size);
1666 res->res_dev.hdr.name = bstrdup(lc->str);
1667 next->next = (RES *)res;
1668 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1669 res->res_dir.hdr.name, rindex, pass);
1674 set_bit(index, res_all.hdr.item_present);
1676 store_alist_res(lc, item, index, pass);
1681 * Store Migration/Copy type
1684 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1688 token = lex_get_token(lc, T_NAME);
1689 /* Store the type both pass 1 and pass 2 */
1690 for (i=0; migtypes[i].type_name; i++) {
1691 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1692 *(uint32_t *)(item->value) = migtypes[i].job_type;
1698 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1701 set_bit(index, res_all.hdr.item_present);
1707 * Store JobType (backup, verify, restore)
1710 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1714 token = lex_get_token(lc, T_NAME);
1715 /* Store the type both pass 1 and pass 2 */
1716 for (i=0; jobtypes[i].type_name; i++) {
1717 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1718 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1724 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1727 set_bit(index, res_all.hdr.item_present);
1731 * Store Job Level (Full, Incremental, ...)
1734 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1738 token = lex_get_token(lc, T_NAME);
1739 /* Store the level pass 2 so that type is defined */
1740 for (i=0; joblevels[i].level_name; i++) {
1741 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1742 *(uint32_t *)(item->value) = joblevels[i].level;
1748 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1751 set_bit(index, res_all.hdr.item_present);
1755 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1758 token = lex_get_token(lc, T_NAME);
1759 /* Scan Replacement options */
1760 for (i=0; ReplaceOptions[i].name; i++) {
1761 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1762 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1768 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1771 set_bit(index, res_all.hdr.item_present);
1775 * Store ACL (access control list)
1778 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1783 token = lex_get_token(lc, T_STRING);
1785 if (((alist **)item->value)[item->code] == NULL) {
1786 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1787 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1789 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1790 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1792 token = lex_get_token(lc, T_ALL);
1793 if (token == T_COMMA) {
1794 continue; /* get another ACL */
1798 set_bit(index, res_all.hdr.item_present);
1801 /* We build RunScripts items here */
1802 static RUNSCRIPT res_runscript;
1804 /* Store a runscript->when in a bit field */
1805 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1807 lex_get_token(lc, T_NAME);
1809 if (strcasecmp(lc->str, "before") == 0) {
1810 *(uint32_t *)(item->value) = SCRIPT_Before ;
1811 } else if (strcasecmp(lc->str, "after") == 0) {
1812 *(uint32_t *)(item->value) = SCRIPT_After;
1813 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1814 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1815 } else if (strcasecmp(lc->str, "always") == 0) {
1816 *(uint32_t *)(item->value) = SCRIPT_Any;
1818 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1823 /* Store a runscript->target
1826 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1828 lex_get_token(lc, T_STRING);
1831 if (strcmp(lc->str, "%c") == 0) {
1832 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1833 } else if (strcasecmp(lc->str, "yes") == 0) {
1834 ((RUNSCRIPT*) item->value)->set_target("%c");
1835 } else if (strcasecmp(lc->str, "no") == 0) {
1836 ((RUNSCRIPT*) item->value)->set_target("");
1838 RES *res = GetResWithName(R_CLIENT, lc->str);
1840 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1841 lc->str, lc->line_no, lc->line);
1844 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1851 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1853 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1855 lex_get_token(lc, T_STRING);
1858 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1859 POOLMEM *c = get_pool_memory(PM_FNAME);
1860 /* Each runscript command takes 2 entries in commands list */
1861 pm_strcpy(c, lc->str);
1862 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1863 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1868 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1870 lex_get_token(lc, T_STRING);
1871 alist **runscripts = (alist **)(item->value) ;
1874 RUNSCRIPT *script = new_runscript();
1875 script->set_job_code_callback(job_code_callback_filesetname);
1877 script->set_command(lc->str);
1879 /* TODO: remove all script->old_proto with bacula 1.42 */
1881 if (strcmp(item->name, "runbeforejob") == 0) {
1882 script->when = SCRIPT_Before;
1883 script->fail_on_error = true;
1884 script->set_target("");
1886 } else if (strcmp(item->name, "runafterjob") == 0) {
1887 script->when = SCRIPT_After;
1888 script->on_success = true;
1889 script->on_failure = false;
1890 script->set_target("");
1892 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1893 script->old_proto = true;
1894 script->when = SCRIPT_After;
1895 script->set_target("%c");
1896 script->on_success = true;
1897 script->on_failure = false;
1899 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1900 script->old_proto = true;
1901 script->when = SCRIPT_Before;
1902 script->set_target("%c");
1903 script->fail_on_error = true;
1905 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1906 script->when = SCRIPT_After;
1907 script->on_failure = true;
1908 script->on_success = false;
1909 script->set_target("");
1912 if (*runscripts == NULL) {
1913 *runscripts = New(alist(10, not_owned_by_alist));
1916 (*runscripts)->append(script);
1923 /* Store a bool in a bit field without modifing res_all.hdr
1924 * We can also add an option to store_bool to skip res_all.hdr
1926 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1928 lex_get_token(lc, T_NAME);
1929 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1930 *(bool *)(item->value) = true;
1931 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1932 *(bool *)(item->value) = false;
1934 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1940 * new RunScript items
1941 * name handler value code flags default_value
1943 static RES_ITEM runscript_items[] = {
1944 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1945 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1946 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1947 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1948 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1949 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1950 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1951 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1952 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1953 {NULL, NULL, {0}, 0, 0, 0}
1957 * Store RunScript info
1959 * Note, when this routine is called, we are inside a Job
1960 * resource. We treat the RunScript like a sort of
1961 * mini-resource within the Job resource.
1963 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1967 alist **runscripts = (alist **)(item->value) ;
1969 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1971 token = lex_get_token(lc, T_SKIP_EOL);
1973 if (token != T_BOB) {
1974 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1976 /* setting on_success, on_failure, fail_on_error */
1977 res_runscript.reset_default();
1980 res_runscript.commands = New(alist(10, not_owned_by_alist));
1983 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1984 if (token == T_EOB) {
1987 if (token != T_IDENTIFIER) {
1988 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1990 for (i=0; runscript_items[i].name; i++) {
1991 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1992 token = lex_get_token(lc, T_SKIP_EOL);
1993 if (token != T_EQUALS) {
1994 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1997 /* Call item handler */
1998 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2005 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2010 /* run on client by default */
2011 if (res_runscript.target == NULL) {
2012 res_runscript.set_target("%c");
2014 if (*runscripts == NULL) {
2015 *runscripts = New(alist(10, not_owned_by_alist));
2018 * commands list contains 2 values per command
2019 * - POOLMEM command string (ex: /bin/true)
2020 * - int command type (ex: SHELL_CMD)
2022 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2023 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2024 t = (intptr_t)res_runscript.commands->pop();
2025 RUNSCRIPT *script = new_runscript();
2026 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2027 script->command = c;
2028 script->cmd_type = t;
2029 /* target is taken from res_runscript, each runscript object have
2032 script->target = NULL;
2033 script->set_target(res_runscript.target);
2035 (*runscripts)->append(script);
2038 delete res_runscript.commands;
2039 /* setting on_success, on_failure... cleanup target field */
2040 res_runscript.reset_default(true);
2044 set_bit(index, res_all.hdr.item_present);
2047 /* callback function for edit_job_codes */
2048 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2050 if (param[0] == 'f') {
2051 return jcr->fileset->name();
2057 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2059 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2060 r_first, r_last, resources, res_head);
2061 return config->parse_config();