2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula Directors,
30 * some parts may be split into separate files such as
31 * the schedule configuration (run_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, January MM
55 /* Define the first and last resource ID record
56 * types. Note, these should be unique for each
57 * daemon though not a requirement.
59 int32_t r_first = R_FIRST;
60 int32_t r_last = R_LAST;
61 static RES *sres_head[R_LAST - R_FIRST + 1];
62 RES **res_head = sres_head;
64 /* Imported subroutines */
65 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
66 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
70 /* Forward referenced subroutines */
72 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
73 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
77 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
84 /* We build the current resource here as we are
85 * scanning the resource configuration definition,
86 * then move it to allocated memory when the resource
90 extern "C" { // work around visual compiler mangling variables
96 int32_t res_all_size = sizeof(res_all);
99 /* Definition of records permitted within each
100 * resource with the routine to process the record
101 * information. NOTE! quoted names must be in lower case.
106 * name handler value code flags default_value
108 static RES_ITEM dir_items[] = {
109 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
110 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
111 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
112 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"dirsourceaddress",store_addresses_address, ITEM(res_dir.DIRsrc_addr), 0, ITEM_DEFAULT, 0},
116 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
117 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
118 {"plugindirectory", store_dir, ITEM(res_dir.plugin_directory), 0, 0, 0},
119 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
120 {"piddirectory", store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
121 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
122 {"maximumconcurrentjobs", store_pint32, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
123 {"maximumconsoleconnections", store_pint32, ITEM(res_dir.MaxConsoleConnect), 0, ITEM_DEFAULT, 20},
124 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
125 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 3 * 60},
126 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 30 * 60},
127 {"heartbeatinterval", store_time, ITEM(res_dir.heartbeat_interval), 0, ITEM_DEFAULT, 0},
128 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
129 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
130 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
131 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
132 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
133 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
134 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
135 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
136 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
137 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
138 {"statisticsretention", store_time, ITEM(res_dir.stats_retention), 0, ITEM_DEFAULT, 60*60*24*31*12*5},
139 {"verid", store_str, ITEM(res_dir.verid), 0, 0, 0},
140 {NULL, NULL, {0}, 0, 0, 0}
146 * name handler value code flags default_value
148 static RES_ITEM con_items[] = {
149 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
150 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
151 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
152 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
153 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
154 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
155 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
156 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
157 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
158 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
159 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
160 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
161 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
162 {"pluginoptionsacl", store_acl, ITEM(res_con.ACL_lists), PluginOptions_ACL, 0, 0},
163 {"tlsauthenticate", store_bool, ITEM(res_con.tls_authenticate), 0, 0, 0},
164 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
165 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
166 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
167 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
168 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
169 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
170 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
171 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
172 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
173 {NULL, NULL, {0}, 0, 0, 0}
178 * Client or File daemon resource
180 * name handler value code flags default_value
183 static RES_ITEM cli_items[] = {
184 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
185 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
186 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
187 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
188 {"fdport", store_pint32, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
189 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
190 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
191 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
192 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
193 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
194 {"heartbeatinterval", store_time, ITEM(res_client.heartbeat_interval), 0, ITEM_DEFAULT, 0},
195 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
196 {"maximumconcurrentjobs", store_pint32, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
197 {"tlsauthenticate", store_bool, ITEM(res_client.tls_authenticate), 0, 0, 0},
198 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
199 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
200 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
201 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
202 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
203 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
204 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
205 {NULL, NULL, {0}, 0, 0, 0}
208 /* Storage daemon resource
210 * name handler value code flags default_value
212 static RES_ITEM store_items[] = {
213 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
214 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
215 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
216 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
217 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
218 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
219 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
220 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
221 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
222 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
223 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
224 {"allowcompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
225 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
226 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
227 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
228 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
229 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
230 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
231 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
232 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
233 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
234 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
235 {NULL, NULL, {0}, 0, 0, 0}
239 * Catalog Resource Directives
241 * name handler value code flags default_value
243 static RES_ITEM cat_items[] = {
244 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
245 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
246 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
247 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
248 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
249 /* keep this password as store_str for the moment */
250 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
251 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
252 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
253 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
254 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
255 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
256 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
257 /* Turned off for the moment */
258 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
259 {"disablebatchinsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
260 {NULL, NULL, {0}, 0, 0, 0}
264 * Job Resource Directives
266 * name handler value code flags default_value
268 RES_ITEM job_items[] = {
269 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
270 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
271 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
272 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
273 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
274 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
275 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
276 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
277 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
278 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
279 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
280 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
281 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
282 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
283 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
284 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
285 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
286 /* Root of where to restore files */
287 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
288 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
289 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
290 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
291 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
292 /* Where to find bootstrap during restore */
293 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
294 /* Where to write bootstrap file during backup */
295 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
296 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
297 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
298 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
299 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
300 /* xxxMaxWaitTime are deprecated */
301 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
302 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
303 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
304 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
305 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
306 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
307 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
308 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
309 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
310 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
311 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
312 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
313 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
314 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
315 {"purgemigrationjob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
316 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
317 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
318 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
319 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
320 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
321 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
322 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
323 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
327 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
328 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
329 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
330 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 5},
331 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
332 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
333 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
334 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
335 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
336 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
337 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
338 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
339 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
340 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
341 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
342 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
343 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
344 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
345 {NULL, NULL, {0}, 0, 0, 0}
350 * name handler value code flags default_value
352 static RES_ITEM fs_items[] = {
353 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
354 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
355 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
356 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
357 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
358 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
359 {NULL, NULL, {0}, 0, 0, 0}
362 /* Schedule -- see run_conf.c */
365 * name handler value code flags default_value
367 static RES_ITEM sch_items[] = {
368 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
369 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
370 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
371 {NULL, NULL, {0}, 0, 0, 0}
376 * name handler value code flags default_value
378 static RES_ITEM pool_items[] = {
379 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
380 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
381 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
382 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
383 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
384 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
385 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
386 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
387 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
388 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
389 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
390 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
391 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
392 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
393 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
394 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
395 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
396 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
397 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
398 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
399 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
400 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
401 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
402 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
403 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
404 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
405 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
406 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
407 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
408 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
409 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
410 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
412 {NULL, NULL, {0}, 0, 0, 0}
417 * name handler value code flags default_value
419 static RES_ITEM counter_items[] = {
420 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
421 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
422 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
423 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
424 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
425 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
426 {NULL, NULL, {0}, 0, 0, 0}
430 /* Message resource */
431 extern RES_ITEM msgs_items[];
434 * This is the master resource definition.
435 * It must have one item for each of the resources.
437 * NOTE!!! keep it in the same order as the R_codes
438 * or eliminate all resources[rindex].name
440 * name items rcode res_head
442 RES_TABLE resources[] = {
443 {"director", dir_items, R_DIRECTOR},
444 {"client", cli_items, R_CLIENT},
445 {"job", job_items, R_JOB},
446 {"storage", store_items, R_STORAGE},
447 {"catalog", cat_items, R_CATALOG},
448 {"schedule", sch_items, R_SCHEDULE},
449 {"fileset", fs_items, R_FILESET},
450 {"pool", pool_items, R_POOL},
451 {"messages", msgs_items, R_MSGS},
452 {"counter", counter_items, R_COUNTER},
453 {"console", con_items, R_CONSOLE},
454 {"jobdefs", job_items, R_JOBDEFS},
455 {"device", NULL, R_DEVICE}, /* info obtained from SD */
460 /* Keywords (RHS) permitted in Job Level records
462 * level_name level job_type
464 struct s_jl joblevels[] = {
465 {"Full", L_FULL, JT_BACKUP},
466 {"Base", L_BASE, JT_BACKUP},
467 {"Incremental", L_INCREMENTAL, JT_BACKUP},
468 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
469 {"Since", L_SINCE, JT_BACKUP},
470 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
471 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
472 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
473 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
474 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
475 {"Data", L_VERIFY_DATA, JT_VERIFY},
476 {" ", L_NONE, JT_ADMIN},
477 {" ", L_NONE, JT_RESTORE},
481 /* Keywords (RHS) permitted in Job type records
485 struct s_jt jobtypes[] = {
486 {"backup", JT_BACKUP},
488 {"verify", JT_VERIFY},
489 {"restore", JT_RESTORE},
490 {"migrate", JT_MIGRATE},
496 /* Keywords (RHS) permitted in Selection type records
500 struct s_jt migtypes[] = {
501 {"smallestvolume", MT_SMALLEST_VOL},
502 {"oldestvolume", MT_OLDEST_VOL},
503 {"pooloccupancy", MT_POOL_OCCUPANCY},
504 {"pooltime", MT_POOL_TIME},
505 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
506 {"client", MT_CLIENT},
507 {"volume", MT_VOLUME},
509 {"sqlquery", MT_SQLQUERY},
515 /* Options permitted in Restore replace= */
516 struct s_kw ReplaceOptions[] = {
517 {"always", REPLACE_ALWAYS},
518 {"ifnewer", REPLACE_IFNEWER},
519 {"ifolder", REPLACE_IFOLDER},
520 {"never", REPLACE_NEVER},
524 char *CAT::display(POOLMEM *dst) {
525 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
526 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
528 name(), NPRTB(db_name),
529 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
530 NPRTB(db_address), db_port, NPRTB(db_socket));
534 const char *level_to_str(int level)
537 static char level_no[30];
538 const char *str = level_no;
540 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
541 for (i=0; joblevels[i].level_name; i++) {
542 if (level == (int)joblevels[i].level) {
543 str = joblevels[i].level_name;
550 /* Dump contents of resource */
551 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
553 URES *res = (URES *)reshdr;
555 char ed1[100], ed2[100], ed3[100];
559 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
562 if (type < 0) { /* no recursion */
568 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
569 reshdr->name, res->res_dir.MaxConcurrentJobs,
570 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
571 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
572 if (res->res_dir.query_file) {
573 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
575 if (res->res_dir.messages) {
576 sendit(sock, _(" --> "));
577 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
581 sendit(sock, _("Console: name=%s SSL=%d\n"),
582 res->res_con.hdr.name, res->res_con.tls_enable);
585 if (res->res_counter.WrapCounter) {
586 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
587 res->res_counter.hdr.name, res->res_counter.MinValue,
588 res->res_counter.MaxValue, res->res_counter.CurrentValue,
589 res->res_counter.WrapCounter->hdr.name);
591 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
592 res->res_counter.hdr.name, res->res_counter.MinValue,
593 res->res_counter.MaxValue);
595 if (res->res_counter.Catalog) {
596 sendit(sock, _(" --> "));
597 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
602 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
603 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
604 res->res_client.MaxConcurrentJobs);
605 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
606 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
607 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
608 res->res_client.AutoPrune);
609 if (res->res_client.catalog) {
610 sendit(sock, _(" --> "));
611 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
618 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
619 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
620 " poolid=%s volname=%s MediaType=%s\n"),
621 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
622 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
623 dev->offline, dev->autochanger,
624 edit_uint64(dev->PoolId, ed1),
625 dev->VolumeName, dev->MediaType);
629 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
630 " DeviceName=%s MediaType=%s StorageId=%s\n"),
631 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
632 res->res_store.MaxConcurrentJobs,
633 res->res_store.dev_name(),
634 res->res_store.media_type,
635 edit_int64(res->res_store.StorageId, ed1));
639 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
640 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
641 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
642 res->res_cat.db_port, res->res_cat.db_name,
643 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
644 res->res_cat.mult_db_connections);
649 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
650 type == R_JOB ? _("Job") : _("JobDefs"),
651 res->res_job.hdr.name, res->res_job.JobType,
652 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
653 res->res_job.enabled);
654 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
655 res->res_job.MaxConcurrentJobs,
656 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
657 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
658 res->res_job.spool_data, res->res_job.write_part_after_job);
659 if (res->res_job.spool_size) {
660 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
662 if (res->res_job.JobType == JT_BACKUP) {
663 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
665 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
666 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
668 if (res->res_job.client) {
669 sendit(sock, _(" --> "));
670 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
672 if (res->res_job.fileset) {
673 sendit(sock, _(" --> "));
674 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
676 if (res->res_job.schedule) {
677 sendit(sock, _(" --> "));
678 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
680 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
681 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
683 if (res->res_job.RegexWhere) {
684 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
686 if (res->res_job.RestoreBootstrap) {
687 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
689 if (res->res_job.WriteBootstrap) {
690 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
692 if (res->res_job.PluginOptions) {
693 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
695 if (res->res_job.MaxRunTime) {
696 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
698 if (res->res_job.MaxWaitTime) {
699 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
701 if (res->res_job.MaxStartDelay) {
702 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
704 if (res->res_job.MaxRunSchedTime) {
705 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
707 if (res->res_job.storage) {
709 foreach_alist(store, res->res_job.storage) {
710 sendit(sock, _(" --> "));
711 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
714 if (res->res_job.base) {
716 foreach_alist(job, res->res_job.base) {
717 sendit(sock, _(" --> Base %s\n"), job->name());
720 if (res->res_job.RunScripts) {
722 foreach_alist(script, res->res_job.RunScripts) {
723 sendit(sock, _(" --> RunScript\n"));
724 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
725 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
726 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
727 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
728 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
729 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
732 if (res->res_job.pool) {
733 sendit(sock, _(" --> "));
734 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
736 if (res->res_job.full_pool) {
737 sendit(sock, _(" --> "));
738 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
740 if (res->res_job.inc_pool) {
741 sendit(sock, _(" --> "));
742 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
744 if (res->res_job.diff_pool) {
745 sendit(sock, _(" --> "));
746 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
748 if (res->res_job.verify_job) {
749 sendit(sock, _(" --> "));
750 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
752 if (res->res_job.run_cmds) {
754 foreach_alist(runcmd, res->res_job.run_cmds) {
755 sendit(sock, _(" --> Run=%s\n"), runcmd);
758 if (res->res_job.selection_pattern) {
759 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
761 if (res->res_job.messages) {
762 sendit(sock, _(" --> "));
763 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
770 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
771 for (i=0; i<res->res_fs.num_includes; i++) {
772 INCEXE *incexe = res->res_fs.include_items[i];
773 for (j=0; j<incexe->num_opts; j++) {
774 FOPTS *fo = incexe->opts_list[j];
775 sendit(sock, " O %s\n", fo->opts);
777 bool enhanced_wild = false;
778 for (k=0; fo->opts[k]!='\0'; k++) {
779 if (fo->opts[k]=='W') {
780 enhanced_wild = true;
785 for (k=0; k<fo->regex.size(); k++) {
786 sendit(sock, " R %s\n", fo->regex.get(k));
788 for (k=0; k<fo->regexdir.size(); k++) {
789 sendit(sock, " RD %s\n", fo->regexdir.get(k));
791 for (k=0; k<fo->regexfile.size(); k++) {
792 sendit(sock, " RF %s\n", fo->regexfile.get(k));
794 for (k=0; k<fo->wild.size(); k++) {
795 sendit(sock, " W %s\n", fo->wild.get(k));
797 for (k=0; k<fo->wilddir.size(); k++) {
798 sendit(sock, " WD %s\n", fo->wilddir.get(k));
800 for (k=0; k<fo->wildfile.size(); k++) {
801 sendit(sock, " WF %s\n", fo->wildfile.get(k));
803 for (k=0; k<fo->wildbase.size(); k++) {
804 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
806 for (k=0; k<fo->base.size(); k++) {
807 sendit(sock, " B %s\n", fo->base.get(k));
809 for (k=0; k<fo->fstype.size(); k++) {
810 sendit(sock, " X %s\n", fo->fstype.get(k));
812 for (k=0; k<fo->drivetype.size(); k++) {
813 sendit(sock, " XD %s\n", fo->drivetype.get(k));
816 sendit(sock, " G %s\n", fo->plugin);
819 sendit(sock, " D %s\n", fo->reader);
822 sendit(sock, " T %s\n", fo->writer);
824 sendit(sock, " N\n");
826 if (incexe->ignoredir) {
827 sendit(sock, " Z %s\n", incexe->ignoredir);
829 for (j=0; j<incexe->name_list.size(); j++) {
830 sendit(sock, " I %s\n", incexe->name_list.get(j));
832 if (incexe->name_list.size()) {
833 sendit(sock, " N\n");
835 for (j=0; j<incexe->plugin_list.size(); j++) {
836 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
838 if (incexe->plugin_list.size()) {
839 sendit(sock, " N\n");
844 for (i=0; i<res->res_fs.num_excludes; i++) {
845 INCEXE *incexe = res->res_fs.exclude_items[i];
846 for (j=0; j<incexe->name_list.size(); j++) {
847 sendit(sock, " E %s\n", incexe->name_list.get(j));
849 if (incexe->name_list.size()) {
850 sendit(sock, " N\n");
857 if (res->res_sch.run) {
859 RUN *run = res->res_sch.run;
860 char buf[1000], num[30];
861 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
866 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
867 bstrncpy(buf, _(" hour="), sizeof(buf));
868 for (i=0; i<24; i++) {
869 if (bit_is_set(i, run->hour)) {
870 bsnprintf(num, sizeof(num), "%d ", i);
871 bstrncat(buf, num, sizeof(buf));
874 bstrncat(buf, "\n", sizeof(buf));
876 bstrncpy(buf, _(" mday="), sizeof(buf));
877 for (i=0; i<31; i++) {
878 if (bit_is_set(i, run->mday)) {
879 bsnprintf(num, sizeof(num), "%d ", i);
880 bstrncat(buf, num, sizeof(buf));
883 bstrncat(buf, "\n", sizeof(buf));
885 bstrncpy(buf, _(" month="), sizeof(buf));
886 for (i=0; i<12; i++) {
887 if (bit_is_set(i, run->month)) {
888 bsnprintf(num, sizeof(num), "%d ", i);
889 bstrncat(buf, num, sizeof(buf));
892 bstrncat(buf, "\n", sizeof(buf));
894 bstrncpy(buf, _(" wday="), sizeof(buf));
895 for (i=0; i<7; i++) {
896 if (bit_is_set(i, run->wday)) {
897 bsnprintf(num, sizeof(num), "%d ", i);
898 bstrncat(buf, num, sizeof(buf));
901 bstrncat(buf, "\n", sizeof(buf));
903 bstrncpy(buf, _(" wom="), sizeof(buf));
904 for (i=0; i<5; i++) {
905 if (bit_is_set(i, run->wom)) {
906 bsnprintf(num, sizeof(num), "%d ", i);
907 bstrncat(buf, num, sizeof(buf));
910 bstrncat(buf, "\n", sizeof(buf));
912 bstrncpy(buf, _(" woy="), sizeof(buf));
913 for (i=0; i<54; i++) {
914 if (bit_is_set(i, run->woy)) {
915 bsnprintf(num, sizeof(num), "%d ", i);
916 bstrncat(buf, num, sizeof(buf));
919 bstrncat(buf, "\n", sizeof(buf));
921 sendit(sock, _(" mins=%d\n"), run->minute);
923 sendit(sock, _(" --> "));
924 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
927 sendit(sock, _(" --> "));
928 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
931 sendit(sock, _(" --> "));
932 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
934 /* If another Run record is chained in, go print it */
940 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
945 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
946 res->res_pool.pool_type);
947 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
948 res->res_pool.use_catalog, res->res_pool.use_volume_once,
949 res->res_pool.catalog_files);
950 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
951 res->res_pool.max_volumes, res->res_pool.AutoPrune,
952 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
953 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
954 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
955 res->res_pool.Recycle,
956 NPRT(res->res_pool.label_format));
957 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
958 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
959 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
960 res->res_pool.recycle_oldest_volume,
961 res->res_pool.purge_oldest_volume,
962 res->res_pool.action_on_purge);
963 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
964 res->res_pool.MaxVolJobs,
965 res->res_pool.MaxVolFiles,
966 edit_uint64(res->res_pool.MaxVolBytes, ed1));
967 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
968 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
969 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
970 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
971 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
972 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
973 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
974 if (res->res_pool.NextPool) {
975 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
977 if (res->res_pool.RecyclePool) {
978 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
980 if (res->res_pool.ScratchPool) {
981 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
983 if (res->res_pool.catalog) {
984 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
986 if (res->res_pool.storage) {
988 foreach_alist(store, res->res_pool.storage) {
989 sendit(sock, _(" --> "));
990 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
993 if (res->res_pool.CopyPool) {
995 foreach_alist(copy, res->res_pool.CopyPool) {
996 sendit(sock, _(" --> "));
997 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1004 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1005 if (res->res_msgs.mail_cmd)
1006 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1007 if (res->res_msgs.operator_cmd)
1008 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1012 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1015 if (recurse && res->res_dir.hdr.next) {
1016 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1021 * Free all the members of an INCEXE structure
1023 static void free_incexe(INCEXE *incexe)
1025 incexe->name_list.destroy();
1026 incexe->plugin_list.destroy();
1027 for (int i=0; i<incexe->num_opts; i++) {
1028 FOPTS *fopt = incexe->opts_list[i];
1029 fopt->regex.destroy();
1030 fopt->regexdir.destroy();
1031 fopt->regexfile.destroy();
1032 fopt->wild.destroy();
1033 fopt->wilddir.destroy();
1034 fopt->wildfile.destroy();
1035 fopt->wildbase.destroy();
1036 fopt->base.destroy();
1037 fopt->fstype.destroy();
1038 fopt->drivetype.destroy();
1050 if (incexe->opts_list) {
1051 free(incexe->opts_list);
1053 if (incexe->ignoredir) {
1054 free(incexe->ignoredir);
1060 * Free memory of resource -- called when daemon terminates.
1061 * NB, we don't need to worry about freeing any references
1062 * to other resources as they will be freed when that
1063 * resource chain is traversed. Mainly we worry about freeing
1064 * allocated strings (names).
1066 void free_resource(RES *sres, int type)
1069 RES *nres; /* next resource if linked */
1070 URES *res = (URES *)sres;
1075 /* common stuff -- free the resource name and description */
1076 nres = (RES *)res->res_dir.hdr.next;
1077 if (res->res_dir.hdr.name) {
1078 free(res->res_dir.hdr.name);
1080 if (res->res_dir.hdr.desc) {
1081 free(res->res_dir.hdr.desc);
1086 if (res->res_dir.working_directory) {
1087 free(res->res_dir.working_directory);
1089 if (res->res_dir.scripts_directory) {
1090 free((char *)res->res_dir.scripts_directory);
1092 if (res->res_dir.plugin_directory) {
1093 free((char *)res->res_dir.plugin_directory);
1095 if (res->res_dir.pid_directory) {
1096 free(res->res_dir.pid_directory);
1098 if (res->res_dir.subsys_directory) {
1099 free(res->res_dir.subsys_directory);
1101 if (res->res_dir.password) {
1102 free(res->res_dir.password);
1104 if (res->res_dir.query_file) {
1105 free(res->res_dir.query_file);
1107 if (res->res_dir.DIRaddrs) {
1108 free_addresses(res->res_dir.DIRaddrs);
1110 if (res->res_dir.DIRsrc_addr) {
1111 free_addresses(res->res_dir.DIRsrc_addr);
1113 if (res->res_dir.tls_ctx) {
1114 free_tls_context(res->res_dir.tls_ctx);
1116 if (res->res_dir.tls_ca_certfile) {
1117 free(res->res_dir.tls_ca_certfile);
1119 if (res->res_dir.tls_ca_certdir) {
1120 free(res->res_dir.tls_ca_certdir);
1122 if (res->res_dir.tls_certfile) {
1123 free(res->res_dir.tls_certfile);
1125 if (res->res_dir.tls_keyfile) {
1126 free(res->res_dir.tls_keyfile);
1128 if (res->res_dir.tls_dhfile) {
1129 free(res->res_dir.tls_dhfile);
1131 if (res->res_dir.tls_allowed_cns) {
1132 delete res->res_dir.tls_allowed_cns;
1134 if (res->res_dir.verid) {
1135 free(res->res_dir.verid);
1142 if (res->res_con.password) {
1143 free(res->res_con.password);
1145 if (res->res_con.tls_ctx) {
1146 free_tls_context(res->res_con.tls_ctx);
1148 if (res->res_con.tls_ca_certfile) {
1149 free(res->res_con.tls_ca_certfile);
1151 if (res->res_con.tls_ca_certdir) {
1152 free(res->res_con.tls_ca_certdir);
1154 if (res->res_con.tls_certfile) {
1155 free(res->res_con.tls_certfile);
1157 if (res->res_con.tls_keyfile) {
1158 free(res->res_con.tls_keyfile);
1160 if (res->res_con.tls_dhfile) {
1161 free(res->res_con.tls_dhfile);
1163 if (res->res_con.tls_allowed_cns) {
1164 delete res->res_con.tls_allowed_cns;
1166 for (int i=0; i<Num_ACL; i++) {
1167 if (res->res_con.ACL_lists[i]) {
1168 delete res->res_con.ACL_lists[i];
1169 res->res_con.ACL_lists[i] = NULL;
1174 if (res->res_client.address) {
1175 free(res->res_client.address);
1177 if (res->res_client.password) {
1178 free(res->res_client.password);
1180 if (res->res_client.tls_ctx) {
1181 free_tls_context(res->res_client.tls_ctx);
1183 if (res->res_client.tls_ca_certfile) {
1184 free(res->res_client.tls_ca_certfile);
1186 if (res->res_client.tls_ca_certdir) {
1187 free(res->res_client.tls_ca_certdir);
1189 if (res->res_client.tls_certfile) {
1190 free(res->res_client.tls_certfile);
1192 if (res->res_client.tls_keyfile) {
1193 free(res->res_client.tls_keyfile);
1195 if (res->res_client.tls_allowed_cns) {
1196 delete res->res_client.tls_allowed_cns;
1200 if (res->res_store.address) {
1201 free(res->res_store.address);
1203 if (res->res_store.password) {
1204 free(res->res_store.password);
1206 if (res->res_store.media_type) {
1207 free(res->res_store.media_type);
1209 if (res->res_store.device) {
1210 delete res->res_store.device;
1212 if (res->res_store.tls_ctx) {
1213 free_tls_context(res->res_store.tls_ctx);
1215 if (res->res_store.tls_ca_certfile) {
1216 free(res->res_store.tls_ca_certfile);
1218 if (res->res_store.tls_ca_certdir) {
1219 free(res->res_store.tls_ca_certdir);
1221 if (res->res_store.tls_certfile) {
1222 free(res->res_store.tls_certfile);
1224 if (res->res_store.tls_keyfile) {
1225 free(res->res_store.tls_keyfile);
1229 if (res->res_cat.db_address) {
1230 free(res->res_cat.db_address);
1232 if (res->res_cat.db_socket) {
1233 free(res->res_cat.db_socket);
1235 if (res->res_cat.db_user) {
1236 free(res->res_cat.db_user);
1238 if (res->res_cat.db_name) {
1239 free(res->res_cat.db_name);
1241 if (res->res_cat.db_driver) {
1242 free(res->res_cat.db_driver);
1244 if (res->res_cat.db_password) {
1245 free(res->res_cat.db_password);
1249 if ((num=res->res_fs.num_includes)) {
1250 while (--num >= 0) {
1251 free_incexe(res->res_fs.include_items[num]);
1253 free(res->res_fs.include_items);
1255 res->res_fs.num_includes = 0;
1256 if ((num=res->res_fs.num_excludes)) {
1257 while (--num >= 0) {
1258 free_incexe(res->res_fs.exclude_items[num]);
1260 free(res->res_fs.exclude_items);
1262 res->res_fs.num_excludes = 0;
1265 if (res->res_pool.pool_type) {
1266 free(res->res_pool.pool_type);
1268 if (res->res_pool.label_format) {
1269 free(res->res_pool.label_format);
1271 if (res->res_pool.cleaning_prefix) {
1272 free(res->res_pool.cleaning_prefix);
1274 if (res->res_pool.storage) {
1275 delete res->res_pool.storage;
1279 if (res->res_sch.run) {
1281 nrun = res->res_sch.run;
1291 if (res->res_job.RestoreWhere) {
1292 free(res->res_job.RestoreWhere);
1294 if (res->res_job.RegexWhere) {
1295 free(res->res_job.RegexWhere);
1297 if (res->res_job.strip_prefix) {
1298 free(res->res_job.strip_prefix);
1300 if (res->res_job.add_prefix) {
1301 free(res->res_job.add_prefix);
1303 if (res->res_job.add_suffix) {
1304 free(res->res_job.add_suffix);
1306 if (res->res_job.RestoreBootstrap) {
1307 free(res->res_job.RestoreBootstrap);
1309 if (res->res_job.WriteBootstrap) {
1310 free(res->res_job.WriteBootstrap);
1312 if (res->res_job.PluginOptions) {
1313 free(res->res_job.PluginOptions);
1315 if (res->res_job.selection_pattern) {
1316 free(res->res_job.selection_pattern);
1318 if (res->res_job.run_cmds) {
1319 delete res->res_job.run_cmds;
1321 if (res->res_job.storage) {
1322 delete res->res_job.storage;
1324 if (res->res_job.base) {
1325 delete res->res_job.base;
1327 if (res->res_job.RunScripts) {
1328 free_runscripts(res->res_job.RunScripts);
1329 delete res->res_job.RunScripts;
1333 if (res->res_msgs.mail_cmd) {
1334 free(res->res_msgs.mail_cmd);
1336 if (res->res_msgs.operator_cmd) {
1337 free(res->res_msgs.operator_cmd);
1339 free_msgs_res((MSGS *)res); /* free message resource */
1343 printf(_("Unknown resource type %d in free_resource.\n"), type);
1345 /* Common stuff again -- free the resource, recurse to next one */
1350 free_resource(nres, type);
1355 * Save the new resource by chaining it into the head list for
1356 * the resource. If this is pass 2, we update any resource
1357 * pointers because they may not have been defined until
1360 void save_resource(int type, RES_ITEM *items, int pass)
1363 int rindex = type - r_first;
1367 /* Check Job requirements after applying JobDefs */
1368 if (type != R_JOB && type != R_JOBDEFS) {
1370 * Ensure that all required items are present
1372 for (i=0; items[i].name; i++) {
1373 if (items[i].flags & ITEM_REQUIRED) {
1374 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1375 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1376 items[i].name, resources[rindex]);
1379 /* If this triggers, take a look at lib/parse_conf.h */
1380 if (i >= MAX_RES_ITEMS) {
1381 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1384 } else if (type == R_JOB) {
1386 * Ensure that the name item is present
1388 if (items[0].flags & ITEM_REQUIRED) {
1389 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1390 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1391 items[0].name, resources[rindex]);
1397 * During pass 2 in each "store" routine, we looked up pointers
1398 * to all the resources referrenced in the current resource, now we
1399 * must copy their addresses from the static record to the allocated
1404 /* Resources not containing a resource */
1412 * Resources containing another resource or alist. First
1413 * look up the resource which contains another resource. It
1414 * was written during pass 1. Then stuff in the pointers to
1415 * the resources it contains, which were inserted this pass.
1416 * Finally, it will all be stored back.
1419 /* Find resource saved in pass 1 */
1420 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1421 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1423 /* Explicitly copy resource pointers from this pass (res_all) */
1424 res->res_pool.NextPool = res_all.res_pool.NextPool;
1425 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1426 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1427 res->res_pool.storage = res_all.res_pool.storage;
1428 res->res_pool.catalog = res_all.res_pool.catalog;
1431 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1432 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1434 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1437 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1438 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1440 res->res_dir.messages = res_all.res_dir.messages;
1441 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1444 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1445 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1446 res_all.res_dir.hdr.name);
1448 /* we must explicitly copy the device alist pointer */
1449 res->res_store.device = res_all.res_store.device;
1453 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1454 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1455 res_all.res_dir.hdr.name);
1457 res->res_job.messages = res_all.res_job.messages;
1458 res->res_job.schedule = res_all.res_job.schedule;
1459 res->res_job.client = res_all.res_job.client;
1460 res->res_job.fileset = res_all.res_job.fileset;
1461 res->res_job.storage = res_all.res_job.storage;
1462 res->res_job.base = res_all.res_job.base;
1463 res->res_job.pool = res_all.res_job.pool;
1464 res->res_job.full_pool = res_all.res_job.full_pool;
1465 res->res_job.inc_pool = res_all.res_job.inc_pool;
1466 res->res_job.diff_pool = res_all.res_job.diff_pool;
1467 res->res_job.verify_job = res_all.res_job.verify_job;
1468 res->res_job.jobdefs = res_all.res_job.jobdefs;
1469 res->res_job.run_cmds = res_all.res_job.run_cmds;
1470 res->res_job.RunScripts = res_all.res_job.RunScripts;
1472 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1473 * is not very useful)
1474 * We have to set_bit(index, res_all.hdr.item_present);
1475 * or something like that
1478 /* we take RegexWhere before all other options */
1479 if (!res->res_job.RegexWhere
1481 (res->res_job.strip_prefix ||
1482 res->res_job.add_suffix ||
1483 res->res_job.add_prefix))
1485 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1486 res->res_job.add_prefix,
1487 res->res_job.add_suffix);
1488 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1489 bregexp_build_where(res->res_job.RegexWhere, len,
1490 res->res_job.strip_prefix,
1491 res->res_job.add_prefix,
1492 res->res_job.add_suffix);
1493 /* TODO: test bregexp */
1496 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1497 free(res->res_job.RestoreWhere);
1498 res->res_job.RestoreWhere = NULL;
1503 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1504 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1506 res->res_counter.Catalog = res_all.res_counter.Catalog;
1507 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1511 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1512 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1514 res->res_client.catalog = res_all.res_client.catalog;
1515 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1519 * Schedule is a bit different in that it contains a RUN record
1520 * chain which isn't a "named" resource. This chain was linked
1521 * in by run_conf.c during pass 2, so here we jam the pointer
1522 * into the Schedule resource.
1524 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1525 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1527 res->res_sch.run = res_all.res_sch.run;
1530 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1534 /* Note, the resource name was already saved during pass 1,
1535 * so here, we can just release it.
1537 if (res_all.res_dir.hdr.name) {
1538 free(res_all.res_dir.hdr.name);
1539 res_all.res_dir.hdr.name = NULL;
1541 if (res_all.res_dir.hdr.desc) {
1542 free(res_all.res_dir.hdr.desc);
1543 res_all.res_dir.hdr.desc = NULL;
1549 * The following code is only executed during pass 1
1553 size = sizeof(DIRRES);
1556 size = sizeof(CONRES);
1559 size =sizeof(CLIENT);
1562 size = sizeof(STORE);
1572 size = sizeof(FILESET);
1575 size = sizeof(SCHED);
1578 size = sizeof(POOL);
1581 size = sizeof(MSGS);
1584 size = sizeof(COUNTER);
1590 printf(_("Unknown resource type %d in save_resource.\n"), type);
1596 res = (URES *)malloc(size);
1597 memcpy(res, &res_all, size);
1598 if (!res_head[rindex]) {
1599 res_head[rindex] = (RES *)res; /* store first entry */
1600 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1601 res->res_dir.hdr.name, rindex);
1604 if (res->res_dir.hdr.name == NULL) {
1605 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1608 /* Add new res to end of chain */
1609 for (last=next=res_head[rindex]; next; next=next->next) {
1611 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1612 Emsg2(M_ERROR_TERM, 0,
1613 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1614 resources[rindex].name, res->res_dir.hdr.name);
1617 last->next = (RES *)res;
1618 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1619 res->res_dir.hdr.name, rindex, pass);
1624 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1626 uint32_t *destination = (uint32_t*)item->value;
1627 lex_get_token(lc, T_NAME);
1628 if (strcasecmp(lc->str, "truncate") == 0) {
1629 *destination = (*destination) | ON_PURGE_TRUNCATE;
1631 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1635 set_bit(index, res_all.hdr.item_present);
1639 * Store Device. Note, the resource is created upon the
1640 * first reference. The details of the resource are obtained
1641 * later from the SD.
1643 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1646 int rindex = R_DEVICE - r_first;
1647 int size = sizeof(DEVICE);
1651 lex_get_token(lc, T_NAME);
1652 if (!res_head[rindex]) {
1653 res = (URES *)malloc(size);
1654 memset(res, 0, size);
1655 res->res_dev.hdr.name = bstrdup(lc->str);
1656 res_head[rindex] = (RES *)res; /* store first entry */
1657 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1658 res->res_dir.hdr.name, rindex);
1661 /* See if it is already defined */
1662 for (next=res_head[rindex]; next->next; next=next->next) {
1663 if (strcmp(next->name, lc->str) == 0) {
1669 res = (URES *)malloc(size);
1670 memset(res, 0, size);
1671 res->res_dev.hdr.name = bstrdup(lc->str);
1672 next->next = (RES *)res;
1673 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1674 res->res_dir.hdr.name, rindex, pass);
1679 set_bit(index, res_all.hdr.item_present);
1681 store_alist_res(lc, item, index, pass);
1686 * Store Migration/Copy type
1689 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1693 lex_get_token(lc, T_NAME);
1694 /* Store the type both pass 1 and pass 2 */
1695 for (i=0; migtypes[i].type_name; i++) {
1696 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1697 *(uint32_t *)(item->value) = migtypes[i].job_type;
1703 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1706 set_bit(index, res_all.hdr.item_present);
1712 * Store JobType (backup, verify, restore)
1715 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1719 lex_get_token(lc, T_NAME);
1720 /* Store the type both pass 1 and pass 2 */
1721 for (i=0; jobtypes[i].type_name; i++) {
1722 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1723 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1729 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1732 set_bit(index, res_all.hdr.item_present);
1736 * Store Job Level (Full, Incremental, ...)
1739 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1743 lex_get_token(lc, T_NAME);
1744 /* Store the level pass 2 so that type is defined */
1745 for (i=0; joblevels[i].level_name; i++) {
1746 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1747 *(uint32_t *)(item->value) = joblevels[i].level;
1753 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1756 set_bit(index, res_all.hdr.item_present);
1760 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1763 lex_get_token(lc, T_NAME);
1764 /* Scan Replacement options */
1765 for (i=0; ReplaceOptions[i].name; i++) {
1766 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1767 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1773 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1776 set_bit(index, res_all.hdr.item_present);
1780 * Store ACL (access control list)
1783 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1788 lex_get_token(lc, T_STRING);
1790 if (((alist **)item->value)[item->code] == NULL) {
1791 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1792 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1794 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1795 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1797 token = lex_get_token(lc, T_ALL);
1798 if (token == T_COMMA) {
1799 continue; /* get another ACL */
1803 set_bit(index, res_all.hdr.item_present);
1806 /* We build RunScripts items here */
1807 static RUNSCRIPT res_runscript;
1809 /* Store a runscript->when in a bit field */
1810 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1812 lex_get_token(lc, T_NAME);
1814 if (strcasecmp(lc->str, "before") == 0) {
1815 *(uint32_t *)(item->value) = SCRIPT_Before ;
1816 } else if (strcasecmp(lc->str, "after") == 0) {
1817 *(uint32_t *)(item->value) = SCRIPT_After;
1818 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1819 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1820 } else if (strcasecmp(lc->str, "always") == 0) {
1821 *(uint32_t *)(item->value) = SCRIPT_Any;
1823 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1828 /* Store a runscript->target
1831 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1833 lex_get_token(lc, T_STRING);
1836 if (strcmp(lc->str, "%c") == 0) {
1837 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1838 } else if (strcasecmp(lc->str, "yes") == 0) {
1839 ((RUNSCRIPT*) item->value)->set_target("%c");
1840 } else if (strcasecmp(lc->str, "no") == 0) {
1841 ((RUNSCRIPT*) item->value)->set_target("");
1843 RES *res = GetResWithName(R_CLIENT, lc->str);
1845 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1846 lc->str, lc->line_no, lc->line);
1849 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1856 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1858 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1860 lex_get_token(lc, T_STRING);
1863 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1864 POOLMEM *c = get_pool_memory(PM_FNAME);
1865 /* Each runscript command takes 2 entries in commands list */
1866 pm_strcpy(c, lc->str);
1867 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1868 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1873 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1875 lex_get_token(lc, T_STRING);
1876 alist **runscripts = (alist **)(item->value) ;
1879 RUNSCRIPT *script = new_runscript();
1880 script->set_job_code_callback(job_code_callback_director);
1882 script->set_command(lc->str);
1884 /* TODO: remove all script->old_proto with bacula 1.42 */
1886 if (strcmp(item->name, "runbeforejob") == 0) {
1887 script->when = SCRIPT_Before;
1888 script->fail_on_error = true;
1889 script->set_target("");
1891 } else if (strcmp(item->name, "runafterjob") == 0) {
1892 script->when = SCRIPT_After;
1893 script->on_success = true;
1894 script->on_failure = false;
1895 script->set_target("");
1897 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1898 script->old_proto = true;
1899 script->when = SCRIPT_After;
1900 script->set_target("%c");
1901 script->on_success = true;
1902 script->on_failure = false;
1904 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1905 script->old_proto = true;
1906 script->when = SCRIPT_Before;
1907 script->set_target("%c");
1908 script->fail_on_error = true;
1910 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1911 script->when = SCRIPT_After;
1912 script->on_failure = true;
1913 script->on_success = false;
1914 script->set_target("");
1917 if (*runscripts == NULL) {
1918 *runscripts = New(alist(10, not_owned_by_alist));
1921 (*runscripts)->append(script);
1928 /* Store a bool in a bit field without modifing res_all.hdr
1929 * We can also add an option to store_bool to skip res_all.hdr
1931 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1933 lex_get_token(lc, T_NAME);
1934 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1935 *(bool *)(item->value) = true;
1936 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1937 *(bool *)(item->value) = false;
1939 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1945 * new RunScript items
1946 * name handler value code flags default_value
1948 static RES_ITEM runscript_items[] = {
1949 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1950 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1951 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1952 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1953 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1954 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1955 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1956 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1957 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1958 {NULL, NULL, {0}, 0, 0, 0}
1962 * Store RunScript info
1964 * Note, when this routine is called, we are inside a Job
1965 * resource. We treat the RunScript like a sort of
1966 * mini-resource within the Job resource.
1968 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1972 alist **runscripts = (alist **)(item->value) ;
1974 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1976 token = lex_get_token(lc, T_SKIP_EOL);
1978 if (token != T_BOB) {
1979 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1981 /* setting on_success, on_failure, fail_on_error */
1982 res_runscript.reset_default();
1985 res_runscript.commands = New(alist(10, not_owned_by_alist));
1988 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1989 if (token == T_EOB) {
1992 if (token != T_IDENTIFIER) {
1993 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1995 for (i=0; runscript_items[i].name; i++) {
1996 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1997 token = lex_get_token(lc, T_SKIP_EOL);
1998 if (token != T_EQUALS) {
1999 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2002 /* Call item handler */
2003 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2010 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2015 /* run on client by default */
2016 if (res_runscript.target == NULL) {
2017 res_runscript.set_target("%c");
2019 if (*runscripts == NULL) {
2020 *runscripts = New(alist(10, not_owned_by_alist));
2023 * commands list contains 2 values per command
2024 * - POOLMEM command string (ex: /bin/true)
2025 * - int command type (ex: SHELL_CMD)
2027 res_runscript.set_job_code_callback(job_code_callback_director);
2028 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2029 t = (intptr_t)res_runscript.commands->pop();
2030 RUNSCRIPT *script = new_runscript();
2031 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2032 script->command = c;
2033 script->cmd_type = t;
2034 /* target is taken from res_runscript, each runscript object have
2037 script->target = NULL;
2038 script->set_target(res_runscript.target);
2040 (*runscripts)->append(script);
2043 delete res_runscript.commands;
2044 /* setting on_success, on_failure... cleanup target field */
2045 res_runscript.reset_default(true);
2049 set_bit(index, res_all.hdr.item_present);
2052 /* callback function for edit_job_codes */
2053 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2054 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2056 static char yes[] = "yes";
2057 static char no[] = "no";
2061 return jcr->fileset->name();
2066 return jcr->client->address;
2071 return jcr->pool->name();
2076 return jcr->wstore->name();
2080 return jcr->spool_data ? yes : no;
2087 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2089 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2090 r_first, r_last, resources, res_head);
2091 return config->parse_config();