2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula Directors,
30 * some parts may be split into separate files such as
31 * the schedule configuration (run_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, January MM
56 /* Define the first and last resource ID record
57 * types. Note, these should be unique for each
58 * daemon though not a requirement.
60 int32_t r_first = R_FIRST;
61 int32_t r_last = R_LAST;
62 static RES *sres_head[R_LAST - R_FIRST + 1];
63 RES **res_head = sres_head;
65 /* Imported subroutines */
66 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
68 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
71 /* Forward referenced subroutines */
73 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
77 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
84 /* We build the current resource here as we are
85 * scanning the resource configuration definition,
86 * then move it to allocated memory when the resource
90 extern "C" { // work around visual compiler mangling variables
96 int32_t res_all_size = sizeof(res_all);
99 /* Definition of records permitted within each
100 * resource with the routine to process the record
101 * information. NOTE! quoted names must be in lower case.
106 * name handler value code flags default_value
108 static RES_ITEM dir_items[] = {
109 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
110 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
111 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
112 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
116 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
117 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
118 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
119 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
120 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
121 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
122 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
123 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
124 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
125 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
126 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
127 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
128 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
129 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
130 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
131 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
132 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
133 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
134 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
135 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
136 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
137 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
138 {NULL, NULL, {0}, 0, 0, 0}
144 * name handler value code flags default_value
146 static RES_ITEM con_items[] = {
147 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
148 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
149 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
150 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
151 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
152 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
153 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
154 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
155 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
156 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
157 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
158 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
159 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
160 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
161 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
162 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
163 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
164 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
165 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
166 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
167 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
168 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
169 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
170 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
171 {NULL, NULL, {0}, 0, 0, 0}
176 * Client or File daemon resource
178 * name handler value code flags default_value
181 static RES_ITEM cli_items[] = {
182 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
183 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
184 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
185 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
186 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
187 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
188 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
189 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
190 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
191 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
192 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
193 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
194 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
195 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
196 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
197 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
198 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
199 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
200 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
201 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
202 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
203 {NULL, NULL, {0}, 0, 0, 0}
206 /* Storage daemon resource
208 * name handler value code flags default_value
210 static RES_ITEM store_items[] = {
211 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
212 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
213 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
214 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
215 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
216 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
217 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
218 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
219 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
220 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
221 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
222 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
223 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
224 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
225 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
226 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
227 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
228 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
229 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
230 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
231 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
232 {NULL, NULL, {0}, 0, 0, 0}
236 * Catalog Resource Directives
238 * name handler value code flags default_value
240 static RES_ITEM cat_items[] = {
241 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
242 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
243 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
244 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
245 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
246 /* keep this password as store_str for the moment */
247 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
248 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
249 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
250 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
251 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
252 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
253 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
254 /* Turned off for the moment */
255 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
256 {NULL, NULL, {0}, 0, 0, 0}
260 * Job Resource Directives
262 * name handler value code flags default_value
264 RES_ITEM job_items[] = {
265 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
266 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
267 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
268 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
269 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
270 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
271 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
272 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
273 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
274 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
275 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
276 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
277 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
278 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
279 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
280 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
281 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
282 /* Root of where to restore files */
283 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
284 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
285 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
286 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
287 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
288 /* Where to find bootstrap during restore */
289 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
290 /* Where to write bootstrap file during backup */
291 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
292 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
293 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
294 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
295 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
296 /* xxxMaxWaitTime are deprecated */
297 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
298 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
299 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
300 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
301 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
302 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
303 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
304 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
305 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
306 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
307 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
308 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
309 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
310 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
311 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
312 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
313 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
314 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
315 {"spoolsize", store_size, ITEM(res_job.spool_size), 0, 0, 0},
316 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
317 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
318 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
319 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
320 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
324 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
325 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
326 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
327 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
328 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
329 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
330 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
331 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
332 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
333 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
334 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, false},
335 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
336 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, true},
337 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
338 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
339 {NULL, NULL, {0}, 0, 0, 0}
344 * name handler value code flags default_value
346 static RES_ITEM fs_items[] = {
347 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
348 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
349 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
350 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
351 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
352 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
353 {NULL, NULL, {0}, 0, 0, 0}
356 /* Schedule -- see run_conf.c */
359 * name handler value code flags default_value
361 static RES_ITEM sch_items[] = {
362 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
363 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
364 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
365 {NULL, NULL, {0}, 0, 0, 0}
370 * name handler value code flags default_value
372 static RES_ITEM pool_items[] = {
373 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
374 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
375 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
376 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
377 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
378 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
379 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
380 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
381 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
382 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
383 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
384 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
385 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
386 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
387 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
388 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
389 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
390 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
391 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
392 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
393 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
394 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
395 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
396 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
397 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
398 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
399 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
400 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
401 {NULL, NULL, {0}, 0, 0, 0}
406 * name handler value code flags default_value
408 static RES_ITEM counter_items[] = {
409 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
410 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
411 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
412 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
413 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
414 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
415 {NULL, NULL, {0}, 0, 0, 0}
419 /* Message resource */
420 extern RES_ITEM msgs_items[];
423 * This is the master resource definition.
424 * It must have one item for each of the resources.
426 * NOTE!!! keep it in the same order as the R_codes
427 * or eliminate all resources[rindex].name
429 * name items rcode res_head
431 RES_TABLE resources[] = {
432 {"director", dir_items, R_DIRECTOR},
433 {"client", cli_items, R_CLIENT},
434 {"job", job_items, R_JOB},
435 {"storage", store_items, R_STORAGE},
436 {"catalog", cat_items, R_CATALOG},
437 {"schedule", sch_items, R_SCHEDULE},
438 {"fileset", fs_items, R_FILESET},
439 {"pool", pool_items, R_POOL},
440 {"messages", msgs_items, R_MSGS},
441 {"counter", counter_items, R_COUNTER},
442 {"console", con_items, R_CONSOLE},
443 {"jobdefs", job_items, R_JOBDEFS},
444 {"device", NULL, R_DEVICE}, /* info obtained from SD */
449 /* Keywords (RHS) permitted in Job Level records
451 * level_name level job_type
453 struct s_jl joblevels[] = {
454 {"Full", L_FULL, JT_BACKUP},
455 {"Base", L_BASE, JT_BACKUP},
456 {"Incremental", L_INCREMENTAL, JT_BACKUP},
457 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
458 {"Since", L_SINCE, JT_BACKUP},
459 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
460 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
461 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
462 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
463 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
464 {"Data", L_VERIFY_DATA, JT_VERIFY},
465 {" ", L_NONE, JT_ADMIN},
466 {" ", L_NONE, JT_RESTORE},
470 /* Keywords (RHS) permitted in Job type records
474 struct s_jt jobtypes[] = {
475 {"backup", JT_BACKUP},
477 {"verify", JT_VERIFY},
478 {"restore", JT_RESTORE},
479 {"migrate", JT_MIGRATE},
485 /* Keywords (RHS) permitted in Selection type records
489 struct s_jt migtypes[] = {
490 {"smallestvolume", MT_SMALLEST_VOL},
491 {"oldestvolume", MT_OLDEST_VOL},
492 {"pooloccupancy", MT_POOL_OCCUPANCY},
493 {"pooltime", MT_POOL_TIME},
494 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
495 {"client", MT_CLIENT},
496 {"volume", MT_VOLUME},
498 {"sqlquery", MT_SQLQUERY},
504 /* Options permitted in Restore replace= */
505 struct s_kw ReplaceOptions[] = {
506 {"always", REPLACE_ALWAYS},
507 {"ifnewer", REPLACE_IFNEWER},
508 {"ifolder", REPLACE_IFOLDER},
509 {"never", REPLACE_NEVER},
513 char *CAT::display(POOLMEM *dst) {
514 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
515 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
517 name(), NPRTB(db_name),
518 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
519 NPRTB(db_address), db_port, NPRTB(db_socket));
523 const char *level_to_str(int level)
526 static char level_no[30];
527 const char *str = level_no;
529 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
530 for (i=0; joblevels[i].level_name; i++) {
531 if (level == (int)joblevels[i].level) {
532 str = joblevels[i].level_name;
539 /* Dump contents of resource */
540 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
542 URES *res = (URES *)reshdr;
544 char ed1[100], ed2[100], ed3[100];
548 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
551 if (type < 0) { /* no recursion */
557 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
558 reshdr->name, res->res_dir.MaxConcurrentJobs,
559 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
560 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
561 if (res->res_dir.query_file) {
562 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
564 if (res->res_dir.messages) {
565 sendit(sock, _(" --> "));
566 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
570 sendit(sock, _("Console: name=%s SSL=%d\n"),
571 res->res_con.hdr.name, res->res_con.tls_enable);
574 if (res->res_counter.WrapCounter) {
575 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
576 res->res_counter.hdr.name, res->res_counter.MinValue,
577 res->res_counter.MaxValue, res->res_counter.CurrentValue,
578 res->res_counter.WrapCounter->hdr.name);
580 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
581 res->res_counter.hdr.name, res->res_counter.MinValue,
582 res->res_counter.MaxValue);
584 if (res->res_counter.Catalog) {
585 sendit(sock, _(" --> "));
586 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
591 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
592 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
593 res->res_client.MaxConcurrentJobs);
594 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
595 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
596 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
597 res->res_client.AutoPrune);
598 if (res->res_client.catalog) {
599 sendit(sock, _(" --> "));
600 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
607 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
608 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
609 " poolid=%s volname=%s MediaType=%s\n"),
610 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
611 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
612 dev->offline, dev->autochanger,
613 edit_uint64(dev->PoolId, ed1),
614 dev->VolumeName, dev->MediaType);
618 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
619 " DeviceName=%s MediaType=%s StorageId=%s\n"),
620 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
621 res->res_store.MaxConcurrentJobs,
622 res->res_store.dev_name(),
623 res->res_store.media_type,
624 edit_int64(res->res_store.StorageId, ed1));
628 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
629 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
630 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
631 res->res_cat.db_port, res->res_cat.db_name,
632 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
633 res->res_cat.mult_db_connections);
638 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
639 type == R_JOB ? _("Job") : _("JobDefs"),
640 res->res_job.hdr.name, res->res_job.JobType,
641 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
642 res->res_job.enabled);
643 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
644 res->res_job.MaxConcurrentJobs,
645 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
646 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
647 res->res_job.spool_data, res->res_job.write_part_after_job);
648 if (res->res_job.spool_size) {
649 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
651 if (res->res_job.JobType == JT_BACKUP) {
652 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
654 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
655 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
657 if (res->res_job.client) {
658 sendit(sock, _(" --> "));
659 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
661 if (res->res_job.fileset) {
662 sendit(sock, _(" --> "));
663 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
665 if (res->res_job.schedule) {
666 sendit(sock, _(" --> "));
667 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
669 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
670 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
672 if (res->res_job.RegexWhere) {
673 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
675 if (res->res_job.RestoreBootstrap) {
676 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
678 if (res->res_job.WriteBootstrap) {
679 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
681 if (res->res_job.PluginOptions) {
682 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
684 if (res->res_job.MaxRunTime) {
685 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
687 if (res->res_job.MaxWaitTime) {
688 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
690 if (res->res_job.MaxStartDelay) {
691 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
693 if (res->res_job.storage) {
695 foreach_alist(store, res->res_job.storage) {
696 sendit(sock, _(" --> "));
697 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
700 if (res->res_job.RunScripts) {
702 foreach_alist(script, res->res_job.RunScripts) {
703 sendit(sock, _(" --> RunScript\n"));
704 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
705 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
706 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
707 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
708 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
709 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
712 if (res->res_job.pool) {
713 sendit(sock, _(" --> "));
714 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
716 if (res->res_job.full_pool) {
717 sendit(sock, _(" --> "));
718 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
720 if (res->res_job.inc_pool) {
721 sendit(sock, _(" --> "));
722 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
724 if (res->res_job.diff_pool) {
725 sendit(sock, _(" --> "));
726 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
728 if (res->res_job.verify_job) {
729 sendit(sock, _(" --> "));
730 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
732 if (res->res_job.run_cmds) {
734 foreach_alist(runcmd, res->res_job.run_cmds) {
735 sendit(sock, _(" --> Run=%s\n"), runcmd);
738 if (res->res_job.selection_pattern) {
739 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
741 if (res->res_job.messages) {
742 sendit(sock, _(" --> "));
743 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
750 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
751 for (i=0; i<res->res_fs.num_includes; i++) {
752 INCEXE *incexe = res->res_fs.include_items[i];
753 for (j=0; j<incexe->num_opts; j++) {
754 FOPTS *fo = incexe->opts_list[j];
755 sendit(sock, " O %s\n", fo->opts);
757 bool enhanced_wild = false;
758 for (k=0; fo->opts[k]!='\0'; k++) {
759 if (fo->opts[k]=='W') {
760 enhanced_wild = true;
765 for (k=0; k<fo->regex.size(); k++) {
766 sendit(sock, " R %s\n", fo->regex.get(k));
768 for (k=0; k<fo->regexdir.size(); k++) {
769 sendit(sock, " RD %s\n", fo->regexdir.get(k));
771 for (k=0; k<fo->regexfile.size(); k++) {
772 sendit(sock, " RF %s\n", fo->regexfile.get(k));
774 for (k=0; k<fo->wild.size(); k++) {
775 sendit(sock, " W %s\n", fo->wild.get(k));
777 for (k=0; k<fo->wilddir.size(); k++) {
778 sendit(sock, " WD %s\n", fo->wilddir.get(k));
780 for (k=0; k<fo->wildfile.size(); k++) {
781 sendit(sock, " WF %s\n", fo->wildfile.get(k));
783 for (k=0; k<fo->wildbase.size(); k++) {
784 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
786 for (k=0; k<fo->base.size(); k++) {
787 sendit(sock, " B %s\n", fo->base.get(k));
789 for (k=0; k<fo->fstype.size(); k++) {
790 sendit(sock, " X %s\n", fo->fstype.get(k));
792 for (k=0; k<fo->drivetype.size(); k++) {
793 sendit(sock, " XD %s\n", fo->drivetype.get(k));
796 sendit(sock, " G %s\n", fo->plugin);
799 sendit(sock, " D %s\n", fo->reader);
802 sendit(sock, " T %s\n", fo->writer);
804 sendit(sock, " N\n");
806 for (j=0; j<incexe->name_list.size(); j++) {
807 sendit(sock, " I %s\n", incexe->name_list.get(j));
809 if (incexe->name_list.size()) {
810 sendit(sock, " N\n");
812 for (j=0; j<incexe->plugin_list.size(); j++) {
813 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
815 if (incexe->plugin_list.size()) {
816 sendit(sock, " N\n");
821 for (i=0; i<res->res_fs.num_excludes; i++) {
822 INCEXE *incexe = res->res_fs.exclude_items[i];
823 for (j=0; j<incexe->name_list.size(); j++) {
824 sendit(sock, " E %s\n", incexe->name_list.get(j));
826 if (incexe->name_list.size()) {
827 sendit(sock, " N\n");
834 if (res->res_sch.run) {
836 RUN *run = res->res_sch.run;
837 char buf[1000], num[30];
838 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
843 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
844 bstrncpy(buf, _(" hour="), sizeof(buf));
845 for (i=0; i<24; i++) {
846 if (bit_is_set(i, run->hour)) {
847 bsnprintf(num, sizeof(num), "%d ", i);
848 bstrncat(buf, num, sizeof(buf));
851 bstrncat(buf, "\n", sizeof(buf));
853 bstrncpy(buf, _(" mday="), sizeof(buf));
854 for (i=0; i<31; i++) {
855 if (bit_is_set(i, run->mday)) {
856 bsnprintf(num, sizeof(num), "%d ", i);
857 bstrncat(buf, num, sizeof(buf));
860 bstrncat(buf, "\n", sizeof(buf));
862 bstrncpy(buf, _(" month="), sizeof(buf));
863 for (i=0; i<12; i++) {
864 if (bit_is_set(i, run->month)) {
865 bsnprintf(num, sizeof(num), "%d ", i);
866 bstrncat(buf, num, sizeof(buf));
869 bstrncat(buf, "\n", sizeof(buf));
871 bstrncpy(buf, _(" wday="), sizeof(buf));
872 for (i=0; i<7; i++) {
873 if (bit_is_set(i, run->wday)) {
874 bsnprintf(num, sizeof(num), "%d ", i);
875 bstrncat(buf, num, sizeof(buf));
878 bstrncat(buf, "\n", sizeof(buf));
880 bstrncpy(buf, _(" wom="), sizeof(buf));
881 for (i=0; i<5; i++) {
882 if (bit_is_set(i, run->wom)) {
883 bsnprintf(num, sizeof(num), "%d ", i);
884 bstrncat(buf, num, sizeof(buf));
887 bstrncat(buf, "\n", sizeof(buf));
889 bstrncpy(buf, _(" woy="), sizeof(buf));
890 for (i=0; i<54; i++) {
891 if (bit_is_set(i, run->woy)) {
892 bsnprintf(num, sizeof(num), "%d ", i);
893 bstrncat(buf, num, sizeof(buf));
896 bstrncat(buf, "\n", sizeof(buf));
898 sendit(sock, _(" mins=%d\n"), run->minute);
900 sendit(sock, _(" --> "));
901 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
904 sendit(sock, _(" --> "));
905 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
908 sendit(sock, _(" --> "));
909 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
911 /* If another Run record is chained in, go print it */
917 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
922 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
923 res->res_pool.pool_type);
924 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
925 res->res_pool.use_catalog, res->res_pool.use_volume_once,
926 res->res_pool.catalog_files);
927 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
928 res->res_pool.max_volumes, res->res_pool.AutoPrune,
929 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
930 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
931 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
932 res->res_pool.Recycle,
933 NPRT(res->res_pool.label_format));
934 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
935 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
936 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
937 res->res_pool.recycle_oldest_volume,
938 res->res_pool.purge_oldest_volume);
939 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
940 res->res_pool.MaxVolJobs,
941 res->res_pool.MaxVolFiles,
942 edit_uint64(res->res_pool.MaxVolFiles, ed1));
943 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
944 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
945 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
946 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
947 if (res->res_pool.NextPool) {
948 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
950 if (res->res_pool.RecyclePool) {
951 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
953 if (res->res_pool.catalog) {
954 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
956 if (res->res_pool.storage) {
958 foreach_alist(store, res->res_pool.storage) {
959 sendit(sock, _(" --> "));
960 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
963 if (res->res_pool.CopyPool) {
965 foreach_alist(copy, res->res_pool.CopyPool) {
966 sendit(sock, _(" --> "));
967 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
974 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
975 if (res->res_msgs.mail_cmd)
976 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
977 if (res->res_msgs.operator_cmd)
978 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
982 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
985 if (recurse && res->res_dir.hdr.next) {
986 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
991 * Free all the members of an INCEXE structure
993 static void free_incexe(INCEXE *incexe)
995 incexe->name_list.destroy();
996 incexe->plugin_list.destroy();
997 for (int i=0; i<incexe->num_opts; i++) {
998 FOPTS *fopt = incexe->opts_list[i];
999 fopt->regex.destroy();
1000 fopt->regexdir.destroy();
1001 fopt->regexfile.destroy();
1002 fopt->wild.destroy();
1003 fopt->wilddir.destroy();
1004 fopt->wildfile.destroy();
1005 fopt->wildbase.destroy();
1006 fopt->base.destroy();
1007 fopt->fstype.destroy();
1008 fopt->drivetype.destroy();
1020 if (incexe->opts_list) {
1021 free(incexe->opts_list);
1027 * Free memory of resource -- called when daemon terminates.
1028 * NB, we don't need to worry about freeing any references
1029 * to other resources as they will be freed when that
1030 * resource chain is traversed. Mainly we worry about freeing
1031 * allocated strings (names).
1033 void free_resource(RES *sres, int type)
1036 RES *nres; /* next resource if linked */
1037 URES *res = (URES *)sres;
1042 /* common stuff -- free the resource name and description */
1043 nres = (RES *)res->res_dir.hdr.next;
1044 if (res->res_dir.hdr.name) {
1045 free(res->res_dir.hdr.name);
1047 if (res->res_dir.hdr.desc) {
1048 free(res->res_dir.hdr.desc);
1053 if (res->res_dir.working_directory) {
1054 free(res->res_dir.working_directory);
1056 if (res->res_dir.scripts_directory) {
1057 free((char *)res->res_dir.scripts_directory);
1059 if (res->res_dir.plugin_directory) {
1060 free((char *)res->res_dir.plugin_directory);
1062 if (res->res_dir.pid_directory) {
1063 free(res->res_dir.pid_directory);
1065 if (res->res_dir.subsys_directory) {
1066 free(res->res_dir.subsys_directory);
1068 if (res->res_dir.password) {
1069 free(res->res_dir.password);
1071 if (res->res_dir.query_file) {
1072 free(res->res_dir.query_file);
1074 if (res->res_dir.DIRaddrs) {
1075 free_addresses(res->res_dir.DIRaddrs);
1077 if (res->res_dir.tls_ctx) {
1078 free_tls_context(res->res_dir.tls_ctx);
1080 if (res->res_dir.tls_ca_certfile) {
1081 free(res->res_dir.tls_ca_certfile);
1083 if (res->res_dir.tls_ca_certdir) {
1084 free(res->res_dir.tls_ca_certdir);
1086 if (res->res_dir.tls_certfile) {
1087 free(res->res_dir.tls_certfile);
1089 if (res->res_dir.tls_keyfile) {
1090 free(res->res_dir.tls_keyfile);
1092 if (res->res_dir.tls_dhfile) {
1093 free(res->res_dir.tls_dhfile);
1095 if (res->res_dir.tls_allowed_cns) {
1096 delete res->res_dir.tls_allowed_cns;
1098 if (res->res_dir.verid) {
1099 free(res->res_dir.verid);
1106 if (res->res_con.password) {
1107 free(res->res_con.password);
1109 if (res->res_con.tls_ctx) {
1110 free_tls_context(res->res_con.tls_ctx);
1112 if (res->res_con.tls_ca_certfile) {
1113 free(res->res_con.tls_ca_certfile);
1115 if (res->res_con.tls_ca_certdir) {
1116 free(res->res_con.tls_ca_certdir);
1118 if (res->res_con.tls_certfile) {
1119 free(res->res_con.tls_certfile);
1121 if (res->res_con.tls_keyfile) {
1122 free(res->res_con.tls_keyfile);
1124 if (res->res_con.tls_dhfile) {
1125 free(res->res_con.tls_dhfile);
1127 if (res->res_con.tls_allowed_cns) {
1128 delete res->res_con.tls_allowed_cns;
1130 for (int i=0; i<Num_ACL; i++) {
1131 if (res->res_con.ACL_lists[i]) {
1132 delete res->res_con.ACL_lists[i];
1133 res->res_con.ACL_lists[i] = NULL;
1138 if (res->res_client.address) {
1139 free(res->res_client.address);
1141 if (res->res_client.password) {
1142 free(res->res_client.password);
1144 if (res->res_client.tls_ctx) {
1145 free_tls_context(res->res_client.tls_ctx);
1147 if (res->res_client.tls_ca_certfile) {
1148 free(res->res_client.tls_ca_certfile);
1150 if (res->res_client.tls_ca_certdir) {
1151 free(res->res_client.tls_ca_certdir);
1153 if (res->res_client.tls_certfile) {
1154 free(res->res_client.tls_certfile);
1156 if (res->res_client.tls_keyfile) {
1157 free(res->res_client.tls_keyfile);
1159 if (res->res_client.tls_allowed_cns) {
1160 delete res->res_client.tls_allowed_cns;
1164 if (res->res_store.address) {
1165 free(res->res_store.address);
1167 if (res->res_store.password) {
1168 free(res->res_store.password);
1170 if (res->res_store.media_type) {
1171 free(res->res_store.media_type);
1173 if (res->res_store.device) {
1174 delete res->res_store.device;
1176 if (res->res_store.tls_ctx) {
1177 free_tls_context(res->res_store.tls_ctx);
1179 if (res->res_store.tls_ca_certfile) {
1180 free(res->res_store.tls_ca_certfile);
1182 if (res->res_store.tls_ca_certdir) {
1183 free(res->res_store.tls_ca_certdir);
1185 if (res->res_store.tls_certfile) {
1186 free(res->res_store.tls_certfile);
1188 if (res->res_store.tls_keyfile) {
1189 free(res->res_store.tls_keyfile);
1193 if (res->res_cat.db_address) {
1194 free(res->res_cat.db_address);
1196 if (res->res_cat.db_socket) {
1197 free(res->res_cat.db_socket);
1199 if (res->res_cat.db_user) {
1200 free(res->res_cat.db_user);
1202 if (res->res_cat.db_name) {
1203 free(res->res_cat.db_name);
1205 if (res->res_cat.db_driver) {
1206 free(res->res_cat.db_driver);
1208 if (res->res_cat.db_password) {
1209 free(res->res_cat.db_password);
1213 if ((num=res->res_fs.num_includes)) {
1214 while (--num >= 0) {
1215 free_incexe(res->res_fs.include_items[num]);
1217 free(res->res_fs.include_items);
1219 res->res_fs.num_includes = 0;
1220 if ((num=res->res_fs.num_excludes)) {
1221 while (--num >= 0) {
1222 free_incexe(res->res_fs.exclude_items[num]);
1224 free(res->res_fs.exclude_items);
1226 res->res_fs.num_excludes = 0;
1229 if (res->res_pool.pool_type) {
1230 free(res->res_pool.pool_type);
1232 if (res->res_pool.label_format) {
1233 free(res->res_pool.label_format);
1235 if (res->res_pool.cleaning_prefix) {
1236 free(res->res_pool.cleaning_prefix);
1238 if (res->res_pool.storage) {
1239 delete res->res_pool.storage;
1243 if (res->res_sch.run) {
1245 nrun = res->res_sch.run;
1255 if (res->res_job.RestoreWhere) {
1256 free(res->res_job.RestoreWhere);
1258 if (res->res_job.RegexWhere) {
1259 free(res->res_job.RegexWhere);
1261 if (res->res_job.strip_prefix) {
1262 free(res->res_job.strip_prefix);
1264 if (res->res_job.add_prefix) {
1265 free(res->res_job.add_prefix);
1267 if (res->res_job.add_suffix) {
1268 free(res->res_job.add_suffix);
1270 if (res->res_job.RestoreBootstrap) {
1271 free(res->res_job.RestoreBootstrap);
1273 if (res->res_job.WriteBootstrap) {
1274 free(res->res_job.WriteBootstrap);
1276 if (res->res_job.PluginOptions) {
1277 free(res->res_job.PluginOptions);
1279 if (res->res_job.selection_pattern) {
1280 free(res->res_job.selection_pattern);
1282 if (res->res_job.run_cmds) {
1283 delete res->res_job.run_cmds;
1285 if (res->res_job.storage) {
1286 delete res->res_job.storage;
1288 if (res->res_job.RunScripts) {
1289 free_runscripts(res->res_job.RunScripts);
1290 delete res->res_job.RunScripts;
1294 if (res->res_msgs.mail_cmd) {
1295 free(res->res_msgs.mail_cmd);
1297 if (res->res_msgs.operator_cmd) {
1298 free(res->res_msgs.operator_cmd);
1300 free_msgs_res((MSGS *)res); /* free message resource */
1304 printf(_("Unknown resource type %d in free_resource.\n"), type);
1306 /* Common stuff again -- free the resource, recurse to next one */
1311 free_resource(nres, type);
1316 * Save the new resource by chaining it into the head list for
1317 * the resource. If this is pass 2, we update any resource
1318 * pointers because they may not have been defined until
1321 void save_resource(int type, RES_ITEM *items, int pass)
1324 int rindex = type - r_first;
1328 /* Check Job requirements after applying JobDefs */
1329 if (type != R_JOB && type != R_JOBDEFS) {
1331 * Ensure that all required items are present
1333 for (i=0; items[i].name; i++) {
1334 if (items[i].flags & ITEM_REQUIRED) {
1335 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1336 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1337 items[i].name, resources[rindex]);
1340 /* If this triggers, take a look at lib/parse_conf.h */
1341 if (i >= MAX_RES_ITEMS) {
1342 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1345 } else if (type == R_JOB) {
1347 * Ensure that the name item is present
1349 if (items[0].flags & ITEM_REQUIRED) {
1350 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1351 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1352 items[0].name, resources[rindex]);
1358 * During pass 2 in each "store" routine, we looked up pointers
1359 * to all the resources referrenced in the current resource, now we
1360 * must copy their addresses from the static record to the allocated
1365 /* Resources not containing a resource */
1373 * Resources containing another resource or alist. First
1374 * look up the resource which contains another resource. It
1375 * was written during pass 1. Then stuff in the pointers to
1376 * the resources it contains, which were inserted this pass.
1377 * Finally, it will all be stored back.
1380 /* Find resource saved in pass 1 */
1381 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1382 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1384 /* Explicitly copy resource pointers from this pass (res_all) */
1385 res->res_pool.NextPool = res_all.res_pool.NextPool;
1386 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1387 res->res_pool.storage = res_all.res_pool.storage;
1388 res->res_pool.catalog = res_all.res_pool.catalog;
1391 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1392 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1394 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1397 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1398 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1400 res->res_dir.messages = res_all.res_dir.messages;
1401 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1404 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1405 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1406 res_all.res_dir.hdr.name);
1408 /* we must explicitly copy the device alist pointer */
1409 res->res_store.device = res_all.res_store.device;
1413 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1414 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1415 res_all.res_dir.hdr.name);
1417 res->res_job.messages = res_all.res_job.messages;
1418 res->res_job.schedule = res_all.res_job.schedule;
1419 res->res_job.client = res_all.res_job.client;
1420 res->res_job.fileset = res_all.res_job.fileset;
1421 res->res_job.storage = res_all.res_job.storage;
1422 res->res_job.pool = res_all.res_job.pool;
1423 res->res_job.full_pool = res_all.res_job.full_pool;
1424 res->res_job.inc_pool = res_all.res_job.inc_pool;
1425 res->res_job.diff_pool = res_all.res_job.diff_pool;
1426 res->res_job.verify_job = res_all.res_job.verify_job;
1427 res->res_job.jobdefs = res_all.res_job.jobdefs;
1428 res->res_job.run_cmds = res_all.res_job.run_cmds;
1429 res->res_job.RunScripts = res_all.res_job.RunScripts;
1431 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1432 * is not very useful)
1433 * We have to set_bit(index, res_all.hdr.item_present);
1434 * or something like that
1437 /* we take RegexWhere before all other options */
1438 if (!res->res_job.RegexWhere
1440 (res->res_job.strip_prefix ||
1441 res->res_job.add_suffix ||
1442 res->res_job.add_prefix))
1444 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1445 res->res_job.add_prefix,
1446 res->res_job.add_suffix);
1447 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1448 bregexp_build_where(res->res_job.RegexWhere, len,
1449 res->res_job.strip_prefix,
1450 res->res_job.add_prefix,
1451 res->res_job.add_suffix);
1452 /* TODO: test bregexp */
1455 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1456 free(res->res_job.RestoreWhere);
1457 res->res_job.RestoreWhere = NULL;
1462 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1463 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1465 res->res_counter.Catalog = res_all.res_counter.Catalog;
1466 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1470 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1471 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1473 res->res_client.catalog = res_all.res_client.catalog;
1474 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1478 * Schedule is a bit different in that it contains a RUN record
1479 * chain which isn't a "named" resource. This chain was linked
1480 * in by run_conf.c during pass 2, so here we jam the pointer
1481 * into the Schedule resource.
1483 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1484 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1486 res->res_sch.run = res_all.res_sch.run;
1489 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1493 /* Note, the resource name was already saved during pass 1,
1494 * so here, we can just release it.
1496 if (res_all.res_dir.hdr.name) {
1497 free(res_all.res_dir.hdr.name);
1498 res_all.res_dir.hdr.name = NULL;
1500 if (res_all.res_dir.hdr.desc) {
1501 free(res_all.res_dir.hdr.desc);
1502 res_all.res_dir.hdr.desc = NULL;
1508 * The following code is only executed during pass 1
1512 size = sizeof(DIRRES);
1515 size = sizeof(CONRES);
1518 size =sizeof(CLIENT);
1521 size = sizeof(STORE);
1531 size = sizeof(FILESET);
1534 size = sizeof(SCHED);
1537 size = sizeof(POOL);
1540 size = sizeof(MSGS);
1543 size = sizeof(COUNTER);
1549 printf(_("Unknown resource type %d in save_resource.\n"), type);
1555 res = (URES *)malloc(size);
1556 memcpy(res, &res_all, size);
1557 if (!res_head[rindex]) {
1558 res_head[rindex] = (RES *)res; /* store first entry */
1559 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1560 res->res_dir.hdr.name, rindex);
1563 if (res->res_dir.hdr.name == NULL) {
1564 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1567 /* Add new res to end of chain */
1568 for (last=next=res_head[rindex]; next; next=next->next) {
1570 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1571 Emsg2(M_ERROR_TERM, 0,
1572 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1573 resources[rindex].name, res->res_dir.hdr.name);
1576 last->next = (RES *)res;
1577 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1578 res->res_dir.hdr.name, rindex, pass);
1584 * Store Device. Note, the resource is created upon the
1585 * first reference. The details of the resource are obtained
1586 * later from the SD.
1588 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1592 int rindex = R_DEVICE - r_first;
1593 int size = sizeof(DEVICE);
1597 token = lex_get_token(lc, T_NAME);
1598 if (!res_head[rindex]) {
1599 res = (URES *)malloc(size);
1600 memset(res, 0, size);
1601 res->res_dev.hdr.name = bstrdup(lc->str);
1602 res_head[rindex] = (RES *)res; /* store first entry */
1603 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1604 res->res_dir.hdr.name, rindex);
1607 /* See if it is already defined */
1608 for (next=res_head[rindex]; next->next; next=next->next) {
1609 if (strcmp(next->name, lc->str) == 0) {
1615 res = (URES *)malloc(size);
1616 memset(res, 0, size);
1617 res->res_dev.hdr.name = bstrdup(lc->str);
1618 next->next = (RES *)res;
1619 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1620 res->res_dir.hdr.name, rindex, pass);
1625 set_bit(index, res_all.hdr.item_present);
1627 store_alist_res(lc, item, index, pass);
1632 * Store Migration/Copy type
1635 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1639 token = lex_get_token(lc, T_NAME);
1640 /* Store the type both pass 1 and pass 2 */
1641 for (i=0; migtypes[i].type_name; i++) {
1642 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1643 *(uint32_t *)(item->value) = migtypes[i].job_type;
1649 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1652 set_bit(index, res_all.hdr.item_present);
1658 * Store JobType (backup, verify, restore)
1661 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1665 token = lex_get_token(lc, T_NAME);
1666 /* Store the type both pass 1 and pass 2 */
1667 for (i=0; jobtypes[i].type_name; i++) {
1668 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1669 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1675 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1678 set_bit(index, res_all.hdr.item_present);
1682 * Store Job Level (Full, Incremental, ...)
1685 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1689 token = lex_get_token(lc, T_NAME);
1690 /* Store the level pass 2 so that type is defined */
1691 for (i=0; joblevels[i].level_name; i++) {
1692 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1693 *(uint32_t *)(item->value) = joblevels[i].level;
1699 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1702 set_bit(index, res_all.hdr.item_present);
1706 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1709 token = lex_get_token(lc, T_NAME);
1710 /* Scan Replacement options */
1711 for (i=0; ReplaceOptions[i].name; i++) {
1712 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1713 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1719 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1722 set_bit(index, res_all.hdr.item_present);
1726 * Store ACL (access control list)
1729 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1734 token = lex_get_token(lc, T_STRING);
1736 if (((alist **)item->value)[item->code] == NULL) {
1737 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1738 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1740 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1741 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1743 token = lex_get_token(lc, T_ALL);
1744 if (token == T_COMMA) {
1745 continue; /* get another ACL */
1749 set_bit(index, res_all.hdr.item_present);
1752 /* We build RunScripts items here */
1753 static RUNSCRIPT res_runscript;
1755 /* Store a runscript->when in a bit field */
1756 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1758 lex_get_token(lc, T_NAME);
1760 if (strcasecmp(lc->str, "before") == 0) {
1761 *(uint32_t *)(item->value) = SCRIPT_Before ;
1762 } else if (strcasecmp(lc->str, "after") == 0) {
1763 *(uint32_t *)(item->value) = SCRIPT_After;
1764 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1765 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1766 } else if (strcasecmp(lc->str, "always") == 0) {
1767 *(uint32_t *)(item->value) = SCRIPT_Any;
1769 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1774 /* Store a runscript->target
1777 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1779 lex_get_token(lc, T_STRING);
1782 if (strcmp(lc->str, "%c") == 0) {
1783 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1784 } else if (strcasecmp(lc->str, "yes") == 0) {
1785 ((RUNSCRIPT*) item->value)->set_target("%c");
1786 } else if (strcasecmp(lc->str, "no") == 0) {
1787 ((RUNSCRIPT*) item->value)->set_target("");
1789 RES *res = GetResWithName(R_CLIENT, lc->str);
1791 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1792 lc->str, lc->line_no, lc->line);
1795 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1802 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1804 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1806 lex_get_token(lc, T_STRING);
1809 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1810 POOLMEM *c = get_pool_memory(PM_FNAME);
1811 /* Each runscript command takes 2 entries in commands list */
1812 pm_strcpy(c, lc->str);
1813 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1814 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1819 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1821 lex_get_token(lc, T_STRING);
1822 alist **runscripts = (alist **)(item->value) ;
1825 RUNSCRIPT *script = new_runscript();
1826 script->set_job_code_callback(job_code_callback_filesetname);
1828 script->set_command(lc->str);
1830 /* TODO: remove all script->old_proto with bacula 1.42 */
1832 if (strcmp(item->name, "runbeforejob") == 0) {
1833 script->when = SCRIPT_Before;
1834 script->fail_on_error = true;
1835 script->set_target("");
1837 } else if (strcmp(item->name, "runafterjob") == 0) {
1838 script->when = SCRIPT_After;
1839 script->on_success = true;
1840 script->on_failure = false;
1841 script->set_target("");
1843 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1844 script->old_proto = true;
1845 script->when = SCRIPT_After;
1846 script->set_target("%c");
1847 script->on_success = true;
1848 script->on_failure = false;
1850 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1851 script->old_proto = true;
1852 script->when = SCRIPT_Before;
1853 script->set_target("%c");
1854 script->fail_on_error = true;
1856 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1857 script->when = SCRIPT_After;
1858 script->on_failure = true;
1859 script->on_success = false;
1860 script->set_target("");
1863 if (*runscripts == NULL) {
1864 *runscripts = New(alist(10, not_owned_by_alist));
1867 (*runscripts)->append(script);
1874 /* Store a bool in a bit field without modifing res_all.hdr
1875 * We can also add an option to store_bool to skip res_all.hdr
1877 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1879 lex_get_token(lc, T_NAME);
1880 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1881 *(bool *)(item->value) = true;
1882 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1883 *(bool *)(item->value) = false;
1885 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1891 * new RunScript items
1892 * name handler value code flags default_value
1894 static RES_ITEM runscript_items[] = {
1895 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1896 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1897 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1898 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1899 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1900 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1901 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1902 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1903 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1904 {NULL, NULL, {0}, 0, 0, 0}
1908 * Store RunScript info
1910 * Note, when this routine is called, we are inside a Job
1911 * resource. We treat the RunScript like a sort of
1912 * mini-resource within the Job resource.
1914 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1918 alist **runscripts = (alist **)(item->value) ;
1920 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1922 token = lex_get_token(lc, T_SKIP_EOL);
1924 if (token != T_BOB) {
1925 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1927 /* setting on_success, on_failure, fail_on_error */
1928 res_runscript.reset_default();
1931 res_runscript.commands = New(alist(10, not_owned_by_alist));
1934 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1935 if (token == T_EOB) {
1938 if (token != T_IDENTIFIER) {
1939 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1941 for (i=0; runscript_items[i].name; i++) {
1942 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1943 token = lex_get_token(lc, T_SKIP_EOL);
1944 if (token != T_EQUALS) {
1945 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1948 /* Call item handler */
1949 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1956 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1961 /* run on client by default */
1962 if (res_runscript.target == NULL) {
1963 res_runscript.set_target("%c");
1965 if (*runscripts == NULL) {
1966 *runscripts = New(alist(10, not_owned_by_alist));
1969 * commands list contains 2 values per command
1970 * - POOLMEM command string (ex: /bin/true)
1971 * - int command type (ex: SHELL_CMD)
1973 res_runscript.set_job_code_callback(job_code_callback_filesetname);
1974 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
1975 t = (long)res_runscript.commands->pop();
1976 RUNSCRIPT *script = new_runscript();
1977 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1978 script->command = c;
1979 script->cmd_type = t;
1980 /* target is taken from res_runscript, each runscript object have
1983 script->target = NULL;
1984 script->set_target(res_runscript.target);
1986 (*runscripts)->append(script);
1989 delete res_runscript.commands;
1990 /* setting on_success, on_failure... cleanup target field */
1991 res_runscript.reset_default(true);
1995 set_bit(index, res_all.hdr.item_present);
1998 /* callback function for edit_job_codes */
1999 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2001 if (param[0] == 'f') {
2002 return jcr->fileset->name();
2008 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2010 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2011 r_first, r_last, resources, res_head);
2012 return config->parse_config();