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 {NULL, NULL, {0}, 0, 0, 0}
263 * Job Resource Directives
265 * name handler value code flags default_value
267 RES_ITEM job_items[] = {
268 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
269 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
270 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
271 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
272 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
273 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
274 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
275 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
276 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
277 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
278 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
279 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
280 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
281 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
282 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
283 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
284 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
285 /* Root of where to restore files */
286 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
287 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
288 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
289 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
290 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
291 /* Where to find bootstrap during restore */
292 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
293 /* Where to write bootstrap file during backup */
294 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
295 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
296 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
297 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
298 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
299 /* xxxMaxWaitTime are deprecated */
300 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
301 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
302 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
303 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
304 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
305 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
306 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
307 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
308 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
309 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
310 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
311 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
312 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
313 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
314 {"purgemigratejob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
315 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
316 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
317 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
318 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
319 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
320 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
321 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
327 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
328 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
329 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
330 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
331 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
332 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
333 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
334 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
335 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
336 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
337 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
338 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
339 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
340 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
341 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
342 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
343 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
344 {NULL, NULL, {0}, 0, 0, 0}
349 * name handler value code flags default_value
351 static RES_ITEM fs_items[] = {
352 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
353 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
354 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
355 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
356 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
357 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
358 {NULL, NULL, {0}, 0, 0, 0}
361 /* Schedule -- see run_conf.c */
364 * name handler value code flags default_value
366 static RES_ITEM sch_items[] = {
367 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
368 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
369 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
370 {NULL, NULL, {0}, 0, 0, 0}
375 * name handler value code flags default_value
377 static RES_ITEM pool_items[] = {
378 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
379 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
380 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
381 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
382 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
383 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
384 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
385 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
386 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
387 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
388 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
389 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
390 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
391 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
392 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
393 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
394 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
395 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
396 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
397 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
398 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
399 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
400 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
401 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
402 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
403 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
404 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
405 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
406 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
407 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
408 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
409 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
411 {NULL, NULL, {0}, 0, 0, 0}
416 * name handler value code flags default_value
418 static RES_ITEM counter_items[] = {
419 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
420 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
421 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
422 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
423 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
424 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
425 {NULL, NULL, {0}, 0, 0, 0}
429 /* Message resource */
430 extern RES_ITEM msgs_items[];
433 * This is the master resource definition.
434 * It must have one item for each of the resources.
436 * NOTE!!! keep it in the same order as the R_codes
437 * or eliminate all resources[rindex].name
439 * name items rcode res_head
441 RES_TABLE resources[] = {
442 {"director", dir_items, R_DIRECTOR},
443 {"client", cli_items, R_CLIENT},
444 {"job", job_items, R_JOB},
445 {"storage", store_items, R_STORAGE},
446 {"catalog", cat_items, R_CATALOG},
447 {"schedule", sch_items, R_SCHEDULE},
448 {"fileset", fs_items, R_FILESET},
449 {"pool", pool_items, R_POOL},
450 {"messages", msgs_items, R_MSGS},
451 {"counter", counter_items, R_COUNTER},
452 {"console", con_items, R_CONSOLE},
453 {"jobdefs", job_items, R_JOBDEFS},
454 {"device", NULL, R_DEVICE}, /* info obtained from SD */
459 /* Keywords (RHS) permitted in Job Level records
461 * level_name level job_type
463 struct s_jl joblevels[] = {
464 {"Full", L_FULL, JT_BACKUP},
465 {"Base", L_BASE, JT_BACKUP},
466 {"Incremental", L_INCREMENTAL, JT_BACKUP},
467 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
468 {"Since", L_SINCE, JT_BACKUP},
469 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
470 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
471 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
472 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
473 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
474 {"Data", L_VERIFY_DATA, JT_VERIFY},
475 {" ", L_NONE, JT_ADMIN},
476 {" ", L_NONE, JT_RESTORE},
480 /* Keywords (RHS) permitted in Job type records
484 struct s_jt jobtypes[] = {
485 {"backup", JT_BACKUP},
487 {"verify", JT_VERIFY},
488 {"restore", JT_RESTORE},
489 {"migrate", JT_MIGRATE},
495 /* Keywords (RHS) permitted in Selection type records
499 struct s_jt migtypes[] = {
500 {"smallestvolume", MT_SMALLEST_VOL},
501 {"oldestvolume", MT_OLDEST_VOL},
502 {"pooloccupancy", MT_POOL_OCCUPANCY},
503 {"pooltime", MT_POOL_TIME},
504 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
505 {"client", MT_CLIENT},
506 {"volume", MT_VOLUME},
508 {"sqlquery", MT_SQLQUERY},
514 /* Options permitted in Restore replace= */
515 struct s_kw ReplaceOptions[] = {
516 {"always", REPLACE_ALWAYS},
517 {"ifnewer", REPLACE_IFNEWER},
518 {"ifolder", REPLACE_IFOLDER},
519 {"never", REPLACE_NEVER},
523 char *CAT::display(POOLMEM *dst) {
524 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
525 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
527 name(), NPRTB(db_name),
528 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
529 NPRTB(db_address), db_port, NPRTB(db_socket));
533 const char *level_to_str(int level)
536 static char level_no[30];
537 const char *str = level_no;
539 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
540 for (i=0; joblevels[i].level_name; i++) {
541 if (level == (int)joblevels[i].level) {
542 str = joblevels[i].level_name;
549 /* Dump contents of resource */
550 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
552 URES *res = (URES *)reshdr;
554 char ed1[100], ed2[100], ed3[100];
558 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
561 if (type < 0) { /* no recursion */
567 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
568 reshdr->name, res->res_dir.MaxConcurrentJobs,
569 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
570 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
571 if (res->res_dir.query_file) {
572 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
574 if (res->res_dir.messages) {
575 sendit(sock, _(" --> "));
576 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
580 sendit(sock, _("Console: name=%s SSL=%d\n"),
581 res->res_con.hdr.name, res->res_con.tls_enable);
584 if (res->res_counter.WrapCounter) {
585 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
586 res->res_counter.hdr.name, res->res_counter.MinValue,
587 res->res_counter.MaxValue, res->res_counter.CurrentValue,
588 res->res_counter.WrapCounter->hdr.name);
590 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
591 res->res_counter.hdr.name, res->res_counter.MinValue,
592 res->res_counter.MaxValue);
594 if (res->res_counter.Catalog) {
595 sendit(sock, _(" --> "));
596 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
601 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
602 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
603 res->res_client.MaxConcurrentJobs);
604 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
605 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
606 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
607 res->res_client.AutoPrune);
608 if (res->res_client.catalog) {
609 sendit(sock, _(" --> "));
610 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
617 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
618 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
619 " poolid=%s volname=%s MediaType=%s\n"),
620 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
621 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
622 dev->offline, dev->autochanger,
623 edit_uint64(dev->PoolId, ed1),
624 dev->VolumeName, dev->MediaType);
628 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
629 " DeviceName=%s MediaType=%s StorageId=%s\n"),
630 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
631 res->res_store.MaxConcurrentJobs,
632 res->res_store.dev_name(),
633 res->res_store.media_type,
634 edit_int64(res->res_store.StorageId, ed1));
638 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
639 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
640 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
641 res->res_cat.db_port, res->res_cat.db_name,
642 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
643 res->res_cat.mult_db_connections);
648 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
649 type == R_JOB ? _("Job") : _("JobDefs"),
650 res->res_job.hdr.name, res->res_job.JobType,
651 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
652 res->res_job.enabled);
653 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
654 res->res_job.MaxConcurrentJobs,
655 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
656 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
657 res->res_job.spool_data, res->res_job.write_part_after_job);
658 if (res->res_job.spool_size) {
659 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
661 if (res->res_job.JobType == JT_BACKUP) {
662 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
664 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
665 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
667 if (res->res_job.client) {
668 sendit(sock, _(" --> "));
669 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
671 if (res->res_job.fileset) {
672 sendit(sock, _(" --> "));
673 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
675 if (res->res_job.schedule) {
676 sendit(sock, _(" --> "));
677 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
679 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
680 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
682 if (res->res_job.RegexWhere) {
683 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
685 if (res->res_job.RestoreBootstrap) {
686 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
688 if (res->res_job.WriteBootstrap) {
689 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
691 if (res->res_job.PluginOptions) {
692 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
694 if (res->res_job.MaxRunTime) {
695 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
697 if (res->res_job.MaxWaitTime) {
698 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
700 if (res->res_job.MaxStartDelay) {
701 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
703 if (res->res_job.storage) {
705 foreach_alist(store, res->res_job.storage) {
706 sendit(sock, _(" --> "));
707 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
710 if (res->res_job.base) {
712 foreach_alist(job, res->res_job.base) {
713 sendit(sock, _(" --> Base %s\n"), job->name());
716 if (res->res_job.RunScripts) {
718 foreach_alist(script, res->res_job.RunScripts) {
719 sendit(sock, _(" --> RunScript\n"));
720 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
721 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
722 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
723 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
724 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
725 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
728 if (res->res_job.pool) {
729 sendit(sock, _(" --> "));
730 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
732 if (res->res_job.full_pool) {
733 sendit(sock, _(" --> "));
734 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
736 if (res->res_job.inc_pool) {
737 sendit(sock, _(" --> "));
738 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
740 if (res->res_job.diff_pool) {
741 sendit(sock, _(" --> "));
742 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
744 if (res->res_job.verify_job) {
745 sendit(sock, _(" --> "));
746 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
748 if (res->res_job.run_cmds) {
750 foreach_alist(runcmd, res->res_job.run_cmds) {
751 sendit(sock, _(" --> Run=%s\n"), runcmd);
754 if (res->res_job.selection_pattern) {
755 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
757 if (res->res_job.messages) {
758 sendit(sock, _(" --> "));
759 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
766 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
767 for (i=0; i<res->res_fs.num_includes; i++) {
768 INCEXE *incexe = res->res_fs.include_items[i];
769 for (j=0; j<incexe->num_opts; j++) {
770 FOPTS *fo = incexe->opts_list[j];
771 sendit(sock, " O %s\n", fo->opts);
773 bool enhanced_wild = false;
774 for (k=0; fo->opts[k]!='\0'; k++) {
775 if (fo->opts[k]=='W') {
776 enhanced_wild = true;
781 for (k=0; k<fo->regex.size(); k++) {
782 sendit(sock, " R %s\n", fo->regex.get(k));
784 for (k=0; k<fo->regexdir.size(); k++) {
785 sendit(sock, " RD %s\n", fo->regexdir.get(k));
787 for (k=0; k<fo->regexfile.size(); k++) {
788 sendit(sock, " RF %s\n", fo->regexfile.get(k));
790 for (k=0; k<fo->wild.size(); k++) {
791 sendit(sock, " W %s\n", fo->wild.get(k));
793 for (k=0; k<fo->wilddir.size(); k++) {
794 sendit(sock, " WD %s\n", fo->wilddir.get(k));
796 for (k=0; k<fo->wildfile.size(); k++) {
797 sendit(sock, " WF %s\n", fo->wildfile.get(k));
799 for (k=0; k<fo->wildbase.size(); k++) {
800 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
802 for (k=0; k<fo->base.size(); k++) {
803 sendit(sock, " B %s\n", fo->base.get(k));
805 for (k=0; k<fo->fstype.size(); k++) {
806 sendit(sock, " X %s\n", fo->fstype.get(k));
808 for (k=0; k<fo->drivetype.size(); k++) {
809 sendit(sock, " XD %s\n", fo->drivetype.get(k));
812 sendit(sock, " G %s\n", fo->plugin);
815 sendit(sock, " D %s\n", fo->reader);
818 sendit(sock, " T %s\n", fo->writer);
820 sendit(sock, " N\n");
822 if (incexe->ignoredir) {
823 sendit(sock, " Z %s\n", incexe->ignoredir);
825 for (j=0; j<incexe->name_list.size(); j++) {
826 sendit(sock, " I %s\n", incexe->name_list.get(j));
828 if (incexe->name_list.size()) {
829 sendit(sock, " N\n");
831 for (j=0; j<incexe->plugin_list.size(); j++) {
832 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
834 if (incexe->plugin_list.size()) {
835 sendit(sock, " N\n");
840 for (i=0; i<res->res_fs.num_excludes; i++) {
841 INCEXE *incexe = res->res_fs.exclude_items[i];
842 for (j=0; j<incexe->name_list.size(); j++) {
843 sendit(sock, " E %s\n", incexe->name_list.get(j));
845 if (incexe->name_list.size()) {
846 sendit(sock, " N\n");
853 if (res->res_sch.run) {
855 RUN *run = res->res_sch.run;
856 char buf[1000], num[30];
857 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
862 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
863 bstrncpy(buf, _(" hour="), sizeof(buf));
864 for (i=0; i<24; i++) {
865 if (bit_is_set(i, run->hour)) {
866 bsnprintf(num, sizeof(num), "%d ", i);
867 bstrncat(buf, num, sizeof(buf));
870 bstrncat(buf, "\n", sizeof(buf));
872 bstrncpy(buf, _(" mday="), sizeof(buf));
873 for (i=0; i<31; i++) {
874 if (bit_is_set(i, run->mday)) {
875 bsnprintf(num, sizeof(num), "%d ", i);
876 bstrncat(buf, num, sizeof(buf));
879 bstrncat(buf, "\n", sizeof(buf));
881 bstrncpy(buf, _(" month="), sizeof(buf));
882 for (i=0; i<12; i++) {
883 if (bit_is_set(i, run->month)) {
884 bsnprintf(num, sizeof(num), "%d ", i);
885 bstrncat(buf, num, sizeof(buf));
888 bstrncat(buf, "\n", sizeof(buf));
890 bstrncpy(buf, _(" wday="), sizeof(buf));
891 for (i=0; i<7; i++) {
892 if (bit_is_set(i, run->wday)) {
893 bsnprintf(num, sizeof(num), "%d ", i);
894 bstrncat(buf, num, sizeof(buf));
897 bstrncat(buf, "\n", sizeof(buf));
899 bstrncpy(buf, _(" wom="), sizeof(buf));
900 for (i=0; i<5; i++) {
901 if (bit_is_set(i, run->wom)) {
902 bsnprintf(num, sizeof(num), "%d ", i);
903 bstrncat(buf, num, sizeof(buf));
906 bstrncat(buf, "\n", sizeof(buf));
908 bstrncpy(buf, _(" woy="), sizeof(buf));
909 for (i=0; i<54; i++) {
910 if (bit_is_set(i, run->woy)) {
911 bsnprintf(num, sizeof(num), "%d ", i);
912 bstrncat(buf, num, sizeof(buf));
915 bstrncat(buf, "\n", sizeof(buf));
917 sendit(sock, _(" mins=%d\n"), run->minute);
919 sendit(sock, _(" --> "));
920 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
923 sendit(sock, _(" --> "));
924 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
927 sendit(sock, _(" --> "));
928 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
930 /* If another Run record is chained in, go print it */
936 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
941 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
942 res->res_pool.pool_type);
943 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
944 res->res_pool.use_catalog, res->res_pool.use_volume_once,
945 res->res_pool.catalog_files);
946 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
947 res->res_pool.max_volumes, res->res_pool.AutoPrune,
948 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
949 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
950 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
951 res->res_pool.Recycle,
952 NPRT(res->res_pool.label_format));
953 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
954 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
955 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
956 res->res_pool.recycle_oldest_volume,
957 res->res_pool.purge_oldest_volume,
958 res->res_pool.action_on_purge);
959 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
960 res->res_pool.MaxVolJobs,
961 res->res_pool.MaxVolFiles,
962 edit_uint64(res->res_pool.MaxVolBytes, ed1));
963 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
964 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
965 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
966 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
967 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
968 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
969 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
970 if (res->res_pool.NextPool) {
971 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
973 if (res->res_pool.RecyclePool) {
974 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
976 if (res->res_pool.ScratchPool) {
977 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
979 if (res->res_pool.catalog) {
980 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
982 if (res->res_pool.storage) {
984 foreach_alist(store, res->res_pool.storage) {
985 sendit(sock, _(" --> "));
986 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
989 if (res->res_pool.CopyPool) {
991 foreach_alist(copy, res->res_pool.CopyPool) {
992 sendit(sock, _(" --> "));
993 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1000 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1001 if (res->res_msgs.mail_cmd)
1002 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1003 if (res->res_msgs.operator_cmd)
1004 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1008 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1011 if (recurse && res->res_dir.hdr.next) {
1012 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1017 * Free all the members of an INCEXE structure
1019 static void free_incexe(INCEXE *incexe)
1021 incexe->name_list.destroy();
1022 incexe->plugin_list.destroy();
1023 for (int i=0; i<incexe->num_opts; i++) {
1024 FOPTS *fopt = incexe->opts_list[i];
1025 fopt->regex.destroy();
1026 fopt->regexdir.destroy();
1027 fopt->regexfile.destroy();
1028 fopt->wild.destroy();
1029 fopt->wilddir.destroy();
1030 fopt->wildfile.destroy();
1031 fopt->wildbase.destroy();
1032 fopt->base.destroy();
1033 fopt->fstype.destroy();
1034 fopt->drivetype.destroy();
1046 if (incexe->opts_list) {
1047 free(incexe->opts_list);
1049 if (incexe->ignoredir) {
1050 free(incexe->ignoredir);
1056 * Free memory of resource -- called when daemon terminates.
1057 * NB, we don't need to worry about freeing any references
1058 * to other resources as they will be freed when that
1059 * resource chain is traversed. Mainly we worry about freeing
1060 * allocated strings (names).
1062 void free_resource(RES *sres, int type)
1065 RES *nres; /* next resource if linked */
1066 URES *res = (URES *)sres;
1071 /* common stuff -- free the resource name and description */
1072 nres = (RES *)res->res_dir.hdr.next;
1073 if (res->res_dir.hdr.name) {
1074 free(res->res_dir.hdr.name);
1076 if (res->res_dir.hdr.desc) {
1077 free(res->res_dir.hdr.desc);
1082 if (res->res_dir.working_directory) {
1083 free(res->res_dir.working_directory);
1085 if (res->res_dir.scripts_directory) {
1086 free((char *)res->res_dir.scripts_directory);
1088 if (res->res_dir.plugin_directory) {
1089 free((char *)res->res_dir.plugin_directory);
1091 if (res->res_dir.pid_directory) {
1092 free(res->res_dir.pid_directory);
1094 if (res->res_dir.subsys_directory) {
1095 free(res->res_dir.subsys_directory);
1097 if (res->res_dir.password) {
1098 free(res->res_dir.password);
1100 if (res->res_dir.query_file) {
1101 free(res->res_dir.query_file);
1103 if (res->res_dir.DIRaddrs) {
1104 free_addresses(res->res_dir.DIRaddrs);
1106 if (res->res_dir.DIRsrc_addr) {
1107 free_addresses(res->res_dir.DIRsrc_addr);
1109 if (res->res_dir.tls_ctx) {
1110 free_tls_context(res->res_dir.tls_ctx);
1112 if (res->res_dir.tls_ca_certfile) {
1113 free(res->res_dir.tls_ca_certfile);
1115 if (res->res_dir.tls_ca_certdir) {
1116 free(res->res_dir.tls_ca_certdir);
1118 if (res->res_dir.tls_certfile) {
1119 free(res->res_dir.tls_certfile);
1121 if (res->res_dir.tls_keyfile) {
1122 free(res->res_dir.tls_keyfile);
1124 if (res->res_dir.tls_dhfile) {
1125 free(res->res_dir.tls_dhfile);
1127 if (res->res_dir.tls_allowed_cns) {
1128 delete res->res_dir.tls_allowed_cns;
1130 if (res->res_dir.verid) {
1131 free(res->res_dir.verid);
1138 if (res->res_con.password) {
1139 free(res->res_con.password);
1141 if (res->res_con.tls_ctx) {
1142 free_tls_context(res->res_con.tls_ctx);
1144 if (res->res_con.tls_ca_certfile) {
1145 free(res->res_con.tls_ca_certfile);
1147 if (res->res_con.tls_ca_certdir) {
1148 free(res->res_con.tls_ca_certdir);
1150 if (res->res_con.tls_certfile) {
1151 free(res->res_con.tls_certfile);
1153 if (res->res_con.tls_keyfile) {
1154 free(res->res_con.tls_keyfile);
1156 if (res->res_con.tls_dhfile) {
1157 free(res->res_con.tls_dhfile);
1159 if (res->res_con.tls_allowed_cns) {
1160 delete res->res_con.tls_allowed_cns;
1162 for (int i=0; i<Num_ACL; i++) {
1163 if (res->res_con.ACL_lists[i]) {
1164 delete res->res_con.ACL_lists[i];
1165 res->res_con.ACL_lists[i] = NULL;
1170 if (res->res_client.address) {
1171 free(res->res_client.address);
1173 if (res->res_client.password) {
1174 free(res->res_client.password);
1176 if (res->res_client.tls_ctx) {
1177 free_tls_context(res->res_client.tls_ctx);
1179 if (res->res_client.tls_ca_certfile) {
1180 free(res->res_client.tls_ca_certfile);
1182 if (res->res_client.tls_ca_certdir) {
1183 free(res->res_client.tls_ca_certdir);
1185 if (res->res_client.tls_certfile) {
1186 free(res->res_client.tls_certfile);
1188 if (res->res_client.tls_keyfile) {
1189 free(res->res_client.tls_keyfile);
1191 if (res->res_client.tls_allowed_cns) {
1192 delete res->res_client.tls_allowed_cns;
1196 if (res->res_store.address) {
1197 free(res->res_store.address);
1199 if (res->res_store.password) {
1200 free(res->res_store.password);
1202 if (res->res_store.media_type) {
1203 free(res->res_store.media_type);
1205 if (res->res_store.device) {
1206 delete res->res_store.device;
1208 if (res->res_store.tls_ctx) {
1209 free_tls_context(res->res_store.tls_ctx);
1211 if (res->res_store.tls_ca_certfile) {
1212 free(res->res_store.tls_ca_certfile);
1214 if (res->res_store.tls_ca_certdir) {
1215 free(res->res_store.tls_ca_certdir);
1217 if (res->res_store.tls_certfile) {
1218 free(res->res_store.tls_certfile);
1220 if (res->res_store.tls_keyfile) {
1221 free(res->res_store.tls_keyfile);
1225 if (res->res_cat.db_address) {
1226 free(res->res_cat.db_address);
1228 if (res->res_cat.db_socket) {
1229 free(res->res_cat.db_socket);
1231 if (res->res_cat.db_user) {
1232 free(res->res_cat.db_user);
1234 if (res->res_cat.db_name) {
1235 free(res->res_cat.db_name);
1237 if (res->res_cat.db_driver) {
1238 free(res->res_cat.db_driver);
1240 if (res->res_cat.db_password) {
1241 free(res->res_cat.db_password);
1245 if ((num=res->res_fs.num_includes)) {
1246 while (--num >= 0) {
1247 free_incexe(res->res_fs.include_items[num]);
1249 free(res->res_fs.include_items);
1251 res->res_fs.num_includes = 0;
1252 if ((num=res->res_fs.num_excludes)) {
1253 while (--num >= 0) {
1254 free_incexe(res->res_fs.exclude_items[num]);
1256 free(res->res_fs.exclude_items);
1258 res->res_fs.num_excludes = 0;
1261 if (res->res_pool.pool_type) {
1262 free(res->res_pool.pool_type);
1264 if (res->res_pool.label_format) {
1265 free(res->res_pool.label_format);
1267 if (res->res_pool.cleaning_prefix) {
1268 free(res->res_pool.cleaning_prefix);
1270 if (res->res_pool.storage) {
1271 delete res->res_pool.storage;
1275 if (res->res_sch.run) {
1277 nrun = res->res_sch.run;
1287 if (res->res_job.RestoreWhere) {
1288 free(res->res_job.RestoreWhere);
1290 if (res->res_job.RegexWhere) {
1291 free(res->res_job.RegexWhere);
1293 if (res->res_job.strip_prefix) {
1294 free(res->res_job.strip_prefix);
1296 if (res->res_job.add_prefix) {
1297 free(res->res_job.add_prefix);
1299 if (res->res_job.add_suffix) {
1300 free(res->res_job.add_suffix);
1302 if (res->res_job.RestoreBootstrap) {
1303 free(res->res_job.RestoreBootstrap);
1305 if (res->res_job.WriteBootstrap) {
1306 free(res->res_job.WriteBootstrap);
1308 if (res->res_job.PluginOptions) {
1309 free(res->res_job.PluginOptions);
1311 if (res->res_job.selection_pattern) {
1312 free(res->res_job.selection_pattern);
1314 if (res->res_job.run_cmds) {
1315 delete res->res_job.run_cmds;
1317 if (res->res_job.storage) {
1318 delete res->res_job.storage;
1320 if (res->res_job.base) {
1321 delete res->res_job.base;
1323 if (res->res_job.RunScripts) {
1324 free_runscripts(res->res_job.RunScripts);
1325 delete res->res_job.RunScripts;
1329 if (res->res_msgs.mail_cmd) {
1330 free(res->res_msgs.mail_cmd);
1332 if (res->res_msgs.operator_cmd) {
1333 free(res->res_msgs.operator_cmd);
1335 free_msgs_res((MSGS *)res); /* free message resource */
1339 printf(_("Unknown resource type %d in free_resource.\n"), type);
1341 /* Common stuff again -- free the resource, recurse to next one */
1346 free_resource(nres, type);
1351 * Save the new resource by chaining it into the head list for
1352 * the resource. If this is pass 2, we update any resource
1353 * pointers because they may not have been defined until
1356 void save_resource(int type, RES_ITEM *items, int pass)
1359 int rindex = type - r_first;
1363 /* Check Job requirements after applying JobDefs */
1364 if (type != R_JOB && type != R_JOBDEFS) {
1366 * Ensure that all required items are present
1368 for (i=0; items[i].name; i++) {
1369 if (items[i].flags & ITEM_REQUIRED) {
1370 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1371 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1372 items[i].name, resources[rindex]);
1375 /* If this triggers, take a look at lib/parse_conf.h */
1376 if (i >= MAX_RES_ITEMS) {
1377 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1380 } else if (type == R_JOB) {
1382 * Ensure that the name item is present
1384 if (items[0].flags & ITEM_REQUIRED) {
1385 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1386 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1387 items[0].name, resources[rindex]);
1393 * During pass 2 in each "store" routine, we looked up pointers
1394 * to all the resources referrenced in the current resource, now we
1395 * must copy their addresses from the static record to the allocated
1400 /* Resources not containing a resource */
1408 * Resources containing another resource or alist. First
1409 * look up the resource which contains another resource. It
1410 * was written during pass 1. Then stuff in the pointers to
1411 * the resources it contains, which were inserted this pass.
1412 * Finally, it will all be stored back.
1415 /* Find resource saved in pass 1 */
1416 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1417 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1419 /* Explicitly copy resource pointers from this pass (res_all) */
1420 res->res_pool.NextPool = res_all.res_pool.NextPool;
1421 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1422 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1423 res->res_pool.storage = res_all.res_pool.storage;
1424 res->res_pool.catalog = res_all.res_pool.catalog;
1427 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1428 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1430 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1433 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1434 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1436 res->res_dir.messages = res_all.res_dir.messages;
1437 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1440 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1441 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1442 res_all.res_dir.hdr.name);
1444 /* we must explicitly copy the device alist pointer */
1445 res->res_store.device = res_all.res_store.device;
1449 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1450 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1451 res_all.res_dir.hdr.name);
1453 res->res_job.messages = res_all.res_job.messages;
1454 res->res_job.schedule = res_all.res_job.schedule;
1455 res->res_job.client = res_all.res_job.client;
1456 res->res_job.fileset = res_all.res_job.fileset;
1457 res->res_job.storage = res_all.res_job.storage;
1458 res->res_job.base = res_all.res_job.base;
1459 res->res_job.pool = res_all.res_job.pool;
1460 res->res_job.full_pool = res_all.res_job.full_pool;
1461 res->res_job.inc_pool = res_all.res_job.inc_pool;
1462 res->res_job.diff_pool = res_all.res_job.diff_pool;
1463 res->res_job.verify_job = res_all.res_job.verify_job;
1464 res->res_job.jobdefs = res_all.res_job.jobdefs;
1465 res->res_job.run_cmds = res_all.res_job.run_cmds;
1466 res->res_job.RunScripts = res_all.res_job.RunScripts;
1468 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1469 * is not very useful)
1470 * We have to set_bit(index, res_all.hdr.item_present);
1471 * or something like that
1474 /* we take RegexWhere before all other options */
1475 if (!res->res_job.RegexWhere
1477 (res->res_job.strip_prefix ||
1478 res->res_job.add_suffix ||
1479 res->res_job.add_prefix))
1481 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1482 res->res_job.add_prefix,
1483 res->res_job.add_suffix);
1484 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1485 bregexp_build_where(res->res_job.RegexWhere, len,
1486 res->res_job.strip_prefix,
1487 res->res_job.add_prefix,
1488 res->res_job.add_suffix);
1489 /* TODO: test bregexp */
1492 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1493 free(res->res_job.RestoreWhere);
1494 res->res_job.RestoreWhere = NULL;
1499 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1500 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1502 res->res_counter.Catalog = res_all.res_counter.Catalog;
1503 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1507 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1508 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1510 res->res_client.catalog = res_all.res_client.catalog;
1511 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1515 * Schedule is a bit different in that it contains a RUN record
1516 * chain which isn't a "named" resource. This chain was linked
1517 * in by run_conf.c during pass 2, so here we jam the pointer
1518 * into the Schedule resource.
1520 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1521 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1523 res->res_sch.run = res_all.res_sch.run;
1526 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1530 /* Note, the resource name was already saved during pass 1,
1531 * so here, we can just release it.
1533 if (res_all.res_dir.hdr.name) {
1534 free(res_all.res_dir.hdr.name);
1535 res_all.res_dir.hdr.name = NULL;
1537 if (res_all.res_dir.hdr.desc) {
1538 free(res_all.res_dir.hdr.desc);
1539 res_all.res_dir.hdr.desc = NULL;
1545 * The following code is only executed during pass 1
1549 size = sizeof(DIRRES);
1552 size = sizeof(CONRES);
1555 size =sizeof(CLIENT);
1558 size = sizeof(STORE);
1568 size = sizeof(FILESET);
1571 size = sizeof(SCHED);
1574 size = sizeof(POOL);
1577 size = sizeof(MSGS);
1580 size = sizeof(COUNTER);
1586 printf(_("Unknown resource type %d in save_resource.\n"), type);
1592 res = (URES *)malloc(size);
1593 memcpy(res, &res_all, size);
1594 if (!res_head[rindex]) {
1595 res_head[rindex] = (RES *)res; /* store first entry */
1596 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1597 res->res_dir.hdr.name, rindex);
1600 if (res->res_dir.hdr.name == NULL) {
1601 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1604 /* Add new res to end of chain */
1605 for (last=next=res_head[rindex]; next; next=next->next) {
1607 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1608 Emsg2(M_ERROR_TERM, 0,
1609 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1610 resources[rindex].name, res->res_dir.hdr.name);
1613 last->next = (RES *)res;
1614 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1615 res->res_dir.hdr.name, rindex, pass);
1620 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1622 uint32_t *destination = (uint32_t*)item->value;
1623 lex_get_token(lc, T_NAME);
1624 if (strcasecmp(lc->str, "truncate") == 0) {
1625 *destination = (*destination) | ON_PURGE_TRUNCATE;
1627 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1631 set_bit(index, res_all.hdr.item_present);
1635 * Store Device. Note, the resource is created upon the
1636 * first reference. The details of the resource are obtained
1637 * later from the SD.
1639 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1643 int rindex = R_DEVICE - r_first;
1644 int size = sizeof(DEVICE);
1648 token = lex_get_token(lc, T_NAME);
1649 if (!res_head[rindex]) {
1650 res = (URES *)malloc(size);
1651 memset(res, 0, size);
1652 res->res_dev.hdr.name = bstrdup(lc->str);
1653 res_head[rindex] = (RES *)res; /* store first entry */
1654 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1655 res->res_dir.hdr.name, rindex);
1658 /* See if it is already defined */
1659 for (next=res_head[rindex]; next->next; next=next->next) {
1660 if (strcmp(next->name, lc->str) == 0) {
1666 res = (URES *)malloc(size);
1667 memset(res, 0, size);
1668 res->res_dev.hdr.name = bstrdup(lc->str);
1669 next->next = (RES *)res;
1670 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1671 res->res_dir.hdr.name, rindex, pass);
1676 set_bit(index, res_all.hdr.item_present);
1678 store_alist_res(lc, item, index, pass);
1683 * Store Migration/Copy type
1686 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1690 token = lex_get_token(lc, T_NAME);
1691 /* Store the type both pass 1 and pass 2 */
1692 for (i=0; migtypes[i].type_name; i++) {
1693 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1694 *(uint32_t *)(item->value) = migtypes[i].job_type;
1700 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1703 set_bit(index, res_all.hdr.item_present);
1709 * Store JobType (backup, verify, restore)
1712 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1716 token = lex_get_token(lc, T_NAME);
1717 /* Store the type both pass 1 and pass 2 */
1718 for (i=0; jobtypes[i].type_name; i++) {
1719 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1720 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1726 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1729 set_bit(index, res_all.hdr.item_present);
1733 * Store Job Level (Full, Incremental, ...)
1736 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1740 token = lex_get_token(lc, T_NAME);
1741 /* Store the level pass 2 so that type is defined */
1742 for (i=0; joblevels[i].level_name; i++) {
1743 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1744 *(uint32_t *)(item->value) = joblevels[i].level;
1750 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1753 set_bit(index, res_all.hdr.item_present);
1757 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1760 token = lex_get_token(lc, T_NAME);
1761 /* Scan Replacement options */
1762 for (i=0; ReplaceOptions[i].name; i++) {
1763 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1764 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1770 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1773 set_bit(index, res_all.hdr.item_present);
1777 * Store ACL (access control list)
1780 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1785 token = lex_get_token(lc, T_STRING);
1787 if (((alist **)item->value)[item->code] == NULL) {
1788 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1789 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1791 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1792 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1794 token = lex_get_token(lc, T_ALL);
1795 if (token == T_COMMA) {
1796 continue; /* get another ACL */
1800 set_bit(index, res_all.hdr.item_present);
1803 /* We build RunScripts items here */
1804 static RUNSCRIPT res_runscript;
1806 /* Store a runscript->when in a bit field */
1807 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1809 lex_get_token(lc, T_NAME);
1811 if (strcasecmp(lc->str, "before") == 0) {
1812 *(uint32_t *)(item->value) = SCRIPT_Before ;
1813 } else if (strcasecmp(lc->str, "after") == 0) {
1814 *(uint32_t *)(item->value) = SCRIPT_After;
1815 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1816 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1817 } else if (strcasecmp(lc->str, "always") == 0) {
1818 *(uint32_t *)(item->value) = SCRIPT_Any;
1820 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1825 /* Store a runscript->target
1828 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1830 lex_get_token(lc, T_STRING);
1833 if (strcmp(lc->str, "%c") == 0) {
1834 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1835 } else if (strcasecmp(lc->str, "yes") == 0) {
1836 ((RUNSCRIPT*) item->value)->set_target("%c");
1837 } else if (strcasecmp(lc->str, "no") == 0) {
1838 ((RUNSCRIPT*) item->value)->set_target("");
1840 RES *res = GetResWithName(R_CLIENT, lc->str);
1842 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1843 lc->str, lc->line_no, lc->line);
1846 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1853 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1855 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1857 lex_get_token(lc, T_STRING);
1860 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1861 POOLMEM *c = get_pool_memory(PM_FNAME);
1862 /* Each runscript command takes 2 entries in commands list */
1863 pm_strcpy(c, lc->str);
1864 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1865 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1870 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1872 lex_get_token(lc, T_STRING);
1873 alist **runscripts = (alist **)(item->value) ;
1876 RUNSCRIPT *script = new_runscript();
1877 script->set_job_code_callback(job_code_callback_filesetname);
1879 script->set_command(lc->str);
1881 /* TODO: remove all script->old_proto with bacula 1.42 */
1883 if (strcmp(item->name, "runbeforejob") == 0) {
1884 script->when = SCRIPT_Before;
1885 script->fail_on_error = true;
1886 script->set_target("");
1888 } else if (strcmp(item->name, "runafterjob") == 0) {
1889 script->when = SCRIPT_After;
1890 script->on_success = true;
1891 script->on_failure = false;
1892 script->set_target("");
1894 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1895 script->old_proto = true;
1896 script->when = SCRIPT_After;
1897 script->set_target("%c");
1898 script->on_success = true;
1899 script->on_failure = false;
1901 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1902 script->old_proto = true;
1903 script->when = SCRIPT_Before;
1904 script->set_target("%c");
1905 script->fail_on_error = true;
1907 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1908 script->when = SCRIPT_After;
1909 script->on_failure = true;
1910 script->on_success = false;
1911 script->set_target("");
1914 if (*runscripts == NULL) {
1915 *runscripts = New(alist(10, not_owned_by_alist));
1918 (*runscripts)->append(script);
1925 /* Store a bool in a bit field without modifing res_all.hdr
1926 * We can also add an option to store_bool to skip res_all.hdr
1928 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1930 lex_get_token(lc, T_NAME);
1931 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1932 *(bool *)(item->value) = true;
1933 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1934 *(bool *)(item->value) = false;
1936 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1942 * new RunScript items
1943 * name handler value code flags default_value
1945 static RES_ITEM runscript_items[] = {
1946 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1947 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1948 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1949 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1950 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1951 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1952 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1953 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1954 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1955 {NULL, NULL, {0}, 0, 0, 0}
1959 * Store RunScript info
1961 * Note, when this routine is called, we are inside a Job
1962 * resource. We treat the RunScript like a sort of
1963 * mini-resource within the Job resource.
1965 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1969 alist **runscripts = (alist **)(item->value) ;
1971 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1973 token = lex_get_token(lc, T_SKIP_EOL);
1975 if (token != T_BOB) {
1976 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1978 /* setting on_success, on_failure, fail_on_error */
1979 res_runscript.reset_default();
1982 res_runscript.commands = New(alist(10, not_owned_by_alist));
1985 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1986 if (token == T_EOB) {
1989 if (token != T_IDENTIFIER) {
1990 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1992 for (i=0; runscript_items[i].name; i++) {
1993 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1994 token = lex_get_token(lc, T_SKIP_EOL);
1995 if (token != T_EQUALS) {
1996 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1999 /* Call item handler */
2000 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2007 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2012 /* run on client by default */
2013 if (res_runscript.target == NULL) {
2014 res_runscript.set_target("%c");
2016 if (*runscripts == NULL) {
2017 *runscripts = New(alist(10, not_owned_by_alist));
2020 * commands list contains 2 values per command
2021 * - POOLMEM command string (ex: /bin/true)
2022 * - int command type (ex: SHELL_CMD)
2024 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2025 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2026 t = (intptr_t)res_runscript.commands->pop();
2027 RUNSCRIPT *script = new_runscript();
2028 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2029 script->command = c;
2030 script->cmd_type = t;
2031 /* target is taken from res_runscript, each runscript object have
2034 script->target = NULL;
2035 script->set_target(res_runscript.target);
2037 (*runscripts)->append(script);
2040 delete res_runscript.commands;
2041 /* setting on_success, on_failure... cleanup target field */
2042 res_runscript.reset_default(true);
2046 set_bit(index, res_all.hdr.item_present);
2049 /* callback function for edit_job_codes */
2050 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2052 if (param[0] == 'f') {
2053 return jcr->fileset->name();
2059 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2061 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2062 r_first, r_last, resources, res_head);
2063 return config->parse_config();