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 two of the GNU 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 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 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
315 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
316 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
317 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
318 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
319 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
320 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
321 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
322 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
326 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
327 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
328 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 0},
329 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
330 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
331 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
332 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
333 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
334 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
335 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
336 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
337 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
338 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
339 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
340 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
341 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
342 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
343 {NULL, NULL, {0}, 0, 0, 0}
348 * name handler value code flags default_value
350 static RES_ITEM fs_items[] = {
351 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
352 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
353 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
354 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
355 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
356 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
357 {NULL, NULL, {0}, 0, 0, 0}
360 /* Schedule -- see run_conf.c */
363 * name handler value code flags default_value
365 static RES_ITEM sch_items[] = {
366 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
367 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
368 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
369 {NULL, NULL, {0}, 0, 0, 0}
374 * name handler value code flags default_value
376 static RES_ITEM pool_items[] = {
377 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
378 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
379 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
380 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
381 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
382 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
383 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
384 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
385 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
386 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
387 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
388 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
389 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
390 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
391 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
392 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
393 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
394 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
395 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
396 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
397 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
398 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
399 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
400 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
401 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
402 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
403 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
404 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
405 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
406 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
407 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
408 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
410 {NULL, NULL, {0}, 0, 0, 0}
415 * name handler value code flags default_value
417 static RES_ITEM counter_items[] = {
418 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
419 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
420 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
421 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
422 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
423 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
424 {NULL, NULL, {0}, 0, 0, 0}
428 /* Message resource */
429 extern RES_ITEM msgs_items[];
432 * This is the master resource definition.
433 * It must have one item for each of the resources.
435 * NOTE!!! keep it in the same order as the R_codes
436 * or eliminate all resources[rindex].name
438 * name items rcode res_head
440 RES_TABLE resources[] = {
441 {"director", dir_items, R_DIRECTOR},
442 {"client", cli_items, R_CLIENT},
443 {"job", job_items, R_JOB},
444 {"storage", store_items, R_STORAGE},
445 {"catalog", cat_items, R_CATALOG},
446 {"schedule", sch_items, R_SCHEDULE},
447 {"fileset", fs_items, R_FILESET},
448 {"pool", pool_items, R_POOL},
449 {"messages", msgs_items, R_MSGS},
450 {"counter", counter_items, R_COUNTER},
451 {"console", con_items, R_CONSOLE},
452 {"jobdefs", job_items, R_JOBDEFS},
453 {"device", NULL, R_DEVICE}, /* info obtained from SD */
458 /* Keywords (RHS) permitted in Job Level records
460 * level_name level job_type
462 struct s_jl joblevels[] = {
463 {"Full", L_FULL, JT_BACKUP},
464 {"Base", L_BASE, JT_BACKUP},
465 {"Incremental", L_INCREMENTAL, JT_BACKUP},
466 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
467 {"Since", L_SINCE, JT_BACKUP},
468 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
469 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
470 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
471 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
472 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
473 {"Data", L_VERIFY_DATA, JT_VERIFY},
474 {" ", L_NONE, JT_ADMIN},
475 {" ", L_NONE, JT_RESTORE},
479 /* Keywords (RHS) permitted in Job type records
483 struct s_jt jobtypes[] = {
484 {"backup", JT_BACKUP},
486 {"verify", JT_VERIFY},
487 {"restore", JT_RESTORE},
488 {"migrate", JT_MIGRATE},
494 /* Keywords (RHS) permitted in Selection type records
498 struct s_jt migtypes[] = {
499 {"smallestvolume", MT_SMALLEST_VOL},
500 {"oldestvolume", MT_OLDEST_VOL},
501 {"pooloccupancy", MT_POOL_OCCUPANCY},
502 {"pooltime", MT_POOL_TIME},
503 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
504 {"client", MT_CLIENT},
505 {"volume", MT_VOLUME},
507 {"sqlquery", MT_SQLQUERY},
513 /* Options permitted in Restore replace= */
514 struct s_kw ReplaceOptions[] = {
515 {"always", REPLACE_ALWAYS},
516 {"ifnewer", REPLACE_IFNEWER},
517 {"ifolder", REPLACE_IFOLDER},
518 {"never", REPLACE_NEVER},
522 char *CAT::display(POOLMEM *dst) {
523 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
524 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
526 name(), NPRTB(db_name),
527 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
528 NPRTB(db_address), db_port, NPRTB(db_socket));
532 const char *level_to_str(int level)
535 static char level_no[30];
536 const char *str = level_no;
538 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
539 for (i=0; joblevels[i].level_name; i++) {
540 if (level == (int)joblevels[i].level) {
541 str = joblevels[i].level_name;
548 /* Dump contents of resource */
549 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
551 URES *res = (URES *)reshdr;
553 char ed1[100], ed2[100], ed3[100];
557 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
560 if (type < 0) { /* no recursion */
566 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
567 reshdr->name, res->res_dir.MaxConcurrentJobs,
568 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
569 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
570 if (res->res_dir.query_file) {
571 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
573 if (res->res_dir.messages) {
574 sendit(sock, _(" --> "));
575 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
579 sendit(sock, _("Console: name=%s SSL=%d\n"),
580 res->res_con.hdr.name, res->res_con.tls_enable);
583 if (res->res_counter.WrapCounter) {
584 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
585 res->res_counter.hdr.name, res->res_counter.MinValue,
586 res->res_counter.MaxValue, res->res_counter.CurrentValue,
587 res->res_counter.WrapCounter->hdr.name);
589 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
590 res->res_counter.hdr.name, res->res_counter.MinValue,
591 res->res_counter.MaxValue);
593 if (res->res_counter.Catalog) {
594 sendit(sock, _(" --> "));
595 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
600 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
601 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
602 res->res_client.MaxConcurrentJobs);
603 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
604 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
605 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
606 res->res_client.AutoPrune);
607 if (res->res_client.catalog) {
608 sendit(sock, _(" --> "));
609 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
616 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
617 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
618 " poolid=%s volname=%s MediaType=%s\n"),
619 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
620 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
621 dev->offline, dev->autochanger,
622 edit_uint64(dev->PoolId, ed1),
623 dev->VolumeName, dev->MediaType);
627 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
628 " DeviceName=%s MediaType=%s StorageId=%s\n"),
629 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
630 res->res_store.MaxConcurrentJobs,
631 res->res_store.dev_name(),
632 res->res_store.media_type,
633 edit_int64(res->res_store.StorageId, ed1));
637 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
638 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
639 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
640 res->res_cat.db_port, res->res_cat.db_name,
641 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
642 res->res_cat.mult_db_connections);
647 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
648 type == R_JOB ? _("Job") : _("JobDefs"),
649 res->res_job.hdr.name, res->res_job.JobType,
650 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
651 res->res_job.enabled);
652 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
653 res->res_job.MaxConcurrentJobs,
654 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
655 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
656 res->res_job.spool_data, res->res_job.write_part_after_job);
657 if (res->res_job.spool_size) {
658 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
660 if (res->res_job.JobType == JT_BACKUP) {
661 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
663 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
664 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
666 if (res->res_job.client) {
667 sendit(sock, _(" --> "));
668 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
670 if (res->res_job.fileset) {
671 sendit(sock, _(" --> "));
672 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
674 if (res->res_job.schedule) {
675 sendit(sock, _(" --> "));
676 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
678 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
679 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
681 if (res->res_job.RegexWhere) {
682 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
684 if (res->res_job.RestoreBootstrap) {
685 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
687 if (res->res_job.WriteBootstrap) {
688 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
690 if (res->res_job.PluginOptions) {
691 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
693 if (res->res_job.MaxRunTime) {
694 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
696 if (res->res_job.MaxWaitTime) {
697 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
699 if (res->res_job.MaxStartDelay) {
700 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
702 if (res->res_job.storage) {
704 foreach_alist(store, res->res_job.storage) {
705 sendit(sock, _(" --> "));
706 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
709 if (res->res_job.base) {
711 foreach_alist(job, res->res_job.base) {
712 sendit(sock, _(" --> Base %s\n"), job->name());
715 if (res->res_job.RunScripts) {
717 foreach_alist(script, res->res_job.RunScripts) {
718 sendit(sock, _(" --> RunScript\n"));
719 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
720 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
721 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
722 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
723 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
724 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
727 if (res->res_job.pool) {
728 sendit(sock, _(" --> "));
729 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
731 if (res->res_job.full_pool) {
732 sendit(sock, _(" --> "));
733 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
735 if (res->res_job.inc_pool) {
736 sendit(sock, _(" --> "));
737 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
739 if (res->res_job.diff_pool) {
740 sendit(sock, _(" --> "));
741 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
743 if (res->res_job.verify_job) {
744 sendit(sock, _(" --> "));
745 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
747 if (res->res_job.run_cmds) {
749 foreach_alist(runcmd, res->res_job.run_cmds) {
750 sendit(sock, _(" --> Run=%s\n"), runcmd);
753 if (res->res_job.selection_pattern) {
754 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
756 if (res->res_job.messages) {
757 sendit(sock, _(" --> "));
758 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
765 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
766 for (i=0; i<res->res_fs.num_includes; i++) {
767 INCEXE *incexe = res->res_fs.include_items[i];
768 for (j=0; j<incexe->num_opts; j++) {
769 FOPTS *fo = incexe->opts_list[j];
770 sendit(sock, " O %s\n", fo->opts);
772 bool enhanced_wild = false;
773 for (k=0; fo->opts[k]!='\0'; k++) {
774 if (fo->opts[k]=='W') {
775 enhanced_wild = true;
780 for (k=0; k<fo->regex.size(); k++) {
781 sendit(sock, " R %s\n", fo->regex.get(k));
783 for (k=0; k<fo->regexdir.size(); k++) {
784 sendit(sock, " RD %s\n", fo->regexdir.get(k));
786 for (k=0; k<fo->regexfile.size(); k++) {
787 sendit(sock, " RF %s\n", fo->regexfile.get(k));
789 for (k=0; k<fo->wild.size(); k++) {
790 sendit(sock, " W %s\n", fo->wild.get(k));
792 for (k=0; k<fo->wilddir.size(); k++) {
793 sendit(sock, " WD %s\n", fo->wilddir.get(k));
795 for (k=0; k<fo->wildfile.size(); k++) {
796 sendit(sock, " WF %s\n", fo->wildfile.get(k));
798 for (k=0; k<fo->wildbase.size(); k++) {
799 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
801 for (k=0; k<fo->base.size(); k++) {
802 sendit(sock, " B %s\n", fo->base.get(k));
804 for (k=0; k<fo->fstype.size(); k++) {
805 sendit(sock, " X %s\n", fo->fstype.get(k));
807 for (k=0; k<fo->drivetype.size(); k++) {
808 sendit(sock, " XD %s\n", fo->drivetype.get(k));
811 sendit(sock, " G %s\n", fo->plugin);
814 sendit(sock, " D %s\n", fo->reader);
817 sendit(sock, " T %s\n", fo->writer);
819 sendit(sock, " N\n");
821 if (incexe->ignoredir) {
822 sendit(sock, " Z %s\n", incexe->ignoredir);
824 for (j=0; j<incexe->name_list.size(); j++) {
825 sendit(sock, " I %s\n", incexe->name_list.get(j));
827 if (incexe->name_list.size()) {
828 sendit(sock, " N\n");
830 for (j=0; j<incexe->plugin_list.size(); j++) {
831 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
833 if (incexe->plugin_list.size()) {
834 sendit(sock, " N\n");
839 for (i=0; i<res->res_fs.num_excludes; i++) {
840 INCEXE *incexe = res->res_fs.exclude_items[i];
841 for (j=0; j<incexe->name_list.size(); j++) {
842 sendit(sock, " E %s\n", incexe->name_list.get(j));
844 if (incexe->name_list.size()) {
845 sendit(sock, " N\n");
852 if (res->res_sch.run) {
854 RUN *run = res->res_sch.run;
855 char buf[1000], num[30];
856 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
861 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
862 bstrncpy(buf, _(" hour="), sizeof(buf));
863 for (i=0; i<24; i++) {
864 if (bit_is_set(i, run->hour)) {
865 bsnprintf(num, sizeof(num), "%d ", i);
866 bstrncat(buf, num, sizeof(buf));
869 bstrncat(buf, "\n", sizeof(buf));
871 bstrncpy(buf, _(" mday="), sizeof(buf));
872 for (i=0; i<31; i++) {
873 if (bit_is_set(i, run->mday)) {
874 bsnprintf(num, sizeof(num), "%d ", i);
875 bstrncat(buf, num, sizeof(buf));
878 bstrncat(buf, "\n", sizeof(buf));
880 bstrncpy(buf, _(" month="), sizeof(buf));
881 for (i=0; i<12; i++) {
882 if (bit_is_set(i, run->month)) {
883 bsnprintf(num, sizeof(num), "%d ", i);
884 bstrncat(buf, num, sizeof(buf));
887 bstrncat(buf, "\n", sizeof(buf));
889 bstrncpy(buf, _(" wday="), sizeof(buf));
890 for (i=0; i<7; i++) {
891 if (bit_is_set(i, run->wday)) {
892 bsnprintf(num, sizeof(num), "%d ", i);
893 bstrncat(buf, num, sizeof(buf));
896 bstrncat(buf, "\n", sizeof(buf));
898 bstrncpy(buf, _(" wom="), sizeof(buf));
899 for (i=0; i<5; i++) {
900 if (bit_is_set(i, run->wom)) {
901 bsnprintf(num, sizeof(num), "%d ", i);
902 bstrncat(buf, num, sizeof(buf));
905 bstrncat(buf, "\n", sizeof(buf));
907 bstrncpy(buf, _(" woy="), sizeof(buf));
908 for (i=0; i<54; i++) {
909 if (bit_is_set(i, run->woy)) {
910 bsnprintf(num, sizeof(num), "%d ", i);
911 bstrncat(buf, num, sizeof(buf));
914 bstrncat(buf, "\n", sizeof(buf));
916 sendit(sock, _(" mins=%d\n"), run->minute);
918 sendit(sock, _(" --> "));
919 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
922 sendit(sock, _(" --> "));
923 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
926 sendit(sock, _(" --> "));
927 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
929 /* If another Run record is chained in, go print it */
935 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
940 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
941 res->res_pool.pool_type);
942 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
943 res->res_pool.use_catalog, res->res_pool.use_volume_once,
944 res->res_pool.catalog_files);
945 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
946 res->res_pool.max_volumes, res->res_pool.AutoPrune,
947 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
948 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
949 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
950 res->res_pool.Recycle,
951 NPRT(res->res_pool.label_format));
952 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
953 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
954 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
955 res->res_pool.recycle_oldest_volume,
956 res->res_pool.purge_oldest_volume,
957 res->res_pool.action_on_purge);
958 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
959 res->res_pool.MaxVolJobs,
960 res->res_pool.MaxVolFiles,
961 edit_uint64(res->res_pool.MaxVolBytes, ed1));
962 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
963 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
964 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
965 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
966 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
967 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
968 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)));
969 if (res->res_pool.NextPool) {
970 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
972 if (res->res_pool.RecyclePool) {
973 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
975 if (res->res_pool.ScratchPool) {
976 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
978 if (res->res_pool.catalog) {
979 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
981 if (res->res_pool.storage) {
983 foreach_alist(store, res->res_pool.storage) {
984 sendit(sock, _(" --> "));
985 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
988 if (res->res_pool.CopyPool) {
990 foreach_alist(copy, res->res_pool.CopyPool) {
991 sendit(sock, _(" --> "));
992 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
999 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1000 if (res->res_msgs.mail_cmd)
1001 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1002 if (res->res_msgs.operator_cmd)
1003 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1007 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1010 if (recurse && res->res_dir.hdr.next) {
1011 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1016 * Free all the members of an INCEXE structure
1018 static void free_incexe(INCEXE *incexe)
1020 incexe->name_list.destroy();
1021 incexe->plugin_list.destroy();
1022 for (int i=0; i<incexe->num_opts; i++) {
1023 FOPTS *fopt = incexe->opts_list[i];
1024 fopt->regex.destroy();
1025 fopt->regexdir.destroy();
1026 fopt->regexfile.destroy();
1027 fopt->wild.destroy();
1028 fopt->wilddir.destroy();
1029 fopt->wildfile.destroy();
1030 fopt->wildbase.destroy();
1031 fopt->base.destroy();
1032 fopt->fstype.destroy();
1033 fopt->drivetype.destroy();
1045 if (incexe->opts_list) {
1046 free(incexe->opts_list);
1048 if (incexe->ignoredir) {
1049 free(incexe->ignoredir);
1055 * Free memory of resource -- called when daemon terminates.
1056 * NB, we don't need to worry about freeing any references
1057 * to other resources as they will be freed when that
1058 * resource chain is traversed. Mainly we worry about freeing
1059 * allocated strings (names).
1061 void free_resource(RES *sres, int type)
1064 RES *nres; /* next resource if linked */
1065 URES *res = (URES *)sres;
1070 /* common stuff -- free the resource name and description */
1071 nres = (RES *)res->res_dir.hdr.next;
1072 if (res->res_dir.hdr.name) {
1073 free(res->res_dir.hdr.name);
1075 if (res->res_dir.hdr.desc) {
1076 free(res->res_dir.hdr.desc);
1081 if (res->res_dir.working_directory) {
1082 free(res->res_dir.working_directory);
1084 if (res->res_dir.scripts_directory) {
1085 free((char *)res->res_dir.scripts_directory);
1087 if (res->res_dir.plugin_directory) {
1088 free((char *)res->res_dir.plugin_directory);
1090 if (res->res_dir.pid_directory) {
1091 free(res->res_dir.pid_directory);
1093 if (res->res_dir.subsys_directory) {
1094 free(res->res_dir.subsys_directory);
1096 if (res->res_dir.password) {
1097 free(res->res_dir.password);
1099 if (res->res_dir.query_file) {
1100 free(res->res_dir.query_file);
1102 if (res->res_dir.DIRaddrs) {
1103 free_addresses(res->res_dir.DIRaddrs);
1105 if (res->res_dir.DIRsrc_addr) {
1106 free_addresses(res->res_dir.DIRsrc_addr);
1108 if (res->res_dir.tls_ctx) {
1109 free_tls_context(res->res_dir.tls_ctx);
1111 if (res->res_dir.tls_ca_certfile) {
1112 free(res->res_dir.tls_ca_certfile);
1114 if (res->res_dir.tls_ca_certdir) {
1115 free(res->res_dir.tls_ca_certdir);
1117 if (res->res_dir.tls_certfile) {
1118 free(res->res_dir.tls_certfile);
1120 if (res->res_dir.tls_keyfile) {
1121 free(res->res_dir.tls_keyfile);
1123 if (res->res_dir.tls_dhfile) {
1124 free(res->res_dir.tls_dhfile);
1126 if (res->res_dir.tls_allowed_cns) {
1127 delete res->res_dir.tls_allowed_cns;
1129 if (res->res_dir.verid) {
1130 free(res->res_dir.verid);
1137 if (res->res_con.password) {
1138 free(res->res_con.password);
1140 if (res->res_con.tls_ctx) {
1141 free_tls_context(res->res_con.tls_ctx);
1143 if (res->res_con.tls_ca_certfile) {
1144 free(res->res_con.tls_ca_certfile);
1146 if (res->res_con.tls_ca_certdir) {
1147 free(res->res_con.tls_ca_certdir);
1149 if (res->res_con.tls_certfile) {
1150 free(res->res_con.tls_certfile);
1152 if (res->res_con.tls_keyfile) {
1153 free(res->res_con.tls_keyfile);
1155 if (res->res_con.tls_dhfile) {
1156 free(res->res_con.tls_dhfile);
1158 if (res->res_con.tls_allowed_cns) {
1159 delete res->res_con.tls_allowed_cns;
1161 for (int i=0; i<Num_ACL; i++) {
1162 if (res->res_con.ACL_lists[i]) {
1163 delete res->res_con.ACL_lists[i];
1164 res->res_con.ACL_lists[i] = NULL;
1169 if (res->res_client.address) {
1170 free(res->res_client.address);
1172 if (res->res_client.password) {
1173 free(res->res_client.password);
1175 if (res->res_client.tls_ctx) {
1176 free_tls_context(res->res_client.tls_ctx);
1178 if (res->res_client.tls_ca_certfile) {
1179 free(res->res_client.tls_ca_certfile);
1181 if (res->res_client.tls_ca_certdir) {
1182 free(res->res_client.tls_ca_certdir);
1184 if (res->res_client.tls_certfile) {
1185 free(res->res_client.tls_certfile);
1187 if (res->res_client.tls_keyfile) {
1188 free(res->res_client.tls_keyfile);
1190 if (res->res_client.tls_allowed_cns) {
1191 delete res->res_client.tls_allowed_cns;
1195 if (res->res_store.address) {
1196 free(res->res_store.address);
1198 if (res->res_store.password) {
1199 free(res->res_store.password);
1201 if (res->res_store.media_type) {
1202 free(res->res_store.media_type);
1204 if (res->res_store.device) {
1205 delete res->res_store.device;
1207 if (res->res_store.tls_ctx) {
1208 free_tls_context(res->res_store.tls_ctx);
1210 if (res->res_store.tls_ca_certfile) {
1211 free(res->res_store.tls_ca_certfile);
1213 if (res->res_store.tls_ca_certdir) {
1214 free(res->res_store.tls_ca_certdir);
1216 if (res->res_store.tls_certfile) {
1217 free(res->res_store.tls_certfile);
1219 if (res->res_store.tls_keyfile) {
1220 free(res->res_store.tls_keyfile);
1224 if (res->res_cat.db_address) {
1225 free(res->res_cat.db_address);
1227 if (res->res_cat.db_socket) {
1228 free(res->res_cat.db_socket);
1230 if (res->res_cat.db_user) {
1231 free(res->res_cat.db_user);
1233 if (res->res_cat.db_name) {
1234 free(res->res_cat.db_name);
1236 if (res->res_cat.db_driver) {
1237 free(res->res_cat.db_driver);
1239 if (res->res_cat.db_password) {
1240 free(res->res_cat.db_password);
1244 if ((num=res->res_fs.num_includes)) {
1245 while (--num >= 0) {
1246 free_incexe(res->res_fs.include_items[num]);
1248 free(res->res_fs.include_items);
1250 res->res_fs.num_includes = 0;
1251 if ((num=res->res_fs.num_excludes)) {
1252 while (--num >= 0) {
1253 free_incexe(res->res_fs.exclude_items[num]);
1255 free(res->res_fs.exclude_items);
1257 res->res_fs.num_excludes = 0;
1260 if (res->res_pool.pool_type) {
1261 free(res->res_pool.pool_type);
1263 if (res->res_pool.label_format) {
1264 free(res->res_pool.label_format);
1266 if (res->res_pool.cleaning_prefix) {
1267 free(res->res_pool.cleaning_prefix);
1269 if (res->res_pool.storage) {
1270 delete res->res_pool.storage;
1274 if (res->res_sch.run) {
1276 nrun = res->res_sch.run;
1286 if (res->res_job.RestoreWhere) {
1287 free(res->res_job.RestoreWhere);
1289 if (res->res_job.RegexWhere) {
1290 free(res->res_job.RegexWhere);
1292 if (res->res_job.strip_prefix) {
1293 free(res->res_job.strip_prefix);
1295 if (res->res_job.add_prefix) {
1296 free(res->res_job.add_prefix);
1298 if (res->res_job.add_suffix) {
1299 free(res->res_job.add_suffix);
1301 if (res->res_job.RestoreBootstrap) {
1302 free(res->res_job.RestoreBootstrap);
1304 if (res->res_job.WriteBootstrap) {
1305 free(res->res_job.WriteBootstrap);
1307 if (res->res_job.PluginOptions) {
1308 free(res->res_job.PluginOptions);
1310 if (res->res_job.selection_pattern) {
1311 free(res->res_job.selection_pattern);
1313 if (res->res_job.run_cmds) {
1314 delete res->res_job.run_cmds;
1316 if (res->res_job.storage) {
1317 delete res->res_job.storage;
1319 if (res->res_job.base) {
1320 delete res->res_job.base;
1322 if (res->res_job.RunScripts) {
1323 free_runscripts(res->res_job.RunScripts);
1324 delete res->res_job.RunScripts;
1328 if (res->res_msgs.mail_cmd) {
1329 free(res->res_msgs.mail_cmd);
1331 if (res->res_msgs.operator_cmd) {
1332 free(res->res_msgs.operator_cmd);
1334 free_msgs_res((MSGS *)res); /* free message resource */
1338 printf(_("Unknown resource type %d in free_resource.\n"), type);
1340 /* Common stuff again -- free the resource, recurse to next one */
1345 free_resource(nres, type);
1350 * Save the new resource by chaining it into the head list for
1351 * the resource. If this is pass 2, we update any resource
1352 * pointers because they may not have been defined until
1355 void save_resource(int type, RES_ITEM *items, int pass)
1358 int rindex = type - r_first;
1362 /* Check Job requirements after applying JobDefs */
1363 if (type != R_JOB && type != R_JOBDEFS) {
1365 * Ensure that all required items are present
1367 for (i=0; items[i].name; i++) {
1368 if (items[i].flags & ITEM_REQUIRED) {
1369 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1370 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1371 items[i].name, resources[rindex]);
1374 /* If this triggers, take a look at lib/parse_conf.h */
1375 if (i >= MAX_RES_ITEMS) {
1376 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1379 } else if (type == R_JOB) {
1381 * Ensure that the name item is present
1383 if (items[0].flags & ITEM_REQUIRED) {
1384 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1385 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1386 items[0].name, resources[rindex]);
1392 * During pass 2 in each "store" routine, we looked up pointers
1393 * to all the resources referrenced in the current resource, now we
1394 * must copy their addresses from the static record to the allocated
1399 /* Resources not containing a resource */
1407 * Resources containing another resource or alist. First
1408 * look up the resource which contains another resource. It
1409 * was written during pass 1. Then stuff in the pointers to
1410 * the resources it contains, which were inserted this pass.
1411 * Finally, it will all be stored back.
1414 /* Find resource saved in pass 1 */
1415 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1416 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1418 /* Explicitly copy resource pointers from this pass (res_all) */
1419 res->res_pool.NextPool = res_all.res_pool.NextPool;
1420 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1421 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1422 res->res_pool.storage = res_all.res_pool.storage;
1423 res->res_pool.catalog = res_all.res_pool.catalog;
1426 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1427 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1429 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1432 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1433 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1435 res->res_dir.messages = res_all.res_dir.messages;
1436 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1439 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1440 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1441 res_all.res_dir.hdr.name);
1443 /* we must explicitly copy the device alist pointer */
1444 res->res_store.device = res_all.res_store.device;
1448 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1449 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1450 res_all.res_dir.hdr.name);
1452 res->res_job.messages = res_all.res_job.messages;
1453 res->res_job.schedule = res_all.res_job.schedule;
1454 res->res_job.client = res_all.res_job.client;
1455 res->res_job.fileset = res_all.res_job.fileset;
1456 res->res_job.storage = res_all.res_job.storage;
1457 res->res_job.base = res_all.res_job.base;
1458 res->res_job.pool = res_all.res_job.pool;
1459 res->res_job.full_pool = res_all.res_job.full_pool;
1460 res->res_job.inc_pool = res_all.res_job.inc_pool;
1461 res->res_job.diff_pool = res_all.res_job.diff_pool;
1462 res->res_job.verify_job = res_all.res_job.verify_job;
1463 res->res_job.jobdefs = res_all.res_job.jobdefs;
1464 res->res_job.run_cmds = res_all.res_job.run_cmds;
1465 res->res_job.RunScripts = res_all.res_job.RunScripts;
1467 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1468 * is not very useful)
1469 * We have to set_bit(index, res_all.hdr.item_present);
1470 * or something like that
1473 /* we take RegexWhere before all other options */
1474 if (!res->res_job.RegexWhere
1476 (res->res_job.strip_prefix ||
1477 res->res_job.add_suffix ||
1478 res->res_job.add_prefix))
1480 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1481 res->res_job.add_prefix,
1482 res->res_job.add_suffix);
1483 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1484 bregexp_build_where(res->res_job.RegexWhere, len,
1485 res->res_job.strip_prefix,
1486 res->res_job.add_prefix,
1487 res->res_job.add_suffix);
1488 /* TODO: test bregexp */
1491 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1492 free(res->res_job.RestoreWhere);
1493 res->res_job.RestoreWhere = NULL;
1498 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1499 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1501 res->res_counter.Catalog = res_all.res_counter.Catalog;
1502 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1506 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1507 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1509 res->res_client.catalog = res_all.res_client.catalog;
1510 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1514 * Schedule is a bit different in that it contains a RUN record
1515 * chain which isn't a "named" resource. This chain was linked
1516 * in by run_conf.c during pass 2, so here we jam the pointer
1517 * into the Schedule resource.
1519 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1520 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1522 res->res_sch.run = res_all.res_sch.run;
1525 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1529 /* Note, the resource name was already saved during pass 1,
1530 * so here, we can just release it.
1532 if (res_all.res_dir.hdr.name) {
1533 free(res_all.res_dir.hdr.name);
1534 res_all.res_dir.hdr.name = NULL;
1536 if (res_all.res_dir.hdr.desc) {
1537 free(res_all.res_dir.hdr.desc);
1538 res_all.res_dir.hdr.desc = NULL;
1544 * The following code is only executed during pass 1
1548 size = sizeof(DIRRES);
1551 size = sizeof(CONRES);
1554 size =sizeof(CLIENT);
1557 size = sizeof(STORE);
1567 size = sizeof(FILESET);
1570 size = sizeof(SCHED);
1573 size = sizeof(POOL);
1576 size = sizeof(MSGS);
1579 size = sizeof(COUNTER);
1585 printf(_("Unknown resource type %d in save_resource.\n"), type);
1591 res = (URES *)malloc(size);
1592 memcpy(res, &res_all, size);
1593 if (!res_head[rindex]) {
1594 res_head[rindex] = (RES *)res; /* store first entry */
1595 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1596 res->res_dir.hdr.name, rindex);
1599 if (res->res_dir.hdr.name == NULL) {
1600 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1603 /* Add new res to end of chain */
1604 for (last=next=res_head[rindex]; next; next=next->next) {
1606 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1607 Emsg2(M_ERROR_TERM, 0,
1608 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1609 resources[rindex].name, res->res_dir.hdr.name);
1612 last->next = (RES *)res;
1613 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1614 res->res_dir.hdr.name, rindex, pass);
1619 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1621 uint32_t *destination = (uint32_t*)item->value;
1622 lex_get_token(lc, T_NAME);
1623 if (strcasecmp(lc->str, "truncate") == 0) {
1624 *destination = (*destination) | ON_PURGE_TRUNCATE;
1626 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1630 set_bit(index, res_all.hdr.item_present);
1634 * Store Device. Note, the resource is created upon the
1635 * first reference. The details of the resource are obtained
1636 * later from the SD.
1638 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1642 int rindex = R_DEVICE - r_first;
1643 int size = sizeof(DEVICE);
1647 token = lex_get_token(lc, T_NAME);
1648 if (!res_head[rindex]) {
1649 res = (URES *)malloc(size);
1650 memset(res, 0, size);
1651 res->res_dev.hdr.name = bstrdup(lc->str);
1652 res_head[rindex] = (RES *)res; /* store first entry */
1653 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1654 res->res_dir.hdr.name, rindex);
1657 /* See if it is already defined */
1658 for (next=res_head[rindex]; next->next; next=next->next) {
1659 if (strcmp(next->name, lc->str) == 0) {
1665 res = (URES *)malloc(size);
1666 memset(res, 0, size);
1667 res->res_dev.hdr.name = bstrdup(lc->str);
1668 next->next = (RES *)res;
1669 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1670 res->res_dir.hdr.name, rindex, pass);
1675 set_bit(index, res_all.hdr.item_present);
1677 store_alist_res(lc, item, index, pass);
1682 * Store Migration/Copy type
1685 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1689 token = lex_get_token(lc, T_NAME);
1690 /* Store the type both pass 1 and pass 2 */
1691 for (i=0; migtypes[i].type_name; i++) {
1692 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1693 *(uint32_t *)(item->value) = migtypes[i].job_type;
1699 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1702 set_bit(index, res_all.hdr.item_present);
1708 * Store JobType (backup, verify, restore)
1711 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1715 token = lex_get_token(lc, T_NAME);
1716 /* Store the type both pass 1 and pass 2 */
1717 for (i=0; jobtypes[i].type_name; i++) {
1718 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1719 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1725 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1728 set_bit(index, res_all.hdr.item_present);
1732 * Store Job Level (Full, Incremental, ...)
1735 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1739 token = lex_get_token(lc, T_NAME);
1740 /* Store the level pass 2 so that type is defined */
1741 for (i=0; joblevels[i].level_name; i++) {
1742 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1743 *(uint32_t *)(item->value) = joblevels[i].level;
1749 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1752 set_bit(index, res_all.hdr.item_present);
1756 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1759 token = lex_get_token(lc, T_NAME);
1760 /* Scan Replacement options */
1761 for (i=0; ReplaceOptions[i].name; i++) {
1762 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1763 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1769 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1772 set_bit(index, res_all.hdr.item_present);
1776 * Store ACL (access control list)
1779 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1784 token = lex_get_token(lc, T_STRING);
1786 if (((alist **)item->value)[item->code] == NULL) {
1787 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1788 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1790 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1791 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1793 token = lex_get_token(lc, T_ALL);
1794 if (token == T_COMMA) {
1795 continue; /* get another ACL */
1799 set_bit(index, res_all.hdr.item_present);
1802 /* We build RunScripts items here */
1803 static RUNSCRIPT res_runscript;
1805 /* Store a runscript->when in a bit field */
1806 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1808 lex_get_token(lc, T_NAME);
1810 if (strcasecmp(lc->str, "before") == 0) {
1811 *(uint32_t *)(item->value) = SCRIPT_Before ;
1812 } else if (strcasecmp(lc->str, "after") == 0) {
1813 *(uint32_t *)(item->value) = SCRIPT_After;
1814 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1815 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1816 } else if (strcasecmp(lc->str, "always") == 0) {
1817 *(uint32_t *)(item->value) = SCRIPT_Any;
1819 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1824 /* Store a runscript->target
1827 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1829 lex_get_token(lc, T_STRING);
1832 if (strcmp(lc->str, "%c") == 0) {
1833 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1834 } else if (strcasecmp(lc->str, "yes") == 0) {
1835 ((RUNSCRIPT*) item->value)->set_target("%c");
1836 } else if (strcasecmp(lc->str, "no") == 0) {
1837 ((RUNSCRIPT*) item->value)->set_target("");
1839 RES *res = GetResWithName(R_CLIENT, lc->str);
1841 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1842 lc->str, lc->line_no, lc->line);
1845 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1852 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1854 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1856 lex_get_token(lc, T_STRING);
1859 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1860 POOLMEM *c = get_pool_memory(PM_FNAME);
1861 /* Each runscript command takes 2 entries in commands list */
1862 pm_strcpy(c, lc->str);
1863 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1864 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1869 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1871 lex_get_token(lc, T_STRING);
1872 alist **runscripts = (alist **)(item->value) ;
1875 RUNSCRIPT *script = new_runscript();
1876 script->set_job_code_callback(job_code_callback_filesetname);
1878 script->set_command(lc->str);
1880 /* TODO: remove all script->old_proto with bacula 1.42 */
1882 if (strcmp(item->name, "runbeforejob") == 0) {
1883 script->when = SCRIPT_Before;
1884 script->fail_on_error = true;
1885 script->set_target("");
1887 } else if (strcmp(item->name, "runafterjob") == 0) {
1888 script->when = SCRIPT_After;
1889 script->on_success = true;
1890 script->on_failure = false;
1891 script->set_target("");
1893 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1894 script->old_proto = true;
1895 script->when = SCRIPT_After;
1896 script->set_target("%c");
1897 script->on_success = true;
1898 script->on_failure = false;
1900 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1901 script->old_proto = true;
1902 script->when = SCRIPT_Before;
1903 script->set_target("%c");
1904 script->fail_on_error = true;
1906 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1907 script->when = SCRIPT_After;
1908 script->on_failure = true;
1909 script->on_success = false;
1910 script->set_target("");
1913 if (*runscripts == NULL) {
1914 *runscripts = New(alist(10, not_owned_by_alist));
1917 (*runscripts)->append(script);
1924 /* Store a bool in a bit field without modifing res_all.hdr
1925 * We can also add an option to store_bool to skip res_all.hdr
1927 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1929 lex_get_token(lc, T_NAME);
1930 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1931 *(bool *)(item->value) = true;
1932 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1933 *(bool *)(item->value) = false;
1935 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1941 * new RunScript items
1942 * name handler value code flags default_value
1944 static RES_ITEM runscript_items[] = {
1945 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1946 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1947 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1948 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1949 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1950 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1951 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1952 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1953 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1954 {NULL, NULL, {0}, 0, 0, 0}
1958 * Store RunScript info
1960 * Note, when this routine is called, we are inside a Job
1961 * resource. We treat the RunScript like a sort of
1962 * mini-resource within the Job resource.
1964 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1968 alist **runscripts = (alist **)(item->value) ;
1970 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1972 token = lex_get_token(lc, T_SKIP_EOL);
1974 if (token != T_BOB) {
1975 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1977 /* setting on_success, on_failure, fail_on_error */
1978 res_runscript.reset_default();
1981 res_runscript.commands = New(alist(10, not_owned_by_alist));
1984 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1985 if (token == T_EOB) {
1988 if (token != T_IDENTIFIER) {
1989 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1991 for (i=0; runscript_items[i].name; i++) {
1992 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1993 token = lex_get_token(lc, T_SKIP_EOL);
1994 if (token != T_EQUALS) {
1995 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1998 /* Call item handler */
1999 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2006 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2011 /* run on client by default */
2012 if (res_runscript.target == NULL) {
2013 res_runscript.set_target("%c");
2015 if (*runscripts == NULL) {
2016 *runscripts = New(alist(10, not_owned_by_alist));
2019 * commands list contains 2 values per command
2020 * - POOLMEM command string (ex: /bin/true)
2021 * - int command type (ex: SHELL_CMD)
2023 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2024 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2025 t = (intptr_t)res_runscript.commands->pop();
2026 RUNSCRIPT *script = new_runscript();
2027 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2028 script->command = c;
2029 script->cmd_type = t;
2030 /* target is taken from res_runscript, each runscript object have
2033 script->target = NULL;
2034 script->set_target(res_runscript.target);
2036 (*runscripts)->append(script);
2039 delete res_runscript.commands;
2040 /* setting on_success, on_failure... cleanup target field */
2041 res_runscript.reset_default(true);
2045 set_bit(index, res_all.hdr.item_present);
2048 /* callback function for edit_job_codes */
2049 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2051 if (param[0] == 'f') {
2052 return jcr->fileset->name();
2058 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2060 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2061 r_first, r_last, resources, res_head);
2062 return config->parse_config();