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 {"maximumconcurrentreadjobs", store_pint32, ITEM(res_store.MaxConcurrentReadJobs), 0, ITEM_DEFAULT, 0},
228 {"sddport", store_pint32, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
229 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
230 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
231 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
232 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
233 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
234 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
235 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
236 {NULL, NULL, {0}, 0, 0, 0}
240 * Catalog Resource Directives
242 * name handler value code flags default_value
244 static RES_ITEM cat_items[] = {
245 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
246 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
247 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
248 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
249 {"dbport", store_pint32, ITEM(res_cat.db_port), 0, 0, 0},
250 /* keep this password as store_str for the moment */
251 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
252 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
253 {"dbuser", store_str, ITEM(res_cat.db_user), 0, 0, 0},
254 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
255 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
256 {"dbdriver", store_str, ITEM(res_cat.db_driver), 0, 0, 0},
257 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
258 /* Turned off for the moment */
259 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
260 {"disablebatchinsert", store_bool, ITEM(res_cat.disable_batch_insert), 0, ITEM_DEFAULT, false},
261 {NULL, NULL, {0}, 0, 0, 0}
265 * Job Resource Directives
267 * name handler value code flags default_value
269 RES_ITEM job_items[] = {
270 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
271 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
272 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
273 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
274 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
275 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
276 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
277 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
278 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
279 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
280 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
281 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
282 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
283 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
284 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
285 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
286 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
287 /* Root of where to restore files */
288 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
289 {"regexwhere", store_str, ITEM(res_job.RegexWhere), 0, 0, 0},
290 {"stripprefix", store_str, ITEM(res_job.strip_prefix), 0, 0, 0},
291 {"addprefix", store_str, ITEM(res_job.add_prefix), 0, 0, 0},
292 {"addsuffix", store_str, ITEM(res_job.add_suffix), 0, 0, 0},
293 /* Where to find bootstrap during restore */
294 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
295 /* Where to write bootstrap file during backup */
296 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
297 {"writeverifylist",store_dir,ITEM(res_job.WriteVerifyList), 0, 0, 0},
298 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
299 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
300 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
301 /* xxxMaxWaitTime are deprecated */
302 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
303 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
304 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
305 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
306 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
307 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
308 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
309 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
310 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
311 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
312 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
313 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
314 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
315 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
316 {"purgemigrationjob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
317 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
318 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
319 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
320 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
321 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
322 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
323 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
324 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
327 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
328 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
329 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
330 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
331 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 5},
332 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
333 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
334 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
335 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
336 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
337 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
338 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
339 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
340 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
341 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
342 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
343 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
344 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
345 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
346 {NULL, NULL, {0}, 0, 0, 0}
351 * name handler value code flags default_value
353 static RES_ITEM fs_items[] = {
354 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
355 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
356 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
357 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
358 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
359 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
360 {NULL, NULL, {0}, 0, 0, 0}
363 /* Schedule -- see run_conf.c */
366 * name handler value code flags default_value
368 static RES_ITEM sch_items[] = {
369 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
370 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
371 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
372 {NULL, NULL, {0}, 0, 0, 0}
377 * name handler value code flags default_value
379 static RES_ITEM pool_items[] = {
380 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
381 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
382 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
383 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
384 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
385 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
386 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
387 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
388 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
389 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
390 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
391 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
392 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
393 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
394 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
395 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
396 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
397 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
398 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
399 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
400 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
401 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
402 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
403 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
404 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
405 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
406 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
407 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
408 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
409 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
410 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
411 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
413 {NULL, NULL, {0}, 0, 0, 0}
418 * name handler value code flags default_value
420 static RES_ITEM counter_items[] = {
421 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
422 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
423 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
424 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
425 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
426 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
427 {NULL, NULL, {0}, 0, 0, 0}
431 /* Message resource */
432 extern RES_ITEM msgs_items[];
435 * This is the master resource definition.
436 * It must have one item for each of the resources.
438 * NOTE!!! keep it in the same order as the R_codes
439 * or eliminate all resources[rindex].name
441 * name items rcode res_head
443 RES_TABLE resources[] = {
444 {"director", dir_items, R_DIRECTOR},
445 {"client", cli_items, R_CLIENT},
446 {"job", job_items, R_JOB},
447 {"storage", store_items, R_STORAGE},
448 {"catalog", cat_items, R_CATALOG},
449 {"schedule", sch_items, R_SCHEDULE},
450 {"fileset", fs_items, R_FILESET},
451 {"pool", pool_items, R_POOL},
452 {"messages", msgs_items, R_MSGS},
453 {"counter", counter_items, R_COUNTER},
454 {"console", con_items, R_CONSOLE},
455 {"jobdefs", job_items, R_JOBDEFS},
456 {"device", NULL, R_DEVICE}, /* info obtained from SD */
461 /* Keywords (RHS) permitted in Job Level records
463 * level_name level job_type
465 struct s_jl joblevels[] = {
466 {"Full", L_FULL, JT_BACKUP},
467 {"Base", L_BASE, JT_BACKUP},
468 {"Incremental", L_INCREMENTAL, JT_BACKUP},
469 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
470 {"Since", L_SINCE, JT_BACKUP},
471 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
472 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
473 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
474 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
475 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
476 {"Data", L_VERIFY_DATA, JT_VERIFY},
477 {" ", L_NONE, JT_ADMIN},
478 {" ", L_NONE, JT_RESTORE},
482 /* Keywords (RHS) permitted in Job type records
486 struct s_jt jobtypes[] = {
487 {"backup", JT_BACKUP},
489 {"verify", JT_VERIFY},
490 {"restore", JT_RESTORE},
491 {"migrate", JT_MIGRATE},
497 /* Keywords (RHS) permitted in Selection type records
501 struct s_jt migtypes[] = {
502 {"smallestvolume", MT_SMALLEST_VOL},
503 {"oldestvolume", MT_OLDEST_VOL},
504 {"pooloccupancy", MT_POOL_OCCUPANCY},
505 {"pooltime", MT_POOL_TIME},
506 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
507 {"client", MT_CLIENT},
508 {"volume", MT_VOLUME},
510 {"sqlquery", MT_SQLQUERY},
516 /* Options permitted in Restore replace= */
517 struct s_kw ReplaceOptions[] = {
518 {"always", REPLACE_ALWAYS},
519 {"ifnewer", REPLACE_IFNEWER},
520 {"ifolder", REPLACE_IFOLDER},
521 {"never", REPLACE_NEVER},
525 char *CAT::display(POOLMEM *dst) {
526 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
527 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
529 name(), NPRTB(db_name),
530 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
531 NPRTB(db_address), db_port, NPRTB(db_socket));
535 const char *level_to_str(int level)
538 static char level_no[30];
539 const char *str = level_no;
541 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
542 for (i=0; joblevels[i].level_name; i++) {
543 if (level == (int)joblevels[i].level) {
544 str = joblevels[i].level_name;
551 /* Dump contents of resource */
552 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
554 URES *res = (URES *)reshdr;
556 char ed1[100], ed2[100], ed3[100];
558 UAContext *ua = (UAContext *)sock;
561 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
564 if (type < 0) { /* no recursion */
570 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
571 reshdr->name, res->res_dir.MaxConcurrentJobs,
572 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
573 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
574 if (res->res_dir.query_file) {
575 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
577 if (res->res_dir.messages) {
578 sendit(sock, _(" --> "));
579 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
583 sendit(sock, _("Console: name=%s SSL=%d\n"),
584 res->res_con.hdr.name, res->res_con.tls_enable);
587 if (res->res_counter.WrapCounter) {
588 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
589 res->res_counter.hdr.name, res->res_counter.MinValue,
590 res->res_counter.MaxValue, res->res_counter.CurrentValue,
591 res->res_counter.WrapCounter->hdr.name);
593 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
594 res->res_counter.hdr.name, res->res_counter.MinValue,
595 res->res_counter.MaxValue);
597 if (res->res_counter.Catalog) {
598 sendit(sock, _(" --> "));
599 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
604 if (!acl_access_ok(ua, Client_ACL, res->res_client.hdr.name)) {
607 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
608 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
609 res->res_client.MaxConcurrentJobs);
610 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
611 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
612 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
613 res->res_client.AutoPrune);
614 if (res->res_client.catalog) {
615 sendit(sock, _(" --> "));
616 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
623 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
624 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
625 " poolid=%s volname=%s MediaType=%s\n"),
626 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
627 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
628 dev->offline, dev->autochanger,
629 edit_uint64(dev->PoolId, ed1),
630 dev->VolumeName, dev->MediaType);
634 if (!acl_access_ok(ua, Storage_ACL, res->res_store.hdr.name)) {
637 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
638 " DeviceName=%s MediaType=%s StorageId=%s\n"),
639 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
640 res->res_store.MaxConcurrentJobs,
641 res->res_store.dev_name(),
642 res->res_store.media_type,
643 edit_int64(res->res_store.StorageId, ed1));
647 if (!acl_access_ok(ua, Catalog_ACL, res->res_cat.hdr.name)) {
650 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
651 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
652 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
653 res->res_cat.db_port, res->res_cat.db_name,
654 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
655 res->res_cat.mult_db_connections);
660 if (!acl_access_ok(ua, Job_ACL, res->res_job.hdr.name)) {
663 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
664 type == R_JOB ? _("Job") : _("JobDefs"),
665 res->res_job.hdr.name, res->res_job.JobType,
666 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
667 res->res_job.enabled);
668 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
669 res->res_job.MaxConcurrentJobs,
670 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
671 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
672 res->res_job.spool_data, res->res_job.write_part_after_job);
673 if (res->res_job.spool_size) {
674 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
676 if (res->res_job.JobType == JT_BACKUP) {
677 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
679 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
680 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
682 if (res->res_job.client) {
683 sendit(sock, _(" --> "));
684 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
686 if (res->res_job.fileset) {
687 sendit(sock, _(" --> "));
688 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
690 if (res->res_job.schedule) {
691 sendit(sock, _(" --> "));
692 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
694 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
695 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
697 if (res->res_job.RegexWhere) {
698 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
700 if (res->res_job.RestoreBootstrap) {
701 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
703 if (res->res_job.WriteBootstrap) {
704 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
706 if (res->res_job.PluginOptions) {
707 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
709 if (res->res_job.MaxRunTime) {
710 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
712 if (res->res_job.MaxWaitTime) {
713 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
715 if (res->res_job.MaxStartDelay) {
716 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
718 if (res->res_job.MaxRunSchedTime) {
719 sendit(sock, _(" --> MaxRunSchedTime=%u\n"), res->res_job.MaxRunSchedTime);
721 if (res->res_job.storage) {
723 foreach_alist(store, res->res_job.storage) {
724 sendit(sock, _(" --> "));
725 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
728 if (res->res_job.base) {
730 foreach_alist(job, res->res_job.base) {
731 sendit(sock, _(" --> Base %s\n"), job->name());
734 if (res->res_job.RunScripts) {
736 foreach_alist(script, res->res_job.RunScripts) {
737 sendit(sock, _(" --> RunScript\n"));
738 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
739 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
740 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
741 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
742 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
743 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
746 if (res->res_job.pool) {
747 sendit(sock, _(" --> "));
748 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
750 if (res->res_job.full_pool) {
751 sendit(sock, _(" --> "));
752 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
754 if (res->res_job.inc_pool) {
755 sendit(sock, _(" --> "));
756 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
758 if (res->res_job.diff_pool) {
759 sendit(sock, _(" --> "));
760 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
762 if (res->res_job.verify_job) {
763 sendit(sock, _(" --> "));
764 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
766 if (res->res_job.run_cmds) {
768 foreach_alist(runcmd, res->res_job.run_cmds) {
769 sendit(sock, _(" --> Run=%s\n"), runcmd);
772 if (res->res_job.selection_pattern) {
773 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
775 if (res->res_job.messages) {
776 sendit(sock, _(" --> "));
777 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
784 if (!acl_access_ok(ua, FileSet_ACL, res->res_fs.hdr.name)) {
787 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
788 for (i=0; i<res->res_fs.num_includes; i++) {
789 INCEXE *incexe = res->res_fs.include_items[i];
790 for (j=0; j<incexe->num_opts; j++) {
791 FOPTS *fo = incexe->opts_list[j];
792 sendit(sock, " O %s\n", fo->opts);
794 bool enhanced_wild = false;
795 for (k=0; fo->opts[k]!='\0'; k++) {
796 if (fo->opts[k]=='W') {
797 enhanced_wild = true;
802 for (k=0; k<fo->regex.size(); k++) {
803 sendit(sock, " R %s\n", fo->regex.get(k));
805 for (k=0; k<fo->regexdir.size(); k++) {
806 sendit(sock, " RD %s\n", fo->regexdir.get(k));
808 for (k=0; k<fo->regexfile.size(); k++) {
809 sendit(sock, " RF %s\n", fo->regexfile.get(k));
811 for (k=0; k<fo->wild.size(); k++) {
812 sendit(sock, " W %s\n", fo->wild.get(k));
814 for (k=0; k<fo->wilddir.size(); k++) {
815 sendit(sock, " WD %s\n", fo->wilddir.get(k));
817 for (k=0; k<fo->wildfile.size(); k++) {
818 sendit(sock, " WF %s\n", fo->wildfile.get(k));
820 for (k=0; k<fo->wildbase.size(); k++) {
821 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
823 for (k=0; k<fo->base.size(); k++) {
824 sendit(sock, " B %s\n", fo->base.get(k));
826 for (k=0; k<fo->fstype.size(); k++) {
827 sendit(sock, " X %s\n", fo->fstype.get(k));
829 for (k=0; k<fo->drivetype.size(); k++) {
830 sendit(sock, " XD %s\n", fo->drivetype.get(k));
833 sendit(sock, " G %s\n", fo->plugin);
836 sendit(sock, " D %s\n", fo->reader);
839 sendit(sock, " T %s\n", fo->writer);
841 sendit(sock, " N\n");
843 if (incexe->ignoredir) {
844 sendit(sock, " Z %s\n", incexe->ignoredir);
846 for (j=0; j<incexe->name_list.size(); j++) {
847 sendit(sock, " I %s\n", incexe->name_list.get(j));
849 if (incexe->name_list.size()) {
850 sendit(sock, " N\n");
852 for (j=0; j<incexe->plugin_list.size(); j++) {
853 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
855 if (incexe->plugin_list.size()) {
856 sendit(sock, " N\n");
861 for (i=0; i<res->res_fs.num_excludes; i++) {
862 INCEXE *incexe = res->res_fs.exclude_items[i];
863 for (j=0; j<incexe->name_list.size(); j++) {
864 sendit(sock, " E %s\n", incexe->name_list.get(j));
866 if (incexe->name_list.size()) {
867 sendit(sock, " N\n");
874 if (!acl_access_ok(ua, Schedule_ACL, res->res_sch.hdr.name)) {
877 if (res->res_sch.run) {
879 RUN *run = res->res_sch.run;
880 char buf[1000], num[30];
881 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
886 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
887 bstrncpy(buf, _(" hour="), sizeof(buf));
888 for (i=0; i<24; i++) {
889 if (bit_is_set(i, run->hour)) {
890 bsnprintf(num, sizeof(num), "%d ", i);
891 bstrncat(buf, num, sizeof(buf));
894 bstrncat(buf, "\n", sizeof(buf));
896 bstrncpy(buf, _(" mday="), sizeof(buf));
897 for (i=0; i<31; i++) {
898 if (bit_is_set(i, run->mday)) {
899 bsnprintf(num, sizeof(num), "%d ", i);
900 bstrncat(buf, num, sizeof(buf));
903 bstrncat(buf, "\n", sizeof(buf));
905 bstrncpy(buf, _(" month="), sizeof(buf));
906 for (i=0; i<12; i++) {
907 if (bit_is_set(i, run->month)) {
908 bsnprintf(num, sizeof(num), "%d ", i);
909 bstrncat(buf, num, sizeof(buf));
912 bstrncat(buf, "\n", sizeof(buf));
914 bstrncpy(buf, _(" wday="), sizeof(buf));
915 for (i=0; i<7; i++) {
916 if (bit_is_set(i, run->wday)) {
917 bsnprintf(num, sizeof(num), "%d ", i);
918 bstrncat(buf, num, sizeof(buf));
921 bstrncat(buf, "\n", sizeof(buf));
923 bstrncpy(buf, _(" wom="), sizeof(buf));
924 for (i=0; i<5; i++) {
925 if (bit_is_set(i, run->wom)) {
926 bsnprintf(num, sizeof(num), "%d ", i);
927 bstrncat(buf, num, sizeof(buf));
930 bstrncat(buf, "\n", sizeof(buf));
932 bstrncpy(buf, _(" woy="), sizeof(buf));
933 for (i=0; i<54; i++) {
934 if (bit_is_set(i, run->woy)) {
935 bsnprintf(num, sizeof(num), "%d ", i);
936 bstrncat(buf, num, sizeof(buf));
939 bstrncat(buf, "\n", sizeof(buf));
941 sendit(sock, _(" mins=%d\n"), run->minute);
943 sendit(sock, _(" --> "));
944 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
947 sendit(sock, _(" --> "));
948 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
951 sendit(sock, _(" --> "));
952 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
954 /* If another Run record is chained in, go print it */
960 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
965 if (!acl_access_ok(ua, Pool_ACL, res->res_pool.hdr.name)) {
968 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
969 res->res_pool.pool_type);
970 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
971 res->res_pool.use_catalog, res->res_pool.use_volume_once,
972 res->res_pool.catalog_files);
973 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
974 res->res_pool.max_volumes, res->res_pool.AutoPrune,
975 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
976 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
977 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
978 res->res_pool.Recycle,
979 NPRT(res->res_pool.label_format));
980 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
981 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
982 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
983 res->res_pool.recycle_oldest_volume,
984 res->res_pool.purge_oldest_volume,
985 res->res_pool.action_on_purge);
986 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
987 res->res_pool.MaxVolJobs,
988 res->res_pool.MaxVolFiles,
989 edit_uint64(res->res_pool.MaxVolBytes, ed1));
990 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
991 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
992 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
993 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
994 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
995 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
996 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
997 if (res->res_pool.NextPool) {
998 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
1000 if (res->res_pool.RecyclePool) {
1001 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
1003 if (res->res_pool.ScratchPool) {
1004 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
1006 if (res->res_pool.catalog) {
1007 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
1009 if (res->res_pool.storage) {
1011 foreach_alist(store, res->res_pool.storage) {
1012 sendit(sock, _(" --> "));
1013 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1016 if (res->res_pool.CopyPool) {
1018 foreach_alist(copy, res->res_pool.CopyPool) {
1019 sendit(sock, _(" --> "));
1020 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1027 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1028 if (res->res_msgs.mail_cmd)
1029 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1030 if (res->res_msgs.operator_cmd)
1031 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1035 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1038 if (recurse && res->res_dir.hdr.next) {
1039 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1044 * Free all the members of an INCEXE structure
1046 static void free_incexe(INCEXE *incexe)
1048 incexe->name_list.destroy();
1049 incexe->plugin_list.destroy();
1050 for (int i=0; i<incexe->num_opts; i++) {
1051 FOPTS *fopt = incexe->opts_list[i];
1052 fopt->regex.destroy();
1053 fopt->regexdir.destroy();
1054 fopt->regexfile.destroy();
1055 fopt->wild.destroy();
1056 fopt->wilddir.destroy();
1057 fopt->wildfile.destroy();
1058 fopt->wildbase.destroy();
1059 fopt->base.destroy();
1060 fopt->fstype.destroy();
1061 fopt->drivetype.destroy();
1073 if (incexe->opts_list) {
1074 free(incexe->opts_list);
1076 if (incexe->ignoredir) {
1077 free(incexe->ignoredir);
1083 * Free memory of resource -- called when daemon terminates.
1084 * NB, we don't need to worry about freeing any references
1085 * to other resources as they will be freed when that
1086 * resource chain is traversed. Mainly we worry about freeing
1087 * allocated strings (names).
1089 void free_resource(RES *sres, int type)
1092 RES *nres; /* next resource if linked */
1093 URES *res = (URES *)sres;
1098 /* common stuff -- free the resource name and description */
1099 nres = (RES *)res->res_dir.hdr.next;
1100 if (res->res_dir.hdr.name) {
1101 free(res->res_dir.hdr.name);
1103 if (res->res_dir.hdr.desc) {
1104 free(res->res_dir.hdr.desc);
1109 if (res->res_dir.working_directory) {
1110 free(res->res_dir.working_directory);
1112 if (res->res_dir.scripts_directory) {
1113 free((char *)res->res_dir.scripts_directory);
1115 if (res->res_dir.plugin_directory) {
1116 free((char *)res->res_dir.plugin_directory);
1118 if (res->res_dir.pid_directory) {
1119 free(res->res_dir.pid_directory);
1121 if (res->res_dir.subsys_directory) {
1122 free(res->res_dir.subsys_directory);
1124 if (res->res_dir.password) {
1125 free(res->res_dir.password);
1127 if (res->res_dir.query_file) {
1128 free(res->res_dir.query_file);
1130 if (res->res_dir.DIRaddrs) {
1131 free_addresses(res->res_dir.DIRaddrs);
1133 if (res->res_dir.DIRsrc_addr) {
1134 free_addresses(res->res_dir.DIRsrc_addr);
1136 if (res->res_dir.tls_ctx) {
1137 free_tls_context(res->res_dir.tls_ctx);
1139 if (res->res_dir.tls_ca_certfile) {
1140 free(res->res_dir.tls_ca_certfile);
1142 if (res->res_dir.tls_ca_certdir) {
1143 free(res->res_dir.tls_ca_certdir);
1145 if (res->res_dir.tls_certfile) {
1146 free(res->res_dir.tls_certfile);
1148 if (res->res_dir.tls_keyfile) {
1149 free(res->res_dir.tls_keyfile);
1151 if (res->res_dir.tls_dhfile) {
1152 free(res->res_dir.tls_dhfile);
1154 if (res->res_dir.tls_allowed_cns) {
1155 delete res->res_dir.tls_allowed_cns;
1157 if (res->res_dir.verid) {
1158 free(res->res_dir.verid);
1165 if (res->res_con.password) {
1166 free(res->res_con.password);
1168 if (res->res_con.tls_ctx) {
1169 free_tls_context(res->res_con.tls_ctx);
1171 if (res->res_con.tls_ca_certfile) {
1172 free(res->res_con.tls_ca_certfile);
1174 if (res->res_con.tls_ca_certdir) {
1175 free(res->res_con.tls_ca_certdir);
1177 if (res->res_con.tls_certfile) {
1178 free(res->res_con.tls_certfile);
1180 if (res->res_con.tls_keyfile) {
1181 free(res->res_con.tls_keyfile);
1183 if (res->res_con.tls_dhfile) {
1184 free(res->res_con.tls_dhfile);
1186 if (res->res_con.tls_allowed_cns) {
1187 delete res->res_con.tls_allowed_cns;
1189 for (int i=0; i<Num_ACL; i++) {
1190 if (res->res_con.ACL_lists[i]) {
1191 delete res->res_con.ACL_lists[i];
1192 res->res_con.ACL_lists[i] = NULL;
1197 if (res->res_client.address) {
1198 free(res->res_client.address);
1200 if (res->res_client.password) {
1201 free(res->res_client.password);
1203 if (res->res_client.tls_ctx) {
1204 free_tls_context(res->res_client.tls_ctx);
1206 if (res->res_client.tls_ca_certfile) {
1207 free(res->res_client.tls_ca_certfile);
1209 if (res->res_client.tls_ca_certdir) {
1210 free(res->res_client.tls_ca_certdir);
1212 if (res->res_client.tls_certfile) {
1213 free(res->res_client.tls_certfile);
1215 if (res->res_client.tls_keyfile) {
1216 free(res->res_client.tls_keyfile);
1218 if (res->res_client.tls_allowed_cns) {
1219 delete res->res_client.tls_allowed_cns;
1223 if (res->res_store.address) {
1224 free(res->res_store.address);
1226 if (res->res_store.password) {
1227 free(res->res_store.password);
1229 if (res->res_store.media_type) {
1230 free(res->res_store.media_type);
1232 if (res->res_store.device) {
1233 delete res->res_store.device;
1235 if (res->res_store.tls_ctx) {
1236 free_tls_context(res->res_store.tls_ctx);
1238 if (res->res_store.tls_ca_certfile) {
1239 free(res->res_store.tls_ca_certfile);
1241 if (res->res_store.tls_ca_certdir) {
1242 free(res->res_store.tls_ca_certdir);
1244 if (res->res_store.tls_certfile) {
1245 free(res->res_store.tls_certfile);
1247 if (res->res_store.tls_keyfile) {
1248 free(res->res_store.tls_keyfile);
1252 if (res->res_cat.db_address) {
1253 free(res->res_cat.db_address);
1255 if (res->res_cat.db_socket) {
1256 free(res->res_cat.db_socket);
1258 if (res->res_cat.db_user) {
1259 free(res->res_cat.db_user);
1261 if (res->res_cat.db_name) {
1262 free(res->res_cat.db_name);
1264 if (res->res_cat.db_driver) {
1265 free(res->res_cat.db_driver);
1267 if (res->res_cat.db_password) {
1268 free(res->res_cat.db_password);
1272 if ((num=res->res_fs.num_includes)) {
1273 while (--num >= 0) {
1274 free_incexe(res->res_fs.include_items[num]);
1276 free(res->res_fs.include_items);
1278 res->res_fs.num_includes = 0;
1279 if ((num=res->res_fs.num_excludes)) {
1280 while (--num >= 0) {
1281 free_incexe(res->res_fs.exclude_items[num]);
1283 free(res->res_fs.exclude_items);
1285 res->res_fs.num_excludes = 0;
1288 if (res->res_pool.pool_type) {
1289 free(res->res_pool.pool_type);
1291 if (res->res_pool.label_format) {
1292 free(res->res_pool.label_format);
1294 if (res->res_pool.cleaning_prefix) {
1295 free(res->res_pool.cleaning_prefix);
1297 if (res->res_pool.storage) {
1298 delete res->res_pool.storage;
1302 if (res->res_sch.run) {
1304 nrun = res->res_sch.run;
1314 if (res->res_job.RestoreWhere) {
1315 free(res->res_job.RestoreWhere);
1317 if (res->res_job.RegexWhere) {
1318 free(res->res_job.RegexWhere);
1320 if (res->res_job.strip_prefix) {
1321 free(res->res_job.strip_prefix);
1323 if (res->res_job.add_prefix) {
1324 free(res->res_job.add_prefix);
1326 if (res->res_job.add_suffix) {
1327 free(res->res_job.add_suffix);
1329 if (res->res_job.RestoreBootstrap) {
1330 free(res->res_job.RestoreBootstrap);
1332 if (res->res_job.WriteBootstrap) {
1333 free(res->res_job.WriteBootstrap);
1335 if (res->res_job.PluginOptions) {
1336 free(res->res_job.PluginOptions);
1338 if (res->res_job.selection_pattern) {
1339 free(res->res_job.selection_pattern);
1341 if (res->res_job.run_cmds) {
1342 delete res->res_job.run_cmds;
1344 if (res->res_job.storage) {
1345 delete res->res_job.storage;
1347 if (res->res_job.base) {
1348 delete res->res_job.base;
1350 if (res->res_job.RunScripts) {
1351 free_runscripts(res->res_job.RunScripts);
1352 delete res->res_job.RunScripts;
1356 if (res->res_msgs.mail_cmd) {
1357 free(res->res_msgs.mail_cmd);
1359 if (res->res_msgs.operator_cmd) {
1360 free(res->res_msgs.operator_cmd);
1362 free_msgs_res((MSGS *)res); /* free message resource */
1366 printf(_("Unknown resource type %d in free_resource.\n"), type);
1368 /* Common stuff again -- free the resource, recurse to next one */
1373 free_resource(nres, type);
1378 * Save the new resource by chaining it into the head list for
1379 * the resource. If this is pass 2, we update any resource
1380 * pointers because they may not have been defined until
1383 void save_resource(int type, RES_ITEM *items, int pass)
1386 int rindex = type - r_first;
1390 /* Check Job requirements after applying JobDefs */
1391 if (type != R_JOB && type != R_JOBDEFS) {
1393 * Ensure that all required items are present
1395 for (i=0; items[i].name; i++) {
1396 if (items[i].flags & ITEM_REQUIRED) {
1397 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1398 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1399 items[i].name, resources[rindex]);
1402 /* If this triggers, take a look at lib/parse_conf.h */
1403 if (i >= MAX_RES_ITEMS) {
1404 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1407 } else if (type == R_JOB) {
1409 * Ensure that the name item is present
1411 if (items[0].flags & ITEM_REQUIRED) {
1412 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1413 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1414 items[0].name, resources[rindex]);
1420 * During pass 2 in each "store" routine, we looked up pointers
1421 * to all the resources referrenced in the current resource, now we
1422 * must copy their addresses from the static record to the allocated
1427 /* Resources not containing a resource */
1435 * Resources containing another resource or alist. First
1436 * look up the resource which contains another resource. It
1437 * was written during pass 1. Then stuff in the pointers to
1438 * the resources it contains, which were inserted this pass.
1439 * Finally, it will all be stored back.
1442 /* Find resource saved in pass 1 */
1443 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1444 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1446 /* Explicitly copy resource pointers from this pass (res_all) */
1447 res->res_pool.NextPool = res_all.res_pool.NextPool;
1448 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1449 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1450 res->res_pool.storage = res_all.res_pool.storage;
1451 res->res_pool.catalog = res_all.res_pool.catalog;
1454 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1455 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1457 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1460 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1461 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1463 res->res_dir.messages = res_all.res_dir.messages;
1464 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1467 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1468 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1469 res_all.res_dir.hdr.name);
1471 /* we must explicitly copy the device alist pointer */
1472 res->res_store.device = res_all.res_store.device;
1476 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1477 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1478 res_all.res_dir.hdr.name);
1480 res->res_job.messages = res_all.res_job.messages;
1481 res->res_job.schedule = res_all.res_job.schedule;
1482 res->res_job.client = res_all.res_job.client;
1483 res->res_job.fileset = res_all.res_job.fileset;
1484 res->res_job.storage = res_all.res_job.storage;
1485 res->res_job.base = res_all.res_job.base;
1486 res->res_job.pool = res_all.res_job.pool;
1487 res->res_job.full_pool = res_all.res_job.full_pool;
1488 res->res_job.inc_pool = res_all.res_job.inc_pool;
1489 res->res_job.diff_pool = res_all.res_job.diff_pool;
1490 res->res_job.verify_job = res_all.res_job.verify_job;
1491 res->res_job.jobdefs = res_all.res_job.jobdefs;
1492 res->res_job.run_cmds = res_all.res_job.run_cmds;
1493 res->res_job.RunScripts = res_all.res_job.RunScripts;
1495 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1496 * is not very useful)
1497 * We have to set_bit(index, res_all.hdr.item_present);
1498 * or something like that
1501 /* we take RegexWhere before all other options */
1502 if (!res->res_job.RegexWhere
1504 (res->res_job.strip_prefix ||
1505 res->res_job.add_suffix ||
1506 res->res_job.add_prefix))
1508 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1509 res->res_job.add_prefix,
1510 res->res_job.add_suffix);
1511 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1512 bregexp_build_where(res->res_job.RegexWhere, len,
1513 res->res_job.strip_prefix,
1514 res->res_job.add_prefix,
1515 res->res_job.add_suffix);
1516 /* TODO: test bregexp */
1519 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1520 free(res->res_job.RestoreWhere);
1521 res->res_job.RestoreWhere = NULL;
1526 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1527 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1529 res->res_counter.Catalog = res_all.res_counter.Catalog;
1530 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1534 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1535 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1537 res->res_client.catalog = res_all.res_client.catalog;
1538 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1542 * Schedule is a bit different in that it contains a RUN record
1543 * chain which isn't a "named" resource. This chain was linked
1544 * in by run_conf.c during pass 2, so here we jam the pointer
1545 * into the Schedule resource.
1547 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1548 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1550 res->res_sch.run = res_all.res_sch.run;
1553 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1557 /* Note, the resource name was already saved during pass 1,
1558 * so here, we can just release it.
1560 if (res_all.res_dir.hdr.name) {
1561 free(res_all.res_dir.hdr.name);
1562 res_all.res_dir.hdr.name = NULL;
1564 if (res_all.res_dir.hdr.desc) {
1565 free(res_all.res_dir.hdr.desc);
1566 res_all.res_dir.hdr.desc = NULL;
1572 * The following code is only executed during pass 1
1576 size = sizeof(DIRRES);
1579 size = sizeof(CONRES);
1582 size =sizeof(CLIENT);
1585 size = sizeof(STORE);
1595 size = sizeof(FILESET);
1598 size = sizeof(SCHED);
1601 size = sizeof(POOL);
1604 size = sizeof(MSGS);
1607 size = sizeof(COUNTER);
1613 printf(_("Unknown resource type %d in save_resource.\n"), type);
1619 res = (URES *)malloc(size);
1620 memcpy(res, &res_all, size);
1621 if (!res_head[rindex]) {
1622 res_head[rindex] = (RES *)res; /* store first entry */
1623 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1624 res->res_dir.hdr.name, rindex);
1627 if (res->res_dir.hdr.name == NULL) {
1628 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1631 /* Add new res to end of chain */
1632 for (last=next=res_head[rindex]; next; next=next->next) {
1634 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1635 Emsg2(M_ERROR_TERM, 0,
1636 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1637 resources[rindex].name, res->res_dir.hdr.name);
1640 last->next = (RES *)res;
1641 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1642 res->res_dir.hdr.name, rindex, pass);
1647 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1649 uint32_t *destination = (uint32_t*)item->value;
1650 lex_get_token(lc, T_NAME);
1651 if (strcasecmp(lc->str, "truncate") == 0) {
1652 *destination = (*destination) | ON_PURGE_TRUNCATE;
1654 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1658 set_bit(index, res_all.hdr.item_present);
1662 * Store Device. Note, the resource is created upon the
1663 * first reference. The details of the resource are obtained
1664 * later from the SD.
1666 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1669 int rindex = R_DEVICE - r_first;
1670 int size = sizeof(DEVICE);
1674 lex_get_token(lc, T_NAME);
1675 if (!res_head[rindex]) {
1676 res = (URES *)malloc(size);
1677 memset(res, 0, size);
1678 res->res_dev.hdr.name = bstrdup(lc->str);
1679 res_head[rindex] = (RES *)res; /* store first entry */
1680 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1681 res->res_dir.hdr.name, rindex);
1684 /* See if it is already defined */
1685 for (next=res_head[rindex]; next->next; next=next->next) {
1686 if (strcmp(next->name, lc->str) == 0) {
1692 res = (URES *)malloc(size);
1693 memset(res, 0, size);
1694 res->res_dev.hdr.name = bstrdup(lc->str);
1695 next->next = (RES *)res;
1696 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1697 res->res_dir.hdr.name, rindex, pass);
1702 set_bit(index, res_all.hdr.item_present);
1704 store_alist_res(lc, item, index, pass);
1709 * Store Migration/Copy type
1712 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1716 lex_get_token(lc, T_NAME);
1717 /* Store the type both pass 1 and pass 2 */
1718 for (i=0; migtypes[i].type_name; i++) {
1719 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1720 *(uint32_t *)(item->value) = migtypes[i].job_type;
1726 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1729 set_bit(index, res_all.hdr.item_present);
1735 * Store JobType (backup, verify, restore)
1738 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1742 lex_get_token(lc, T_NAME);
1743 /* Store the type both pass 1 and pass 2 */
1744 for (i=0; jobtypes[i].type_name; i++) {
1745 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1746 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1752 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1755 set_bit(index, res_all.hdr.item_present);
1759 * Store Job Level (Full, Incremental, ...)
1762 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1766 lex_get_token(lc, T_NAME);
1767 /* Store the level pass 2 so that type is defined */
1768 for (i=0; joblevels[i].level_name; i++) {
1769 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1770 *(uint32_t *)(item->value) = joblevels[i].level;
1776 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1779 set_bit(index, res_all.hdr.item_present);
1783 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1786 lex_get_token(lc, T_NAME);
1787 /* Scan Replacement options */
1788 for (i=0; ReplaceOptions[i].name; i++) {
1789 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1790 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1796 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1799 set_bit(index, res_all.hdr.item_present);
1803 * Store ACL (access control list)
1806 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1811 lex_get_token(lc, T_STRING);
1813 if (((alist **)item->value)[item->code] == NULL) {
1814 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1815 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1817 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1818 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1820 token = lex_get_token(lc, T_ALL);
1821 if (token == T_COMMA) {
1822 continue; /* get another ACL */
1826 set_bit(index, res_all.hdr.item_present);
1829 /* We build RunScripts items here */
1830 static RUNSCRIPT res_runscript;
1832 /* Store a runscript->when in a bit field */
1833 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1835 lex_get_token(lc, T_NAME);
1837 if (strcasecmp(lc->str, "before") == 0) {
1838 *(uint32_t *)(item->value) = SCRIPT_Before ;
1839 } else if (strcasecmp(lc->str, "after") == 0) {
1840 *(uint32_t *)(item->value) = SCRIPT_After;
1841 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1842 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1843 } else if (strcasecmp(lc->str, "always") == 0) {
1844 *(uint32_t *)(item->value) = SCRIPT_Any;
1846 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1851 /* Store a runscript->target
1854 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1856 lex_get_token(lc, T_STRING);
1859 if (strcmp(lc->str, "%c") == 0) {
1860 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1861 } else if (strcasecmp(lc->str, "yes") == 0) {
1862 ((RUNSCRIPT*) item->value)->set_target("%c");
1863 } else if (strcasecmp(lc->str, "no") == 0) {
1864 ((RUNSCRIPT*) item->value)->set_target("");
1866 RES *res = GetResWithName(R_CLIENT, lc->str);
1868 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1869 lc->str, lc->line_no, lc->line);
1872 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1879 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1881 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1883 lex_get_token(lc, T_STRING);
1886 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1887 POOLMEM *c = get_pool_memory(PM_FNAME);
1888 /* Each runscript command takes 2 entries in commands list */
1889 pm_strcpy(c, lc->str);
1890 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1891 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1896 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1898 lex_get_token(lc, T_STRING);
1899 alist **runscripts = (alist **)(item->value) ;
1902 RUNSCRIPT *script = new_runscript();
1903 script->set_job_code_callback(job_code_callback_director);
1905 script->set_command(lc->str);
1907 /* TODO: remove all script->old_proto with bacula 1.42 */
1909 if (strcmp(item->name, "runbeforejob") == 0) {
1910 script->when = SCRIPT_Before;
1911 script->fail_on_error = true;
1912 script->set_target("");
1914 } else if (strcmp(item->name, "runafterjob") == 0) {
1915 script->when = SCRIPT_After;
1916 script->on_success = true;
1917 script->on_failure = false;
1918 script->set_target("");
1920 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1921 script->old_proto = true;
1922 script->when = SCRIPT_After;
1923 script->set_target("%c");
1924 script->on_success = true;
1925 script->on_failure = false;
1927 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1928 script->old_proto = true;
1929 script->when = SCRIPT_Before;
1930 script->set_target("%c");
1931 script->fail_on_error = true;
1933 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1934 script->when = SCRIPT_After;
1935 script->on_failure = true;
1936 script->on_success = false;
1937 script->set_target("");
1940 if (*runscripts == NULL) {
1941 *runscripts = New(alist(10, not_owned_by_alist));
1944 (*runscripts)->append(script);
1951 /* Store a bool in a bit field without modifing res_all.hdr
1952 * We can also add an option to store_bool to skip res_all.hdr
1954 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1956 lex_get_token(lc, T_NAME);
1957 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1958 *(bool *)(item->value) = true;
1959 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1960 *(bool *)(item->value) = false;
1962 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1968 * new RunScript items
1969 * name handler value code flags default_value
1971 static RES_ITEM runscript_items[] = {
1972 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1973 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1974 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1975 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1976 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1977 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1978 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1979 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1980 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1981 {NULL, NULL, {0}, 0, 0, 0}
1985 * Store RunScript info
1987 * Note, when this routine is called, we are inside a Job
1988 * resource. We treat the RunScript like a sort of
1989 * mini-resource within the Job resource.
1991 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1995 alist **runscripts = (alist **)(item->value) ;
1997 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1999 token = lex_get_token(lc, T_SKIP_EOL);
2001 if (token != T_BOB) {
2002 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
2004 /* setting on_success, on_failure, fail_on_error */
2005 res_runscript.reset_default();
2008 res_runscript.commands = New(alist(10, not_owned_by_alist));
2011 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
2012 if (token == T_EOB) {
2015 if (token != T_IDENTIFIER) {
2016 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2018 for (i=0; runscript_items[i].name; i++) {
2019 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2020 token = lex_get_token(lc, T_SKIP_EOL);
2021 if (token != T_EQUALS) {
2022 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2025 /* Call item handler */
2026 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2033 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2038 /* run on client by default */
2039 if (res_runscript.target == NULL) {
2040 res_runscript.set_target("%c");
2042 if (*runscripts == NULL) {
2043 *runscripts = New(alist(10, not_owned_by_alist));
2046 * commands list contains 2 values per command
2047 * - POOLMEM command string (ex: /bin/true)
2048 * - int command type (ex: SHELL_CMD)
2050 res_runscript.set_job_code_callback(job_code_callback_director);
2051 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2052 t = (intptr_t)res_runscript.commands->pop();
2053 RUNSCRIPT *script = new_runscript();
2054 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2055 script->command = c;
2056 script->cmd_type = t;
2057 /* target is taken from res_runscript, each runscript object have
2060 script->target = NULL;
2061 script->set_target(res_runscript.target);
2063 (*runscripts)->append(script);
2066 delete res_runscript.commands;
2067 /* setting on_success, on_failure... cleanup target field */
2068 res_runscript.reset_default(true);
2072 set_bit(index, res_all.hdr.item_present);
2075 /* callback function for edit_job_codes */
2076 /* See ../lib/util.c, function edit_job_codes, for more remaining codes */
2077 extern "C" char *job_code_callback_director(JCR *jcr, const char* param)
2079 static char yes[] = "yes";
2080 static char no[] = "no";
2084 return jcr->fileset->name();
2089 return jcr->client->address;
2094 return jcr->pool->name();
2099 return jcr->wstore->name();
2103 return jcr->spool_data ? yes : no;
2112 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2114 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2115 r_first, r_last, resources, res_head);
2116 return config->parse_config();