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)
1647 int rindex = R_DEVICE - r_first;
1648 int size = sizeof(DEVICE);
1652 token = lex_get_token(lc, T_NAME);
1653 if (!res_head[rindex]) {
1654 res = (URES *)malloc(size);
1655 memset(res, 0, size);
1656 res->res_dev.hdr.name = bstrdup(lc->str);
1657 res_head[rindex] = (RES *)res; /* store first entry */
1658 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1659 res->res_dir.hdr.name, rindex);
1662 /* See if it is already defined */
1663 for (next=res_head[rindex]; next->next; next=next->next) {
1664 if (strcmp(next->name, lc->str) == 0) {
1670 res = (URES *)malloc(size);
1671 memset(res, 0, size);
1672 res->res_dev.hdr.name = bstrdup(lc->str);
1673 next->next = (RES *)res;
1674 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1675 res->res_dir.hdr.name, rindex, pass);
1680 set_bit(index, res_all.hdr.item_present);
1682 store_alist_res(lc, item, index, pass);
1687 * Store Migration/Copy type
1690 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1694 token = lex_get_token(lc, T_NAME);
1695 /* Store the type both pass 1 and pass 2 */
1696 for (i=0; migtypes[i].type_name; i++) {
1697 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1698 *(uint32_t *)(item->value) = migtypes[i].job_type;
1704 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1707 set_bit(index, res_all.hdr.item_present);
1713 * Store JobType (backup, verify, restore)
1716 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1720 token = lex_get_token(lc, T_NAME);
1721 /* Store the type both pass 1 and pass 2 */
1722 for (i=0; jobtypes[i].type_name; i++) {
1723 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1724 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1730 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1733 set_bit(index, res_all.hdr.item_present);
1737 * Store Job Level (Full, Incremental, ...)
1740 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1744 token = lex_get_token(lc, T_NAME);
1745 /* Store the level pass 2 so that type is defined */
1746 for (i=0; joblevels[i].level_name; i++) {
1747 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1748 *(uint32_t *)(item->value) = joblevels[i].level;
1754 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1757 set_bit(index, res_all.hdr.item_present);
1761 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1764 token = lex_get_token(lc, T_NAME);
1765 /* Scan Replacement options */
1766 for (i=0; ReplaceOptions[i].name; i++) {
1767 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1768 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1774 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1777 set_bit(index, res_all.hdr.item_present);
1781 * Store ACL (access control list)
1784 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1789 token = lex_get_token(lc, T_STRING);
1791 if (((alist **)item->value)[item->code] == NULL) {
1792 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1793 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1795 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1796 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1798 token = lex_get_token(lc, T_ALL);
1799 if (token == T_COMMA) {
1800 continue; /* get another ACL */
1804 set_bit(index, res_all.hdr.item_present);
1807 /* We build RunScripts items here */
1808 static RUNSCRIPT res_runscript;
1810 /* Store a runscript->when in a bit field */
1811 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1813 lex_get_token(lc, T_NAME);
1815 if (strcasecmp(lc->str, "before") == 0) {
1816 *(uint32_t *)(item->value) = SCRIPT_Before ;
1817 } else if (strcasecmp(lc->str, "after") == 0) {
1818 *(uint32_t *)(item->value) = SCRIPT_After;
1819 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1820 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1821 } else if (strcasecmp(lc->str, "always") == 0) {
1822 *(uint32_t *)(item->value) = SCRIPT_Any;
1824 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1829 /* Store a runscript->target
1832 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1834 lex_get_token(lc, T_STRING);
1837 if (strcmp(lc->str, "%c") == 0) {
1838 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1839 } else if (strcasecmp(lc->str, "yes") == 0) {
1840 ((RUNSCRIPT*) item->value)->set_target("%c");
1841 } else if (strcasecmp(lc->str, "no") == 0) {
1842 ((RUNSCRIPT*) item->value)->set_target("");
1844 RES *res = GetResWithName(R_CLIENT, lc->str);
1846 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1847 lc->str, lc->line_no, lc->line);
1850 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1857 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1859 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1861 lex_get_token(lc, T_STRING);
1864 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1865 POOLMEM *c = get_pool_memory(PM_FNAME);
1866 /* Each runscript command takes 2 entries in commands list */
1867 pm_strcpy(c, lc->str);
1868 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1869 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1874 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1876 lex_get_token(lc, T_STRING);
1877 alist **runscripts = (alist **)(item->value) ;
1880 RUNSCRIPT *script = new_runscript();
1881 script->set_job_code_callback(job_code_callback_director);
1883 script->set_command(lc->str);
1885 /* TODO: remove all script->old_proto with bacula 1.42 */
1887 if (strcmp(item->name, "runbeforejob") == 0) {
1888 script->when = SCRIPT_Before;
1889 script->fail_on_error = true;
1890 script->set_target("");
1892 } else if (strcmp(item->name, "runafterjob") == 0) {
1893 script->when = SCRIPT_After;
1894 script->on_success = true;
1895 script->on_failure = false;
1896 script->set_target("");
1898 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1899 script->old_proto = true;
1900 script->when = SCRIPT_After;
1901 script->set_target("%c");
1902 script->on_success = true;
1903 script->on_failure = false;
1905 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1906 script->old_proto = true;
1907 script->when = SCRIPT_Before;
1908 script->set_target("%c");
1909 script->fail_on_error = true;
1911 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1912 script->when = SCRIPT_After;
1913 script->on_failure = true;
1914 script->on_success = false;
1915 script->set_target("");
1918 if (*runscripts == NULL) {
1919 *runscripts = New(alist(10, not_owned_by_alist));
1922 (*runscripts)->append(script);
1929 /* Store a bool in a bit field without modifing res_all.hdr
1930 * We can also add an option to store_bool to skip res_all.hdr
1932 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1934 lex_get_token(lc, T_NAME);
1935 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1936 *(bool *)(item->value) = true;
1937 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1938 *(bool *)(item->value) = false;
1940 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1946 * new RunScript items
1947 * name handler value code flags default_value
1949 static RES_ITEM runscript_items[] = {
1950 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1951 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1952 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1953 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1954 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1955 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1956 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1957 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1958 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1959 {NULL, NULL, {0}, 0, 0, 0}
1963 * Store RunScript info
1965 * Note, when this routine is called, we are inside a Job
1966 * resource. We treat the RunScript like a sort of
1967 * mini-resource within the Job resource.
1969 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1973 alist **runscripts = (alist **)(item->value) ;
1975 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1977 token = lex_get_token(lc, T_SKIP_EOL);
1979 if (token != T_BOB) {
1980 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1982 /* setting on_success, on_failure, fail_on_error */
1983 res_runscript.reset_default();
1986 res_runscript.commands = New(alist(10, not_owned_by_alist));
1989 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1990 if (token == T_EOB) {
1993 if (token != T_IDENTIFIER) {
1994 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1996 for (i=0; runscript_items[i].name; i++) {
1997 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1998 token = lex_get_token(lc, T_SKIP_EOL);
1999 if (token != T_EQUALS) {
2000 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2003 /* Call item handler */
2004 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2011 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2016 /* run on client by default */
2017 if (res_runscript.target == NULL) {
2018 res_runscript.set_target("%c");
2020 if (*runscripts == NULL) {
2021 *runscripts = New(alist(10, not_owned_by_alist));
2024 * commands list contains 2 values per command
2025 * - POOLMEM command string (ex: /bin/true)
2026 * - int command type (ex: SHELL_CMD)
2028 res_runscript.set_job_code_callback(job_code_callback_director);
2029 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2030 t = (intptr_t)res_runscript.commands->pop();
2031 RUNSCRIPT *script = new_runscript();
2032 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2033 script->command = c;
2034 script->cmd_type = t;
2035 /* target is taken from res_runscript, each runscript object have
2038 script->target = NULL;
2039 script->set_target(res_runscript.target);
2041 (*runscripts)->append(script);
2044 delete res_runscript.commands;
2045 /* setting on_success, on_failure... cleanup target field */
2046 res_runscript.reset_default(true);
2050 set_bit(index, res_all.hdr.item_present);
2053 /* callback function for edit_job_codes */
2054 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2055 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2057 static char yes[] = "yes";
2058 static char no[] = "no";
2062 return jcr->fileset->name();
2067 return jcr->client->address;
2072 return jcr->pool->name();
2077 return jcr->wstore->name();
2081 return jcr->spool_data ? yes : no;
2090 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2092 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2093 r_first, r_last, resources, res_head);
2094 return config->parse_config();