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];
557 UAContext *ua = (UAContext *)sock;
560 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
563 if (type < 0) { /* no recursion */
569 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
570 reshdr->name, res->res_dir.MaxConcurrentJobs,
571 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
572 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
573 if (res->res_dir.query_file) {
574 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
576 if (res->res_dir.messages) {
577 sendit(sock, _(" --> "));
578 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
582 sendit(sock, _("Console: name=%s SSL=%d\n"),
583 res->res_con.hdr.name, res->res_con.tls_enable);
586 if (res->res_counter.WrapCounter) {
587 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
588 res->res_counter.hdr.name, res->res_counter.MinValue,
589 res->res_counter.MaxValue, res->res_counter.CurrentValue,
590 res->res_counter.WrapCounter->hdr.name);
592 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
593 res->res_counter.hdr.name, res->res_counter.MinValue,
594 res->res_counter.MaxValue);
596 if (res->res_counter.Catalog) {
597 sendit(sock, _(" --> "));
598 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
603 if (!acl_access_ok(ua, Client_ACL, res->res_client.hdr.name)) {
606 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
607 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
608 res->res_client.MaxConcurrentJobs);
609 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
610 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
611 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
612 res->res_client.AutoPrune);
613 if (res->res_client.catalog) {
614 sendit(sock, _(" --> "));
615 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
622 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
623 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
624 " poolid=%s volname=%s MediaType=%s\n"),
625 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
626 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
627 dev->offline, dev->autochanger,
628 edit_uint64(dev->PoolId, ed1),
629 dev->VolumeName, dev->MediaType);
633 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
636 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
637 " DeviceName=%s MediaType=%s StorageId=%s\n"),
638 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
639 res->res_store.MaxConcurrentJobs,
640 res->res_store.dev_name(),
641 res->res_store.media_type,
642 edit_int64(res->res_store.StorageId, ed1));
646 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
649 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
650 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
651 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
652 res->res_cat.db_port, res->res_cat.db_name,
653 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
654 res->res_cat.mult_db_connections);
659 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
662 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
663 type == R_JOB ? _("Job") : _("JobDefs"),
664 res->res_job.hdr.name, res->res_job.JobType,
665 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
666 res->res_job.enabled);
667 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
668 res->res_job.MaxConcurrentJobs,
669 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
670 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
671 res->res_job.spool_data, res->res_job.write_part_after_job);
672 if (res->res_job.spool_size) {
673 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
675 if (res->res_job.JobType == JT_BACKUP) {
676 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
678 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
679 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
681 if (res->res_job.client) {
682 sendit(sock, _(" --> "));
683 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
685 if (res->res_job.fileset) {
686 sendit(sock, _(" --> "));
687 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
689 if (res->res_job.schedule) {
690 sendit(sock, _(" --> "));
691 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
693 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
694 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
696 if (res->res_job.RegexWhere) {
697 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
699 if (res->res_job.RestoreBootstrap) {
700 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
702 if (res->res_job.WriteBootstrap) {
703 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
705 if (res->res_job.PluginOptions) {
706 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
708 if (res->res_job.MaxRunTime) {
709 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
711 if (res->res_job.MaxWaitTime) {
712 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
714 if (res->res_job.MaxStartDelay) {
715 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
717 if (res->res_job.MaxRunSchedTime) {
718 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
720 if (res->res_job.storage) {
722 foreach_alist(store, res->res_job.storage) {
723 sendit(sock, _(" --> "));
724 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
727 if (res->res_job.base) {
729 foreach_alist(job, res->res_job.base) {
730 sendit(sock, _(" --> Base %s\n"), job->name());
733 if (res->res_job.RunScripts) {
735 foreach_alist(script, res->res_job.RunScripts) {
736 sendit(sock, _(" --> RunScript\n"));
737 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
738 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
739 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
740 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
741 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
742 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
745 if (res->res_job.pool) {
746 sendit(sock, _(" --> "));
747 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
749 if (res->res_job.full_pool) {
750 sendit(sock, _(" --> "));
751 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
753 if (res->res_job.inc_pool) {
754 sendit(sock, _(" --> "));
755 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
757 if (res->res_job.diff_pool) {
758 sendit(sock, _(" --> "));
759 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
761 if (res->res_job.verify_job) {
762 sendit(sock, _(" --> "));
763 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
765 if (res->res_job.run_cmds) {
767 foreach_alist(runcmd, res->res_job.run_cmds) {
768 sendit(sock, _(" --> Run=%s\n"), runcmd);
771 if (res->res_job.selection_pattern) {
772 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
774 if (res->res_job.messages) {
775 sendit(sock, _(" --> "));
776 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
783 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
786 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
787 for (i=0; i<res->res_fs.num_includes; i++) {
788 INCEXE *incexe = res->res_fs.include_items[i];
789 for (j=0; j<incexe->num_opts; j++) {
790 FOPTS *fo = incexe->opts_list[j];
791 sendit(sock, " O %s\n", fo->opts);
793 bool enhanced_wild = false;
794 for (k=0; fo->opts[k]!='\0'; k++) {
795 if (fo->opts[k]=='W') {
796 enhanced_wild = true;
801 for (k=0; k<fo->regex.size(); k++) {
802 sendit(sock, " R %s\n", fo->regex.get(k));
804 for (k=0; k<fo->regexdir.size(); k++) {
805 sendit(sock, " RD %s\n", fo->regexdir.get(k));
807 for (k=0; k<fo->regexfile.size(); k++) {
808 sendit(sock, " RF %s\n", fo->regexfile.get(k));
810 for (k=0; k<fo->wild.size(); k++) {
811 sendit(sock, " W %s\n", fo->wild.get(k));
813 for (k=0; k<fo->wilddir.size(); k++) {
814 sendit(sock, " WD %s\n", fo->wilddir.get(k));
816 for (k=0; k<fo->wildfile.size(); k++) {
817 sendit(sock, " WF %s\n", fo->wildfile.get(k));
819 for (k=0; k<fo->wildbase.size(); k++) {
820 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
822 for (k=0; k<fo->base.size(); k++) {
823 sendit(sock, " B %s\n", fo->base.get(k));
825 for (k=0; k<fo->fstype.size(); k++) {
826 sendit(sock, " X %s\n", fo->fstype.get(k));
828 for (k=0; k<fo->drivetype.size(); k++) {
829 sendit(sock, " XD %s\n", fo->drivetype.get(k));
832 sendit(sock, " G %s\n", fo->plugin);
835 sendit(sock, " D %s\n", fo->reader);
838 sendit(sock, " T %s\n", fo->writer);
840 sendit(sock, " N\n");
842 if (incexe->ignoredir) {
843 sendit(sock, " Z %s\n", incexe->ignoredir);
845 for (j=0; j<incexe->name_list.size(); j++) {
846 sendit(sock, " I %s\n", incexe->name_list.get(j));
848 if (incexe->name_list.size()) {
849 sendit(sock, " N\n");
851 for (j=0; j<incexe->plugin_list.size(); j++) {
852 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
854 if (incexe->plugin_list.size()) {
855 sendit(sock, " N\n");
860 for (i=0; i<res->res_fs.num_excludes; i++) {
861 INCEXE *incexe = res->res_fs.exclude_items[i];
862 for (j=0; j<incexe->name_list.size(); j++) {
863 sendit(sock, " E %s\n", incexe->name_list.get(j));
865 if (incexe->name_list.size()) {
866 sendit(sock, " N\n");
873 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
876 if (res->res_sch.run) {
878 RUN *run = res->res_sch.run;
879 char buf[1000], num[30];
880 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
885 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
886 bstrncpy(buf, _(" hour="), sizeof(buf));
887 for (i=0; i<24; i++) {
888 if (bit_is_set(i, run->hour)) {
889 bsnprintf(num, sizeof(num), "%d ", i);
890 bstrncat(buf, num, sizeof(buf));
893 bstrncat(buf, "\n", sizeof(buf));
895 bstrncpy(buf, _(" mday="), sizeof(buf));
896 for (i=0; i<31; i++) {
897 if (bit_is_set(i, run->mday)) {
898 bsnprintf(num, sizeof(num), "%d ", i);
899 bstrncat(buf, num, sizeof(buf));
902 bstrncat(buf, "\n", sizeof(buf));
904 bstrncpy(buf, _(" month="), sizeof(buf));
905 for (i=0; i<12; i++) {
906 if (bit_is_set(i, run->month)) {
907 bsnprintf(num, sizeof(num), "%d ", i);
908 bstrncat(buf, num, sizeof(buf));
911 bstrncat(buf, "\n", sizeof(buf));
913 bstrncpy(buf, _(" wday="), sizeof(buf));
914 for (i=0; i<7; i++) {
915 if (bit_is_set(i, run->wday)) {
916 bsnprintf(num, sizeof(num), "%d ", i);
917 bstrncat(buf, num, sizeof(buf));
920 bstrncat(buf, "\n", sizeof(buf));
922 bstrncpy(buf, _(" wom="), sizeof(buf));
923 for (i=0; i<5; i++) {
924 if (bit_is_set(i, run->wom)) {
925 bsnprintf(num, sizeof(num), "%d ", i);
926 bstrncat(buf, num, sizeof(buf));
929 bstrncat(buf, "\n", sizeof(buf));
931 bstrncpy(buf, _(" woy="), sizeof(buf));
932 for (i=0; i<54; i++) {
933 if (bit_is_set(i, run->woy)) {
934 bsnprintf(num, sizeof(num), "%d ", i);
935 bstrncat(buf, num, sizeof(buf));
938 bstrncat(buf, "\n", sizeof(buf));
940 sendit(sock, _(" mins=%d\n"), run->minute);
942 sendit(sock, _(" --> "));
943 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
946 sendit(sock, _(" --> "));
947 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
950 sendit(sock, _(" --> "));
951 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
953 /* If another Run record is chained in, go print it */
959 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
964 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
967 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
968 res->res_pool.pool_type);
969 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
970 res->res_pool.use_catalog, res->res_pool.use_volume_once,
971 res->res_pool.catalog_files);
972 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
973 res->res_pool.max_volumes, res->res_pool.AutoPrune,
974 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
975 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
976 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
977 res->res_pool.Recycle,
978 NPRT(res->res_pool.label_format));
979 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
980 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
981 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
982 res->res_pool.recycle_oldest_volume,
983 res->res_pool.purge_oldest_volume,
984 res->res_pool.action_on_purge);
985 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
986 res->res_pool.MaxVolJobs,
987 res->res_pool.MaxVolFiles,
988 edit_uint64(res->res_pool.MaxVolBytes, ed1));
989 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
990 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
991 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
992 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
993 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
994 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
995 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
996 if (res->res_pool.NextPool) {
997 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
999 if (res->res_pool.RecyclePool) {
1000 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1002 if (res->res_pool.ScratchPool) {
1003 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1005 if (res->res_pool.catalog) {
1006 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1008 if (res->res_pool.storage) {
1010 foreach_alist(store, res->res_pool.storage) {
1011 sendit(sock, _(" --> "));
1012 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1015 if (res->res_pool.CopyPool) {
1017 foreach_alist(copy, res->res_pool.CopyPool) {
1018 sendit(sock, _(" --> "));
1019 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1026 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1027 if (res->res_msgs.mail_cmd)
1028 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1029 if (res->res_msgs.operator_cmd)
1030 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1034 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1037 if (recurse && res->res_dir.hdr.next) {
1038 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1043 * Free all the members of an INCEXE structure
1045 static void free_incexe(INCEXE *incexe)
1047 incexe->name_list.destroy();
1048 incexe->plugin_list.destroy();
1049 for (int i=0; i<incexe->num_opts; i++) {
1050 FOPTS *fopt = incexe->opts_list[i];
1051 fopt->regex.destroy();
1052 fopt->regexdir.destroy();
1053 fopt->regexfile.destroy();
1054 fopt->wild.destroy();
1055 fopt->wilddir.destroy();
1056 fopt->wildfile.destroy();
1057 fopt->wildbase.destroy();
1058 fopt->base.destroy();
1059 fopt->fstype.destroy();
1060 fopt->drivetype.destroy();
1072 if (incexe->opts_list) {
1073 free(incexe->opts_list);
1075 if (incexe->ignoredir) {
1076 free(incexe->ignoredir);
1082 * Free memory of resource -- called when daemon terminates.
1083 * NB, we don't need to worry about freeing any references
1084 * to other resources as they will be freed when that
1085 * resource chain is traversed. Mainly we worry about freeing
1086 * allocated strings (names).
1088 void free_resource(RES *sres, int type)
1091 RES *nres; /* next resource if linked */
1092 URES *res = (URES *)sres;
1097 /* common stuff -- free the resource name and description */
1098 nres = (RES *)res->res_dir.hdr.next;
1099 if (res->res_dir.hdr.name) {
1100 free(res->res_dir.hdr.name);
1102 if (res->res_dir.hdr.desc) {
1103 free(res->res_dir.hdr.desc);
1108 if (res->res_dir.working_directory) {
1109 free(res->res_dir.working_directory);
1111 if (res->res_dir.scripts_directory) {
1112 free((char *)res->res_dir.scripts_directory);
1114 if (res->res_dir.plugin_directory) {
1115 free((char *)res->res_dir.plugin_directory);
1117 if (res->res_dir.pid_directory) {
1118 free(res->res_dir.pid_directory);
1120 if (res->res_dir.subsys_directory) {
1121 free(res->res_dir.subsys_directory);
1123 if (res->res_dir.password) {
1124 free(res->res_dir.password);
1126 if (res->res_dir.query_file) {
1127 free(res->res_dir.query_file);
1129 if (res->res_dir.DIRaddrs) {
1130 free_addresses(res->res_dir.DIRaddrs);
1132 if (res->res_dir.DIRsrc_addr) {
1133 free_addresses(res->res_dir.DIRsrc_addr);
1135 if (res->res_dir.tls_ctx) {
1136 free_tls_context(res->res_dir.tls_ctx);
1138 if (res->res_dir.tls_ca_certfile) {
1139 free(res->res_dir.tls_ca_certfile);
1141 if (res->res_dir.tls_ca_certdir) {
1142 free(res->res_dir.tls_ca_certdir);
1144 if (res->res_dir.tls_certfile) {
1145 free(res->res_dir.tls_certfile);
1147 if (res->res_dir.tls_keyfile) {
1148 free(res->res_dir.tls_keyfile);
1150 if (res->res_dir.tls_dhfile) {
1151 free(res->res_dir.tls_dhfile);
1153 if (res->res_dir.tls_allowed_cns) {
1154 delete res->res_dir.tls_allowed_cns;
1156 if (res->res_dir.verid) {
1157 free(res->res_dir.verid);
1164 if (res->res_con.password) {
1165 free(res->res_con.password);
1167 if (res->res_con.tls_ctx) {
1168 free_tls_context(res->res_con.tls_ctx);
1170 if (res->res_con.tls_ca_certfile) {
1171 free(res->res_con.tls_ca_certfile);
1173 if (res->res_con.tls_ca_certdir) {
1174 free(res->res_con.tls_ca_certdir);
1176 if (res->res_con.tls_certfile) {
1177 free(res->res_con.tls_certfile);
1179 if (res->res_con.tls_keyfile) {
1180 free(res->res_con.tls_keyfile);
1182 if (res->res_con.tls_dhfile) {
1183 free(res->res_con.tls_dhfile);
1185 if (res->res_con.tls_allowed_cns) {
1186 delete res->res_con.tls_allowed_cns;
1188 for (int i=0; i<Num_ACL; i++) {
1189 if (res->res_con.ACL_lists[i]) {
1190 delete res->res_con.ACL_lists[i];
1191 res->res_con.ACL_lists[i] = NULL;
1196 if (res->res_client.address) {
1197 free(res->res_client.address);
1199 if (res->res_client.password) {
1200 free(res->res_client.password);
1202 if (res->res_client.tls_ctx) {
1203 free_tls_context(res->res_client.tls_ctx);
1205 if (res->res_client.tls_ca_certfile) {
1206 free(res->res_client.tls_ca_certfile);
1208 if (res->res_client.tls_ca_certdir) {
1209 free(res->res_client.tls_ca_certdir);
1211 if (res->res_client.tls_certfile) {
1212 free(res->res_client.tls_certfile);
1214 if (res->res_client.tls_keyfile) {
1215 free(res->res_client.tls_keyfile);
1217 if (res->res_client.tls_allowed_cns) {
1218 delete res->res_client.tls_allowed_cns;
1222 if (res->res_store.address) {
1223 free(res->res_store.address);
1225 if (res->res_store.password) {
1226 free(res->res_store.password);
1228 if (res->res_store.media_type) {
1229 free(res->res_store.media_type);
1231 if (res->res_store.device) {
1232 delete res->res_store.device;
1234 if (res->res_store.tls_ctx) {
1235 free_tls_context(res->res_store.tls_ctx);
1237 if (res->res_store.tls_ca_certfile) {
1238 free(res->res_store.tls_ca_certfile);
1240 if (res->res_store.tls_ca_certdir) {
1241 free(res->res_store.tls_ca_certdir);
1243 if (res->res_store.tls_certfile) {
1244 free(res->res_store.tls_certfile);
1246 if (res->res_store.tls_keyfile) {
1247 free(res->res_store.tls_keyfile);
1251 if (res->res_cat.db_address) {
1252 free(res->res_cat.db_address);
1254 if (res->res_cat.db_socket) {
1255 free(res->res_cat.db_socket);
1257 if (res->res_cat.db_user) {
1258 free(res->res_cat.db_user);
1260 if (res->res_cat.db_name) {
1261 free(res->res_cat.db_name);
1263 if (res->res_cat.db_driver) {
1264 free(res->res_cat.db_driver);
1266 if (res->res_cat.db_password) {
1267 free(res->res_cat.db_password);
1271 if ((num=res->res_fs.num_includes)) {
1272 while (--num >= 0) {
1273 free_incexe(res->res_fs.include_items[num]);
1275 free(res->res_fs.include_items);
1277 res->res_fs.num_includes = 0;
1278 if ((num=res->res_fs.num_excludes)) {
1279 while (--num >= 0) {
1280 free_incexe(res->res_fs.exclude_items[num]);
1282 free(res->res_fs.exclude_items);
1284 res->res_fs.num_excludes = 0;
1287 if (res->res_pool.pool_type) {
1288 free(res->res_pool.pool_type);
1290 if (res->res_pool.label_format) {
1291 free(res->res_pool.label_format);
1293 if (res->res_pool.cleaning_prefix) {
1294 free(res->res_pool.cleaning_prefix);
1296 if (res->res_pool.storage) {
1297 delete res->res_pool.storage;
1301 if (res->res_sch.run) {
1303 nrun = res->res_sch.run;
1313 if (res->res_job.RestoreWhere) {
1314 free(res->res_job.RestoreWhere);
1316 if (res->res_job.RegexWhere) {
1317 free(res->res_job.RegexWhere);
1319 if (res->res_job.strip_prefix) {
1320 free(res->res_job.strip_prefix);
1322 if (res->res_job.add_prefix) {
1323 free(res->res_job.add_prefix);
1325 if (res->res_job.add_suffix) {
1326 free(res->res_job.add_suffix);
1328 if (res->res_job.RestoreBootstrap) {
1329 free(res->res_job.RestoreBootstrap);
1331 if (res->res_job.WriteBootstrap) {
1332 free(res->res_job.WriteBootstrap);
1334 if (res->res_job.PluginOptions) {
1335 free(res->res_job.PluginOptions);
1337 if (res->res_job.selection_pattern) {
1338 free(res->res_job.selection_pattern);
1340 if (res->res_job.run_cmds) {
1341 delete res->res_job.run_cmds;
1343 if (res->res_job.storage) {
1344 delete res->res_job.storage;
1346 if (res->res_job.base) {
1347 delete res->res_job.base;
1349 if (res->res_job.RunScripts) {
1350 free_runscripts(res->res_job.RunScripts);
1351 delete res->res_job.RunScripts;
1355 if (res->res_msgs.mail_cmd) {
1356 free(res->res_msgs.mail_cmd);
1358 if (res->res_msgs.operator_cmd) {
1359 free(res->res_msgs.operator_cmd);
1361 free_msgs_res((MSGS *)res); /* free message resource */
1365 printf(_("Unknown resource type %d in free_resource.\n"), type);
1367 /* Common stuff again -- free the resource, recurse to next one */
1372 free_resource(nres, type);
1377 * Save the new resource by chaining it into the head list for
1378 * the resource. If this is pass 2, we update any resource
1379 * pointers because they may not have been defined until
1382 void save_resource(int type, RES_ITEM *items, int pass)
1385 int rindex = type - r_first;
1389 /* Check Job requirements after applying JobDefs */
1390 if (type != R_JOB && type != R_JOBDEFS) {
1392 * Ensure that all required items are present
1394 for (i=0; items[i].name; i++) {
1395 if (items[i].flags & ITEM_REQUIRED) {
1396 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1397 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1398 items[i].name, resources[rindex]);
1401 /* If this triggers, take a look at lib/parse_conf.h */
1402 if (i >= MAX_RES_ITEMS) {
1403 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1406 } else if (type == R_JOB) {
1408 * Ensure that the name item is present
1410 if (items[0].flags & ITEM_REQUIRED) {
1411 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1412 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1413 items[0].name, resources[rindex]);
1419 * During pass 2 in each "store" routine, we looked up pointers
1420 * to all the resources referrenced in the current resource, now we
1421 * must copy their addresses from the static record to the allocated
1426 /* Resources not containing a resource */
1434 * Resources containing another resource or alist. First
1435 * look up the resource which contains another resource. It
1436 * was written during pass 1. Then stuff in the pointers to
1437 * the resources it contains, which were inserted this pass.
1438 * Finally, it will all be stored back.
1441 /* Find resource saved in pass 1 */
1442 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1443 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1445 /* Explicitly copy resource pointers from this pass (res_all) */
1446 res->res_pool.NextPool = res_all.res_pool.NextPool;
1447 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1448 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1449 res->res_pool.storage = res_all.res_pool.storage;
1450 res->res_pool.catalog = res_all.res_pool.catalog;
1453 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1454 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1456 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1459 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1460 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1462 res->res_dir.messages = res_all.res_dir.messages;
1463 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1466 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1467 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1468 res_all.res_dir.hdr.name);
1470 /* we must explicitly copy the device alist pointer */
1471 res->res_store.device = res_all.res_store.device;
1475 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1476 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1477 res_all.res_dir.hdr.name);
1479 res->res_job.messages = res_all.res_job.messages;
1480 res->res_job.schedule = res_all.res_job.schedule;
1481 res->res_job.client = res_all.res_job.client;
1482 res->res_job.fileset = res_all.res_job.fileset;
1483 res->res_job.storage = res_all.res_job.storage;
1484 res->res_job.base = res_all.res_job.base;
1485 res->res_job.pool = res_all.res_job.pool;
1486 res->res_job.full_pool = res_all.res_job.full_pool;
1487 res->res_job.inc_pool = res_all.res_job.inc_pool;
1488 res->res_job.diff_pool = res_all.res_job.diff_pool;
1489 res->res_job.verify_job = res_all.res_job.verify_job;
1490 res->res_job.jobdefs = res_all.res_job.jobdefs;
1491 res->res_job.run_cmds = res_all.res_job.run_cmds;
1492 res->res_job.RunScripts = res_all.res_job.RunScripts;
1494 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1495 * is not very useful)
1496 * We have to set_bit(index, res_all.hdr.item_present);
1497 * or something like that
1500 /* we take RegexWhere before all other options */
1501 if (!res->res_job.RegexWhere
1503 (res->res_job.strip_prefix ||
1504 res->res_job.add_suffix ||
1505 res->res_job.add_prefix))
1507 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1508 res->res_job.add_prefix,
1509 res->res_job.add_suffix);
1510 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1511 bregexp_build_where(res->res_job.RegexWhere, len,
1512 res->res_job.strip_prefix,
1513 res->res_job.add_prefix,
1514 res->res_job.add_suffix);
1515 /* TODO: test bregexp */
1518 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1519 free(res->res_job.RestoreWhere);
1520 res->res_job.RestoreWhere = NULL;
1525 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1526 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1528 res->res_counter.Catalog = res_all.res_counter.Catalog;
1529 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1533 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1534 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1536 res->res_client.catalog = res_all.res_client.catalog;
1537 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1541 * Schedule is a bit different in that it contains a RUN record
1542 * chain which isn't a "named" resource. This chain was linked
1543 * in by run_conf.c during pass 2, so here we jam the pointer
1544 * into the Schedule resource.
1546 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1547 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1549 res->res_sch.run = res_all.res_sch.run;
1552 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1556 /* Note, the resource name was already saved during pass 1,
1557 * so here, we can just release it.
1559 if (res_all.res_dir.hdr.name) {
1560 free(res_all.res_dir.hdr.name);
1561 res_all.res_dir.hdr.name = NULL;
1563 if (res_all.res_dir.hdr.desc) {
1564 free(res_all.res_dir.hdr.desc);
1565 res_all.res_dir.hdr.desc = NULL;
1571 * The following code is only executed during pass 1
1575 size = sizeof(DIRRES);
1578 size = sizeof(CONRES);
1581 size =sizeof(CLIENT);
1584 size = sizeof(STORE);
1594 size = sizeof(FILESET);
1597 size = sizeof(SCHED);
1600 size = sizeof(POOL);
1603 size = sizeof(MSGS);
1606 size = sizeof(COUNTER);
1612 printf(_("Unknown resource type %d in save_resource.\n"), type);
1618 res = (URES *)malloc(size);
1619 memcpy(res, &res_all, size);
1620 if (!res_head[rindex]) {
1621 res_head[rindex] = (RES *)res; /* store first entry */
1622 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1623 res->res_dir.hdr.name, rindex);
1626 if (res->res_dir.hdr.name == NULL) {
1627 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1630 /* Add new res to end of chain */
1631 for (last=next=res_head[rindex]; next; next=next->next) {
1633 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1634 Emsg2(M_ERROR_TERM, 0,
1635 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1636 resources[rindex].name, res->res_dir.hdr.name);
1639 last->next = (RES *)res;
1640 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1641 res->res_dir.hdr.name, rindex, pass);
1646 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1648 uint32_t *destination = (uint32_t*)item->value;
1649 lex_get_token(lc, T_NAME);
1650 if (strcasecmp(lc->str, "truncate") == 0) {
1651 *destination = (*destination) | ON_PURGE_TRUNCATE;
1653 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1657 set_bit(index, res_all.hdr.item_present);
1661 * Store Device. Note, the resource is created upon the
1662 * first reference. The details of the resource are obtained
1663 * later from the SD.
1665 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1668 int rindex = R_DEVICE - r_first;
1669 int size = sizeof(DEVICE);
1673 lex_get_token(lc, T_NAME);
1674 if (!res_head[rindex]) {
1675 res = (URES *)malloc(size);
1676 memset(res, 0, size);
1677 res->res_dev.hdr.name = bstrdup(lc->str);
1678 res_head[rindex] = (RES *)res; /* store first entry */
1679 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1680 res->res_dir.hdr.name, rindex);
1683 /* See if it is already defined */
1684 for (next=res_head[rindex]; next->next; next=next->next) {
1685 if (strcmp(next->name, lc->str) == 0) {
1691 res = (URES *)malloc(size);
1692 memset(res, 0, size);
1693 res->res_dev.hdr.name = bstrdup(lc->str);
1694 next->next = (RES *)res;
1695 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1696 res->res_dir.hdr.name, rindex, pass);
1701 set_bit(index, res_all.hdr.item_present);
1703 store_alist_res(lc, item, index, pass);
1708 * Store Migration/Copy type
1711 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1715 lex_get_token(lc, T_NAME);
1716 /* Store the type both pass 1 and pass 2 */
1717 for (i=0; migtypes[i].type_name; i++) {
1718 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1719 *(uint32_t *)(item->value) = migtypes[i].job_type;
1725 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1728 set_bit(index, res_all.hdr.item_present);
1734 * Store JobType (backup, verify, restore)
1737 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1741 lex_get_token(lc, T_NAME);
1742 /* Store the type both pass 1 and pass 2 */
1743 for (i=0; jobtypes[i].type_name; i++) {
1744 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1745 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1751 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1754 set_bit(index, res_all.hdr.item_present);
1758 * Store Job Level (Full, Incremental, ...)
1761 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1765 lex_get_token(lc, T_NAME);
1766 /* Store the level pass 2 so that type is defined */
1767 for (i=0; joblevels[i].level_name; i++) {
1768 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1769 *(uint32_t *)(item->value) = joblevels[i].level;
1775 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1778 set_bit(index, res_all.hdr.item_present);
1782 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1785 lex_get_token(lc, T_NAME);
1786 /* Scan Replacement options */
1787 for (i=0; ReplaceOptions[i].name; i++) {
1788 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1789 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1795 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1798 set_bit(index, res_all.hdr.item_present);
1802 * Store ACL (access control list)
1805 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1810 lex_get_token(lc, T_STRING);
1812 if (((alist **)item->value)[item->code] == NULL) {
1813 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1814 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1816 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1817 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1819 token = lex_get_token(lc, T_ALL);
1820 if (token == T_COMMA) {
1821 continue; /* get another ACL */
1825 set_bit(index, res_all.hdr.item_present);
1828 /* We build RunScripts items here */
1829 static RUNSCRIPT res_runscript;
1831 /* Store a runscript->when in a bit field */
1832 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1834 lex_get_token(lc, T_NAME);
1836 if (strcasecmp(lc->str, "before") == 0) {
1837 *(uint32_t *)(item->value) = SCRIPT_Before ;
1838 } else if (strcasecmp(lc->str, "after") == 0) {
1839 *(uint32_t *)(item->value) = SCRIPT_After;
1840 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1841 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1842 } else if (strcasecmp(lc->str, "always") == 0) {
1843 *(uint32_t *)(item->value) = SCRIPT_Any;
1845 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1850 /* Store a runscript->target
1853 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1855 lex_get_token(lc, T_STRING);
1858 if (strcmp(lc->str, "%c") == 0) {
1859 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1860 } else if (strcasecmp(lc->str, "yes") == 0) {
1861 ((RUNSCRIPT*) item->value)->set_target("%c");
1862 } else if (strcasecmp(lc->str, "no") == 0) {
1863 ((RUNSCRIPT*) item->value)->set_target("");
1865 RES *res = GetResWithName(R_CLIENT, lc->str);
1867 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1868 lc->str, lc->line_no, lc->line);
1871 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1878 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1880 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1882 lex_get_token(lc, T_STRING);
1885 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1886 POOLMEM *c = get_pool_memory(PM_FNAME);
1887 /* Each runscript command takes 2 entries in commands list */
1888 pm_strcpy(c, lc->str);
1889 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1890 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1895 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1897 lex_get_token(lc, T_STRING);
1898 alist **runscripts = (alist **)(item->value) ;
1901 RUNSCRIPT *script = new_runscript();
1902 script->set_job_code_callback(job_code_callback_director);
1904 script->set_command(lc->str);
1906 /* TODO: remove all script->old_proto with bacula 1.42 */
1908 if (strcmp(item->name, "runbeforejob") == 0) {
1909 script->when = SCRIPT_Before;
1910 script->fail_on_error = true;
1911 script->set_target("");
1913 } else if (strcmp(item->name, "runafterjob") == 0) {
1914 script->when = SCRIPT_After;
1915 script->on_success = true;
1916 script->on_failure = false;
1917 script->set_target("");
1919 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1920 script->old_proto = true;
1921 script->when = SCRIPT_After;
1922 script->set_target("%c");
1923 script->on_success = true;
1924 script->on_failure = false;
1926 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1927 script->old_proto = true;
1928 script->when = SCRIPT_Before;
1929 script->set_target("%c");
1930 script->fail_on_error = true;
1932 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1933 script->when = SCRIPT_After;
1934 script->on_failure = true;
1935 script->on_success = false;
1936 script->set_target("");
1939 if (*runscripts == NULL) {
1940 *runscripts = New(alist(10, not_owned_by_alist));
1943 (*runscripts)->append(script);
1950 /* Store a bool in a bit field without modifing res_all.hdr
1951 * We can also add an option to store_bool to skip res_all.hdr
1953 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1955 lex_get_token(lc, T_NAME);
1956 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1957 *(bool *)(item->value) = true;
1958 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1959 *(bool *)(item->value) = false;
1961 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1967 * new RunScript items
1968 * name handler value code flags default_value
1970 static RES_ITEM runscript_items[] = {
1971 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1972 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1973 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1974 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1975 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1976 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1977 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1978 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1979 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1980 {NULL, NULL, {0}, 0, 0, 0}
1984 * Store RunScript info
1986 * Note, when this routine is called, we are inside a Job
1987 * resource. We treat the RunScript like a sort of
1988 * mini-resource within the Job resource.
1990 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1994 alist **runscripts = (alist **)(item->value) ;
1996 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1998 token = lex_get_token(lc, T_SKIP_EOL);
2000 if (token != T_BOB) {
2001 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2003 /* setting on_success, on_failure, fail_on_error */
2004 res_runscript.reset_default();
2007 res_runscript.commands = New(alist(10, not_owned_by_alist));
2010 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2011 if (token == T_EOB) {
2014 if (token != T_IDENTIFIER) {
2015 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2017 for (i=0; runscript_items[i].name; i++) {
2018 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2019 token = lex_get_token(lc, T_SKIP_EOL);
2020 if (token != T_EQUALS) {
2021 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2024 /* Call item handler */
2025 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2032 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2037 /* run on client by default */
2038 if (res_runscript.target == NULL) {
2039 res_runscript.set_target("%c");
2041 if (*runscripts == NULL) {
2042 *runscripts = New(alist(10, not_owned_by_alist));
2045 * commands list contains 2 values per command
2046 * - POOLMEM command string (ex: /bin/true)
2047 * - int command type (ex: SHELL_CMD)
2049 res_runscript.set_job_code_callback(job_code_callback_director);
2050 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2051 t = (intptr_t)res_runscript.commands->pop();
2052 RUNSCRIPT *script = new_runscript();
2053 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2054 script->command = c;
2055 script->cmd_type = t;
2056 /* target is taken from res_runscript, each runscript object have
2059 script->target = NULL;
2060 script->set_target(res_runscript.target);
2062 (*runscripts)->append(script);
2065 delete res_runscript.commands;
2066 /* setting on_success, on_failure... cleanup target field */
2067 res_runscript.reset_default(true);
2071 set_bit(index, res_all.hdr.item_present);
2074 /* callback function for edit_job_codes */
2075 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2076 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2078 static char yes[] = "yes";
2079 static char no[] = "no";
2083 return jcr->fileset->name();
2088 return jcr->client->address;
2093 return jcr->pool->name();
2098 return jcr->wstore->name();
2102 return jcr->spool_data ? yes : no;
2111 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2113 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2114 r_first, r_last, resources, res_head);
2115 return config->parse_config();