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 {NULL, NULL, {0}, 0, 0, 0}
208 /* Storage daemon resource
210 * name handler value code flags default_value
212 static RES_ITEM store_items[] = {
213 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
214 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
215 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
216 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
217 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
218 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
219 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
220 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
221 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
222 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
223 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
224 {"allowcompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
225 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
226 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
227 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
228 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
229 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
230 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
231 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
232 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
233 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
234 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
235 {NULL, NULL, {0}, 0, 0, 0}
239 * Catalog Resource Directives
241 * name handler value code flags default_value
243 static RES_ITEM cat_items[] = {
244 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
245 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
246 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
247 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
248 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
249 /* keep this password as store_str for the moment */
250 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
251 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
252 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
253 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
254 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
255 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
256 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
257 /* Turned off for the moment */
258 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
259 {"disablebatchinsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
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 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
299 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
300 /* xxxMaxWaitTime are deprecated */
301 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
302 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
303 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
304 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
305 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
306 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
307 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
308 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
309 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
310 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
311 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
312 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
313 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
314 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
315 {"purgemigratejob", store_bool, ITEM(res_job.PurgeMigrateJob), 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 {"rescheduleincompletejobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
330 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
331 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 5},
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.catalog) {
611 sendit(sock, _(" --> "));
612 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
619 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
620 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
621 " poolid=%s volname=%s MediaType=%s\n"),
622 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
623 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
624 dev->offline, dev->autochanger,
625 edit_uint64(dev->PoolId, ed1),
626 dev->VolumeName, dev->MediaType);
630 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
631 " DeviceName=%s MediaType=%s StorageId=%s\n"),
632 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
633 res->res_store.MaxConcurrentJobs,
634 res->res_store.dev_name(),
635 res->res_store.media_type,
636 edit_int64(res->res_store.StorageId, ed1));
640 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
641 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
642 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
643 res->res_cat.db_port, res->res_cat.db_name,
644 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
645 res->res_cat.mult_db_connections);
650 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
651 type == R_JOB ? _("Job") : _("JobDefs"),
652 res->res_job.hdr.name, res->res_job.JobType,
653 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
654 res->res_job.enabled);
655 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
656 res->res_job.MaxConcurrentJobs,
657 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
658 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
659 res->res_job.spool_data, res->res_job.write_part_after_job);
660 if (res->res_job.spool_size) {
661 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
663 if (res->res_job.JobType == JT_BACKUP) {
664 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
666 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
667 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
669 if (res->res_job.client) {
670 sendit(sock, _(" --> "));
671 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
673 if (res->res_job.fileset) {
674 sendit(sock, _(" --> "));
675 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
677 if (res->res_job.schedule) {
678 sendit(sock, _(" --> "));
679 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
681 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
682 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
684 if (res->res_job.RegexWhere) {
685 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
687 if (res->res_job.RestoreBootstrap) {
688 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
690 if (res->res_job.WriteBootstrap) {
691 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
693 if (res->res_job.PluginOptions) {
694 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
696 if (res->res_job.MaxRunTime) {
697 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
699 if (res->res_job.MaxWaitTime) {
700 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
702 if (res->res_job.MaxStartDelay) {
703 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
705 if (res->res_job.storage) {
707 foreach_alist(store, res->res_job.storage) {
708 sendit(sock, _(" --> "));
709 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
712 if (res->res_job.base) {
714 foreach_alist(job, res->res_job.base) {
715 sendit(sock, _(" --> Base %s\n"), job->name());
718 if (res->res_job.RunScripts) {
720 foreach_alist(script, res->res_job.RunScripts) {
721 sendit(sock, _(" --> RunScript\n"));
722 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
723 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
724 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
725 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
726 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
727 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
730 if (res->res_job.pool) {
731 sendit(sock, _(" --> "));
732 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
734 if (res->res_job.full_pool) {
735 sendit(sock, _(" --> "));
736 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
738 if (res->res_job.inc_pool) {
739 sendit(sock, _(" --> "));
740 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
742 if (res->res_job.diff_pool) {
743 sendit(sock, _(" --> "));
744 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
746 if (res->res_job.verify_job) {
747 sendit(sock, _(" --> "));
748 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
750 if (res->res_job.run_cmds) {
752 foreach_alist(runcmd, res->res_job.run_cmds) {
753 sendit(sock, _(" --> Run=%s\n"), runcmd);
756 if (res->res_job.selection_pattern) {
757 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
759 if (res->res_job.messages) {
760 sendit(sock, _(" --> "));
761 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
768 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
769 for (i=0; i<res->res_fs.num_includes; i++) {
770 INCEXE *incexe = res->res_fs.include_items[i];
771 for (j=0; j<incexe->num_opts; j++) {
772 FOPTS *fo = incexe->opts_list[j];
773 sendit(sock, " O %s\n", fo->opts);
775 bool enhanced_wild = false;
776 for (k=0; fo->opts[k]!='\0'; k++) {
777 if (fo->opts[k]=='W') {
778 enhanced_wild = true;
783 for (k=0; k<fo->regex.size(); k++) {
784 sendit(sock, " R %s\n", fo->regex.get(k));
786 for (k=0; k<fo->regexdir.size(); k++) {
787 sendit(sock, " RD %s\n", fo->regexdir.get(k));
789 for (k=0; k<fo->regexfile.size(); k++) {
790 sendit(sock, " RF %s\n", fo->regexfile.get(k));
792 for (k=0; k<fo->wild.size(); k++) {
793 sendit(sock, " W %s\n", fo->wild.get(k));
795 for (k=0; k<fo->wilddir.size(); k++) {
796 sendit(sock, " WD %s\n", fo->wilddir.get(k));
798 for (k=0; k<fo->wildfile.size(); k++) {
799 sendit(sock, " WF %s\n", fo->wildfile.get(k));
801 for (k=0; k<fo->wildbase.size(); k++) {
802 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
804 for (k=0; k<fo->base.size(); k++) {
805 sendit(sock, " B %s\n", fo->base.get(k));
807 for (k=0; k<fo->fstype.size(); k++) {
808 sendit(sock, " X %s\n", fo->fstype.get(k));
810 for (k=0; k<fo->drivetype.size(); k++) {
811 sendit(sock, " XD %s\n", fo->drivetype.get(k));
814 sendit(sock, " G %s\n", fo->plugin);
817 sendit(sock, " D %s\n", fo->reader);
820 sendit(sock, " T %s\n", fo->writer);
822 sendit(sock, " N\n");
824 if (incexe->ignoredir) {
825 sendit(sock, " Z %s\n", incexe->ignoredir);
827 for (j=0; j<incexe->name_list.size(); j++) {
828 sendit(sock, " I %s\n", incexe->name_list.get(j));
830 if (incexe->name_list.size()) {
831 sendit(sock, " N\n");
833 for (j=0; j<incexe->plugin_list.size(); j++) {
834 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
836 if (incexe->plugin_list.size()) {
837 sendit(sock, " N\n");
842 for (i=0; i<res->res_fs.num_excludes; i++) {
843 INCEXE *incexe = res->res_fs.exclude_items[i];
844 for (j=0; j<incexe->name_list.size(); j++) {
845 sendit(sock, " E %s\n", incexe->name_list.get(j));
847 if (incexe->name_list.size()) {
848 sendit(sock, " N\n");
855 if (res->res_sch.run) {
857 RUN *run = res->res_sch.run;
858 char buf[1000], num[30];
859 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
864 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
865 bstrncpy(buf, _(" hour="), sizeof(buf));
866 for (i=0; i<24; i++) {
867 if (bit_is_set(i, run->hour)) {
868 bsnprintf(num, sizeof(num), "%d ", i);
869 bstrncat(buf, num, sizeof(buf));
872 bstrncat(buf, "\n", sizeof(buf));
874 bstrncpy(buf, _(" mday="), sizeof(buf));
875 for (i=0; i<31; i++) {
876 if (bit_is_set(i, run->mday)) {
877 bsnprintf(num, sizeof(num), "%d ", i);
878 bstrncat(buf, num, sizeof(buf));
881 bstrncat(buf, "\n", sizeof(buf));
883 bstrncpy(buf, _(" month="), sizeof(buf));
884 for (i=0; i<12; i++) {
885 if (bit_is_set(i, run->month)) {
886 bsnprintf(num, sizeof(num), "%d ", i);
887 bstrncat(buf, num, sizeof(buf));
890 bstrncat(buf, "\n", sizeof(buf));
892 bstrncpy(buf, _(" wday="), sizeof(buf));
893 for (i=0; i<7; i++) {
894 if (bit_is_set(i, run->wday)) {
895 bsnprintf(num, sizeof(num), "%d ", i);
896 bstrncat(buf, num, sizeof(buf));
899 bstrncat(buf, "\n", sizeof(buf));
901 bstrncpy(buf, _(" wom="), sizeof(buf));
902 for (i=0; i<5; i++) {
903 if (bit_is_set(i, run->wom)) {
904 bsnprintf(num, sizeof(num), "%d ", i);
905 bstrncat(buf, num, sizeof(buf));
908 bstrncat(buf, "\n", sizeof(buf));
910 bstrncpy(buf, _(" woy="), sizeof(buf));
911 for (i=0; i<54; i++) {
912 if (bit_is_set(i, run->woy)) {
913 bsnprintf(num, sizeof(num), "%d ", i);
914 bstrncat(buf, num, sizeof(buf));
917 bstrncat(buf, "\n", sizeof(buf));
919 sendit(sock, _(" mins=%d\n"), run->minute);
921 sendit(sock, _(" --> "));
922 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
925 sendit(sock, _(" --> "));
926 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
929 sendit(sock, _(" --> "));
930 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
932 /* If another Run record is chained in, go print it */
938 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
943 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
944 res->res_pool.pool_type);
945 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
946 res->res_pool.use_catalog, res->res_pool.use_volume_once,
947 res->res_pool.catalog_files);
948 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
949 res->res_pool.max_volumes, res->res_pool.AutoPrune,
950 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
951 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
952 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
953 res->res_pool.Recycle,
954 NPRT(res->res_pool.label_format));
955 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
956 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
957 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
958 res->res_pool.recycle_oldest_volume,
959 res->res_pool.purge_oldest_volume,
960 res->res_pool.action_on_purge);
961 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
962 res->res_pool.MaxVolJobs,
963 res->res_pool.MaxVolFiles,
964 edit_uint64(res->res_pool.MaxVolBytes, ed1));
965 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
966 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
967 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
968 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
969 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
970 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
971 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
972 if (res->res_pool.NextPool) {
973 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
975 if (res->res_pool.RecyclePool) {
976 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
978 if (res->res_pool.ScratchPool) {
979 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
981 if (res->res_pool.catalog) {
982 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
984 if (res->res_pool.storage) {
986 foreach_alist(store, res->res_pool.storage) {
987 sendit(sock, _(" --> "));
988 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
991 if (res->res_pool.CopyPool) {
993 foreach_alist(copy, res->res_pool.CopyPool) {
994 sendit(sock, _(" --> "));
995 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1002 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1003 if (res->res_msgs.mail_cmd)
1004 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1005 if (res->res_msgs.operator_cmd)
1006 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1010 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1013 if (recurse && res->res_dir.hdr.next) {
1014 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1019 * Free all the members of an INCEXE structure
1021 static void free_incexe(INCEXE *incexe)
1023 incexe->name_list.destroy();
1024 incexe->plugin_list.destroy();
1025 for (int i=0; i<incexe->num_opts; i++) {
1026 FOPTS *fopt = incexe->opts_list[i];
1027 fopt->regex.destroy();
1028 fopt->regexdir.destroy();
1029 fopt->regexfile.destroy();
1030 fopt->wild.destroy();
1031 fopt->wilddir.destroy();
1032 fopt->wildfile.destroy();
1033 fopt->wildbase.destroy();
1034 fopt->base.destroy();
1035 fopt->fstype.destroy();
1036 fopt->drivetype.destroy();
1048 if (incexe->opts_list) {
1049 free(incexe->opts_list);
1051 if (incexe->ignoredir) {
1052 free(incexe->ignoredir);
1058 * Free memory of resource -- called when daemon terminates.
1059 * NB, we don't need to worry about freeing any references
1060 * to other resources as they will be freed when that
1061 * resource chain is traversed. Mainly we worry about freeing
1062 * allocated strings (names).
1064 void free_resource(RES *sres, int type)
1067 RES *nres; /* next resource if linked */
1068 URES *res = (URES *)sres;
1073 /* common stuff -- free the resource name and description */
1074 nres = (RES *)res->res_dir.hdr.next;
1075 if (res->res_dir.hdr.name) {
1076 free(res->res_dir.hdr.name);
1078 if (res->res_dir.hdr.desc) {
1079 free(res->res_dir.hdr.desc);
1084 if (res->res_dir.working_directory) {
1085 free(res->res_dir.working_directory);
1087 if (res->res_dir.scripts_directory) {
1088 free((char *)res->res_dir.scripts_directory);
1090 if (res->res_dir.plugin_directory) {
1091 free((char *)res->res_dir.plugin_directory);
1093 if (res->res_dir.pid_directory) {
1094 free(res->res_dir.pid_directory);
1096 if (res->res_dir.subsys_directory) {
1097 free(res->res_dir.subsys_directory);
1099 if (res->res_dir.password) {
1100 free(res->res_dir.password);
1102 if (res->res_dir.query_file) {
1103 free(res->res_dir.query_file);
1105 if (res->res_dir.DIRaddrs) {
1106 free_addresses(res->res_dir.DIRaddrs);
1108 if (res->res_dir.DIRsrc_addr) {
1109 free_addresses(res->res_dir.DIRsrc_addr);
1111 if (res->res_dir.tls_ctx) {
1112 free_tls_context(res->res_dir.tls_ctx);
1114 if (res->res_dir.tls_ca_certfile) {
1115 free(res->res_dir.tls_ca_certfile);
1117 if (res->res_dir.tls_ca_certdir) {
1118 free(res->res_dir.tls_ca_certdir);
1120 if (res->res_dir.tls_certfile) {
1121 free(res->res_dir.tls_certfile);
1123 if (res->res_dir.tls_keyfile) {
1124 free(res->res_dir.tls_keyfile);
1126 if (res->res_dir.tls_dhfile) {
1127 free(res->res_dir.tls_dhfile);
1129 if (res->res_dir.tls_allowed_cns) {
1130 delete res->res_dir.tls_allowed_cns;
1132 if (res->res_dir.verid) {
1133 free(res->res_dir.verid);
1140 if (res->res_con.password) {
1141 free(res->res_con.password);
1143 if (res->res_con.tls_ctx) {
1144 free_tls_context(res->res_con.tls_ctx);
1146 if (res->res_con.tls_ca_certfile) {
1147 free(res->res_con.tls_ca_certfile);
1149 if (res->res_con.tls_ca_certdir) {
1150 free(res->res_con.tls_ca_certdir);
1152 if (res->res_con.tls_certfile) {
1153 free(res->res_con.tls_certfile);
1155 if (res->res_con.tls_keyfile) {
1156 free(res->res_con.tls_keyfile);
1158 if (res->res_con.tls_dhfile) {
1159 free(res->res_con.tls_dhfile);
1161 if (res->res_con.tls_allowed_cns) {
1162 delete res->res_con.tls_allowed_cns;
1164 for (int i=0; i<Num_ACL; i++) {
1165 if (res->res_con.ACL_lists[i]) {
1166 delete res->res_con.ACL_lists[i];
1167 res->res_con.ACL_lists[i] = NULL;
1172 if (res->res_client.address) {
1173 free(res->res_client.address);
1175 if (res->res_client.password) {
1176 free(res->res_client.password);
1178 if (res->res_client.tls_ctx) {
1179 free_tls_context(res->res_client.tls_ctx);
1181 if (res->res_client.tls_ca_certfile) {
1182 free(res->res_client.tls_ca_certfile);
1184 if (res->res_client.tls_ca_certdir) {
1185 free(res->res_client.tls_ca_certdir);
1187 if (res->res_client.tls_certfile) {
1188 free(res->res_client.tls_certfile);
1190 if (res->res_client.tls_keyfile) {
1191 free(res->res_client.tls_keyfile);
1193 if (res->res_client.tls_allowed_cns) {
1194 delete res->res_client.tls_allowed_cns;
1198 if (res->res_store.address) {
1199 free(res->res_store.address);
1201 if (res->res_store.password) {
1202 free(res->res_store.password);
1204 if (res->res_store.media_type) {
1205 free(res->res_store.media_type);
1207 if (res->res_store.device) {
1208 delete res->res_store.device;
1210 if (res->res_store.tls_ctx) {
1211 free_tls_context(res->res_store.tls_ctx);
1213 if (res->res_store.tls_ca_certfile) {
1214 free(res->res_store.tls_ca_certfile);
1216 if (res->res_store.tls_ca_certdir) {
1217 free(res->res_store.tls_ca_certdir);
1219 if (res->res_store.tls_certfile) {
1220 free(res->res_store.tls_certfile);
1222 if (res->res_store.tls_keyfile) {
1223 free(res->res_store.tls_keyfile);
1227 if (res->res_cat.db_address) {
1228 free(res->res_cat.db_address);
1230 if (res->res_cat.db_socket) {
1231 free(res->res_cat.db_socket);
1233 if (res->res_cat.db_user) {
1234 free(res->res_cat.db_user);
1236 if (res->res_cat.db_name) {
1237 free(res->res_cat.db_name);
1239 if (res->res_cat.db_driver) {
1240 free(res->res_cat.db_driver);
1242 if (res->res_cat.db_password) {
1243 free(res->res_cat.db_password);
1247 if ((num=res->res_fs.num_includes)) {
1248 while (--num >= 0) {
1249 free_incexe(res->res_fs.include_items[num]);
1251 free(res->res_fs.include_items);
1253 res->res_fs.num_includes = 0;
1254 if ((num=res->res_fs.num_excludes)) {
1255 while (--num >= 0) {
1256 free_incexe(res->res_fs.exclude_items[num]);
1258 free(res->res_fs.exclude_items);
1260 res->res_fs.num_excludes = 0;
1263 if (res->res_pool.pool_type) {
1264 free(res->res_pool.pool_type);
1266 if (res->res_pool.label_format) {
1267 free(res->res_pool.label_format);
1269 if (res->res_pool.cleaning_prefix) {
1270 free(res->res_pool.cleaning_prefix);
1272 if (res->res_pool.storage) {
1273 delete res->res_pool.storage;
1277 if (res->res_sch.run) {
1279 nrun = res->res_sch.run;
1289 if (res->res_job.RestoreWhere) {
1290 free(res->res_job.RestoreWhere);
1292 if (res->res_job.RegexWhere) {
1293 free(res->res_job.RegexWhere);
1295 if (res->res_job.strip_prefix) {
1296 free(res->res_job.strip_prefix);
1298 if (res->res_job.add_prefix) {
1299 free(res->res_job.add_prefix);
1301 if (res->res_job.add_suffix) {
1302 free(res->res_job.add_suffix);
1304 if (res->res_job.RestoreBootstrap) {
1305 free(res->res_job.RestoreBootstrap);
1307 if (res->res_job.WriteBootstrap) {
1308 free(res->res_job.WriteBootstrap);
1310 if (res->res_job.PluginOptions) {
1311 free(res->res_job.PluginOptions);
1313 if (res->res_job.selection_pattern) {
1314 free(res->res_job.selection_pattern);
1316 if (res->res_job.run_cmds) {
1317 delete res->res_job.run_cmds;
1319 if (res->res_job.storage) {
1320 delete res->res_job.storage;
1322 if (res->res_job.base) {
1323 delete res->res_job.base;
1325 if (res->res_job.RunScripts) {
1326 free_runscripts(res->res_job.RunScripts);
1327 delete res->res_job.RunScripts;
1331 if (res->res_msgs.mail_cmd) {
1332 free(res->res_msgs.mail_cmd);
1334 if (res->res_msgs.operator_cmd) {
1335 free(res->res_msgs.operator_cmd);
1337 free_msgs_res((MSGS *)res); /* free message resource */
1341 printf(_("Unknown resource type %d in free_resource.\n"), type);
1343 /* Common stuff again -- free the resource, recurse to next one */
1348 free_resource(nres, type);
1353 * Save the new resource by chaining it into the head list for
1354 * the resource. If this is pass 2, we update any resource
1355 * pointers because they may not have been defined until
1358 void save_resource(int type, RES_ITEM *items, int pass)
1361 int rindex = type - r_first;
1365 /* Check Job requirements after applying JobDefs */
1366 if (type != R_JOB && type != R_JOBDEFS) {
1368 * Ensure that all required items are present
1370 for (i=0; items[i].name; i++) {
1371 if (items[i].flags & ITEM_REQUIRED) {
1372 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1373 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1374 items[i].name, resources[rindex]);
1377 /* If this triggers, take a look at lib/parse_conf.h */
1378 if (i >= MAX_RES_ITEMS) {
1379 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1382 } else if (type == R_JOB) {
1384 * Ensure that the name item is present
1386 if (items[0].flags & ITEM_REQUIRED) {
1387 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1388 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1389 items[0].name, resources[rindex]);
1395 * During pass 2 in each "store" routine, we looked up pointers
1396 * to all the resources referrenced in the current resource, now we
1397 * must copy their addresses from the static record to the allocated
1402 /* Resources not containing a resource */
1410 * Resources containing another resource or alist. First
1411 * look up the resource which contains another resource. It
1412 * was written during pass 1. Then stuff in the pointers to
1413 * the resources it contains, which were inserted this pass.
1414 * Finally, it will all be stored back.
1417 /* Find resource saved in pass 1 */
1418 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1419 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1421 /* Explicitly copy resource pointers from this pass (res_all) */
1422 res->res_pool.NextPool = res_all.res_pool.NextPool;
1423 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1424 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1425 res->res_pool.storage = res_all.res_pool.storage;
1426 res->res_pool.catalog = res_all.res_pool.catalog;
1429 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1430 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1432 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1435 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1436 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1438 res->res_dir.messages = res_all.res_dir.messages;
1439 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1442 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1443 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1444 res_all.res_dir.hdr.name);
1446 /* we must explicitly copy the device alist pointer */
1447 res->res_store.device = res_all.res_store.device;
1451 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1452 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1453 res_all.res_dir.hdr.name);
1455 res->res_job.messages = res_all.res_job.messages;
1456 res->res_job.schedule = res_all.res_job.schedule;
1457 res->res_job.client = res_all.res_job.client;
1458 res->res_job.fileset = res_all.res_job.fileset;
1459 res->res_job.storage = res_all.res_job.storage;
1460 res->res_job.base = res_all.res_job.base;
1461 res->res_job.pool = res_all.res_job.pool;
1462 res->res_job.full_pool = res_all.res_job.full_pool;
1463 res->res_job.inc_pool = res_all.res_job.inc_pool;
1464 res->res_job.diff_pool = res_all.res_job.diff_pool;
1465 res->res_job.verify_job = res_all.res_job.verify_job;
1466 res->res_job.jobdefs = res_all.res_job.jobdefs;
1467 res->res_job.run_cmds = res_all.res_job.run_cmds;
1468 res->res_job.RunScripts = res_all.res_job.RunScripts;
1470 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1471 * is not very useful)
1472 * We have to set_bit(index, res_all.hdr.item_present);
1473 * or something like that
1476 /* we take RegexWhere before all other options */
1477 if (!res->res_job.RegexWhere
1479 (res->res_job.strip_prefix ||
1480 res->res_job.add_suffix ||
1481 res->res_job.add_prefix))
1483 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1484 res->res_job.add_prefix,
1485 res->res_job.add_suffix);
1486 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1487 bregexp_build_where(res->res_job.RegexWhere, len,
1488 res->res_job.strip_prefix,
1489 res->res_job.add_prefix,
1490 res->res_job.add_suffix);
1491 /* TODO: test bregexp */
1494 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1495 free(res->res_job.RestoreWhere);
1496 res->res_job.RestoreWhere = NULL;
1501 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1502 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1504 res->res_counter.Catalog = res_all.res_counter.Catalog;
1505 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1509 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1510 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1512 res->res_client.catalog = res_all.res_client.catalog;
1513 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1517 * Schedule is a bit different in that it contains a RUN record
1518 * chain which isn't a "named" resource. This chain was linked
1519 * in by run_conf.c during pass 2, so here we jam the pointer
1520 * into the Schedule resource.
1522 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1523 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1525 res->res_sch.run = res_all.res_sch.run;
1528 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1532 /* Note, the resource name was already saved during pass 1,
1533 * so here, we can just release it.
1535 if (res_all.res_dir.hdr.name) {
1536 free(res_all.res_dir.hdr.name);
1537 res_all.res_dir.hdr.name = NULL;
1539 if (res_all.res_dir.hdr.desc) {
1540 free(res_all.res_dir.hdr.desc);
1541 res_all.res_dir.hdr.desc = NULL;
1547 * The following code is only executed during pass 1
1551 size = sizeof(DIRRES);
1554 size = sizeof(CONRES);
1557 size =sizeof(CLIENT);
1560 size = sizeof(STORE);
1570 size = sizeof(FILESET);
1573 size = sizeof(SCHED);
1576 size = sizeof(POOL);
1579 size = sizeof(MSGS);
1582 size = sizeof(COUNTER);
1588 printf(_("Unknown resource type %d in save_resource.\n"), type);
1594 res = (URES *)malloc(size);
1595 memcpy(res, &res_all, size);
1596 if (!res_head[rindex]) {
1597 res_head[rindex] = (RES *)res; /* store first entry */
1598 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1599 res->res_dir.hdr.name, rindex);
1602 if (res->res_dir.hdr.name == NULL) {
1603 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1606 /* Add new res to end of chain */
1607 for (last=next=res_head[rindex]; next; next=next->next) {
1609 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1610 Emsg2(M_ERROR_TERM, 0,
1611 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1612 resources[rindex].name, res->res_dir.hdr.name);
1615 last->next = (RES *)res;
1616 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1617 res->res_dir.hdr.name, rindex, pass);
1622 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1624 uint32_t *destination = (uint32_t*)item->value;
1625 lex_get_token(lc, T_NAME);
1626 if (strcasecmp(lc->str, "truncate") == 0) {
1627 *destination = (*destination) | ON_PURGE_TRUNCATE;
1629 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1633 set_bit(index, res_all.hdr.item_present);
1637 * Store Device. Note, the resource is created upon the
1638 * first reference. The details of the resource are obtained
1639 * later from the SD.
1641 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1645 int rindex = R_DEVICE - r_first;
1646 int size = sizeof(DEVICE);
1650 token = lex_get_token(lc, T_NAME);
1651 if (!res_head[rindex]) {
1652 res = (URES *)malloc(size);
1653 memset(res, 0, size);
1654 res->res_dev.hdr.name = bstrdup(lc->str);
1655 res_head[rindex] = (RES *)res; /* store first entry */
1656 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1657 res->res_dir.hdr.name, rindex);
1660 /* See if it is already defined */
1661 for (next=res_head[rindex]; next->next; next=next->next) {
1662 if (strcmp(next->name, lc->str) == 0) {
1668 res = (URES *)malloc(size);
1669 memset(res, 0, size);
1670 res->res_dev.hdr.name = bstrdup(lc->str);
1671 next->next = (RES *)res;
1672 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1673 res->res_dir.hdr.name, rindex, pass);
1678 set_bit(index, res_all.hdr.item_present);
1680 store_alist_res(lc, item, index, pass);
1685 * Store Migration/Copy type
1688 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1692 token = lex_get_token(lc, T_NAME);
1693 /* Store the type both pass 1 and pass 2 */
1694 for (i=0; migtypes[i].type_name; i++) {
1695 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1696 *(uint32_t *)(item->value) = migtypes[i].job_type;
1702 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1705 set_bit(index, res_all.hdr.item_present);
1711 * Store JobType (backup, verify, restore)
1714 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1718 token = lex_get_token(lc, T_NAME);
1719 /* Store the type both pass 1 and pass 2 */
1720 for (i=0; jobtypes[i].type_name; i++) {
1721 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1722 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1728 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1731 set_bit(index, res_all.hdr.item_present);
1735 * Store Job Level (Full, Incremental, ...)
1738 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1742 token = lex_get_token(lc, T_NAME);
1743 /* Store the level pass 2 so that type is defined */
1744 for (i=0; joblevels[i].level_name; i++) {
1745 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1746 *(uint32_t *)(item->value) = joblevels[i].level;
1752 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1755 set_bit(index, res_all.hdr.item_present);
1759 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1762 token = lex_get_token(lc, T_NAME);
1763 /* Scan Replacement options */
1764 for (i=0; ReplaceOptions[i].name; i++) {
1765 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1766 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1772 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1775 set_bit(index, res_all.hdr.item_present);
1779 * Store ACL (access control list)
1782 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1787 token = lex_get_token(lc, T_STRING);
1789 if (((alist **)item->value)[item->code] == NULL) {
1790 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1791 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1793 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1794 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1796 token = lex_get_token(lc, T_ALL);
1797 if (token == T_COMMA) {
1798 continue; /* get another ACL */
1802 set_bit(index, res_all.hdr.item_present);
1805 /* We build RunScripts items here */
1806 static RUNSCRIPT res_runscript;
1808 /* Store a runscript->when in a bit field */
1809 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1811 lex_get_token(lc, T_NAME);
1813 if (strcasecmp(lc->str, "before") == 0) {
1814 *(uint32_t *)(item->value) = SCRIPT_Before ;
1815 } else if (strcasecmp(lc->str, "after") == 0) {
1816 *(uint32_t *)(item->value) = SCRIPT_After;
1817 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1818 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1819 } else if (strcasecmp(lc->str, "always") == 0) {
1820 *(uint32_t *)(item->value) = SCRIPT_Any;
1822 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1827 /* Store a runscript->target
1830 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1832 lex_get_token(lc, T_STRING);
1835 if (strcmp(lc->str, "%c") == 0) {
1836 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1837 } else if (strcasecmp(lc->str, "yes") == 0) {
1838 ((RUNSCRIPT*) item->value)->set_target("%c");
1839 } else if (strcasecmp(lc->str, "no") == 0) {
1840 ((RUNSCRIPT*) item->value)->set_target("");
1842 RES *res = GetResWithName(R_CLIENT, lc->str);
1844 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1845 lc->str, lc->line_no, lc->line);
1848 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1855 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1857 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1859 lex_get_token(lc, T_STRING);
1862 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1863 POOLMEM *c = get_pool_memory(PM_FNAME);
1864 /* Each runscript command takes 2 entries in commands list */
1865 pm_strcpy(c, lc->str);
1866 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1867 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1872 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1874 lex_get_token(lc, T_STRING);
1875 alist **runscripts = (alist **)(item->value) ;
1878 RUNSCRIPT *script = new_runscript();
1879 script->set_job_code_callback(job_code_callback_filesetname);
1881 script->set_command(lc->str);
1883 /* TODO: remove all script->old_proto with bacula 1.42 */
1885 if (strcmp(item->name, "runbeforejob") == 0) {
1886 script->when = SCRIPT_Before;
1887 script->fail_on_error = true;
1888 script->set_target("");
1890 } else if (strcmp(item->name, "runafterjob") == 0) {
1891 script->when = SCRIPT_After;
1892 script->on_success = true;
1893 script->on_failure = false;
1894 script->set_target("");
1896 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1897 script->old_proto = true;
1898 script->when = SCRIPT_After;
1899 script->set_target("%c");
1900 script->on_success = true;
1901 script->on_failure = false;
1903 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1904 script->old_proto = true;
1905 script->when = SCRIPT_Before;
1906 script->set_target("%c");
1907 script->fail_on_error = true;
1909 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1910 script->when = SCRIPT_After;
1911 script->on_failure = true;
1912 script->on_success = false;
1913 script->set_target("");
1916 if (*runscripts == NULL) {
1917 *runscripts = New(alist(10, not_owned_by_alist));
1920 (*runscripts)->append(script);
1927 /* Store a bool in a bit field without modifing res_all.hdr
1928 * We can also add an option to store_bool to skip res_all.hdr
1930 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1932 lex_get_token(lc, T_NAME);
1933 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1934 *(bool *)(item->value) = true;
1935 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1936 *(bool *)(item->value) = false;
1938 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1944 * new RunScript items
1945 * name handler value code flags default_value
1947 static RES_ITEM runscript_items[] = {
1948 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1949 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1950 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1951 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1952 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1953 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1954 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1955 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1956 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1957 {NULL, NULL, {0}, 0, 0, 0}
1961 * Store RunScript info
1963 * Note, when this routine is called, we are inside a Job
1964 * resource. We treat the RunScript like a sort of
1965 * mini-resource within the Job resource.
1967 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1971 alist **runscripts = (alist **)(item->value) ;
1973 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1975 token = lex_get_token(lc, T_SKIP_EOL);
1977 if (token != T_BOB) {
1978 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1980 /* setting on_success, on_failure, fail_on_error */
1981 res_runscript.reset_default();
1984 res_runscript.commands = New(alist(10, not_owned_by_alist));
1987 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1988 if (token == T_EOB) {
1991 if (token != T_IDENTIFIER) {
1992 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1994 for (i=0; runscript_items[i].name; i++) {
1995 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1996 token = lex_get_token(lc, T_SKIP_EOL);
1997 if (token != T_EQUALS) {
1998 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2001 /* Call item handler */
2002 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2009 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2014 /* run on client by default */
2015 if (res_runscript.target == NULL) {
2016 res_runscript.set_target("%c");
2018 if (*runscripts == NULL) {
2019 *runscripts = New(alist(10, not_owned_by_alist));
2022 * commands list contains 2 values per command
2023 * - POOLMEM command string (ex: /bin/true)
2024 * - int command type (ex: SHELL_CMD)
2026 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2027 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2028 t = (intptr_t)res_runscript.commands->pop();
2029 RUNSCRIPT *script = new_runscript();
2030 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2031 script->command = c;
2032 script->cmd_type = t;
2033 /* target is taken from res_runscript, each runscript object have
2036 script->target = NULL;
2037 script->set_target(res_runscript.target);
2039 (*runscripts)->append(script);
2042 delete res_runscript.commands;
2043 /* setting on_success, on_failure... cleanup target field */
2044 res_runscript.reset_default(true);
2048 set_bit(index, res_all.hdr.item_present);
2051 /* callback function for edit_job_codes */
2052 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2054 if (param[0] == 'f' && jcr->fileset) {
2055 return jcr->fileset->name();
2057 } else if (param[0] == 'h' && jcr->client) {
2058 return jcr->client->address;
2063 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2065 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2066 r_first, r_last, resources, res_head);
2067 return config->parse_config();