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 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
330 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
331 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
332 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
333 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
334 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
335 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
336 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
337 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
338 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
339 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
340 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
341 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
342 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
343 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
344 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
345 {NULL, NULL, {0}, 0, 0, 0}
350 * name handler value code flags default_value
352 static RES_ITEM fs_items[] = {
353 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
354 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
355 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
356 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
357 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
358 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
359 {NULL, NULL, {0}, 0, 0, 0}
362 /* Schedule -- see run_conf.c */
365 * name handler value code flags default_value
367 static RES_ITEM sch_items[] = {
368 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
369 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
370 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
371 {NULL, NULL, {0}, 0, 0, 0}
376 * name handler value code flags default_value
378 static RES_ITEM pool_items[] = {
379 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
380 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
381 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
382 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
383 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
384 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
385 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
386 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
387 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
388 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
389 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
390 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
391 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
392 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
393 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
394 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
395 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
396 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
397 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
398 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
399 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
400 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
401 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
402 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
403 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
404 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
405 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
406 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
407 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
408 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
409 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
410 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
412 {NULL, NULL, {0}, 0, 0, 0}
417 * name handler value code flags default_value
419 static RES_ITEM counter_items[] = {
420 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
421 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
422 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
423 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
424 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
425 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
426 {NULL, NULL, {0}, 0, 0, 0}
430 /* Message resource */
431 extern RES_ITEM msgs_items[];
434 * This is the master resource definition.
435 * It must have one item for each of the resources.
437 * NOTE!!! keep it in the same order as the R_codes
438 * or eliminate all resources[rindex].name
440 * name items rcode res_head
442 RES_TABLE resources[] = {
443 {"director", dir_items, R_DIRECTOR},
444 {"client", cli_items, R_CLIENT},
445 {"job", job_items, R_JOB},
446 {"storage", store_items, R_STORAGE},
447 {"catalog", cat_items, R_CATALOG},
448 {"schedule", sch_items, R_SCHEDULE},
449 {"fileset", fs_items, R_FILESET},
450 {"pool", pool_items, R_POOL},
451 {"messages", msgs_items, R_MSGS},
452 {"counter", counter_items, R_COUNTER},
453 {"console", con_items, R_CONSOLE},
454 {"jobdefs", job_items, R_JOBDEFS},
455 {"device", NULL, R_DEVICE}, /* info obtained from SD */
460 /* Keywords (RHS) permitted in Job Level records
462 * level_name level job_type
464 struct s_jl joblevels[] = {
465 {"Full", L_FULL, JT_BACKUP},
466 {"Base", L_BASE, JT_BACKUP},
467 {"Incremental", L_INCREMENTAL, JT_BACKUP},
468 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
469 {"Since", L_SINCE, JT_BACKUP},
470 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
471 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
472 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
473 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
474 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
475 {"Data", L_VERIFY_DATA, JT_VERIFY},
476 {" ", L_NONE, JT_ADMIN},
477 {" ", L_NONE, JT_RESTORE},
481 /* Keywords (RHS) permitted in Job type records
485 struct s_jt jobtypes[] = {
486 {"backup", JT_BACKUP},
488 {"verify", JT_VERIFY},
489 {"restore", JT_RESTORE},
490 {"migrate", JT_MIGRATE},
496 /* Keywords (RHS) permitted in Selection type records
500 struct s_jt migtypes[] = {
501 {"smallestvolume", MT_SMALLEST_VOL},
502 {"oldestvolume", MT_OLDEST_VOL},
503 {"pooloccupancy", MT_POOL_OCCUPANCY},
504 {"pooltime", MT_POOL_TIME},
505 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
506 {"client", MT_CLIENT},
507 {"volume", MT_VOLUME},
509 {"sqlquery", MT_SQLQUERY},
515 /* Options permitted in Restore replace= */
516 struct s_kw ReplaceOptions[] = {
517 {"always", REPLACE_ALWAYS},
518 {"ifnewer", REPLACE_IFNEWER},
519 {"ifolder", REPLACE_IFOLDER},
520 {"never", REPLACE_NEVER},
524 char *CAT::display(POOLMEM *dst) {
525 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
526 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
528 name(), NPRTB(db_name),
529 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
530 NPRTB(db_address), db_port, NPRTB(db_socket));
534 const char *level_to_str(int level)
537 static char level_no[30];
538 const char *str = level_no;
540 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
541 for (i=0; joblevels[i].level_name; i++) {
542 if (level == (int)joblevels[i].level) {
543 str = joblevels[i].level_name;
550 /* Dump contents of resource */
551 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
553 URES *res = (URES *)reshdr;
555 char ed1[100], ed2[100], ed3[100];
559 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
562 if (type < 0) { /* no recursion */
568 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
569 reshdr->name, res->res_dir.MaxConcurrentJobs,
570 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
571 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
572 if (res->res_dir.query_file) {
573 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
575 if (res->res_dir.messages) {
576 sendit(sock, _(" --> "));
577 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
581 sendit(sock, _("Console: name=%s SSL=%d\n"),
582 res->res_con.hdr.name, res->res_con.tls_enable);
585 if (res->res_counter.WrapCounter) {
586 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
587 res->res_counter.hdr.name, res->res_counter.MinValue,
588 res->res_counter.MaxValue, res->res_counter.CurrentValue,
589 res->res_counter.WrapCounter->hdr.name);
591 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
592 res->res_counter.hdr.name, res->res_counter.MinValue,
593 res->res_counter.MaxValue);
595 if (res->res_counter.Catalog) {
596 sendit(sock, _(" --> "));
597 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
602 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
603 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
604 res->res_client.MaxConcurrentJobs);
605 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
606 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
607 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
608 res->res_client.AutoPrune);
609 if (res->res_client.catalog) {
610 sendit(sock, _(" --> "));
611 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
618 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
619 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
620 " poolid=%s volname=%s MediaType=%s\n"),
621 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
622 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
623 dev->offline, dev->autochanger,
624 edit_uint64(dev->PoolId, ed1),
625 dev->VolumeName, dev->MediaType);
629 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
630 " DeviceName=%s MediaType=%s StorageId=%s\n"),
631 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
632 res->res_store.MaxConcurrentJobs,
633 res->res_store.dev_name(),
634 res->res_store.media_type,
635 edit_int64(res->res_store.StorageId, ed1));
639 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
640 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
641 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
642 res->res_cat.db_port, res->res_cat.db_name,
643 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
644 res->res_cat.mult_db_connections);
649 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
650 type == R_JOB ? _("Job") : _("JobDefs"),
651 res->res_job.hdr.name, res->res_job.JobType,
652 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
653 res->res_job.enabled);
654 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
655 res->res_job.MaxConcurrentJobs,
656 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
657 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
658 res->res_job.spool_data, res->res_job.write_part_after_job);
659 if (res->res_job.spool_size) {
660 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
662 if (res->res_job.JobType == JT_BACKUP) {
663 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
665 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
666 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
668 if (res->res_job.client) {
669 sendit(sock, _(" --> "));
670 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
672 if (res->res_job.fileset) {
673 sendit(sock, _(" --> "));
674 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
676 if (res->res_job.schedule) {
677 sendit(sock, _(" --> "));
678 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
680 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
681 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
683 if (res->res_job.RegexWhere) {
684 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
686 if (res->res_job.RestoreBootstrap) {
687 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
689 if (res->res_job.WriteBootstrap) {
690 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
692 if (res->res_job.PluginOptions) {
693 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
695 if (res->res_job.MaxRunTime) {
696 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
698 if (res->res_job.MaxWaitTime) {
699 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
701 if (res->res_job.MaxStartDelay) {
702 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
704 if (res->res_job.storage) {
706 foreach_alist(store, res->res_job.storage) {
707 sendit(sock, _(" --> "));
708 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
711 if (res->res_job.base) {
713 foreach_alist(job, res->res_job.base) {
714 sendit(sock, _(" --> Base %s\n"), job->name());
717 if (res->res_job.RunScripts) {
719 foreach_alist(script, res->res_job.RunScripts) {
720 sendit(sock, _(" --> RunScript\n"));
721 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
722 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
723 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
724 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
725 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
726 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
729 if (res->res_job.pool) {
730 sendit(sock, _(" --> "));
731 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
733 if (res->res_job.full_pool) {
734 sendit(sock, _(" --> "));
735 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
737 if (res->res_job.inc_pool) {
738 sendit(sock, _(" --> "));
739 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
741 if (res->res_job.diff_pool) {
742 sendit(sock, _(" --> "));
743 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
745 if (res->res_job.verify_job) {
746 sendit(sock, _(" --> "));
747 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
749 if (res->res_job.run_cmds) {
751 foreach_alist(runcmd, res->res_job.run_cmds) {
752 sendit(sock, _(" --> Run=%s\n"), runcmd);
755 if (res->res_job.selection_pattern) {
756 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
758 if (res->res_job.messages) {
759 sendit(sock, _(" --> "));
760 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
767 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
768 for (i=0; i<res->res_fs.num_includes; i++) {
769 INCEXE *incexe = res->res_fs.include_items[i];
770 for (j=0; j<incexe->num_opts; j++) {
771 FOPTS *fo = incexe->opts_list[j];
772 sendit(sock, " O %s\n", fo->opts);
774 bool enhanced_wild = false;
775 for (k=0; fo->opts[k]!='\0'; k++) {
776 if (fo->opts[k]=='W') {
777 enhanced_wild = true;
782 for (k=0; k<fo->regex.size(); k++) {
783 sendit(sock, " R %s\n", fo->regex.get(k));
785 for (k=0; k<fo->regexdir.size(); k++) {
786 sendit(sock, " RD %s\n", fo->regexdir.get(k));
788 for (k=0; k<fo->regexfile.size(); k++) {
789 sendit(sock, " RF %s\n", fo->regexfile.get(k));
791 for (k=0; k<fo->wild.size(); k++) {
792 sendit(sock, " W %s\n", fo->wild.get(k));
794 for (k=0; k<fo->wilddir.size(); k++) {
795 sendit(sock, " WD %s\n", fo->wilddir.get(k));
797 for (k=0; k<fo->wildfile.size(); k++) {
798 sendit(sock, " WF %s\n", fo->wildfile.get(k));
800 for (k=0; k<fo->wildbase.size(); k++) {
801 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
803 for (k=0; k<fo->base.size(); k++) {
804 sendit(sock, " B %s\n", fo->base.get(k));
806 for (k=0; k<fo->fstype.size(); k++) {
807 sendit(sock, " X %s\n", fo->fstype.get(k));
809 for (k=0; k<fo->drivetype.size(); k++) {
810 sendit(sock, " XD %s\n", fo->drivetype.get(k));
813 sendit(sock, " G %s\n", fo->plugin);
816 sendit(sock, " D %s\n", fo->reader);
819 sendit(sock, " T %s\n", fo->writer);
821 sendit(sock, " N\n");
823 if (incexe->ignoredir) {
824 sendit(sock, " Z %s\n", incexe->ignoredir);
826 for (j=0; j<incexe->name_list.size(); j++) {
827 sendit(sock, " I %s\n", incexe->name_list.get(j));
829 if (incexe->name_list.size()) {
830 sendit(sock, " N\n");
832 for (j=0; j<incexe->plugin_list.size(); j++) {
833 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
835 if (incexe->plugin_list.size()) {
836 sendit(sock, " N\n");
841 for (i=0; i<res->res_fs.num_excludes; i++) {
842 INCEXE *incexe = res->res_fs.exclude_items[i];
843 for (j=0; j<incexe->name_list.size(); j++) {
844 sendit(sock, " E %s\n", incexe->name_list.get(j));
846 if (incexe->name_list.size()) {
847 sendit(sock, " N\n");
854 if (res->res_sch.run) {
856 RUN *run = res->res_sch.run;
857 char buf[1000], num[30];
858 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
863 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
864 bstrncpy(buf, _(" hour="), sizeof(buf));
865 for (i=0; i<24; i++) {
866 if (bit_is_set(i, run->hour)) {
867 bsnprintf(num, sizeof(num), "%d ", i);
868 bstrncat(buf, num, sizeof(buf));
871 bstrncat(buf, "\n", sizeof(buf));
873 bstrncpy(buf, _(" mday="), sizeof(buf));
874 for (i=0; i<31; i++) {
875 if (bit_is_set(i, run->mday)) {
876 bsnprintf(num, sizeof(num), "%d ", i);
877 bstrncat(buf, num, sizeof(buf));
880 bstrncat(buf, "\n", sizeof(buf));
882 bstrncpy(buf, _(" month="), sizeof(buf));
883 for (i=0; i<12; i++) {
884 if (bit_is_set(i, run->month)) {
885 bsnprintf(num, sizeof(num), "%d ", i);
886 bstrncat(buf, num, sizeof(buf));
889 bstrncat(buf, "\n", sizeof(buf));
891 bstrncpy(buf, _(" wday="), sizeof(buf));
892 for (i=0; i<7; i++) {
893 if (bit_is_set(i, run->wday)) {
894 bsnprintf(num, sizeof(num), "%d ", i);
895 bstrncat(buf, num, sizeof(buf));
898 bstrncat(buf, "\n", sizeof(buf));
900 bstrncpy(buf, _(" wom="), sizeof(buf));
901 for (i=0; i<5; i++) {
902 if (bit_is_set(i, run->wom)) {
903 bsnprintf(num, sizeof(num), "%d ", i);
904 bstrncat(buf, num, sizeof(buf));
907 bstrncat(buf, "\n", sizeof(buf));
909 bstrncpy(buf, _(" woy="), sizeof(buf));
910 for (i=0; i<54; i++) {
911 if (bit_is_set(i, run->woy)) {
912 bsnprintf(num, sizeof(num), "%d ", i);
913 bstrncat(buf, num, sizeof(buf));
916 bstrncat(buf, "\n", sizeof(buf));
918 sendit(sock, _(" mins=%d\n"), run->minute);
920 sendit(sock, _(" --> "));
921 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
924 sendit(sock, _(" --> "));
925 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
928 sendit(sock, _(" --> "));
929 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
931 /* If another Run record is chained in, go print it */
937 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
942 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
943 res->res_pool.pool_type);
944 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
945 res->res_pool.use_catalog, res->res_pool.use_volume_once,
946 res->res_pool.catalog_files);
947 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
948 res->res_pool.max_volumes, res->res_pool.AutoPrune,
949 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
950 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
951 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
952 res->res_pool.Recycle,
953 NPRT(res->res_pool.label_format));
954 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
955 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
956 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
957 res->res_pool.recycle_oldest_volume,
958 res->res_pool.purge_oldest_volume,
959 res->res_pool.action_on_purge);
960 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
961 res->res_pool.MaxVolJobs,
962 res->res_pool.MaxVolFiles,
963 edit_uint64(res->res_pool.MaxVolBytes, ed1));
964 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
965 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
966 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
967 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
968 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
969 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
970 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
971 if (res->res_pool.NextPool) {
972 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
974 if (res->res_pool.RecyclePool) {
975 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
977 if (res->res_pool.ScratchPool) {
978 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
980 if (res->res_pool.catalog) {
981 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
983 if (res->res_pool.storage) {
985 foreach_alist(store, res->res_pool.storage) {
986 sendit(sock, _(" --> "));
987 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
990 if (res->res_pool.CopyPool) {
992 foreach_alist(copy, res->res_pool.CopyPool) {
993 sendit(sock, _(" --> "));
994 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1001 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1002 if (res->res_msgs.mail_cmd)
1003 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1004 if (res->res_msgs.operator_cmd)
1005 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1009 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1012 if (recurse && res->res_dir.hdr.next) {
1013 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1018 * Free all the members of an INCEXE structure
1020 static void free_incexe(INCEXE *incexe)
1022 incexe->name_list.destroy();
1023 incexe->plugin_list.destroy();
1024 for (int i=0; i<incexe->num_opts; i++) {
1025 FOPTS *fopt = incexe->opts_list[i];
1026 fopt->regex.destroy();
1027 fopt->regexdir.destroy();
1028 fopt->regexfile.destroy();
1029 fopt->wild.destroy();
1030 fopt->wilddir.destroy();
1031 fopt->wildfile.destroy();
1032 fopt->wildbase.destroy();
1033 fopt->base.destroy();
1034 fopt->fstype.destroy();
1035 fopt->drivetype.destroy();
1047 if (incexe->opts_list) {
1048 free(incexe->opts_list);
1050 if (incexe->ignoredir) {
1051 free(incexe->ignoredir);
1057 * Free memory of resource -- called when daemon terminates.
1058 * NB, we don't need to worry about freeing any references
1059 * to other resources as they will be freed when that
1060 * resource chain is traversed. Mainly we worry about freeing
1061 * allocated strings (names).
1063 void free_resource(RES *sres, int type)
1066 RES *nres; /* next resource if linked */
1067 URES *res = (URES *)sres;
1072 /* common stuff -- free the resource name and description */
1073 nres = (RES *)res->res_dir.hdr.next;
1074 if (res->res_dir.hdr.name) {
1075 free(res->res_dir.hdr.name);
1077 if (res->res_dir.hdr.desc) {
1078 free(res->res_dir.hdr.desc);
1083 if (res->res_dir.working_directory) {
1084 free(res->res_dir.working_directory);
1086 if (res->res_dir.scripts_directory) {
1087 free((char *)res->res_dir.scripts_directory);
1089 if (res->res_dir.plugin_directory) {
1090 free((char *)res->res_dir.plugin_directory);
1092 if (res->res_dir.pid_directory) {
1093 free(res->res_dir.pid_directory);
1095 if (res->res_dir.subsys_directory) {
1096 free(res->res_dir.subsys_directory);
1098 if (res->res_dir.password) {
1099 free(res->res_dir.password);
1101 if (res->res_dir.query_file) {
1102 free(res->res_dir.query_file);
1104 if (res->res_dir.DIRaddrs) {
1105 free_addresses(res->res_dir.DIRaddrs);
1107 if (res->res_dir.DIRsrc_addr) {
1108 free_addresses(res->res_dir.DIRsrc_addr);
1110 if (res->res_dir.tls_ctx) {
1111 free_tls_context(res->res_dir.tls_ctx);
1113 if (res->res_dir.tls_ca_certfile) {
1114 free(res->res_dir.tls_ca_certfile);
1116 if (res->res_dir.tls_ca_certdir) {
1117 free(res->res_dir.tls_ca_certdir);
1119 if (res->res_dir.tls_certfile) {
1120 free(res->res_dir.tls_certfile);
1122 if (res->res_dir.tls_keyfile) {
1123 free(res->res_dir.tls_keyfile);
1125 if (res->res_dir.tls_dhfile) {
1126 free(res->res_dir.tls_dhfile);
1128 if (res->res_dir.tls_allowed_cns) {
1129 delete res->res_dir.tls_allowed_cns;
1131 if (res->res_dir.verid) {
1132 free(res->res_dir.verid);
1139 if (res->res_con.password) {
1140 free(res->res_con.password);
1142 if (res->res_con.tls_ctx) {
1143 free_tls_context(res->res_con.tls_ctx);
1145 if (res->res_con.tls_ca_certfile) {
1146 free(res->res_con.tls_ca_certfile);
1148 if (res->res_con.tls_ca_certdir) {
1149 free(res->res_con.tls_ca_certdir);
1151 if (res->res_con.tls_certfile) {
1152 free(res->res_con.tls_certfile);
1154 if (res->res_con.tls_keyfile) {
1155 free(res->res_con.tls_keyfile);
1157 if (res->res_con.tls_dhfile) {
1158 free(res->res_con.tls_dhfile);
1160 if (res->res_con.tls_allowed_cns) {
1161 delete res->res_con.tls_allowed_cns;
1163 for (int i=0; i<Num_ACL; i++) {
1164 if (res->res_con.ACL_lists[i]) {
1165 delete res->res_con.ACL_lists[i];
1166 res->res_con.ACL_lists[i] = NULL;
1171 if (res->res_client.address) {
1172 free(res->res_client.address);
1174 if (res->res_client.password) {
1175 free(res->res_client.password);
1177 if (res->res_client.tls_ctx) {
1178 free_tls_context(res->res_client.tls_ctx);
1180 if (res->res_client.tls_ca_certfile) {
1181 free(res->res_client.tls_ca_certfile);
1183 if (res->res_client.tls_ca_certdir) {
1184 free(res->res_client.tls_ca_certdir);
1186 if (res->res_client.tls_certfile) {
1187 free(res->res_client.tls_certfile);
1189 if (res->res_client.tls_keyfile) {
1190 free(res->res_client.tls_keyfile);
1192 if (res->res_client.tls_allowed_cns) {
1193 delete res->res_client.tls_allowed_cns;
1197 if (res->res_store.address) {
1198 free(res->res_store.address);
1200 if (res->res_store.password) {
1201 free(res->res_store.password);
1203 if (res->res_store.media_type) {
1204 free(res->res_store.media_type);
1206 if (res->res_store.device) {
1207 delete res->res_store.device;
1209 if (res->res_store.tls_ctx) {
1210 free_tls_context(res->res_store.tls_ctx);
1212 if (res->res_store.tls_ca_certfile) {
1213 free(res->res_store.tls_ca_certfile);
1215 if (res->res_store.tls_ca_certdir) {
1216 free(res->res_store.tls_ca_certdir);
1218 if (res->res_store.tls_certfile) {
1219 free(res->res_store.tls_certfile);
1221 if (res->res_store.tls_keyfile) {
1222 free(res->res_store.tls_keyfile);
1226 if (res->res_cat.db_address) {
1227 free(res->res_cat.db_address);
1229 if (res->res_cat.db_socket) {
1230 free(res->res_cat.db_socket);
1232 if (res->res_cat.db_user) {
1233 free(res->res_cat.db_user);
1235 if (res->res_cat.db_name) {
1236 free(res->res_cat.db_name);
1238 if (res->res_cat.db_driver) {
1239 free(res->res_cat.db_driver);
1241 if (res->res_cat.db_password) {
1242 free(res->res_cat.db_password);
1246 if ((num=res->res_fs.num_includes)) {
1247 while (--num >= 0) {
1248 free_incexe(res->res_fs.include_items[num]);
1250 free(res->res_fs.include_items);
1252 res->res_fs.num_includes = 0;
1253 if ((num=res->res_fs.num_excludes)) {
1254 while (--num >= 0) {
1255 free_incexe(res->res_fs.exclude_items[num]);
1257 free(res->res_fs.exclude_items);
1259 res->res_fs.num_excludes = 0;
1262 if (res->res_pool.pool_type) {
1263 free(res->res_pool.pool_type);
1265 if (res->res_pool.label_format) {
1266 free(res->res_pool.label_format);
1268 if (res->res_pool.cleaning_prefix) {
1269 free(res->res_pool.cleaning_prefix);
1271 if (res->res_pool.storage) {
1272 delete res->res_pool.storage;
1276 if (res->res_sch.run) {
1278 nrun = res->res_sch.run;
1288 if (res->res_job.RestoreWhere) {
1289 free(res->res_job.RestoreWhere);
1291 if (res->res_job.RegexWhere) {
1292 free(res->res_job.RegexWhere);
1294 if (res->res_job.strip_prefix) {
1295 free(res->res_job.strip_prefix);
1297 if (res->res_job.add_prefix) {
1298 free(res->res_job.add_prefix);
1300 if (res->res_job.add_suffix) {
1301 free(res->res_job.add_suffix);
1303 if (res->res_job.RestoreBootstrap) {
1304 free(res->res_job.RestoreBootstrap);
1306 if (res->res_job.WriteBootstrap) {
1307 free(res->res_job.WriteBootstrap);
1309 if (res->res_job.PluginOptions) {
1310 free(res->res_job.PluginOptions);
1312 if (res->res_job.selection_pattern) {
1313 free(res->res_job.selection_pattern);
1315 if (res->res_job.run_cmds) {
1316 delete res->res_job.run_cmds;
1318 if (res->res_job.storage) {
1319 delete res->res_job.storage;
1321 if (res->res_job.base) {
1322 delete res->res_job.base;
1324 if (res->res_job.RunScripts) {
1325 free_runscripts(res->res_job.RunScripts);
1326 delete res->res_job.RunScripts;
1330 if (res->res_msgs.mail_cmd) {
1331 free(res->res_msgs.mail_cmd);
1333 if (res->res_msgs.operator_cmd) {
1334 free(res->res_msgs.operator_cmd);
1336 free_msgs_res((MSGS *)res); /* free message resource */
1340 printf(_("Unknown resource type %d in free_resource.\n"), type);
1342 /* Common stuff again -- free the resource, recurse to next one */
1347 free_resource(nres, type);
1352 * Save the new resource by chaining it into the head list for
1353 * the resource. If this is pass 2, we update any resource
1354 * pointers because they may not have been defined until
1357 void save_resource(int type, RES_ITEM *items, int pass)
1360 int rindex = type - r_first;
1364 /* Check Job requirements after applying JobDefs */
1365 if (type != R_JOB && type != R_JOBDEFS) {
1367 * Ensure that all required items are present
1369 for (i=0; items[i].name; i++) {
1370 if (items[i].flags & ITEM_REQUIRED) {
1371 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1372 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1373 items[i].name, resources[rindex]);
1376 /* If this triggers, take a look at lib/parse_conf.h */
1377 if (i >= MAX_RES_ITEMS) {
1378 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1381 } else if (type == R_JOB) {
1383 * Ensure that the name item is present
1385 if (items[0].flags & ITEM_REQUIRED) {
1386 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1387 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1388 items[0].name, resources[rindex]);
1394 * During pass 2 in each "store" routine, we looked up pointers
1395 * to all the resources referrenced in the current resource, now we
1396 * must copy their addresses from the static record to the allocated
1401 /* Resources not containing a resource */
1409 * Resources containing another resource or alist. First
1410 * look up the resource which contains another resource. It
1411 * was written during pass 1. Then stuff in the pointers to
1412 * the resources it contains, which were inserted this pass.
1413 * Finally, it will all be stored back.
1416 /* Find resource saved in pass 1 */
1417 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1418 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1420 /* Explicitly copy resource pointers from this pass (res_all) */
1421 res->res_pool.NextPool = res_all.res_pool.NextPool;
1422 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1423 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1424 res->res_pool.storage = res_all.res_pool.storage;
1425 res->res_pool.catalog = res_all.res_pool.catalog;
1428 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1429 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1431 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1434 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1435 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1437 res->res_dir.messages = res_all.res_dir.messages;
1438 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1441 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1442 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1443 res_all.res_dir.hdr.name);
1445 /* we must explicitly copy the device alist pointer */
1446 res->res_store.device = res_all.res_store.device;
1450 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1451 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1452 res_all.res_dir.hdr.name);
1454 res->res_job.messages = res_all.res_job.messages;
1455 res->res_job.schedule = res_all.res_job.schedule;
1456 res->res_job.client = res_all.res_job.client;
1457 res->res_job.fileset = res_all.res_job.fileset;
1458 res->res_job.storage = res_all.res_job.storage;
1459 res->res_job.base = res_all.res_job.base;
1460 res->res_job.pool = res_all.res_job.pool;
1461 res->res_job.full_pool = res_all.res_job.full_pool;
1462 res->res_job.inc_pool = res_all.res_job.inc_pool;
1463 res->res_job.diff_pool = res_all.res_job.diff_pool;
1464 res->res_job.verify_job = res_all.res_job.verify_job;
1465 res->res_job.jobdefs = res_all.res_job.jobdefs;
1466 res->res_job.run_cmds = res_all.res_job.run_cmds;
1467 res->res_job.RunScripts = res_all.res_job.RunScripts;
1469 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1470 * is not very useful)
1471 * We have to set_bit(index, res_all.hdr.item_present);
1472 * or something like that
1475 /* we take RegexWhere before all other options */
1476 if (!res->res_job.RegexWhere
1478 (res->res_job.strip_prefix ||
1479 res->res_job.add_suffix ||
1480 res->res_job.add_prefix))
1482 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1483 res->res_job.add_prefix,
1484 res->res_job.add_suffix);
1485 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1486 bregexp_build_where(res->res_job.RegexWhere, len,
1487 res->res_job.strip_prefix,
1488 res->res_job.add_prefix,
1489 res->res_job.add_suffix);
1490 /* TODO: test bregexp */
1493 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1494 free(res->res_job.RestoreWhere);
1495 res->res_job.RestoreWhere = NULL;
1500 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1501 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1503 res->res_counter.Catalog = res_all.res_counter.Catalog;
1504 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1508 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1509 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1511 res->res_client.catalog = res_all.res_client.catalog;
1512 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1516 * Schedule is a bit different in that it contains a RUN record
1517 * chain which isn't a "named" resource. This chain was linked
1518 * in by run_conf.c during pass 2, so here we jam the pointer
1519 * into the Schedule resource.
1521 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1522 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1524 res->res_sch.run = res_all.res_sch.run;
1527 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1531 /* Note, the resource name was already saved during pass 1,
1532 * so here, we can just release it.
1534 if (res_all.res_dir.hdr.name) {
1535 free(res_all.res_dir.hdr.name);
1536 res_all.res_dir.hdr.name = NULL;
1538 if (res_all.res_dir.hdr.desc) {
1539 free(res_all.res_dir.hdr.desc);
1540 res_all.res_dir.hdr.desc = NULL;
1546 * The following code is only executed during pass 1
1550 size = sizeof(DIRRES);
1553 size = sizeof(CONRES);
1556 size =sizeof(CLIENT);
1559 size = sizeof(STORE);
1569 size = sizeof(FILESET);
1572 size = sizeof(SCHED);
1575 size = sizeof(POOL);
1578 size = sizeof(MSGS);
1581 size = sizeof(COUNTER);
1587 printf(_("Unknown resource type %d in save_resource.\n"), type);
1593 res = (URES *)malloc(size);
1594 memcpy(res, &res_all, size);
1595 if (!res_head[rindex]) {
1596 res_head[rindex] = (RES *)res; /* store first entry */
1597 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1598 res->res_dir.hdr.name, rindex);
1601 if (res->res_dir.hdr.name == NULL) {
1602 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1605 /* Add new res to end of chain */
1606 for (last=next=res_head[rindex]; next; next=next->next) {
1608 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1609 Emsg2(M_ERROR_TERM, 0,
1610 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1611 resources[rindex].name, res->res_dir.hdr.name);
1614 last->next = (RES *)res;
1615 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1616 res->res_dir.hdr.name, rindex, pass);
1621 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1623 uint32_t *destination = (uint32_t*)item->value;
1624 lex_get_token(lc, T_NAME);
1625 if (strcasecmp(lc->str, "truncate") == 0) {
1626 *destination = (*destination) | ON_PURGE_TRUNCATE;
1628 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1632 set_bit(index, res_all.hdr.item_present);
1636 * Store Device. Note, the resource is created upon the
1637 * first reference. The details of the resource are obtained
1638 * later from the SD.
1640 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1644 int rindex = R_DEVICE - r_first;
1645 int size = sizeof(DEVICE);
1649 token = lex_get_token(lc, T_NAME);
1650 if (!res_head[rindex]) {
1651 res = (URES *)malloc(size);
1652 memset(res, 0, size);
1653 res->res_dev.hdr.name = bstrdup(lc->str);
1654 res_head[rindex] = (RES *)res; /* store first entry */
1655 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1656 res->res_dir.hdr.name, rindex);
1659 /* See if it is already defined */
1660 for (next=res_head[rindex]; next->next; next=next->next) {
1661 if (strcmp(next->name, lc->str) == 0) {
1667 res = (URES *)malloc(size);
1668 memset(res, 0, size);
1669 res->res_dev.hdr.name = bstrdup(lc->str);
1670 next->next = (RES *)res;
1671 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1672 res->res_dir.hdr.name, rindex, pass);
1677 set_bit(index, res_all.hdr.item_present);
1679 store_alist_res(lc, item, index, pass);
1684 * Store Migration/Copy type
1687 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1691 token = lex_get_token(lc, T_NAME);
1692 /* Store the type both pass 1 and pass 2 */
1693 for (i=0; migtypes[i].type_name; i++) {
1694 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1695 *(uint32_t *)(item->value) = migtypes[i].job_type;
1701 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1704 set_bit(index, res_all.hdr.item_present);
1710 * Store JobType (backup, verify, restore)
1713 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1717 token = lex_get_token(lc, T_NAME);
1718 /* Store the type both pass 1 and pass 2 */
1719 for (i=0; jobtypes[i].type_name; i++) {
1720 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1721 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1727 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1730 set_bit(index, res_all.hdr.item_present);
1734 * Store Job Level (Full, Incremental, ...)
1737 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1741 token = lex_get_token(lc, T_NAME);
1742 /* Store the level pass 2 so that type is defined */
1743 for (i=0; joblevels[i].level_name; i++) {
1744 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1745 *(uint32_t *)(item->value) = joblevels[i].level;
1751 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1754 set_bit(index, res_all.hdr.item_present);
1758 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1761 token = lex_get_token(lc, T_NAME);
1762 /* Scan Replacement options */
1763 for (i=0; ReplaceOptions[i].name; i++) {
1764 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1765 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1771 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1774 set_bit(index, res_all.hdr.item_present);
1778 * Store ACL (access control list)
1781 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1786 token = lex_get_token(lc, T_STRING);
1788 if (((alist **)item->value)[item->code] == NULL) {
1789 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1790 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1792 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1793 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1795 token = lex_get_token(lc, T_ALL);
1796 if (token == T_COMMA) {
1797 continue; /* get another ACL */
1801 set_bit(index, res_all.hdr.item_present);
1804 /* We build RunScripts items here */
1805 static RUNSCRIPT res_runscript;
1807 /* Store a runscript->when in a bit field */
1808 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1810 lex_get_token(lc, T_NAME);
1812 if (strcasecmp(lc->str, "before") == 0) {
1813 *(uint32_t *)(item->value) = SCRIPT_Before ;
1814 } else if (strcasecmp(lc->str, "after") == 0) {
1815 *(uint32_t *)(item->value) = SCRIPT_After;
1816 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1817 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1818 } else if (strcasecmp(lc->str, "always") == 0) {
1819 *(uint32_t *)(item->value) = SCRIPT_Any;
1821 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1826 /* Store a runscript->target
1829 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1831 lex_get_token(lc, T_STRING);
1834 if (strcmp(lc->str, "%c") == 0) {
1835 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1836 } else if (strcasecmp(lc->str, "yes") == 0) {
1837 ((RUNSCRIPT*) item->value)->set_target("%c");
1838 } else if (strcasecmp(lc->str, "no") == 0) {
1839 ((RUNSCRIPT*) item->value)->set_target("");
1841 RES *res = GetResWithName(R_CLIENT, lc->str);
1843 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1844 lc->str, lc->line_no, lc->line);
1847 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1854 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1856 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1858 lex_get_token(lc, T_STRING);
1861 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1862 POOLMEM *c = get_pool_memory(PM_FNAME);
1863 /* Each runscript command takes 2 entries in commands list */
1864 pm_strcpy(c, lc->str);
1865 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1866 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1871 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1873 lex_get_token(lc, T_STRING);
1874 alist **runscripts = (alist **)(item->value) ;
1877 RUNSCRIPT *script = new_runscript();
1878 script->set_job_code_callback(job_code_callback_filesetname);
1880 script->set_command(lc->str);
1882 /* TODO: remove all script->old_proto with bacula 1.42 */
1884 if (strcmp(item->name, "runbeforejob") == 0) {
1885 script->when = SCRIPT_Before;
1886 script->fail_on_error = true;
1887 script->set_target("");
1889 } else if (strcmp(item->name, "runafterjob") == 0) {
1890 script->when = SCRIPT_After;
1891 script->on_success = true;
1892 script->on_failure = false;
1893 script->set_target("");
1895 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1896 script->old_proto = true;
1897 script->when = SCRIPT_After;
1898 script->set_target("%c");
1899 script->on_success = true;
1900 script->on_failure = false;
1902 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1903 script->old_proto = true;
1904 script->when = SCRIPT_Before;
1905 script->set_target("%c");
1906 script->fail_on_error = true;
1908 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1909 script->when = SCRIPT_After;
1910 script->on_failure = true;
1911 script->on_success = false;
1912 script->set_target("");
1915 if (*runscripts == NULL) {
1916 *runscripts = New(alist(10, not_owned_by_alist));
1919 (*runscripts)->append(script);
1926 /* Store a bool in a bit field without modifing res_all.hdr
1927 * We can also add an option to store_bool to skip res_all.hdr
1929 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1931 lex_get_token(lc, T_NAME);
1932 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1933 *(bool *)(item->value) = true;
1934 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1935 *(bool *)(item->value) = false;
1937 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1943 * new RunScript items
1944 * name handler value code flags default_value
1946 static RES_ITEM runscript_items[] = {
1947 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1948 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1949 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1950 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1951 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1952 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1953 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1954 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1955 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1956 {NULL, NULL, {0}, 0, 0, 0}
1960 * Store RunScript info
1962 * Note, when this routine is called, we are inside a Job
1963 * resource. We treat the RunScript like a sort of
1964 * mini-resource within the Job resource.
1966 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1970 alist **runscripts = (alist **)(item->value) ;
1972 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1974 token = lex_get_token(lc, T_SKIP_EOL);
1976 if (token != T_BOB) {
1977 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1979 /* setting on_success, on_failure, fail_on_error */
1980 res_runscript.reset_default();
1983 res_runscript.commands = New(alist(10, not_owned_by_alist));
1986 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1987 if (token == T_EOB) {
1990 if (token != T_IDENTIFIER) {
1991 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1993 for (i=0; runscript_items[i].name; i++) {
1994 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1995 token = lex_get_token(lc, T_SKIP_EOL);
1996 if (token != T_EQUALS) {
1997 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2000 /* Call item handler */
2001 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2008 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2013 /* run on client by default */
2014 if (res_runscript.target == NULL) {
2015 res_runscript.set_target("%c");
2017 if (*runscripts == NULL) {
2018 *runscripts = New(alist(10, not_owned_by_alist));
2021 * commands list contains 2 values per command
2022 * - POOLMEM command string (ex: /bin/true)
2023 * - int command type (ex: SHELL_CMD)
2025 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2026 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2027 t = (intptr_t)res_runscript.commands->pop();
2028 RUNSCRIPT *script = new_runscript();
2029 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2030 script->command = c;
2031 script->cmd_type = t;
2032 /* target is taken from res_runscript, each runscript object have
2035 script->target = NULL;
2036 script->set_target(res_runscript.target);
2038 (*runscripts)->append(script);
2041 delete res_runscript.commands;
2042 /* setting on_success, on_failure... cleanup target field */
2043 res_runscript.reset_default(true);
2047 set_bit(index, res_all.hdr.item_present);
2050 /* callback function for edit_job_codes */
2051 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2053 if (param[0] == 'f') {
2054 return jcr->fileset->name();
2060 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2062 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2063 r_first, r_last, resources, res_head);
2064 return config->parse_config();