2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 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
56 /* Define the first and last resource ID record
57 * types. Note, these should be unique for each
58 * daemon though not a requirement.
60 int32_t r_first = R_FIRST;
61 int32_t r_last = R_LAST;
62 static RES *sres_head[R_LAST - R_FIRST + 1];
63 RES **res_head = sres_head;
65 /* Imported subroutines */
66 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
68 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
71 /* Forward referenced subroutines */
73 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
77 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
83 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
85 /* We build the current resource here as we are
86 * scanning the resource configuration definition,
87 * then move it to allocated memory when the resource
91 extern "C" { // work around visual compiler mangling variables
97 int32_t res_all_size = sizeof(res_all);
100 /* Definition of records permitted within each
101 * resource with the routine to process the record
102 * information. NOTE! quoted names must be in lower case.
107 * name handler value code flags default_value
109 static RES_ITEM dir_items[] = {
110 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
111 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
112 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
113 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
116 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
117 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
118 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
119 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
120 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
121 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
122 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
123 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
124 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
125 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
126 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
127 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
128 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
129 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
130 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
131 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
132 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
133 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
134 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
135 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
136 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
137 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
138 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
139 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
140 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
141 {NULL, NULL, {0}, 0, 0, 0}
147 * name handler value code flags default_value
149 static RES_ITEM con_items[] = {
150 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
151 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
152 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
153 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
154 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
155 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
156 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
157 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
158 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
159 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
160 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
161 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
162 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
163 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
164 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
165 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
166 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
167 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
168 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
169 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
170 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
171 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
172 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
173 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
174 {NULL, NULL, {0}, 0, 0, 0}
179 * Client or File daemon resource
181 * name handler value code flags default_value
184 static RES_ITEM cli_items[] = {
185 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
186 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
187 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
188 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
189 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
190 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
191 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
192 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
193 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
194 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
195 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
196 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
197 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
198 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
199 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
200 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
201 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
202 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
203 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
204 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
205 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
206 {NULL, NULL, {0}, 0, 0, 0}
209 /* Storage daemon resource
211 * name handler value code flags default_value
213 static RES_ITEM store_items[] = {
214 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
215 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
216 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
217 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
218 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
219 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
220 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
221 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
222 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
223 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
224 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
225 {"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 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
311 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
312 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
313 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
314 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
315 {"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, false},
338 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
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 {NULL, NULL, {0}, 0, 0, 0}
412 * name handler value code flags default_value
414 static RES_ITEM counter_items[] = {
415 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
416 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
417 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
418 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
419 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
420 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
421 {NULL, NULL, {0}, 0, 0, 0}
425 /* Message resource */
426 extern RES_ITEM msgs_items[];
429 * This is the master resource definition.
430 * It must have one item for each of the resources.
432 * NOTE!!! keep it in the same order as the R_codes
433 * or eliminate all resources[rindex].name
435 * name items rcode res_head
437 RES_TABLE resources[] = {
438 {"director", dir_items, R_DIRECTOR},
439 {"client", cli_items, R_CLIENT},
440 {"job", job_items, R_JOB},
441 {"storage", store_items, R_STORAGE},
442 {"catalog", cat_items, R_CATALOG},
443 {"schedule", sch_items, R_SCHEDULE},
444 {"fileset", fs_items, R_FILESET},
445 {"pool", pool_items, R_POOL},
446 {"messages", msgs_items, R_MSGS},
447 {"counter", counter_items, R_COUNTER},
448 {"console", con_items, R_CONSOLE},
449 {"jobdefs", job_items, R_JOBDEFS},
450 {"device", NULL, R_DEVICE}, /* info obtained from SD */
455 /* Keywords (RHS) permitted in Job Level records
457 * level_name level job_type
459 struct s_jl joblevels[] = {
460 {"Full", L_FULL, JT_BACKUP},
461 {"Base", L_BASE, JT_BACKUP},
462 {"Incremental", L_INCREMENTAL, JT_BACKUP},
463 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
464 {"Since", L_SINCE, JT_BACKUP},
465 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
466 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
467 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
468 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
469 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
470 {"Data", L_VERIFY_DATA, JT_VERIFY},
471 {" ", L_NONE, JT_ADMIN},
472 {" ", L_NONE, JT_RESTORE},
476 /* Keywords (RHS) permitted in Job type records
480 struct s_jt jobtypes[] = {
481 {"backup", JT_BACKUP},
483 {"verify", JT_VERIFY},
484 {"restore", JT_RESTORE},
485 {"migrate", JT_MIGRATE},
491 /* Keywords (RHS) permitted in Selection type records
495 struct s_jt migtypes[] = {
496 {"smallestvolume", MT_SMALLEST_VOL},
497 {"oldestvolume", MT_OLDEST_VOL},
498 {"pooloccupancy", MT_POOL_OCCUPANCY},
499 {"pooltime", MT_POOL_TIME},
500 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
501 {"client", MT_CLIENT},
502 {"volume", MT_VOLUME},
504 {"sqlquery", MT_SQLQUERY},
510 /* Options permitted in Restore replace= */
511 struct s_kw ReplaceOptions[] = {
512 {"always", REPLACE_ALWAYS},
513 {"ifnewer", REPLACE_IFNEWER},
514 {"ifolder", REPLACE_IFOLDER},
515 {"never", REPLACE_NEVER},
519 char *CAT::display(POOLMEM *dst) {
520 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
521 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
523 name(), NPRTB(db_name),
524 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
525 NPRTB(db_address), db_port, NPRTB(db_socket));
529 const char *level_to_str(int level)
532 static char level_no[30];
533 const char *str = level_no;
535 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
536 for (i=0; joblevels[i].level_name; i++) {
537 if (level == (int)joblevels[i].level) {
538 str = joblevels[i].level_name;
545 /* Dump contents of resource */
546 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
548 URES *res = (URES *)reshdr;
550 char ed1[100], ed2[100], ed3[100];
554 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
557 if (type < 0) { /* no recursion */
563 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
564 reshdr->name, res->res_dir.MaxConcurrentJobs,
565 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
566 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
567 if (res->res_dir.query_file) {
568 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
570 if (res->res_dir.messages) {
571 sendit(sock, _(" --> "));
572 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
576 sendit(sock, _("Console: name=%s SSL=%d\n"),
577 res->res_con.hdr.name, res->res_con.tls_enable);
580 if (res->res_counter.WrapCounter) {
581 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
582 res->res_counter.hdr.name, res->res_counter.MinValue,
583 res->res_counter.MaxValue, res->res_counter.CurrentValue,
584 res->res_counter.WrapCounter->hdr.name);
586 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
587 res->res_counter.hdr.name, res->res_counter.MinValue,
588 res->res_counter.MaxValue);
590 if (res->res_counter.Catalog) {
591 sendit(sock, _(" --> "));
592 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
597 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
598 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
599 res->res_client.MaxConcurrentJobs);
600 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
601 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
602 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
603 res->res_client.AutoPrune);
604 if (res->res_client.catalog) {
605 sendit(sock, _(" --> "));
606 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
613 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
614 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
615 " poolid=%s volname=%s MediaType=%s\n"),
616 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
617 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
618 dev->offline, dev->autochanger,
619 edit_uint64(dev->PoolId, ed1),
620 dev->VolumeName, dev->MediaType);
624 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
625 " DeviceName=%s MediaType=%s StorageId=%s\n"),
626 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
627 res->res_store.MaxConcurrentJobs,
628 res->res_store.dev_name(),
629 res->res_store.media_type,
630 edit_int64(res->res_store.StorageId, ed1));
634 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
635 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
636 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
637 res->res_cat.db_port, res->res_cat.db_name,
638 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
639 res->res_cat.mult_db_connections);
644 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
645 type == R_JOB ? _("Job") : _("JobDefs"),
646 res->res_job.hdr.name, res->res_job.JobType,
647 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
648 res->res_job.enabled);
649 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
650 res->res_job.MaxConcurrentJobs,
651 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
652 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
653 res->res_job.spool_data, res->res_job.write_part_after_job);
654 if (res->res_job.spool_size) {
655 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
657 if (res->res_job.JobType == JT_BACKUP) {
658 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
660 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
661 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
663 if (res->res_job.client) {
664 sendit(sock, _(" --> "));
665 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
667 if (res->res_job.fileset) {
668 sendit(sock, _(" --> "));
669 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
671 if (res->res_job.schedule) {
672 sendit(sock, _(" --> "));
673 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
675 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
676 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
678 if (res->res_job.RegexWhere) {
679 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
681 if (res->res_job.RestoreBootstrap) {
682 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
684 if (res->res_job.WriteBootstrap) {
685 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
687 if (res->res_job.PluginOptions) {
688 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
690 if (res->res_job.MaxRunTime) {
691 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
693 if (res->res_job.MaxWaitTime) {
694 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
696 if (res->res_job.MaxStartDelay) {
697 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
699 if (res->res_job.storage) {
701 foreach_alist(store, res->res_job.storage) {
702 sendit(sock, _(" --> "));
703 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
706 if (res->res_job.base) {
708 foreach_alist(job, res->res_job.base) {
709 sendit(sock, _(" --> Base %s\n"), job->name());
712 if (res->res_job.RunScripts) {
714 foreach_alist(script, res->res_job.RunScripts) {
715 sendit(sock, _(" --> RunScript\n"));
716 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
717 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
718 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
719 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
720 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
721 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
724 if (res->res_job.pool) {
725 sendit(sock, _(" --> "));
726 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
728 if (res->res_job.full_pool) {
729 sendit(sock, _(" --> "));
730 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
732 if (res->res_job.inc_pool) {
733 sendit(sock, _(" --> "));
734 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
736 if (res->res_job.diff_pool) {
737 sendit(sock, _(" --> "));
738 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
740 if (res->res_job.verify_job) {
741 sendit(sock, _(" --> "));
742 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
744 if (res->res_job.run_cmds) {
746 foreach_alist(runcmd, res->res_job.run_cmds) {
747 sendit(sock, _(" --> Run=%s\n"), runcmd);
750 if (res->res_job.selection_pattern) {
751 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
753 if (res->res_job.messages) {
754 sendit(sock, _(" --> "));
755 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
762 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
763 for (i=0; i<res->res_fs.num_includes; i++) {
764 INCEXE *incexe = res->res_fs.include_items[i];
765 for (j=0; j<incexe->num_opts; j++) {
766 FOPTS *fo = incexe->opts_list[j];
767 sendit(sock, " O %s\n", fo->opts);
769 bool enhanced_wild = false;
770 for (k=0; fo->opts[k]!='\0'; k++) {
771 if (fo->opts[k]=='W') {
772 enhanced_wild = true;
777 for (k=0; k<fo->regex.size(); k++) {
778 sendit(sock, " R %s\n", fo->regex.get(k));
780 for (k=0; k<fo->regexdir.size(); k++) {
781 sendit(sock, " RD %s\n", fo->regexdir.get(k));
783 for (k=0; k<fo->regexfile.size(); k++) {
784 sendit(sock, " RF %s\n", fo->regexfile.get(k));
786 for (k=0; k<fo->wild.size(); k++) {
787 sendit(sock, " W %s\n", fo->wild.get(k));
789 for (k=0; k<fo->wilddir.size(); k++) {
790 sendit(sock, " WD %s\n", fo->wilddir.get(k));
792 for (k=0; k<fo->wildfile.size(); k++) {
793 sendit(sock, " WF %s\n", fo->wildfile.get(k));
795 for (k=0; k<fo->wildbase.size(); k++) {
796 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
798 for (k=0; k<fo->base.size(); k++) {
799 sendit(sock, " B %s\n", fo->base.get(k));
801 for (k=0; k<fo->fstype.size(); k++) {
802 sendit(sock, " X %s\n", fo->fstype.get(k));
804 for (k=0; k<fo->drivetype.size(); k++) {
805 sendit(sock, " XD %s\n", fo->drivetype.get(k));
808 sendit(sock, " G %s\n", fo->plugin);
811 sendit(sock, " D %s\n", fo->reader);
814 sendit(sock, " T %s\n", fo->writer);
816 sendit(sock, " N\n");
818 if (incexe->ignoredir) {
819 sendit(sock, " Z %s\n", incexe->ignoredir);
821 for (j=0; j<incexe->name_list.size(); j++) {
822 sendit(sock, " I %s\n", incexe->name_list.get(j));
824 if (incexe->name_list.size()) {
825 sendit(sock, " N\n");
827 for (j=0; j<incexe->plugin_list.size(); j++) {
828 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
830 if (incexe->plugin_list.size()) {
831 sendit(sock, " N\n");
836 for (i=0; i<res->res_fs.num_excludes; i++) {
837 INCEXE *incexe = res->res_fs.exclude_items[i];
838 for (j=0; j<incexe->name_list.size(); j++) {
839 sendit(sock, " E %s\n", incexe->name_list.get(j));
841 if (incexe->name_list.size()) {
842 sendit(sock, " N\n");
849 if (res->res_sch.run) {
851 RUN *run = res->res_sch.run;
852 char buf[1000], num[30];
853 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
858 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
859 bstrncpy(buf, _(" hour="), sizeof(buf));
860 for (i=0; i<24; i++) {
861 if (bit_is_set(i, run->hour)) {
862 bsnprintf(num, sizeof(num), "%d ", i);
863 bstrncat(buf, num, sizeof(buf));
866 bstrncat(buf, "\n", sizeof(buf));
868 bstrncpy(buf, _(" mday="), sizeof(buf));
869 for (i=0; i<31; i++) {
870 if (bit_is_set(i, run->mday)) {
871 bsnprintf(num, sizeof(num), "%d ", i);
872 bstrncat(buf, num, sizeof(buf));
875 bstrncat(buf, "\n", sizeof(buf));
877 bstrncpy(buf, _(" month="), sizeof(buf));
878 for (i=0; i<12; i++) {
879 if (bit_is_set(i, run->month)) {
880 bsnprintf(num, sizeof(num), "%d ", i);
881 bstrncat(buf, num, sizeof(buf));
884 bstrncat(buf, "\n", sizeof(buf));
886 bstrncpy(buf, _(" wday="), sizeof(buf));
887 for (i=0; i<7; i++) {
888 if (bit_is_set(i, run->wday)) {
889 bsnprintf(num, sizeof(num), "%d ", i);
890 bstrncat(buf, num, sizeof(buf));
893 bstrncat(buf, "\n", sizeof(buf));
895 bstrncpy(buf, _(" wom="), sizeof(buf));
896 for (i=0; i<5; i++) {
897 if (bit_is_set(i, run->wom)) {
898 bsnprintf(num, sizeof(num), "%d ", i);
899 bstrncat(buf, num, sizeof(buf));
902 bstrncat(buf, "\n", sizeof(buf));
904 bstrncpy(buf, _(" woy="), sizeof(buf));
905 for (i=0; i<54; i++) {
906 if (bit_is_set(i, run->woy)) {
907 bsnprintf(num, sizeof(num), "%d ", i);
908 bstrncat(buf, num, sizeof(buf));
911 bstrncat(buf, "\n", sizeof(buf));
913 sendit(sock, _(" mins=%d\n"), run->minute);
915 sendit(sock, _(" --> "));
916 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
919 sendit(sock, _(" --> "));
920 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
923 sendit(sock, _(" --> "));
924 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
926 /* If another Run record is chained in, go print it */
932 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
937 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
938 res->res_pool.pool_type);
939 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
940 res->res_pool.use_catalog, res->res_pool.use_volume_once,
941 res->res_pool.catalog_files);
942 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
943 res->res_pool.max_volumes, res->res_pool.AutoPrune,
944 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
945 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
946 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
947 res->res_pool.Recycle,
948 NPRT(res->res_pool.label_format));
949 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
950 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
951 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
952 res->res_pool.recycle_oldest_volume,
953 res->res_pool.purge_oldest_volume,
954 res->res_pool.action_on_purge);
955 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
956 res->res_pool.MaxVolJobs,
957 res->res_pool.MaxVolFiles,
958 edit_uint64(res->res_pool.MaxVolBytes, ed1));
959 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
960 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
961 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
962 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
963 if (res->res_pool.NextPool) {
964 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
966 if (res->res_pool.RecyclePool) {
967 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
969 if (res->res_pool.ScratchPool) {
970 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
972 if (res->res_pool.catalog) {
973 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
975 if (res->res_pool.storage) {
977 foreach_alist(store, res->res_pool.storage) {
978 sendit(sock, _(" --> "));
979 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
982 if (res->res_pool.CopyPool) {
984 foreach_alist(copy, res->res_pool.CopyPool) {
985 sendit(sock, _(" --> "));
986 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
993 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
994 if (res->res_msgs.mail_cmd)
995 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
996 if (res->res_msgs.operator_cmd)
997 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1001 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1004 if (recurse && res->res_dir.hdr.next) {
1005 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1010 * Free all the members of an INCEXE structure
1012 static void free_incexe(INCEXE *incexe)
1014 incexe->name_list.destroy();
1015 incexe->plugin_list.destroy();
1016 for (int i=0; i<incexe->num_opts; i++) {
1017 FOPTS *fopt = incexe->opts_list[i];
1018 fopt->regex.destroy();
1019 fopt->regexdir.destroy();
1020 fopt->regexfile.destroy();
1021 fopt->wild.destroy();
1022 fopt->wilddir.destroy();
1023 fopt->wildfile.destroy();
1024 fopt->wildbase.destroy();
1025 fopt->base.destroy();
1026 fopt->fstype.destroy();
1027 fopt->drivetype.destroy();
1039 if (incexe->opts_list) {
1040 free(incexe->opts_list);
1042 if (incexe->ignoredir) {
1043 free(incexe->ignoredir);
1049 * Free memory of resource -- called when daemon terminates.
1050 * NB, we don't need to worry about freeing any references
1051 * to other resources as they will be freed when that
1052 * resource chain is traversed. Mainly we worry about freeing
1053 * allocated strings (names).
1055 void free_resource(RES *sres, int type)
1058 RES *nres; /* next resource if linked */
1059 URES *res = (URES *)sres;
1064 /* common stuff -- free the resource name and description */
1065 nres = (RES *)res->res_dir.hdr.next;
1066 if (res->res_dir.hdr.name) {
1067 free(res->res_dir.hdr.name);
1069 if (res->res_dir.hdr.desc) {
1070 free(res->res_dir.hdr.desc);
1075 if (res->res_dir.working_directory) {
1076 free(res->res_dir.working_directory);
1078 if (res->res_dir.scripts_directory) {
1079 free((char *)res->res_dir.scripts_directory);
1081 if (res->res_dir.plugin_directory) {
1082 free((char *)res->res_dir.plugin_directory);
1084 if (res->res_dir.pid_directory) {
1085 free(res->res_dir.pid_directory);
1087 if (res->res_dir.subsys_directory) {
1088 free(res->res_dir.subsys_directory);
1090 if (res->res_dir.password) {
1091 free(res->res_dir.password);
1093 if (res->res_dir.query_file) {
1094 free(res->res_dir.query_file);
1096 if (res->res_dir.DIRaddrs) {
1097 free_addresses(res->res_dir.DIRaddrs);
1099 if (res->res_dir.DIRsrc_addr) {
1100 free_addresses(res->res_dir.DIRsrc_addr);
1102 if (res->res_dir.tls_ctx) {
1103 free_tls_context(res->res_dir.tls_ctx);
1105 if (res->res_dir.tls_ca_certfile) {
1106 free(res->res_dir.tls_ca_certfile);
1108 if (res->res_dir.tls_ca_certdir) {
1109 free(res->res_dir.tls_ca_certdir);
1111 if (res->res_dir.tls_certfile) {
1112 free(res->res_dir.tls_certfile);
1114 if (res->res_dir.tls_keyfile) {
1115 free(res->res_dir.tls_keyfile);
1117 if (res->res_dir.tls_dhfile) {
1118 free(res->res_dir.tls_dhfile);
1120 if (res->res_dir.tls_allowed_cns) {
1121 delete res->res_dir.tls_allowed_cns;
1123 if (res->res_dir.verid) {
1124 free(res->res_dir.verid);
1131 if (res->res_con.password) {
1132 free(res->res_con.password);
1134 if (res->res_con.tls_ctx) {
1135 free_tls_context(res->res_con.tls_ctx);
1137 if (res->res_con.tls_ca_certfile) {
1138 free(res->res_con.tls_ca_certfile);
1140 if (res->res_con.tls_ca_certdir) {
1141 free(res->res_con.tls_ca_certdir);
1143 if (res->res_con.tls_certfile) {
1144 free(res->res_con.tls_certfile);
1146 if (res->res_con.tls_keyfile) {
1147 free(res->res_con.tls_keyfile);
1149 if (res->res_con.tls_dhfile) {
1150 free(res->res_con.tls_dhfile);
1152 if (res->res_con.tls_allowed_cns) {
1153 delete res->res_con.tls_allowed_cns;
1155 for (int i=0; i<Num_ACL; i++) {
1156 if (res->res_con.ACL_lists[i]) {
1157 delete res->res_con.ACL_lists[i];
1158 res->res_con.ACL_lists[i] = NULL;
1163 if (res->res_client.address) {
1164 free(res->res_client.address);
1166 if (res->res_client.password) {
1167 free(res->res_client.password);
1169 if (res->res_client.tls_ctx) {
1170 free_tls_context(res->res_client.tls_ctx);
1172 if (res->res_client.tls_ca_certfile) {
1173 free(res->res_client.tls_ca_certfile);
1175 if (res->res_client.tls_ca_certdir) {
1176 free(res->res_client.tls_ca_certdir);
1178 if (res->res_client.tls_certfile) {
1179 free(res->res_client.tls_certfile);
1181 if (res->res_client.tls_keyfile) {
1182 free(res->res_client.tls_keyfile);
1184 if (res->res_client.tls_allowed_cns) {
1185 delete res->res_client.tls_allowed_cns;
1189 if (res->res_store.address) {
1190 free(res->res_store.address);
1192 if (res->res_store.password) {
1193 free(res->res_store.password);
1195 if (res->res_store.media_type) {
1196 free(res->res_store.media_type);
1198 if (res->res_store.device) {
1199 delete res->res_store.device;
1201 if (res->res_store.tls_ctx) {
1202 free_tls_context(res->res_store.tls_ctx);
1204 if (res->res_store.tls_ca_certfile) {
1205 free(res->res_store.tls_ca_certfile);
1207 if (res->res_store.tls_ca_certdir) {
1208 free(res->res_store.tls_ca_certdir);
1210 if (res->res_store.tls_certfile) {
1211 free(res->res_store.tls_certfile);
1213 if (res->res_store.tls_keyfile) {
1214 free(res->res_store.tls_keyfile);
1218 if (res->res_cat.db_address) {
1219 free(res->res_cat.db_address);
1221 if (res->res_cat.db_socket) {
1222 free(res->res_cat.db_socket);
1224 if (res->res_cat.db_user) {
1225 free(res->res_cat.db_user);
1227 if (res->res_cat.db_name) {
1228 free(res->res_cat.db_name);
1230 if (res->res_cat.db_driver) {
1231 free(res->res_cat.db_driver);
1233 if (res->res_cat.db_password) {
1234 free(res->res_cat.db_password);
1238 if ((num=res->res_fs.num_includes)) {
1239 while (--num >= 0) {
1240 free_incexe(res->res_fs.include_items[num]);
1242 free(res->res_fs.include_items);
1244 res->res_fs.num_includes = 0;
1245 if ((num=res->res_fs.num_excludes)) {
1246 while (--num >= 0) {
1247 free_incexe(res->res_fs.exclude_items[num]);
1249 free(res->res_fs.exclude_items);
1251 res->res_fs.num_excludes = 0;
1254 if (res->res_pool.pool_type) {
1255 free(res->res_pool.pool_type);
1257 if (res->res_pool.label_format) {
1258 free(res->res_pool.label_format);
1260 if (res->res_pool.cleaning_prefix) {
1261 free(res->res_pool.cleaning_prefix);
1263 if (res->res_pool.storage) {
1264 delete res->res_pool.storage;
1268 if (res->res_sch.run) {
1270 nrun = res->res_sch.run;
1280 if (res->res_job.RestoreWhere) {
1281 free(res->res_job.RestoreWhere);
1283 if (res->res_job.RegexWhere) {
1284 free(res->res_job.RegexWhere);
1286 if (res->res_job.strip_prefix) {
1287 free(res->res_job.strip_prefix);
1289 if (res->res_job.add_prefix) {
1290 free(res->res_job.add_prefix);
1292 if (res->res_job.add_suffix) {
1293 free(res->res_job.add_suffix);
1295 if (res->res_job.RestoreBootstrap) {
1296 free(res->res_job.RestoreBootstrap);
1298 if (res->res_job.WriteBootstrap) {
1299 free(res->res_job.WriteBootstrap);
1301 if (res->res_job.PluginOptions) {
1302 free(res->res_job.PluginOptions);
1304 if (res->res_job.selection_pattern) {
1305 free(res->res_job.selection_pattern);
1307 if (res->res_job.run_cmds) {
1308 delete res->res_job.run_cmds;
1310 if (res->res_job.storage) {
1311 delete res->res_job.storage;
1313 if (res->res_job.base) {
1314 delete res->res_job.base;
1316 if (res->res_job.RunScripts) {
1317 free_runscripts(res->res_job.RunScripts);
1318 delete res->res_job.RunScripts;
1322 if (res->res_msgs.mail_cmd) {
1323 free(res->res_msgs.mail_cmd);
1325 if (res->res_msgs.operator_cmd) {
1326 free(res->res_msgs.operator_cmd);
1328 free_msgs_res((MSGS *)res); /* free message resource */
1332 printf(_("Unknown resource type %d in free_resource.\n"), type);
1334 /* Common stuff again -- free the resource, recurse to next one */
1339 free_resource(nres, type);
1344 * Save the new resource by chaining it into the head list for
1345 * the resource. If this is pass 2, we update any resource
1346 * pointers because they may not have been defined until
1349 void save_resource(int type, RES_ITEM *items, int pass)
1352 int rindex = type - r_first;
1356 /* Check Job requirements after applying JobDefs */
1357 if (type != R_JOB && type != R_JOBDEFS) {
1359 * Ensure that all required items are present
1361 for (i=0; items[i].name; i++) {
1362 if (items[i].flags & ITEM_REQUIRED) {
1363 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1364 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1365 items[i].name, resources[rindex]);
1368 /* If this triggers, take a look at lib/parse_conf.h */
1369 if (i >= MAX_RES_ITEMS) {
1370 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1373 } else if (type == R_JOB) {
1375 * Ensure that the name item is present
1377 if (items[0].flags & ITEM_REQUIRED) {
1378 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1379 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1380 items[0].name, resources[rindex]);
1386 * During pass 2 in each "store" routine, we looked up pointers
1387 * to all the resources referrenced in the current resource, now we
1388 * must copy their addresses from the static record to the allocated
1393 /* Resources not containing a resource */
1401 * Resources containing another resource or alist. First
1402 * look up the resource which contains another resource. It
1403 * was written during pass 1. Then stuff in the pointers to
1404 * the resources it contains, which were inserted this pass.
1405 * Finally, it will all be stored back.
1408 /* Find resource saved in pass 1 */
1409 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1410 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1412 /* Explicitly copy resource pointers from this pass (res_all) */
1413 res->res_pool.NextPool = res_all.res_pool.NextPool;
1414 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1415 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1416 res->res_pool.storage = res_all.res_pool.storage;
1417 res->res_pool.catalog = res_all.res_pool.catalog;
1420 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1421 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1423 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1426 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1427 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1429 res->res_dir.messages = res_all.res_dir.messages;
1430 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1433 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1434 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1435 res_all.res_dir.hdr.name);
1437 /* we must explicitly copy the device alist pointer */
1438 res->res_store.device = res_all.res_store.device;
1442 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1443 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1444 res_all.res_dir.hdr.name);
1446 res->res_job.messages = res_all.res_job.messages;
1447 res->res_job.schedule = res_all.res_job.schedule;
1448 res->res_job.client = res_all.res_job.client;
1449 res->res_job.fileset = res_all.res_job.fileset;
1450 res->res_job.storage = res_all.res_job.storage;
1451 res->res_job.base = res_all.res_job.base;
1452 res->res_job.pool = res_all.res_job.pool;
1453 res->res_job.full_pool = res_all.res_job.full_pool;
1454 res->res_job.inc_pool = res_all.res_job.inc_pool;
1455 res->res_job.diff_pool = res_all.res_job.diff_pool;
1456 res->res_job.verify_job = res_all.res_job.verify_job;
1457 res->res_job.jobdefs = res_all.res_job.jobdefs;
1458 res->res_job.run_cmds = res_all.res_job.run_cmds;
1459 res->res_job.RunScripts = res_all.res_job.RunScripts;
1461 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1462 * is not very useful)
1463 * We have to set_bit(index, res_all.hdr.item_present);
1464 * or something like that
1467 /* we take RegexWhere before all other options */
1468 if (!res->res_job.RegexWhere
1470 (res->res_job.strip_prefix ||
1471 res->res_job.add_suffix ||
1472 res->res_job.add_prefix))
1474 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1475 res->res_job.add_prefix,
1476 res->res_job.add_suffix);
1477 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1478 bregexp_build_where(res->res_job.RegexWhere, len,
1479 res->res_job.strip_prefix,
1480 res->res_job.add_prefix,
1481 res->res_job.add_suffix);
1482 /* TODO: test bregexp */
1485 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1486 free(res->res_job.RestoreWhere);
1487 res->res_job.RestoreWhere = NULL;
1492 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1493 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1495 res->res_counter.Catalog = res_all.res_counter.Catalog;
1496 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1500 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1501 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1503 res->res_client.catalog = res_all.res_client.catalog;
1504 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1508 * Schedule is a bit different in that it contains a RUN record
1509 * chain which isn't a "named" resource. This chain was linked
1510 * in by run_conf.c during pass 2, so here we jam the pointer
1511 * into the Schedule resource.
1513 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1514 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1516 res->res_sch.run = res_all.res_sch.run;
1519 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1523 /* Note, the resource name was already saved during pass 1,
1524 * so here, we can just release it.
1526 if (res_all.res_dir.hdr.name) {
1527 free(res_all.res_dir.hdr.name);
1528 res_all.res_dir.hdr.name = NULL;
1530 if (res_all.res_dir.hdr.desc) {
1531 free(res_all.res_dir.hdr.desc);
1532 res_all.res_dir.hdr.desc = NULL;
1538 * The following code is only executed during pass 1
1542 size = sizeof(DIRRES);
1545 size = sizeof(CONRES);
1548 size =sizeof(CLIENT);
1551 size = sizeof(STORE);
1561 size = sizeof(FILESET);
1564 size = sizeof(SCHED);
1567 size = sizeof(POOL);
1570 size = sizeof(MSGS);
1573 size = sizeof(COUNTER);
1579 printf(_("Unknown resource type %d in save_resource.\n"), type);
1585 res = (URES *)malloc(size);
1586 memcpy(res, &res_all, size);
1587 if (!res_head[rindex]) {
1588 res_head[rindex] = (RES *)res; /* store first entry */
1589 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1590 res->res_dir.hdr.name, rindex);
1593 if (res->res_dir.hdr.name == NULL) {
1594 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1597 /* Add new res to end of chain */
1598 for (last=next=res_head[rindex]; next; next=next->next) {
1600 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1601 Emsg2(M_ERROR_TERM, 0,
1602 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1603 resources[rindex].name, res->res_dir.hdr.name);
1606 last->next = (RES *)res;
1607 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1608 res->res_dir.hdr.name, rindex, pass);
1613 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1615 uint32_t *destination = (uint32_t*)item->value;
1616 lex_get_token(lc, T_NAME);
1617 if (strcasecmp(lc->str, "truncate") == 0) {
1618 *destination = (*destination) | AOP_TRUNCATE;
1620 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1624 set_bit(index, res_all.hdr.item_present);
1628 * Store Device. Note, the resource is created upon the
1629 * first reference. The details of the resource are obtained
1630 * later from the SD.
1632 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1636 int rindex = R_DEVICE - r_first;
1637 int size = sizeof(DEVICE);
1641 token = lex_get_token(lc, T_NAME);
1642 if (!res_head[rindex]) {
1643 res = (URES *)malloc(size);
1644 memset(res, 0, size);
1645 res->res_dev.hdr.name = bstrdup(lc->str);
1646 res_head[rindex] = (RES *)res; /* store first entry */
1647 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1648 res->res_dir.hdr.name, rindex);
1651 /* See if it is already defined */
1652 for (next=res_head[rindex]; next->next; next=next->next) {
1653 if (strcmp(next->name, lc->str) == 0) {
1659 res = (URES *)malloc(size);
1660 memset(res, 0, size);
1661 res->res_dev.hdr.name = bstrdup(lc->str);
1662 next->next = (RES *)res;
1663 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1664 res->res_dir.hdr.name, rindex, pass);
1669 set_bit(index, res_all.hdr.item_present);
1671 store_alist_res(lc, item, index, pass);
1676 * Store Migration/Copy type
1679 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1683 token = lex_get_token(lc, T_NAME);
1684 /* Store the type both pass 1 and pass 2 */
1685 for (i=0; migtypes[i].type_name; i++) {
1686 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1687 *(uint32_t *)(item->value) = migtypes[i].job_type;
1693 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1696 set_bit(index, res_all.hdr.item_present);
1702 * Store JobType (backup, verify, restore)
1705 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1709 token = lex_get_token(lc, T_NAME);
1710 /* Store the type both pass 1 and pass 2 */
1711 for (i=0; jobtypes[i].type_name; i++) {
1712 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1713 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1719 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1722 set_bit(index, res_all.hdr.item_present);
1726 * Store Job Level (Full, Incremental, ...)
1729 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1733 token = lex_get_token(lc, T_NAME);
1734 /* Store the level pass 2 so that type is defined */
1735 for (i=0; joblevels[i].level_name; i++) {
1736 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1737 *(uint32_t *)(item->value) = joblevels[i].level;
1743 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1746 set_bit(index, res_all.hdr.item_present);
1750 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1753 token = lex_get_token(lc, T_NAME);
1754 /* Scan Replacement options */
1755 for (i=0; ReplaceOptions[i].name; i++) {
1756 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1757 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1763 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1766 set_bit(index, res_all.hdr.item_present);
1770 * Store ACL (access control list)
1773 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1778 token = lex_get_token(lc, T_STRING);
1780 if (((alist **)item->value)[item->code] == NULL) {
1781 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1782 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1784 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1785 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1787 token = lex_get_token(lc, T_ALL);
1788 if (token == T_COMMA) {
1789 continue; /* get another ACL */
1793 set_bit(index, res_all.hdr.item_present);
1796 /* We build RunScripts items here */
1797 static RUNSCRIPT res_runscript;
1799 /* Store a runscript->when in a bit field */
1800 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1802 lex_get_token(lc, T_NAME);
1804 if (strcasecmp(lc->str, "before") == 0) {
1805 *(uint32_t *)(item->value) = SCRIPT_Before ;
1806 } else if (strcasecmp(lc->str, "after") == 0) {
1807 *(uint32_t *)(item->value) = SCRIPT_After;
1808 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1809 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1810 } else if (strcasecmp(lc->str, "always") == 0) {
1811 *(uint32_t *)(item->value) = SCRIPT_Any;
1813 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1818 /* Store a runscript->target
1821 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1823 lex_get_token(lc, T_STRING);
1826 if (strcmp(lc->str, "%c") == 0) {
1827 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1828 } else if (strcasecmp(lc->str, "yes") == 0) {
1829 ((RUNSCRIPT*) item->value)->set_target("%c");
1830 } else if (strcasecmp(lc->str, "no") == 0) {
1831 ((RUNSCRIPT*) item->value)->set_target("");
1833 RES *res = GetResWithName(R_CLIENT, lc->str);
1835 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1836 lc->str, lc->line_no, lc->line);
1839 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1846 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1848 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1850 lex_get_token(lc, T_STRING);
1853 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1854 POOLMEM *c = get_pool_memory(PM_FNAME);
1855 /* Each runscript command takes 2 entries in commands list */
1856 pm_strcpy(c, lc->str);
1857 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1858 ((RUNSCRIPT*) item->value)->commands->prepend((void *)item->code); /* command type */
1863 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1865 lex_get_token(lc, T_STRING);
1866 alist **runscripts = (alist **)(item->value) ;
1869 RUNSCRIPT *script = new_runscript();
1870 script->set_job_code_callback(job_code_callback_filesetname);
1872 script->set_command(lc->str);
1874 /* TODO: remove all script->old_proto with bacula 1.42 */
1876 if (strcmp(item->name, "runbeforejob") == 0) {
1877 script->when = SCRIPT_Before;
1878 script->fail_on_error = true;
1879 script->set_target("");
1881 } else if (strcmp(item->name, "runafterjob") == 0) {
1882 script->when = SCRIPT_After;
1883 script->on_success = true;
1884 script->on_failure = false;
1885 script->set_target("");
1887 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1888 script->old_proto = true;
1889 script->when = SCRIPT_After;
1890 script->set_target("%c");
1891 script->on_success = true;
1892 script->on_failure = false;
1894 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1895 script->old_proto = true;
1896 script->when = SCRIPT_Before;
1897 script->set_target("%c");
1898 script->fail_on_error = true;
1900 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1901 script->when = SCRIPT_After;
1902 script->on_failure = true;
1903 script->on_success = false;
1904 script->set_target("");
1907 if (*runscripts == NULL) {
1908 *runscripts = New(alist(10, not_owned_by_alist));
1911 (*runscripts)->append(script);
1918 /* Store a bool in a bit field without modifing res_all.hdr
1919 * We can also add an option to store_bool to skip res_all.hdr
1921 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1923 lex_get_token(lc, T_NAME);
1924 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1925 *(bool *)(item->value) = true;
1926 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1927 *(bool *)(item->value) = false;
1929 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1935 * new RunScript items
1936 * name handler value code flags default_value
1938 static RES_ITEM runscript_items[] = {
1939 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1940 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1941 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1942 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1943 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1944 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1945 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1946 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1947 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1948 {NULL, NULL, {0}, 0, 0, 0}
1952 * Store RunScript info
1954 * Note, when this routine is called, we are inside a Job
1955 * resource. We treat the RunScript like a sort of
1956 * mini-resource within the Job resource.
1958 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1962 alist **runscripts = (alist **)(item->value) ;
1964 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1966 token = lex_get_token(lc, T_SKIP_EOL);
1968 if (token != T_BOB) {
1969 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1971 /* setting on_success, on_failure, fail_on_error */
1972 res_runscript.reset_default();
1975 res_runscript.commands = New(alist(10, not_owned_by_alist));
1978 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1979 if (token == T_EOB) {
1982 if (token != T_IDENTIFIER) {
1983 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1985 for (i=0; runscript_items[i].name; i++) {
1986 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1987 token = lex_get_token(lc, T_SKIP_EOL);
1988 if (token != T_EQUALS) {
1989 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1992 /* Call item handler */
1993 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2000 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2005 /* run on client by default */
2006 if (res_runscript.target == NULL) {
2007 res_runscript.set_target("%c");
2009 if (*runscripts == NULL) {
2010 *runscripts = New(alist(10, not_owned_by_alist));
2013 * commands list contains 2 values per command
2014 * - POOLMEM command string (ex: /bin/true)
2015 * - int command type (ex: SHELL_CMD)
2017 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2018 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2019 t = (intptr_t)res_runscript.commands->pop();
2020 RUNSCRIPT *script = new_runscript();
2021 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2022 script->command = c;
2023 script->cmd_type = t;
2024 /* target is taken from res_runscript, each runscript object have
2027 script->target = NULL;
2028 script->set_target(res_runscript.target);
2030 (*runscripts)->append(script);
2033 delete res_runscript.commands;
2034 /* setting on_success, on_failure... cleanup target field */
2035 res_runscript.reset_default(true);
2039 set_bit(index, res_all.hdr.item_present);
2042 /* callback function for edit_job_codes */
2043 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2045 if (param[0] == 'f') {
2046 return jcr->fileset->name();
2052 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2054 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2055 r_first, r_last, resources, res_head);
2056 return config->parse_config();