2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 three of the GNU Affero 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 Affero 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
55 /* Define the first and last resource ID record
56 * types. Note, these should be unique for each
57 * daemon though not a requirement.
59 int32_t r_first = R_FIRST;
60 int32_t r_last = R_LAST;
61 static RES *sres_head[R_LAST - R_FIRST + 1];
62 RES **res_head = sres_head;
64 /* Imported subroutines */
65 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
66 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
70 /* Forward referenced subroutines */
72 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
73 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
77 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
84 /* We build the current resource here as we are
85 * scanning the resource configuration definition,
86 * then move it to allocated memory when the resource
90 extern "C" { // work around visual compiler mangling variables
96 int32_t res_all_size = sizeof(res_all);
99 /* Definition of records permitted within each
100 * resource with the routine to process the record
101 * information. NOTE! quoted names must be in lower case.
106 * name handler value code flags default_value
108 static RES_ITEM dir_items[] = {
109 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
110 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
111 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
112 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
116 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
117 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
118 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
119 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
120 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
121 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
122 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
123 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
124 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
125 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
126 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
127 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
128 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
129 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
130 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
131 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
132 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
133 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
134 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
135 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
136 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
137 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
138 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
139 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
140 {NULL, NULL, {0}, 0, 0, 0}
146 * name handler value code flags default_value
148 static RES_ITEM con_items[] = {
149 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
150 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
151 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
152 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
153 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
154 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
155 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
156 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
157 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
158 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
159 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
160 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
161 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
162 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
163 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
164 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
165 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
166 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
167 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
168 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
169 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
170 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
171 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
172 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
173 {NULL, NULL, {0}, 0, 0, 0}
178 * Client or File daemon resource
180 * name handler value code flags default_value
183 static RES_ITEM cli_items[] = {
184 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
185 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
186 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
187 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
188 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
189 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
190 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
191 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
192 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
193 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
194 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
195 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
196 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
197 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
198 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
199 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
200 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
201 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
202 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
203 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
204 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
205 {"maximumbandwidth", store_speed, ITEM(res_client.max_bandwidth), 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 {"allowcompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
226 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
227 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
228 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
229 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
230 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
231 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
232 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
233 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
234 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
235 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
236 {NULL, NULL, {0}, 0, 0, 0}
240 * Catalog Resource Directives
242 * name handler value code flags default_value
244 static RES_ITEM cat_items[] = {
245 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
246 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
247 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
248 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
249 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
250 /* keep this password as store_str for the moment */
251 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
252 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
253 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
254 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
255 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
256 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
257 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
258 /* Turned off for the moment */
259 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
260 {NULL, NULL, {0}, 0, 0, 0}
264 * Job Resource Directives
266 * name handler value code flags default_value
268 RES_ITEM job_items[] = {
269 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
270 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
271 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
272 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
273 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
274 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
275 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
276 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
277 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
278 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
279 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
280 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
281 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
282 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
283 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
284 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
285 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
286 /* Root of where to restore files */
287 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
288 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
289 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
290 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
291 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
292 /* Where to find bootstrap during restore */
293 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
294 /* Where to write bootstrap file during backup */
295 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
296 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
297 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
298 {"maximumbandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
299 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
300 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
301 /* xxxMaxWaitTime are deprecated */
302 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
303 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
304 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
305 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
306 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
307 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
308 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
309 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
310 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
311 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
312 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
313 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
314 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
315 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
316 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
317 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
318 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
319 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
320 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
321 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
322 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
327 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
328 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
329 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
330 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
331 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
332 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
333 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
334 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
335 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
336 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
337 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
338 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
339 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
340 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
341 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
342 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
343 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
344 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
345 {NULL, NULL, {0}, 0, 0, 0}
350 * name handler value code flags default_value
352 static RES_ITEM fs_items[] = {
353 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
354 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
355 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
356 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
357 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
358 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
359 {NULL, NULL, {0}, 0, 0, 0}
362 /* Schedule -- see run_conf.c */
365 * name handler value code flags default_value
367 static RES_ITEM sch_items[] = {
368 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
369 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
370 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
371 {NULL, NULL, {0}, 0, 0, 0}
376 * name handler value code flags default_value
378 static RES_ITEM pool_items[] = {
379 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
380 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
381 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
382 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
383 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
384 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
385 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
386 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
387 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
388 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
389 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
390 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
391 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
392 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
393 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
394 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
395 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
396 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
397 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
398 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
399 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
400 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
401 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
402 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
403 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
404 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
405 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
406 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
407 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
408 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
409 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
410 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
412 {NULL, NULL, {0}, 0, 0, 0}
417 * name handler value code flags default_value
419 static RES_ITEM counter_items[] = {
420 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
421 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
422 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
423 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
424 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
425 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
426 {NULL, NULL, {0}, 0, 0, 0}
430 /* Message resource */
431 extern RES_ITEM msgs_items[];
434 * This is the master resource definition.
435 * It must have one item for each of the resources.
437 * NOTE!!! keep it in the same order as the R_codes
438 * or eliminate all resources[rindex].name
440 * name items rcode res_head
442 RES_TABLE resources[] = {
443 {"director", dir_items, R_DIRECTOR},
444 {"client", cli_items, R_CLIENT},
445 {"job", job_items, R_JOB},
446 {"storage", store_items, R_STORAGE},
447 {"catalog", cat_items, R_CATALOG},
448 {"schedule", sch_items, R_SCHEDULE},
449 {"fileset", fs_items, R_FILESET},
450 {"pool", pool_items, R_POOL},
451 {"messages", msgs_items, R_MSGS},
452 {"counter", counter_items, R_COUNTER},
453 {"console", con_items, R_CONSOLE},
454 {"jobdefs", job_items, R_JOBDEFS},
455 {"device", NULL, R_DEVICE}, /* info obtained from SD */
460 /* Keywords (RHS) permitted in Job Level records
462 * level_name level job_type
464 struct s_jl joblevels[] = {
465 {"Full", L_FULL, JT_BACKUP},
466 {"Base", L_BASE, JT_BACKUP},
467 {"Incremental", L_INCREMENTAL, JT_BACKUP},
468 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
469 {"Since", L_SINCE, JT_BACKUP},
470 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
471 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
472 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
473 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
474 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
475 {"Data", L_VERIFY_DATA, JT_VERIFY},
476 {" ", L_NONE, JT_ADMIN},
477 {" ", L_NONE, JT_RESTORE},
481 /* Keywords (RHS) permitted in Job type records
485 struct s_jt jobtypes[] = {
486 {"backup", JT_BACKUP},
488 {"verify", JT_VERIFY},
489 {"restore", JT_RESTORE},
490 {"migrate", JT_MIGRATE},
496 /* Keywords (RHS) permitted in Selection type records
500 struct s_jt migtypes[] = {
501 {"smallestvolume", MT_SMALLEST_VOL},
502 {"oldestvolume", MT_OLDEST_VOL},
503 {"pooloccupancy", MT_POOL_OCCUPANCY},
504 {"pooltime", MT_POOL_TIME},
505 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
506 {"client", MT_CLIENT},
507 {"volume", MT_VOLUME},
509 {"sqlquery", MT_SQLQUERY},
515 /* Options permitted in Restore replace= */
516 struct s_kw ReplaceOptions[] = {
517 {"always", REPLACE_ALWAYS},
518 {"ifnewer", REPLACE_IFNEWER},
519 {"ifolder", REPLACE_IFOLDER},
520 {"never", REPLACE_NEVER},
524 char *CAT::display(POOLMEM *dst) {
525 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
526 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
528 name(), NPRTB(db_name),
529 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
530 NPRTB(db_address), db_port, NPRTB(db_socket));
534 const char *level_to_str(int level)
537 static char level_no[30];
538 const char *str = level_no;
540 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
541 for (i=0; joblevels[i].level_name; i++) {
542 if (level == (int)joblevels[i].level) {
543 str = joblevels[i].level_name;
550 /* Dump contents of resource */
551 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
553 URES *res = (URES *)reshdr;
555 char ed1[100], ed2[100], ed3[100];
559 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
562 if (type < 0) { /* no recursion */
568 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
569 reshdr->name, res->res_dir.MaxConcurrentJobs,
570 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
571 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
572 if (res->res_dir.query_file) {
573 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
575 if (res->res_dir.messages) {
576 sendit(sock, _(" --> "));
577 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
581 sendit(sock, _("Console: name=%s SSL=%d\n"),
582 res->res_con.hdr.name, res->res_con.tls_enable);
585 if (res->res_counter.WrapCounter) {
586 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
587 res->res_counter.hdr.name, res->res_counter.MinValue,
588 res->res_counter.MaxValue, res->res_counter.CurrentValue,
589 res->res_counter.WrapCounter->hdr.name);
591 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
592 res->res_counter.hdr.name, res->res_counter.MinValue,
593 res->res_counter.MaxValue);
595 if (res->res_counter.Catalog) {
596 sendit(sock, _(" --> "));
597 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
602 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
603 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
604 res->res_client.MaxConcurrentJobs);
605 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
606 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
607 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
608 res->res_client.AutoPrune);
609 if (res->res_client.max_bandwidth) {
610 sendit(sock, _(" MaximumBandwidth=%lld\n"),
611 res->res_client.max_bandwidth);
613 if (res->res_client.catalog) {
614 sendit(sock, _(" --> "));
615 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
622 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
623 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
624 " poolid=%s volname=%s MediaType=%s\n"),
625 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
626 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
627 dev->offline, dev->autochanger,
628 edit_uint64(dev->PoolId, ed1),
629 dev->VolumeName, dev->MediaType);
633 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
634 " DeviceName=%s MediaType=%s StorageId=%s\n"),
635 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
636 res->res_store.MaxConcurrentJobs,
637 res->res_store.dev_name(),
638 res->res_store.media_type,
639 edit_int64(res->res_store.StorageId, ed1));
643 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
644 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
645 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
646 res->res_cat.db_port, res->res_cat.db_name,
647 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
648 res->res_cat.mult_db_connections);
653 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
654 type == R_JOB ? _("Job") : _("JobDefs"),
655 res->res_job.hdr.name, res->res_job.JobType,
656 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
657 res->res_job.enabled);
658 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
659 res->res_job.MaxConcurrentJobs,
660 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
661 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
662 res->res_job.spool_data, res->res_job.write_part_after_job);
663 if (res->res_job.spool_size) {
664 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
666 if (res->res_job.JobType == JT_BACKUP) {
667 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
669 if (res->res_job.max_bandwidth) {
670 sendit(sock, _(" MaximumBandwidth=%lld\n"),
671 res->res_job.max_bandwidth);
673 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
674 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
676 if (res->res_job.client) {
677 sendit(sock, _(" --> "));
678 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
680 if (res->res_job.fileset) {
681 sendit(sock, _(" --> "));
682 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
684 if (res->res_job.schedule) {
685 sendit(sock, _(" --> "));
686 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
688 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
689 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
691 if (res->res_job.RegexWhere) {
692 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
694 if (res->res_job.RestoreBootstrap) {
695 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
697 if (res->res_job.WriteBootstrap) {
698 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
700 if (res->res_job.PluginOptions) {
701 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
703 if (res->res_job.MaxRunTime) {
704 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
706 if (res->res_job.MaxWaitTime) {
707 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
709 if (res->res_job.MaxStartDelay) {
710 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
712 if (res->res_job.storage) {
714 foreach_alist(store, res->res_job.storage) {
715 sendit(sock, _(" --> "));
716 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
719 if (res->res_job.base) {
721 foreach_alist(job, res->res_job.base) {
722 sendit(sock, _(" --> Base %s\n"), job->name());
725 if (res->res_job.RunScripts) {
727 foreach_alist(script, res->res_job.RunScripts) {
728 sendit(sock, _(" --> RunScript\n"));
729 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
730 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
731 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
732 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
733 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
734 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
737 if (res->res_job.pool) {
738 sendit(sock, _(" --> "));
739 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
741 if (res->res_job.full_pool) {
742 sendit(sock, _(" --> "));
743 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
745 if (res->res_job.inc_pool) {
746 sendit(sock, _(" --> "));
747 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
749 if (res->res_job.diff_pool) {
750 sendit(sock, _(" --> "));
751 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
753 if (res->res_job.verify_job) {
754 sendit(sock, _(" --> "));
755 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
757 if (res->res_job.run_cmds) {
759 foreach_alist(runcmd, res->res_job.run_cmds) {
760 sendit(sock, _(" --> Run=%s\n"), runcmd);
763 if (res->res_job.selection_pattern) {
764 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
766 if (res->res_job.messages) {
767 sendit(sock, _(" --> "));
768 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
775 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
776 for (i=0; i<res->res_fs.num_includes; i++) {
777 INCEXE *incexe = res->res_fs.include_items[i];
778 for (j=0; j<incexe->num_opts; j++) {
779 FOPTS *fo = incexe->opts_list[j];
780 sendit(sock, " O %s\n", fo->opts);
782 bool enhanced_wild = false;
783 for (k=0; fo->opts[k]!='\0'; k++) {
784 if (fo->opts[k]=='W') {
785 enhanced_wild = true;
790 for (k=0; k<fo->regex.size(); k++) {
791 sendit(sock, " R %s\n", fo->regex.get(k));
793 for (k=0; k<fo->regexdir.size(); k++) {
794 sendit(sock, " RD %s\n", fo->regexdir.get(k));
796 for (k=0; k<fo->regexfile.size(); k++) {
797 sendit(sock, " RF %s\n", fo->regexfile.get(k));
799 for (k=0; k<fo->wild.size(); k++) {
800 sendit(sock, " W %s\n", fo->wild.get(k));
802 for (k=0; k<fo->wilddir.size(); k++) {
803 sendit(sock, " WD %s\n", fo->wilddir.get(k));
805 for (k=0; k<fo->wildfile.size(); k++) {
806 sendit(sock, " WF %s\n", fo->wildfile.get(k));
808 for (k=0; k<fo->wildbase.size(); k++) {
809 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
811 for (k=0; k<fo->base.size(); k++) {
812 sendit(sock, " B %s\n", fo->base.get(k));
814 for (k=0; k<fo->fstype.size(); k++) {
815 sendit(sock, " X %s\n", fo->fstype.get(k));
817 for (k=0; k<fo->drivetype.size(); k++) {
818 sendit(sock, " XD %s\n", fo->drivetype.get(k));
821 sendit(sock, " G %s\n", fo->plugin);
824 sendit(sock, " D %s\n", fo->reader);
827 sendit(sock, " T %s\n", fo->writer);
829 sendit(sock, " N\n");
831 if (incexe->ignoredir) {
832 sendit(sock, " Z %s\n", incexe->ignoredir);
834 for (j=0; j<incexe->name_list.size(); j++) {
835 sendit(sock, " I %s\n", incexe->name_list.get(j));
837 if (incexe->name_list.size()) {
838 sendit(sock, " N\n");
840 for (j=0; j<incexe->plugin_list.size(); j++) {
841 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
843 if (incexe->plugin_list.size()) {
844 sendit(sock, " N\n");
849 for (i=0; i<res->res_fs.num_excludes; i++) {
850 INCEXE *incexe = res->res_fs.exclude_items[i];
851 for (j=0; j<incexe->name_list.size(); j++) {
852 sendit(sock, " E %s\n", incexe->name_list.get(j));
854 if (incexe->name_list.size()) {
855 sendit(sock, " N\n");
862 if (res->res_sch.run) {
864 RUN *run = res->res_sch.run;
865 char buf[1000], num[30];
866 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
871 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
872 bstrncpy(buf, _(" hour="), sizeof(buf));
873 for (i=0; i<24; i++) {
874 if (bit_is_set(i, run->hour)) {
875 bsnprintf(num, sizeof(num), "%d ", i);
876 bstrncat(buf, num, sizeof(buf));
879 bstrncat(buf, "\n", sizeof(buf));
881 bstrncpy(buf, _(" mday="), sizeof(buf));
882 for (i=0; i<31; i++) {
883 if (bit_is_set(i, run->mday)) {
884 bsnprintf(num, sizeof(num), "%d ", i);
885 bstrncat(buf, num, sizeof(buf));
888 bstrncat(buf, "\n", sizeof(buf));
890 bstrncpy(buf, _(" month="), sizeof(buf));
891 for (i=0; i<12; i++) {
892 if (bit_is_set(i, run->month)) {
893 bsnprintf(num, sizeof(num), "%d ", i);
894 bstrncat(buf, num, sizeof(buf));
897 bstrncat(buf, "\n", sizeof(buf));
899 bstrncpy(buf, _(" wday="), sizeof(buf));
900 for (i=0; i<7; i++) {
901 if (bit_is_set(i, run->wday)) {
902 bsnprintf(num, sizeof(num), "%d ", i);
903 bstrncat(buf, num, sizeof(buf));
906 bstrncat(buf, "\n", sizeof(buf));
908 bstrncpy(buf, _(" wom="), sizeof(buf));
909 for (i=0; i<5; i++) {
910 if (bit_is_set(i, run->wom)) {
911 bsnprintf(num, sizeof(num), "%d ", i);
912 bstrncat(buf, num, sizeof(buf));
915 bstrncat(buf, "\n", sizeof(buf));
917 bstrncpy(buf, _(" woy="), sizeof(buf));
918 for (i=0; i<54; i++) {
919 if (bit_is_set(i, run->woy)) {
920 bsnprintf(num, sizeof(num), "%d ", i);
921 bstrncat(buf, num, sizeof(buf));
924 bstrncat(buf, "\n", sizeof(buf));
926 sendit(sock, _(" mins=%d\n"), run->minute);
928 sendit(sock, _(" --> "));
929 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
932 sendit(sock, _(" --> "));
933 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
936 sendit(sock, _(" --> "));
937 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
939 /* If another Run record is chained in, go print it */
945 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
950 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
951 res->res_pool.pool_type);
952 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
953 res->res_pool.use_catalog, res->res_pool.use_volume_once,
954 res->res_pool.catalog_files);
955 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
956 res->res_pool.max_volumes, res->res_pool.AutoPrune,
957 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
958 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
959 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
960 res->res_pool.Recycle,
961 NPRT(res->res_pool.label_format));
962 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
963 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
964 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
965 res->res_pool.recycle_oldest_volume,
966 res->res_pool.purge_oldest_volume,
967 res->res_pool.action_on_purge);
968 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
969 res->res_pool.MaxVolJobs,
970 res->res_pool.MaxVolFiles,
971 edit_uint64(res->res_pool.MaxVolBytes, ed1));
972 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
973 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
974 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
975 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
976 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
977 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
978 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
979 if (res->res_pool.NextPool) {
980 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
982 if (res->res_pool.RecyclePool) {
983 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
985 if (res->res_pool.ScratchPool) {
986 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
988 if (res->res_pool.catalog) {
989 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
991 if (res->res_pool.storage) {
993 foreach_alist(store, res->res_pool.storage) {
994 sendit(sock, _(" --> "));
995 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
998 if (res->res_pool.CopyPool) {
1000 foreach_alist(copy, res->res_pool.CopyPool) {
1001 sendit(sock, _(" --> "));
1002 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1009 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1010 if (res->res_msgs.mail_cmd)
1011 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1012 if (res->res_msgs.operator_cmd)
1013 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1017 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1020 if (recurse && res->res_dir.hdr.next) {
1021 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1026 * Free all the members of an INCEXE structure
1028 static void free_incexe(INCEXE *incexe)
1030 incexe->name_list.destroy();
1031 incexe->plugin_list.destroy();
1032 for (int i=0; i<incexe->num_opts; i++) {
1033 FOPTS *fopt = incexe->opts_list[i];
1034 fopt->regex.destroy();
1035 fopt->regexdir.destroy();
1036 fopt->regexfile.destroy();
1037 fopt->wild.destroy();
1038 fopt->wilddir.destroy();
1039 fopt->wildfile.destroy();
1040 fopt->wildbase.destroy();
1041 fopt->base.destroy();
1042 fopt->fstype.destroy();
1043 fopt->drivetype.destroy();
1055 if (incexe->opts_list) {
1056 free(incexe->opts_list);
1058 if (incexe->ignoredir) {
1059 free(incexe->ignoredir);
1065 * Free memory of resource -- called when daemon terminates.
1066 * NB, we don't need to worry about freeing any references
1067 * to other resources as they will be freed when that
1068 * resource chain is traversed. Mainly we worry about freeing
1069 * allocated strings (names).
1071 void free_resource(RES *sres, int type)
1074 RES *nres; /* next resource if linked */
1075 URES *res = (URES *)sres;
1080 /* common stuff -- free the resource name and description */
1081 nres = (RES *)res->res_dir.hdr.next;
1082 if (res->res_dir.hdr.name) {
1083 free(res->res_dir.hdr.name);
1085 if (res->res_dir.hdr.desc) {
1086 free(res->res_dir.hdr.desc);
1091 if (res->res_dir.working_directory) {
1092 free(res->res_dir.working_directory);
1094 if (res->res_dir.scripts_directory) {
1095 free((char *)res->res_dir.scripts_directory);
1097 if (res->res_dir.plugin_directory) {
1098 free((char *)res->res_dir.plugin_directory);
1100 if (res->res_dir.pid_directory) {
1101 free(res->res_dir.pid_directory);
1103 if (res->res_dir.subsys_directory) {
1104 free(res->res_dir.subsys_directory);
1106 if (res->res_dir.password) {
1107 free(res->res_dir.password);
1109 if (res->res_dir.query_file) {
1110 free(res->res_dir.query_file);
1112 if (res->res_dir.DIRaddrs) {
1113 free_addresses(res->res_dir.DIRaddrs);
1115 if (res->res_dir.DIRsrc_addr) {
1116 free_addresses(res->res_dir.DIRsrc_addr);
1118 if (res->res_dir.tls_ctx) {
1119 free_tls_context(res->res_dir.tls_ctx);
1121 if (res->res_dir.tls_ca_certfile) {
1122 free(res->res_dir.tls_ca_certfile);
1124 if (res->res_dir.tls_ca_certdir) {
1125 free(res->res_dir.tls_ca_certdir);
1127 if (res->res_dir.tls_certfile) {
1128 free(res->res_dir.tls_certfile);
1130 if (res->res_dir.tls_keyfile) {
1131 free(res->res_dir.tls_keyfile);
1133 if (res->res_dir.tls_dhfile) {
1134 free(res->res_dir.tls_dhfile);
1136 if (res->res_dir.tls_allowed_cns) {
1137 delete res->res_dir.tls_allowed_cns;
1139 if (res->res_dir.verid) {
1140 free(res->res_dir.verid);
1147 if (res->res_con.password) {
1148 free(res->res_con.password);
1150 if (res->res_con.tls_ctx) {
1151 free_tls_context(res->res_con.tls_ctx);
1153 if (res->res_con.tls_ca_certfile) {
1154 free(res->res_con.tls_ca_certfile);
1156 if (res->res_con.tls_ca_certdir) {
1157 free(res->res_con.tls_ca_certdir);
1159 if (res->res_con.tls_certfile) {
1160 free(res->res_con.tls_certfile);
1162 if (res->res_con.tls_keyfile) {
1163 free(res->res_con.tls_keyfile);
1165 if (res->res_con.tls_dhfile) {
1166 free(res->res_con.tls_dhfile);
1168 if (res->res_con.tls_allowed_cns) {
1169 delete res->res_con.tls_allowed_cns;
1171 for (int i=0; i<Num_ACL; i++) {
1172 if (res->res_con.ACL_lists[i]) {
1173 delete res->res_con.ACL_lists[i];
1174 res->res_con.ACL_lists[i] = NULL;
1179 if (res->res_client.address) {
1180 free(res->res_client.address);
1182 if (res->res_client.password) {
1183 free(res->res_client.password);
1185 if (res->res_client.tls_ctx) {
1186 free_tls_context(res->res_client.tls_ctx);
1188 if (res->res_client.tls_ca_certfile) {
1189 free(res->res_client.tls_ca_certfile);
1191 if (res->res_client.tls_ca_certdir) {
1192 free(res->res_client.tls_ca_certdir);
1194 if (res->res_client.tls_certfile) {
1195 free(res->res_client.tls_certfile);
1197 if (res->res_client.tls_keyfile) {
1198 free(res->res_client.tls_keyfile);
1200 if (res->res_client.tls_allowed_cns) {
1201 delete res->res_client.tls_allowed_cns;
1205 if (res->res_store.address) {
1206 free(res->res_store.address);
1208 if (res->res_store.password) {
1209 free(res->res_store.password);
1211 if (res->res_store.media_type) {
1212 free(res->res_store.media_type);
1214 if (res->res_store.device) {
1215 delete res->res_store.device;
1217 if (res->res_store.tls_ctx) {
1218 free_tls_context(res->res_store.tls_ctx);
1220 if (res->res_store.tls_ca_certfile) {
1221 free(res->res_store.tls_ca_certfile);
1223 if (res->res_store.tls_ca_certdir) {
1224 free(res->res_store.tls_ca_certdir);
1226 if (res->res_store.tls_certfile) {
1227 free(res->res_store.tls_certfile);
1229 if (res->res_store.tls_keyfile) {
1230 free(res->res_store.tls_keyfile);
1234 if (res->res_cat.db_address) {
1235 free(res->res_cat.db_address);
1237 if (res->res_cat.db_socket) {
1238 free(res->res_cat.db_socket);
1240 if (res->res_cat.db_user) {
1241 free(res->res_cat.db_user);
1243 if (res->res_cat.db_name) {
1244 free(res->res_cat.db_name);
1246 if (res->res_cat.db_driver) {
1247 free(res->res_cat.db_driver);
1249 if (res->res_cat.db_password) {
1250 free(res->res_cat.db_password);
1254 if ((num=res->res_fs.num_includes)) {
1255 while (--num >= 0) {
1256 free_incexe(res->res_fs.include_items[num]);
1258 free(res->res_fs.include_items);
1260 res->res_fs.num_includes = 0;
1261 if ((num=res->res_fs.num_excludes)) {
1262 while (--num >= 0) {
1263 free_incexe(res->res_fs.exclude_items[num]);
1265 free(res->res_fs.exclude_items);
1267 res->res_fs.num_excludes = 0;
1270 if (res->res_pool.pool_type) {
1271 free(res->res_pool.pool_type);
1273 if (res->res_pool.label_format) {
1274 free(res->res_pool.label_format);
1276 if (res->res_pool.cleaning_prefix) {
1277 free(res->res_pool.cleaning_prefix);
1279 if (res->res_pool.storage) {
1280 delete res->res_pool.storage;
1284 if (res->res_sch.run) {
1286 nrun = res->res_sch.run;
1296 if (res->res_job.RestoreWhere) {
1297 free(res->res_job.RestoreWhere);
1299 if (res->res_job.RegexWhere) {
1300 free(res->res_job.RegexWhere);
1302 if (res->res_job.strip_prefix) {
1303 free(res->res_job.strip_prefix);
1305 if (res->res_job.add_prefix) {
1306 free(res->res_job.add_prefix);
1308 if (res->res_job.add_suffix) {
1309 free(res->res_job.add_suffix);
1311 if (res->res_job.RestoreBootstrap) {
1312 free(res->res_job.RestoreBootstrap);
1314 if (res->res_job.WriteBootstrap) {
1315 free(res->res_job.WriteBootstrap);
1317 if (res->res_job.PluginOptions) {
1318 free(res->res_job.PluginOptions);
1320 if (res->res_job.selection_pattern) {
1321 free(res->res_job.selection_pattern);
1323 if (res->res_job.run_cmds) {
1324 delete res->res_job.run_cmds;
1326 if (res->res_job.storage) {
1327 delete res->res_job.storage;
1329 if (res->res_job.base) {
1330 delete res->res_job.base;
1332 if (res->res_job.RunScripts) {
1333 free_runscripts(res->res_job.RunScripts);
1334 delete res->res_job.RunScripts;
1338 if (res->res_msgs.mail_cmd) {
1339 free(res->res_msgs.mail_cmd);
1341 if (res->res_msgs.operator_cmd) {
1342 free(res->res_msgs.operator_cmd);
1344 free_msgs_res((MSGS *)res); /* free message resource */
1348 printf(_("Unknown resource type %d in free_resource.\n"), type);
1350 /* Common stuff again -- free the resource, recurse to next one */
1355 free_resource(nres, type);
1360 * Save the new resource by chaining it into the head list for
1361 * the resource. If this is pass 2, we update any resource
1362 * pointers because they may not have been defined until
1365 void save_resource(int type, RES_ITEM *items, int pass)
1368 int rindex = type - r_first;
1372 /* Check Job requirements after applying JobDefs */
1373 if (type != R_JOB && type != R_JOBDEFS) {
1375 * Ensure that all required items are present
1377 for (i=0; items[i].name; i++) {
1378 if (items[i].flags & ITEM_REQUIRED) {
1379 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1380 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1381 items[i].name, resources[rindex]);
1384 /* If this triggers, take a look at lib/parse_conf.h */
1385 if (i >= MAX_RES_ITEMS) {
1386 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1389 } else if (type == R_JOB) {
1391 * Ensure that the name item is present
1393 if (items[0].flags & ITEM_REQUIRED) {
1394 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1395 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1396 items[0].name, resources[rindex]);
1402 * During pass 2 in each "store" routine, we looked up pointers
1403 * to all the resources referrenced in the current resource, now we
1404 * must copy their addresses from the static record to the allocated
1409 /* Resources not containing a resource */
1417 * Resources containing another resource or alist. First
1418 * look up the resource which contains another resource. It
1419 * was written during pass 1. Then stuff in the pointers to
1420 * the resources it contains, which were inserted this pass.
1421 * Finally, it will all be stored back.
1424 /* Find resource saved in pass 1 */
1425 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1426 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1428 /* Explicitly copy resource pointers from this pass (res_all) */
1429 res->res_pool.NextPool = res_all.res_pool.NextPool;
1430 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1431 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1432 res->res_pool.storage = res_all.res_pool.storage;
1433 res->res_pool.catalog = res_all.res_pool.catalog;
1436 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1437 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1439 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1442 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1443 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1445 res->res_dir.messages = res_all.res_dir.messages;
1446 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1449 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1450 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1451 res_all.res_dir.hdr.name);
1453 /* we must explicitly copy the device alist pointer */
1454 res->res_store.device = res_all.res_store.device;
1458 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1459 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1460 res_all.res_dir.hdr.name);
1462 res->res_job.messages = res_all.res_job.messages;
1463 res->res_job.schedule = res_all.res_job.schedule;
1464 res->res_job.client = res_all.res_job.client;
1465 res->res_job.fileset = res_all.res_job.fileset;
1466 res->res_job.storage = res_all.res_job.storage;
1467 res->res_job.base = res_all.res_job.base;
1468 res->res_job.pool = res_all.res_job.pool;
1469 res->res_job.full_pool = res_all.res_job.full_pool;
1470 res->res_job.inc_pool = res_all.res_job.inc_pool;
1471 res->res_job.diff_pool = res_all.res_job.diff_pool;
1472 res->res_job.verify_job = res_all.res_job.verify_job;
1473 res->res_job.jobdefs = res_all.res_job.jobdefs;
1474 res->res_job.run_cmds = res_all.res_job.run_cmds;
1475 res->res_job.RunScripts = res_all.res_job.RunScripts;
1477 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1478 * is not very useful)
1479 * We have to set_bit(index, res_all.hdr.item_present);
1480 * or something like that
1483 /* we take RegexWhere before all other options */
1484 if (!res->res_job.RegexWhere
1486 (res->res_job.strip_prefix ||
1487 res->res_job.add_suffix ||
1488 res->res_job.add_prefix))
1490 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1491 res->res_job.add_prefix,
1492 res->res_job.add_suffix);
1493 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1494 bregexp_build_where(res->res_job.RegexWhere, len,
1495 res->res_job.strip_prefix,
1496 res->res_job.add_prefix,
1497 res->res_job.add_suffix);
1498 /* TODO: test bregexp */
1501 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1502 free(res->res_job.RestoreWhere);
1503 res->res_job.RestoreWhere = NULL;
1508 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1509 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1511 res->res_counter.Catalog = res_all.res_counter.Catalog;
1512 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1516 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1517 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1519 res->res_client.catalog = res_all.res_client.catalog;
1520 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1524 * Schedule is a bit different in that it contains a RUN record
1525 * chain which isn't a "named" resource. This chain was linked
1526 * in by run_conf.c during pass 2, so here we jam the pointer
1527 * into the Schedule resource.
1529 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1530 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1532 res->res_sch.run = res_all.res_sch.run;
1535 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1539 /* Note, the resource name was already saved during pass 1,
1540 * so here, we can just release it.
1542 if (res_all.res_dir.hdr.name) {
1543 free(res_all.res_dir.hdr.name);
1544 res_all.res_dir.hdr.name = NULL;
1546 if (res_all.res_dir.hdr.desc) {
1547 free(res_all.res_dir.hdr.desc);
1548 res_all.res_dir.hdr.desc = NULL;
1554 * The following code is only executed during pass 1
1558 size = sizeof(DIRRES);
1561 size = sizeof(CONRES);
1564 size =sizeof(CLIENT);
1567 size = sizeof(STORE);
1577 size = sizeof(FILESET);
1580 size = sizeof(SCHED);
1583 size = sizeof(POOL);
1586 size = sizeof(MSGS);
1589 size = sizeof(COUNTER);
1595 printf(_("Unknown resource type %d in save_resource.\n"), type);
1601 res = (URES *)malloc(size);
1602 memcpy(res, &res_all, size);
1603 if (!res_head[rindex]) {
1604 res_head[rindex] = (RES *)res; /* store first entry */
1605 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1606 res->res_dir.hdr.name, rindex);
1609 if (res->res_dir.hdr.name == NULL) {
1610 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1613 /* Add new res to end of chain */
1614 for (last=next=res_head[rindex]; next; next=next->next) {
1616 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1617 Emsg2(M_ERROR_TERM, 0,
1618 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1619 resources[rindex].name, res->res_dir.hdr.name);
1622 last->next = (RES *)res;
1623 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1624 res->res_dir.hdr.name, rindex, pass);
1629 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1631 uint32_t *destination = (uint32_t*)item->value;
1632 lex_get_token(lc, T_NAME);
1633 if (strcasecmp(lc->str, "truncate") == 0) {
1634 *destination = (*destination) | ON_PURGE_TRUNCATE;
1636 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1640 set_bit(index, res_all.hdr.item_present);
1644 * Store Device. Note, the resource is created upon the
1645 * first reference. The details of the resource are obtained
1646 * later from the SD.
1648 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1652 int rindex = R_DEVICE - r_first;
1653 int size = sizeof(DEVICE);
1657 token = lex_get_token(lc, T_NAME);
1658 if (!res_head[rindex]) {
1659 res = (URES *)malloc(size);
1660 memset(res, 0, size);
1661 res->res_dev.hdr.name = bstrdup(lc->str);
1662 res_head[rindex] = (RES *)res; /* store first entry */
1663 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1664 res->res_dir.hdr.name, rindex);
1667 /* See if it is already defined */
1668 for (next=res_head[rindex]; next->next; next=next->next) {
1669 if (strcmp(next->name, lc->str) == 0) {
1675 res = (URES *)malloc(size);
1676 memset(res, 0, size);
1677 res->res_dev.hdr.name = bstrdup(lc->str);
1678 next->next = (RES *)res;
1679 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1680 res->res_dir.hdr.name, rindex, pass);
1685 set_bit(index, res_all.hdr.item_present);
1687 store_alist_res(lc, item, index, pass);
1692 * Store Migration/Copy type
1695 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1699 token = lex_get_token(lc, T_NAME);
1700 /* Store the type both pass 1 and pass 2 */
1701 for (i=0; migtypes[i].type_name; i++) {
1702 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1703 *(uint32_t *)(item->value) = migtypes[i].job_type;
1709 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1712 set_bit(index, res_all.hdr.item_present);
1718 * Store JobType (backup, verify, restore)
1721 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1725 token = lex_get_token(lc, T_NAME);
1726 /* Store the type both pass 1 and pass 2 */
1727 for (i=0; jobtypes[i].type_name; i++) {
1728 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1729 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1735 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1738 set_bit(index, res_all.hdr.item_present);
1742 * Store Job Level (Full, Incremental, ...)
1745 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1749 token = lex_get_token(lc, T_NAME);
1750 /* Store the level pass 2 so that type is defined */
1751 for (i=0; joblevels[i].level_name; i++) {
1752 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1753 *(uint32_t *)(item->value) = joblevels[i].level;
1759 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1762 set_bit(index, res_all.hdr.item_present);
1766 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1769 token = lex_get_token(lc, T_NAME);
1770 /* Scan Replacement options */
1771 for (i=0; ReplaceOptions[i].name; i++) {
1772 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1773 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1779 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1782 set_bit(index, res_all.hdr.item_present);
1786 * Store ACL (access control list)
1789 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1794 token = lex_get_token(lc, T_STRING);
1796 if (((alist **)item->value)[item->code] == NULL) {
1797 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1798 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1800 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1801 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1803 token = lex_get_token(lc, T_ALL);
1804 if (token == T_COMMA) {
1805 continue; /* get another ACL */
1809 set_bit(index, res_all.hdr.item_present);
1812 /* We build RunScripts items here */
1813 static RUNSCRIPT res_runscript;
1815 /* Store a runscript->when in a bit field */
1816 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1818 lex_get_token(lc, T_NAME);
1820 if (strcasecmp(lc->str, "before") == 0) {
1821 *(uint32_t *)(item->value) = SCRIPT_Before ;
1822 } else if (strcasecmp(lc->str, "after") == 0) {
1823 *(uint32_t *)(item->value) = SCRIPT_After;
1824 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1825 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1826 } else if (strcasecmp(lc->str, "always") == 0) {
1827 *(uint32_t *)(item->value) = SCRIPT_Any;
1829 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1834 /* Store a runscript->target
1837 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1839 lex_get_token(lc, T_STRING);
1842 if (strcmp(lc->str, "%c") == 0) {
1843 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1844 } else if (strcasecmp(lc->str, "yes") == 0) {
1845 ((RUNSCRIPT*) item->value)->set_target("%c");
1846 } else if (strcasecmp(lc->str, "no") == 0) {
1847 ((RUNSCRIPT*) item->value)->set_target("");
1849 RES *res = GetResWithName(R_CLIENT, lc->str);
1851 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1852 lc->str, lc->line_no, lc->line);
1855 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1862 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1864 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1866 lex_get_token(lc, T_STRING);
1869 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1870 POOLMEM *c = get_pool_memory(PM_FNAME);
1871 /* Each runscript command takes 2 entries in commands list */
1872 pm_strcpy(c, lc->str);
1873 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1874 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1879 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1881 lex_get_token(lc, T_STRING);
1882 alist **runscripts = (alist **)(item->value) ;
1885 RUNSCRIPT *script = new_runscript();
1886 script->set_job_code_callback(job_code_callback_filesetname);
1888 script->set_command(lc->str);
1890 /* TODO: remove all script->old_proto with bacula 1.42 */
1892 if (strcmp(item->name, "runbeforejob") == 0) {
1893 script->when = SCRIPT_Before;
1894 script->fail_on_error = true;
1895 script->set_target("");
1897 } else if (strcmp(item->name, "runafterjob") == 0) {
1898 script->when = SCRIPT_After;
1899 script->on_success = true;
1900 script->on_failure = false;
1901 script->set_target("");
1903 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1904 script->old_proto = true;
1905 script->when = SCRIPT_After;
1906 script->set_target("%c");
1907 script->on_success = true;
1908 script->on_failure = false;
1910 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1911 script->old_proto = true;
1912 script->when = SCRIPT_Before;
1913 script->set_target("%c");
1914 script->fail_on_error = true;
1916 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1917 script->when = SCRIPT_After;
1918 script->on_failure = true;
1919 script->on_success = false;
1920 script->set_target("");
1923 if (*runscripts == NULL) {
1924 *runscripts = New(alist(10, not_owned_by_alist));
1927 (*runscripts)->append(script);
1934 /* Store a bool in a bit field without modifing res_all.hdr
1935 * We can also add an option to store_bool to skip res_all.hdr
1937 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1939 lex_get_token(lc, T_NAME);
1940 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1941 *(bool *)(item->value) = true;
1942 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1943 *(bool *)(item->value) = false;
1945 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1951 * new RunScript items
1952 * name handler value code flags default_value
1954 static RES_ITEM runscript_items[] = {
1955 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1956 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1957 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1958 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1959 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1960 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1961 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1962 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1963 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1964 {NULL, NULL, {0}, 0, 0, 0}
1968 * Store RunScript info
1970 * Note, when this routine is called, we are inside a Job
1971 * resource. We treat the RunScript like a sort of
1972 * mini-resource within the Job resource.
1974 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1978 alist **runscripts = (alist **)(item->value) ;
1980 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1982 token = lex_get_token(lc, T_SKIP_EOL);
1984 if (token != T_BOB) {
1985 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1987 /* setting on_success, on_failure, fail_on_error */
1988 res_runscript.reset_default();
1991 res_runscript.commands = New(alist(10, not_owned_by_alist));
1994 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1995 if (token == T_EOB) {
1998 if (token != T_IDENTIFIER) {
1999 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2001 for (i=0; runscript_items[i].name; i++) {
2002 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2003 token = lex_get_token(lc, T_SKIP_EOL);
2004 if (token != T_EQUALS) {
2005 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2008 /* Call item handler */
2009 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2016 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2021 /* run on client by default */
2022 if (res_runscript.target == NULL) {
2023 res_runscript.set_target("%c");
2025 if (*runscripts == NULL) {
2026 *runscripts = New(alist(10, not_owned_by_alist));
2029 * commands list contains 2 values per command
2030 * - POOLMEM command string (ex: /bin/true)
2031 * - int command type (ex: SHELL_CMD)
2033 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2034 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2035 t = (intptr_t)res_runscript.commands->pop();
2036 RUNSCRIPT *script = new_runscript();
2037 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2038 script->command = c;
2039 script->cmd_type = t;
2040 /* target is taken from res_runscript, each runscript object have
2043 script->target = NULL;
2044 script->set_target(res_runscript.target);
2046 (*runscripts)->append(script);
2049 delete res_runscript.commands;
2050 /* setting on_success, on_failure... cleanup target field */
2051 res_runscript.reset_default(true);
2055 set_bit(index, res_all.hdr.item_present);
2058 /* callback function for edit_job_codes */
2059 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2061 if (param[0] == 'f') {
2062 return jcr->fileset->name();
2068 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2070 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2071 r_first, r_last, resources, res_head);
2072 return config->parse_config();