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 {"maximumbandwidthperjob", 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 {"purgemigratejob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
317 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
318 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
319 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
320 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
321 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
322 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
323 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
327 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
328 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
329 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
330 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
331 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
332 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
333 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
334 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
335 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
336 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
337 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
338 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
339 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
340 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
341 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
342 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
343 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
344 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
345 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
346 {NULL, NULL, {0}, 0, 0, 0}
351 * name handler value code flags default_value
353 static RES_ITEM fs_items[] = {
354 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
355 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
356 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
357 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
358 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
359 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
360 {NULL, NULL, {0}, 0, 0, 0}
363 /* Schedule -- see run_conf.c */
366 * name handler value code flags default_value
368 static RES_ITEM sch_items[] = {
369 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
370 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
371 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
372 {NULL, NULL, {0}, 0, 0, 0}
377 * name handler value code flags default_value
379 static RES_ITEM pool_items[] = {
380 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
381 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
382 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
383 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
384 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
385 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
386 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
387 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
388 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
389 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
390 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
391 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
392 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
393 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
394 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
395 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
396 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
397 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
398 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
399 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
400 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
401 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
402 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
403 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
404 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
405 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
406 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
407 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
408 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
409 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
410 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
411 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
413 {NULL, NULL, {0}, 0, 0, 0}
418 * name handler value code flags default_value
420 static RES_ITEM counter_items[] = {
421 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
422 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
423 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
424 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
425 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
426 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
427 {NULL, NULL, {0}, 0, 0, 0}
431 /* Message resource */
432 extern RES_ITEM msgs_items[];
435 * This is the master resource definition.
436 * It must have one item for each of the resources.
438 * NOTE!!! keep it in the same order as the R_codes
439 * or eliminate all resources[rindex].name
441 * name items rcode res_head
443 RES_TABLE resources[] = {
444 {"director", dir_items, R_DIRECTOR},
445 {"client", cli_items, R_CLIENT},
446 {"job", job_items, R_JOB},
447 {"storage", store_items, R_STORAGE},
448 {"catalog", cat_items, R_CATALOG},
449 {"schedule", sch_items, R_SCHEDULE},
450 {"fileset", fs_items, R_FILESET},
451 {"pool", pool_items, R_POOL},
452 {"messages", msgs_items, R_MSGS},
453 {"counter", counter_items, R_COUNTER},
454 {"console", con_items, R_CONSOLE},
455 {"jobdefs", job_items, R_JOBDEFS},
456 {"device", NULL, R_DEVICE}, /* info obtained from SD */
461 /* Keywords (RHS) permitted in Job Level records
463 * level_name level job_type
465 struct s_jl joblevels[] = {
466 {"Full", L_FULL, JT_BACKUP},
467 {"Base", L_BASE, JT_BACKUP},
468 {"Incremental", L_INCREMENTAL, JT_BACKUP},
469 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
470 {"Since", L_SINCE, JT_BACKUP},
471 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
472 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
473 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
474 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
475 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
476 {"Data", L_VERIFY_DATA, JT_VERIFY},
477 {" ", L_NONE, JT_ADMIN},
478 {" ", L_NONE, JT_RESTORE},
482 /* Keywords (RHS) permitted in Job type records
486 struct s_jt jobtypes[] = {
487 {"backup", JT_BACKUP},
489 {"verify", JT_VERIFY},
490 {"restore", JT_RESTORE},
491 {"migrate", JT_MIGRATE},
497 /* Keywords (RHS) permitted in Selection type records
501 struct s_jt migtypes[] = {
502 {"smallestvolume", MT_SMALLEST_VOL},
503 {"oldestvolume", MT_OLDEST_VOL},
504 {"pooloccupancy", MT_POOL_OCCUPANCY},
505 {"pooltime", MT_POOL_TIME},
506 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
507 {"client", MT_CLIENT},
508 {"volume", MT_VOLUME},
510 {"sqlquery", MT_SQLQUERY},
516 /* Options permitted in Restore replace= */
517 struct s_kw ReplaceOptions[] = {
518 {"always", REPLACE_ALWAYS},
519 {"ifnewer", REPLACE_IFNEWER},
520 {"ifolder", REPLACE_IFOLDER},
521 {"never", REPLACE_NEVER},
525 char *CAT::display(POOLMEM *dst) {
526 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
527 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
529 name(), NPRTB(db_name),
530 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
531 NPRTB(db_address), db_port, NPRTB(db_socket));
535 const char *level_to_str(int level)
538 static char level_no[30];
539 const char *str = level_no;
541 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
542 for (i=0; joblevels[i].level_name; i++) {
543 if (level == (int)joblevels[i].level) {
544 str = joblevels[i].level_name;
551 /* Dump contents of resource */
552 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
554 URES *res = (URES *)reshdr;
556 char ed1[100], ed2[100], ed3[100];
560 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
563 if (type < 0) { /* no recursion */
569 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
570 reshdr->name, res->res_dir.MaxConcurrentJobs,
571 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
572 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
573 if (res->res_dir.query_file) {
574 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
576 if (res->res_dir.messages) {
577 sendit(sock, _(" --> "));
578 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
582 sendit(sock, _("Console: name=%s SSL=%d\n"),
583 res->res_con.hdr.name, res->res_con.tls_enable);
586 if (res->res_counter.WrapCounter) {
587 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
588 res->res_counter.hdr.name, res->res_counter.MinValue,
589 res->res_counter.MaxValue, res->res_counter.CurrentValue,
590 res->res_counter.WrapCounter->hdr.name);
592 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
593 res->res_counter.hdr.name, res->res_counter.MinValue,
594 res->res_counter.MaxValue);
596 if (res->res_counter.Catalog) {
597 sendit(sock, _(" --> "));
598 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
603 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
604 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
605 res->res_client.MaxConcurrentJobs);
606 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
607 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
608 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
609 res->res_client.AutoPrune);
610 if (res->res_client.max_bandwidth) {
611 sendit(sock, _(" MaximumBandwidth=%lld\n"),
612 res->res_client.max_bandwidth);
614 if (res->res_client.catalog) {
615 sendit(sock, _(" --> "));
616 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
623 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
624 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
625 " poolid=%s volname=%s MediaType=%s\n"),
626 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
627 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
628 dev->offline, dev->autochanger,
629 edit_uint64(dev->PoolId, ed1),
630 dev->VolumeName, dev->MediaType);
634 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
635 " DeviceName=%s MediaType=%s StorageId=%s\n"),
636 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
637 res->res_store.MaxConcurrentJobs,
638 res->res_store.dev_name(),
639 res->res_store.media_type,
640 edit_int64(res->res_store.StorageId, ed1));
644 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
645 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
646 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
647 res->res_cat.db_port, res->res_cat.db_name,
648 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
649 res->res_cat.mult_db_connections);
654 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
655 type == R_JOB ? _("Job") : _("JobDefs"),
656 res->res_job.hdr.name, res->res_job.JobType,
657 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
658 res->res_job.enabled);
659 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
660 res->res_job.MaxConcurrentJobs,
661 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
662 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
663 res->res_job.spool_data, res->res_job.write_part_after_job);
664 if (res->res_job.spool_size) {
665 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
667 if (res->res_job.JobType == JT_BACKUP) {
668 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
670 if (res->res_job.max_bandwidth) {
671 sendit(sock, _(" MaximumBandwidth=%lld\n"),
672 res->res_job.max_bandwidth);
674 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
675 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
677 if (res->res_job.client) {
678 sendit(sock, _(" --> "));
679 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
681 if (res->res_job.fileset) {
682 sendit(sock, _(" --> "));
683 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
685 if (res->res_job.schedule) {
686 sendit(sock, _(" --> "));
687 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
689 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
690 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
692 if (res->res_job.RegexWhere) {
693 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
695 if (res->res_job.RestoreBootstrap) {
696 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
698 if (res->res_job.WriteBootstrap) {
699 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
701 if (res->res_job.PluginOptions) {
702 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
704 if (res->res_job.MaxRunTime) {
705 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
707 if (res->res_job.MaxWaitTime) {
708 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
710 if (res->res_job.MaxStartDelay) {
711 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
713 if (res->res_job.storage) {
715 foreach_alist(store, res->res_job.storage) {
716 sendit(sock, _(" --> "));
717 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
720 if (res->res_job.base) {
722 foreach_alist(job, res->res_job.base) {
723 sendit(sock, _(" --> Base %s\n"), job->name());
726 if (res->res_job.RunScripts) {
728 foreach_alist(script, res->res_job.RunScripts) {
729 sendit(sock, _(" --> RunScript\n"));
730 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
731 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
732 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
733 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
734 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
735 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
738 if (res->res_job.pool) {
739 sendit(sock, _(" --> "));
740 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
742 if (res->res_job.full_pool) {
743 sendit(sock, _(" --> "));
744 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
746 if (res->res_job.inc_pool) {
747 sendit(sock, _(" --> "));
748 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
750 if (res->res_job.diff_pool) {
751 sendit(sock, _(" --> "));
752 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
754 if (res->res_job.verify_job) {
755 sendit(sock, _(" --> "));
756 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
758 if (res->res_job.run_cmds) {
760 foreach_alist(runcmd, res->res_job.run_cmds) {
761 sendit(sock, _(" --> Run=%s\n"), runcmd);
764 if (res->res_job.selection_pattern) {
765 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
767 if (res->res_job.messages) {
768 sendit(sock, _(" --> "));
769 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
776 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
777 for (i=0; i<res->res_fs.num_includes; i++) {
778 INCEXE *incexe = res->res_fs.include_items[i];
779 for (j=0; j<incexe->num_opts; j++) {
780 FOPTS *fo = incexe->opts_list[j];
781 sendit(sock, " O %s\n", fo->opts);
783 bool enhanced_wild = false;
784 for (k=0; fo->opts[k]!='\0'; k++) {
785 if (fo->opts[k]=='W') {
786 enhanced_wild = true;
791 for (k=0; k<fo->regex.size(); k++) {
792 sendit(sock, " R %s\n", fo->regex.get(k));
794 for (k=0; k<fo->regexdir.size(); k++) {
795 sendit(sock, " RD %s\n", fo->regexdir.get(k));
797 for (k=0; k<fo->regexfile.size(); k++) {
798 sendit(sock, " RF %s\n", fo->regexfile.get(k));
800 for (k=0; k<fo->wild.size(); k++) {
801 sendit(sock, " W %s\n", fo->wild.get(k));
803 for (k=0; k<fo->wilddir.size(); k++) {
804 sendit(sock, " WD %s\n", fo->wilddir.get(k));
806 for (k=0; k<fo->wildfile.size(); k++) {
807 sendit(sock, " WF %s\n", fo->wildfile.get(k));
809 for (k=0; k<fo->wildbase.size(); k++) {
810 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
812 for (k=0; k<fo->base.size(); k++) {
813 sendit(sock, " B %s\n", fo->base.get(k));
815 for (k=0; k<fo->fstype.size(); k++) {
816 sendit(sock, " X %s\n", fo->fstype.get(k));
818 for (k=0; k<fo->drivetype.size(); k++) {
819 sendit(sock, " XD %s\n", fo->drivetype.get(k));
822 sendit(sock, " G %s\n", fo->plugin);
825 sendit(sock, " D %s\n", fo->reader);
828 sendit(sock, " T %s\n", fo->writer);
830 sendit(sock, " N\n");
832 if (incexe->ignoredir) {
833 sendit(sock, " Z %s\n", incexe->ignoredir);
835 for (j=0; j<incexe->name_list.size(); j++) {
836 sendit(sock, " I %s\n", incexe->name_list.get(j));
838 if (incexe->name_list.size()) {
839 sendit(sock, " N\n");
841 for (j=0; j<incexe->plugin_list.size(); j++) {
842 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
844 if (incexe->plugin_list.size()) {
845 sendit(sock, " N\n");
850 for (i=0; i<res->res_fs.num_excludes; i++) {
851 INCEXE *incexe = res->res_fs.exclude_items[i];
852 for (j=0; j<incexe->name_list.size(); j++) {
853 sendit(sock, " E %s\n", incexe->name_list.get(j));
855 if (incexe->name_list.size()) {
856 sendit(sock, " N\n");
863 if (res->res_sch.run) {
865 RUN *run = res->res_sch.run;
866 char buf[1000], num[30];
867 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
872 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
873 bstrncpy(buf, _(" hour="), sizeof(buf));
874 for (i=0; i<24; i++) {
875 if (bit_is_set(i, run->hour)) {
876 bsnprintf(num, sizeof(num), "%d ", i);
877 bstrncat(buf, num, sizeof(buf));
880 bstrncat(buf, "\n", sizeof(buf));
882 bstrncpy(buf, _(" mday="), sizeof(buf));
883 for (i=0; i<31; i++) {
884 if (bit_is_set(i, run->mday)) {
885 bsnprintf(num, sizeof(num), "%d ", i);
886 bstrncat(buf, num, sizeof(buf));
889 bstrncat(buf, "\n", sizeof(buf));
891 bstrncpy(buf, _(" month="), sizeof(buf));
892 for (i=0; i<12; i++) {
893 if (bit_is_set(i, run->month)) {
894 bsnprintf(num, sizeof(num), "%d ", i);
895 bstrncat(buf, num, sizeof(buf));
898 bstrncat(buf, "\n", sizeof(buf));
900 bstrncpy(buf, _(" wday="), sizeof(buf));
901 for (i=0; i<7; i++) {
902 if (bit_is_set(i, run->wday)) {
903 bsnprintf(num, sizeof(num), "%d ", i);
904 bstrncat(buf, num, sizeof(buf));
907 bstrncat(buf, "\n", sizeof(buf));
909 bstrncpy(buf, _(" wom="), sizeof(buf));
910 for (i=0; i<5; i++) {
911 if (bit_is_set(i, run->wom)) {
912 bsnprintf(num, sizeof(num), "%d ", i);
913 bstrncat(buf, num, sizeof(buf));
916 bstrncat(buf, "\n", sizeof(buf));
918 bstrncpy(buf, _(" woy="), sizeof(buf));
919 for (i=0; i<54; i++) {
920 if (bit_is_set(i, run->woy)) {
921 bsnprintf(num, sizeof(num), "%d ", i);
922 bstrncat(buf, num, sizeof(buf));
925 bstrncat(buf, "\n", sizeof(buf));
927 sendit(sock, _(" mins=%d\n"), run->minute);
929 sendit(sock, _(" --> "));
930 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
933 sendit(sock, _(" --> "));
934 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
937 sendit(sock, _(" --> "));
938 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
940 /* If another Run record is chained in, go print it */
946 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
951 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
952 res->res_pool.pool_type);
953 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
954 res->res_pool.use_catalog, res->res_pool.use_volume_once,
955 res->res_pool.catalog_files);
956 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
957 res->res_pool.max_volumes, res->res_pool.AutoPrune,
958 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
959 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
960 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
961 res->res_pool.Recycle,
962 NPRT(res->res_pool.label_format));
963 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
964 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
965 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
966 res->res_pool.recycle_oldest_volume,
967 res->res_pool.purge_oldest_volume,
968 res->res_pool.action_on_purge);
969 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
970 res->res_pool.MaxVolJobs,
971 res->res_pool.MaxVolFiles,
972 edit_uint64(res->res_pool.MaxVolBytes, ed1));
973 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
974 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
975 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
976 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
977 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
978 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
979 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
980 if (res->res_pool.NextPool) {
981 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
983 if (res->res_pool.RecyclePool) {
984 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
986 if (res->res_pool.ScratchPool) {
987 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
989 if (res->res_pool.catalog) {
990 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
992 if (res->res_pool.storage) {
994 foreach_alist(store, res->res_pool.storage) {
995 sendit(sock, _(" --> "));
996 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
999 if (res->res_pool.CopyPool) {
1001 foreach_alist(copy, res->res_pool.CopyPool) {
1002 sendit(sock, _(" --> "));
1003 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1010 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1011 if (res->res_msgs.mail_cmd)
1012 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1013 if (res->res_msgs.operator_cmd)
1014 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1018 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1021 if (recurse && res->res_dir.hdr.next) {
1022 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1027 * Free all the members of an INCEXE structure
1029 static void free_incexe(INCEXE *incexe)
1031 incexe->name_list.destroy();
1032 incexe->plugin_list.destroy();
1033 for (int i=0; i<incexe->num_opts; i++) {
1034 FOPTS *fopt = incexe->opts_list[i];
1035 fopt->regex.destroy();
1036 fopt->regexdir.destroy();
1037 fopt->regexfile.destroy();
1038 fopt->wild.destroy();
1039 fopt->wilddir.destroy();
1040 fopt->wildfile.destroy();
1041 fopt->wildbase.destroy();
1042 fopt->base.destroy();
1043 fopt->fstype.destroy();
1044 fopt->drivetype.destroy();
1056 if (incexe->opts_list) {
1057 free(incexe->opts_list);
1059 if (incexe->ignoredir) {
1060 free(incexe->ignoredir);
1066 * Free memory of resource -- called when daemon terminates.
1067 * NB, we don't need to worry about freeing any references
1068 * to other resources as they will be freed when that
1069 * resource chain is traversed. Mainly we worry about freeing
1070 * allocated strings (names).
1072 void free_resource(RES *sres, int type)
1075 RES *nres; /* next resource if linked */
1076 URES *res = (URES *)sres;
1081 /* common stuff -- free the resource name and description */
1082 nres = (RES *)res->res_dir.hdr.next;
1083 if (res->res_dir.hdr.name) {
1084 free(res->res_dir.hdr.name);
1086 if (res->res_dir.hdr.desc) {
1087 free(res->res_dir.hdr.desc);
1092 if (res->res_dir.working_directory) {
1093 free(res->res_dir.working_directory);
1095 if (res->res_dir.scripts_directory) {
1096 free((char *)res->res_dir.scripts_directory);
1098 if (res->res_dir.plugin_directory) {
1099 free((char *)res->res_dir.plugin_directory);
1101 if (res->res_dir.pid_directory) {
1102 free(res->res_dir.pid_directory);
1104 if (res->res_dir.subsys_directory) {
1105 free(res->res_dir.subsys_directory);
1107 if (res->res_dir.password) {
1108 free(res->res_dir.password);
1110 if (res->res_dir.query_file) {
1111 free(res->res_dir.query_file);
1113 if (res->res_dir.DIRaddrs) {
1114 free_addresses(res->res_dir.DIRaddrs);
1116 if (res->res_dir.DIRsrc_addr) {
1117 free_addresses(res->res_dir.DIRsrc_addr);
1119 if (res->res_dir.tls_ctx) {
1120 free_tls_context(res->res_dir.tls_ctx);
1122 if (res->res_dir.tls_ca_certfile) {
1123 free(res->res_dir.tls_ca_certfile);
1125 if (res->res_dir.tls_ca_certdir) {
1126 free(res->res_dir.tls_ca_certdir);
1128 if (res->res_dir.tls_certfile) {
1129 free(res->res_dir.tls_certfile);
1131 if (res->res_dir.tls_keyfile) {
1132 free(res->res_dir.tls_keyfile);
1134 if (res->res_dir.tls_dhfile) {
1135 free(res->res_dir.tls_dhfile);
1137 if (res->res_dir.tls_allowed_cns) {
1138 delete res->res_dir.tls_allowed_cns;
1140 if (res->res_dir.verid) {
1141 free(res->res_dir.verid);
1148 if (res->res_con.password) {
1149 free(res->res_con.password);
1151 if (res->res_con.tls_ctx) {
1152 free_tls_context(res->res_con.tls_ctx);
1154 if (res->res_con.tls_ca_certfile) {
1155 free(res->res_con.tls_ca_certfile);
1157 if (res->res_con.tls_ca_certdir) {
1158 free(res->res_con.tls_ca_certdir);
1160 if (res->res_con.tls_certfile) {
1161 free(res->res_con.tls_certfile);
1163 if (res->res_con.tls_keyfile) {
1164 free(res->res_con.tls_keyfile);
1166 if (res->res_con.tls_dhfile) {
1167 free(res->res_con.tls_dhfile);
1169 if (res->res_con.tls_allowed_cns) {
1170 delete res->res_con.tls_allowed_cns;
1172 for (int i=0; i<Num_ACL; i++) {
1173 if (res->res_con.ACL_lists[i]) {
1174 delete res->res_con.ACL_lists[i];
1175 res->res_con.ACL_lists[i] = NULL;
1180 if (res->res_client.address) {
1181 free(res->res_client.address);
1183 if (res->res_client.password) {
1184 free(res->res_client.password);
1186 if (res->res_client.tls_ctx) {
1187 free_tls_context(res->res_client.tls_ctx);
1189 if (res->res_client.tls_ca_certfile) {
1190 free(res->res_client.tls_ca_certfile);
1192 if (res->res_client.tls_ca_certdir) {
1193 free(res->res_client.tls_ca_certdir);
1195 if (res->res_client.tls_certfile) {
1196 free(res->res_client.tls_certfile);
1198 if (res->res_client.tls_keyfile) {
1199 free(res->res_client.tls_keyfile);
1201 if (res->res_client.tls_allowed_cns) {
1202 delete res->res_client.tls_allowed_cns;
1206 if (res->res_store.address) {
1207 free(res->res_store.address);
1209 if (res->res_store.password) {
1210 free(res->res_store.password);
1212 if (res->res_store.media_type) {
1213 free(res->res_store.media_type);
1215 if (res->res_store.device) {
1216 delete res->res_store.device;
1218 if (res->res_store.tls_ctx) {
1219 free_tls_context(res->res_store.tls_ctx);
1221 if (res->res_store.tls_ca_certfile) {
1222 free(res->res_store.tls_ca_certfile);
1224 if (res->res_store.tls_ca_certdir) {
1225 free(res->res_store.tls_ca_certdir);
1227 if (res->res_store.tls_certfile) {
1228 free(res->res_store.tls_certfile);
1230 if (res->res_store.tls_keyfile) {
1231 free(res->res_store.tls_keyfile);
1235 if (res->res_cat.db_address) {
1236 free(res->res_cat.db_address);
1238 if (res->res_cat.db_socket) {
1239 free(res->res_cat.db_socket);
1241 if (res->res_cat.db_user) {
1242 free(res->res_cat.db_user);
1244 if (res->res_cat.db_name) {
1245 free(res->res_cat.db_name);
1247 if (res->res_cat.db_driver) {
1248 free(res->res_cat.db_driver);
1250 if (res->res_cat.db_password) {
1251 free(res->res_cat.db_password);
1255 if ((num=res->res_fs.num_includes)) {
1256 while (--num >= 0) {
1257 free_incexe(res->res_fs.include_items[num]);
1259 free(res->res_fs.include_items);
1261 res->res_fs.num_includes = 0;
1262 if ((num=res->res_fs.num_excludes)) {
1263 while (--num >= 0) {
1264 free_incexe(res->res_fs.exclude_items[num]);
1266 free(res->res_fs.exclude_items);
1268 res->res_fs.num_excludes = 0;
1271 if (res->res_pool.pool_type) {
1272 free(res->res_pool.pool_type);
1274 if (res->res_pool.label_format) {
1275 free(res->res_pool.label_format);
1277 if (res->res_pool.cleaning_prefix) {
1278 free(res->res_pool.cleaning_prefix);
1280 if (res->res_pool.storage) {
1281 delete res->res_pool.storage;
1285 if (res->res_sch.run) {
1287 nrun = res->res_sch.run;
1297 if (res->res_job.RestoreWhere) {
1298 free(res->res_job.RestoreWhere);
1300 if (res->res_job.RegexWhere) {
1301 free(res->res_job.RegexWhere);
1303 if (res->res_job.strip_prefix) {
1304 free(res->res_job.strip_prefix);
1306 if (res->res_job.add_prefix) {
1307 free(res->res_job.add_prefix);
1309 if (res->res_job.add_suffix) {
1310 free(res->res_job.add_suffix);
1312 if (res->res_job.RestoreBootstrap) {
1313 free(res->res_job.RestoreBootstrap);
1315 if (res->res_job.WriteBootstrap) {
1316 free(res->res_job.WriteBootstrap);
1318 if (res->res_job.PluginOptions) {
1319 free(res->res_job.PluginOptions);
1321 if (res->res_job.selection_pattern) {
1322 free(res->res_job.selection_pattern);
1324 if (res->res_job.run_cmds) {
1325 delete res->res_job.run_cmds;
1327 if (res->res_job.storage) {
1328 delete res->res_job.storage;
1330 if (res->res_job.base) {
1331 delete res->res_job.base;
1333 if (res->res_job.RunScripts) {
1334 free_runscripts(res->res_job.RunScripts);
1335 delete res->res_job.RunScripts;
1339 if (res->res_msgs.mail_cmd) {
1340 free(res->res_msgs.mail_cmd);
1342 if (res->res_msgs.operator_cmd) {
1343 free(res->res_msgs.operator_cmd);
1345 free_msgs_res((MSGS *)res); /* free message resource */
1349 printf(_("Unknown resource type %d in free_resource.\n"), type);
1351 /* Common stuff again -- free the resource, recurse to next one */
1356 free_resource(nres, type);
1361 * Save the new resource by chaining it into the head list for
1362 * the resource. If this is pass 2, we update any resource
1363 * pointers because they may not have been defined until
1366 void save_resource(int type, RES_ITEM *items, int pass)
1369 int rindex = type - r_first;
1373 /* Check Job requirements after applying JobDefs */
1374 if (type != R_JOB && type != R_JOBDEFS) {
1376 * Ensure that all required items are present
1378 for (i=0; items[i].name; i++) {
1379 if (items[i].flags & ITEM_REQUIRED) {
1380 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1381 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1382 items[i].name, resources[rindex]);
1385 /* If this triggers, take a look at lib/parse_conf.h */
1386 if (i >= MAX_RES_ITEMS) {
1387 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1390 } else if (type == R_JOB) {
1392 * Ensure that the name item is present
1394 if (items[0].flags & ITEM_REQUIRED) {
1395 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1396 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1397 items[0].name, resources[rindex]);
1403 * During pass 2 in each "store" routine, we looked up pointers
1404 * to all the resources referrenced in the current resource, now we
1405 * must copy their addresses from the static record to the allocated
1410 /* Resources not containing a resource */
1418 * Resources containing another resource or alist. First
1419 * look up the resource which contains another resource. It
1420 * was written during pass 1. Then stuff in the pointers to
1421 * the resources it contains, which were inserted this pass.
1422 * Finally, it will all be stored back.
1425 /* Find resource saved in pass 1 */
1426 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1427 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1429 /* Explicitly copy resource pointers from this pass (res_all) */
1430 res->res_pool.NextPool = res_all.res_pool.NextPool;
1431 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1432 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1433 res->res_pool.storage = res_all.res_pool.storage;
1434 res->res_pool.catalog = res_all.res_pool.catalog;
1437 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1438 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1440 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1443 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1444 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1446 res->res_dir.messages = res_all.res_dir.messages;
1447 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1450 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1451 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1452 res_all.res_dir.hdr.name);
1454 /* we must explicitly copy the device alist pointer */
1455 res->res_store.device = res_all.res_store.device;
1459 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1460 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1461 res_all.res_dir.hdr.name);
1463 res->res_job.messages = res_all.res_job.messages;
1464 res->res_job.schedule = res_all.res_job.schedule;
1465 res->res_job.client = res_all.res_job.client;
1466 res->res_job.fileset = res_all.res_job.fileset;
1467 res->res_job.storage = res_all.res_job.storage;
1468 res->res_job.base = res_all.res_job.base;
1469 res->res_job.pool = res_all.res_job.pool;
1470 res->res_job.full_pool = res_all.res_job.full_pool;
1471 res->res_job.inc_pool = res_all.res_job.inc_pool;
1472 res->res_job.diff_pool = res_all.res_job.diff_pool;
1473 res->res_job.verify_job = res_all.res_job.verify_job;
1474 res->res_job.jobdefs = res_all.res_job.jobdefs;
1475 res->res_job.run_cmds = res_all.res_job.run_cmds;
1476 res->res_job.RunScripts = res_all.res_job.RunScripts;
1478 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1479 * is not very useful)
1480 * We have to set_bit(index, res_all.hdr.item_present);
1481 * or something like that
1484 /* we take RegexWhere before all other options */
1485 if (!res->res_job.RegexWhere
1487 (res->res_job.strip_prefix ||
1488 res->res_job.add_suffix ||
1489 res->res_job.add_prefix))
1491 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1492 res->res_job.add_prefix,
1493 res->res_job.add_suffix);
1494 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1495 bregexp_build_where(res->res_job.RegexWhere, len,
1496 res->res_job.strip_prefix,
1497 res->res_job.add_prefix,
1498 res->res_job.add_suffix);
1499 /* TODO: test bregexp */
1502 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1503 free(res->res_job.RestoreWhere);
1504 res->res_job.RestoreWhere = NULL;
1509 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1510 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1512 res->res_counter.Catalog = res_all.res_counter.Catalog;
1513 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1517 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1518 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1520 res->res_client.catalog = res_all.res_client.catalog;
1521 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1525 * Schedule is a bit different in that it contains a RUN record
1526 * chain which isn't a "named" resource. This chain was linked
1527 * in by run_conf.c during pass 2, so here we jam the pointer
1528 * into the Schedule resource.
1530 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1531 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1533 res->res_sch.run = res_all.res_sch.run;
1536 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1540 /* Note, the resource name was already saved during pass 1,
1541 * so here, we can just release it.
1543 if (res_all.res_dir.hdr.name) {
1544 free(res_all.res_dir.hdr.name);
1545 res_all.res_dir.hdr.name = NULL;
1547 if (res_all.res_dir.hdr.desc) {
1548 free(res_all.res_dir.hdr.desc);
1549 res_all.res_dir.hdr.desc = NULL;
1555 * The following code is only executed during pass 1
1559 size = sizeof(DIRRES);
1562 size = sizeof(CONRES);
1565 size =sizeof(CLIENT);
1568 size = sizeof(STORE);
1578 size = sizeof(FILESET);
1581 size = sizeof(SCHED);
1584 size = sizeof(POOL);
1587 size = sizeof(MSGS);
1590 size = sizeof(COUNTER);
1596 printf(_("Unknown resource type %d in save_resource.\n"), type);
1602 res = (URES *)malloc(size);
1603 memcpy(res, &res_all, size);
1604 if (!res_head[rindex]) {
1605 res_head[rindex] = (RES *)res; /* store first entry */
1606 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1607 res->res_dir.hdr.name, rindex);
1610 if (res->res_dir.hdr.name == NULL) {
1611 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1614 /* Add new res to end of chain */
1615 for (last=next=res_head[rindex]; next; next=next->next) {
1617 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1618 Emsg2(M_ERROR_TERM, 0,
1619 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1620 resources[rindex].name, res->res_dir.hdr.name);
1623 last->next = (RES *)res;
1624 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1625 res->res_dir.hdr.name, rindex, pass);
1630 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1632 uint32_t *destination = (uint32_t*)item->value;
1633 lex_get_token(lc, T_NAME);
1634 if (strcasecmp(lc->str, "truncate") == 0) {
1635 *destination = (*destination) | ON_PURGE_TRUNCATE;
1637 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1641 set_bit(index, res_all.hdr.item_present);
1645 * Store Device. Note, the resource is created upon the
1646 * first reference. The details of the resource are obtained
1647 * later from the SD.
1649 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1653 int rindex = R_DEVICE - r_first;
1654 int size = sizeof(DEVICE);
1658 token = lex_get_token(lc, T_NAME);
1659 if (!res_head[rindex]) {
1660 res = (URES *)malloc(size);
1661 memset(res, 0, size);
1662 res->res_dev.hdr.name = bstrdup(lc->str);
1663 res_head[rindex] = (RES *)res; /* store first entry */
1664 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1665 res->res_dir.hdr.name, rindex);
1668 /* See if it is already defined */
1669 for (next=res_head[rindex]; next->next; next=next->next) {
1670 if (strcmp(next->name, lc->str) == 0) {
1676 res = (URES *)malloc(size);
1677 memset(res, 0, size);
1678 res->res_dev.hdr.name = bstrdup(lc->str);
1679 next->next = (RES *)res;
1680 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1681 res->res_dir.hdr.name, rindex, pass);
1686 set_bit(index, res_all.hdr.item_present);
1688 store_alist_res(lc, item, index, pass);
1693 * Store Migration/Copy type
1696 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1700 token = lex_get_token(lc, T_NAME);
1701 /* Store the type both pass 1 and pass 2 */
1702 for (i=0; migtypes[i].type_name; i++) {
1703 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1704 *(uint32_t *)(item->value) = migtypes[i].job_type;
1710 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1713 set_bit(index, res_all.hdr.item_present);
1719 * Store JobType (backup, verify, restore)
1722 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1726 token = lex_get_token(lc, T_NAME);
1727 /* Store the type both pass 1 and pass 2 */
1728 for (i=0; jobtypes[i].type_name; i++) {
1729 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1730 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1736 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1739 set_bit(index, res_all.hdr.item_present);
1743 * Store Job Level (Full, Incremental, ...)
1746 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1750 token = lex_get_token(lc, T_NAME);
1751 /* Store the level pass 2 so that type is defined */
1752 for (i=0; joblevels[i].level_name; i++) {
1753 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1754 *(uint32_t *)(item->value) = joblevels[i].level;
1760 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1763 set_bit(index, res_all.hdr.item_present);
1767 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1770 token = lex_get_token(lc, T_NAME);
1771 /* Scan Replacement options */
1772 for (i=0; ReplaceOptions[i].name; i++) {
1773 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1774 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1780 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1783 set_bit(index, res_all.hdr.item_present);
1787 * Store ACL (access control list)
1790 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1795 token = lex_get_token(lc, T_STRING);
1797 if (((alist **)item->value)[item->code] == NULL) {
1798 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1799 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1801 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1802 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1804 token = lex_get_token(lc, T_ALL);
1805 if (token == T_COMMA) {
1806 continue; /* get another ACL */
1810 set_bit(index, res_all.hdr.item_present);
1813 /* We build RunScripts items here */
1814 static RUNSCRIPT res_runscript;
1816 /* Store a runscript->when in a bit field */
1817 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1819 lex_get_token(lc, T_NAME);
1821 if (strcasecmp(lc->str, "before") == 0) {
1822 *(uint32_t *)(item->value) = SCRIPT_Before ;
1823 } else if (strcasecmp(lc->str, "after") == 0) {
1824 *(uint32_t *)(item->value) = SCRIPT_After;
1825 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1826 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1827 } else if (strcasecmp(lc->str, "always") == 0) {
1828 *(uint32_t *)(item->value) = SCRIPT_Any;
1830 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1835 /* Store a runscript->target
1838 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1840 lex_get_token(lc, T_STRING);
1843 if (strcmp(lc->str, "%c") == 0) {
1844 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1845 } else if (strcasecmp(lc->str, "yes") == 0) {
1846 ((RUNSCRIPT*) item->value)->set_target("%c");
1847 } else if (strcasecmp(lc->str, "no") == 0) {
1848 ((RUNSCRIPT*) item->value)->set_target("");
1850 RES *res = GetResWithName(R_CLIENT, lc->str);
1852 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1853 lc->str, lc->line_no, lc->line);
1856 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1863 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1865 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1867 lex_get_token(lc, T_STRING);
1870 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1871 POOLMEM *c = get_pool_memory(PM_FNAME);
1872 /* Each runscript command takes 2 entries in commands list */
1873 pm_strcpy(c, lc->str);
1874 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1875 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1880 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1882 lex_get_token(lc, T_STRING);
1883 alist **runscripts = (alist **)(item->value) ;
1886 RUNSCRIPT *script = new_runscript();
1887 script->set_job_code_callback(job_code_callback_filesetname);
1889 script->set_command(lc->str);
1891 /* TODO: remove all script->old_proto with bacula 1.42 */
1893 if (strcmp(item->name, "runbeforejob") == 0) {
1894 script->when = SCRIPT_Before;
1895 script->fail_on_error = true;
1896 script->set_target("");
1898 } else if (strcmp(item->name, "runafterjob") == 0) {
1899 script->when = SCRIPT_After;
1900 script->on_success = true;
1901 script->on_failure = false;
1902 script->set_target("");
1904 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1905 script->old_proto = true;
1906 script->when = SCRIPT_After;
1907 script->set_target("%c");
1908 script->on_success = true;
1909 script->on_failure = false;
1911 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1912 script->old_proto = true;
1913 script->when = SCRIPT_Before;
1914 script->set_target("%c");
1915 script->fail_on_error = true;
1917 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1918 script->when = SCRIPT_After;
1919 script->on_failure = true;
1920 script->on_success = false;
1921 script->set_target("");
1924 if (*runscripts == NULL) {
1925 *runscripts = New(alist(10, not_owned_by_alist));
1928 (*runscripts)->append(script);
1935 /* Store a bool in a bit field without modifing res_all.hdr
1936 * We can also add an option to store_bool to skip res_all.hdr
1938 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1940 lex_get_token(lc, T_NAME);
1941 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1942 *(bool *)(item->value) = true;
1943 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1944 *(bool *)(item->value) = false;
1946 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1952 * new RunScript items
1953 * name handler value code flags default_value
1955 static RES_ITEM runscript_items[] = {
1956 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1957 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1958 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1959 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1960 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1961 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1962 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1963 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1964 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1965 {NULL, NULL, {0}, 0, 0, 0}
1969 * Store RunScript info
1971 * Note, when this routine is called, we are inside a Job
1972 * resource. We treat the RunScript like a sort of
1973 * mini-resource within the Job resource.
1975 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1979 alist **runscripts = (alist **)(item->value) ;
1981 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1983 token = lex_get_token(lc, T_SKIP_EOL);
1985 if (token != T_BOB) {
1986 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1988 /* setting on_success, on_failure, fail_on_error */
1989 res_runscript.reset_default();
1992 res_runscript.commands = New(alist(10, not_owned_by_alist));
1995 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1996 if (token == T_EOB) {
1999 if (token != T_IDENTIFIER) {
2000 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2002 for (i=0; runscript_items[i].name; i++) {
2003 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2004 token = lex_get_token(lc, T_SKIP_EOL);
2005 if (token != T_EQUALS) {
2006 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2009 /* Call item handler */
2010 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2017 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2022 /* run on client by default */
2023 if (res_runscript.target == NULL) {
2024 res_runscript.set_target("%c");
2026 if (*runscripts == NULL) {
2027 *runscripts = New(alist(10, not_owned_by_alist));
2030 * commands list contains 2 values per command
2031 * - POOLMEM command string (ex: /bin/true)
2032 * - int command type (ex: SHELL_CMD)
2034 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2035 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2036 t = (intptr_t)res_runscript.commands->pop();
2037 RUNSCRIPT *script = new_runscript();
2038 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2039 script->command = c;
2040 script->cmd_type = t;
2041 /* target is taken from res_runscript, each runscript object have
2044 script->target = NULL;
2045 script->set_target(res_runscript.target);
2047 (*runscripts)->append(script);
2050 delete res_runscript.commands;
2051 /* setting on_success, on_failure... cleanup target field */
2052 res_runscript.reset_default(true);
2056 set_bit(index, res_all.hdr.item_present);
2059 /* callback function for edit_job_codes */
2060 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2062 if (param[0] == 'f') {
2063 return jcr->fileset->name();
2069 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2071 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2072 r_first, r_last, resources, res_head);
2073 return config->parse_config();