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 {"maximumbandwidthperjob", store_speed, ITEM(res_client.max_bandwidth), 0, 0, 0},
206 {NULL, NULL, {0}, 0, 0, 0}
209 /* Storage daemon resource
211 * name handler value code flags default_value
213 static RES_ITEM store_items[] = {
214 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
215 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
216 {"sdport", store_pint32, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
217 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
218 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
219 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
220 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
221 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
222 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
223 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
224 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
225 {"allowcompression", store_bool, ITEM(res_store.AllowCompress), 0, ITEM_DEFAULT, true},
226 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
227 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
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 {"maximumbandwidth", store_speed, ITEM(res_job.max_bandwidth), 0, 0, 0},
300 {"maxrunschedtime", store_time, ITEM(res_job.MaxRunSchedTime), 0, 0, 0},
301 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
302 /* xxxMaxWaitTime are deprecated */
303 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
304 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
305 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
306 {"fullmaxruntime", store_time, ITEM(res_job.FullMaxRunTime), 0, 0, 0},
307 {"incrementalmaxruntime", store_time, ITEM(res_job.IncMaxRunTime), 0, 0, 0},
308 {"differentialmaxruntime", store_time, ITEM(res_job.DiffMaxRunTime), 0, 0, 0},
309 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
310 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
311 {"maxfullinterval", store_time, ITEM(res_job.MaxFullInterval), 0, 0, 0},
312 {"maxdiffinterval", store_time, ITEM(res_job.MaxDiffInterval), 0, 0, 0},
313 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
314 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
315 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
316 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
317 {"purgemigratejob", store_bool, ITEM(res_job.PurgeMigrateJob), 0, ITEM_DEFAULT, false},
318 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
319 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
320 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
321 {"spoolsize", store_size64, ITEM(res_job.spool_size), 0, 0, 0},
322 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
323 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
324 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
325 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
326 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
327 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
328 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
329 {"maximumconcurrentjobs", store_pint32, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
330 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
331 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
332 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 5},
333 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
334 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
335 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
336 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
337 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
338 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
339 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
340 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
341 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
342 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
343 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
344 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
345 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
346 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
347 {NULL, NULL, {0}, 0, 0, 0}
352 * name handler value code flags default_value
354 static RES_ITEM fs_items[] = {
355 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
356 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
357 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
358 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
359 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
360 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
361 {NULL, NULL, {0}, 0, 0, 0}
364 /* Schedule -- see run_conf.c */
367 * name handler value code flags default_value
369 static RES_ITEM sch_items[] = {
370 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
371 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
372 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
373 {NULL, NULL, {0}, 0, 0, 0}
378 * name handler value code flags default_value
380 static RES_ITEM pool_items[] = {
381 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
382 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
383 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
384 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
385 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
386 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
387 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
388 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
389 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
390 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
391 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
392 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
393 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
394 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
395 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
396 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
397 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
398 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
399 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
400 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
401 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
402 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
403 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
404 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
405 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
406 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
407 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
408 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
409 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
410 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
411 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
412 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
414 {NULL, NULL, {0}, 0, 0, 0}
419 * name handler value code flags default_value
421 static RES_ITEM counter_items[] = {
422 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
423 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
424 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
425 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
426 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
427 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
428 {NULL, NULL, {0}, 0, 0, 0}
432 /* Message resource */
433 extern RES_ITEM msgs_items[];
436 * This is the master resource definition.
437 * It must have one item for each of the resources.
439 * NOTE!!! keep it in the same order as the R_codes
440 * or eliminate all resources[rindex].name
442 * name items rcode res_head
444 RES_TABLE resources[] = {
445 {"director", dir_items, R_DIRECTOR},
446 {"client", cli_items, R_CLIENT},
447 {"job", job_items, R_JOB},
448 {"storage", store_items, R_STORAGE},
449 {"catalog", cat_items, R_CATALOG},
450 {"schedule", sch_items, R_SCHEDULE},
451 {"fileset", fs_items, R_FILESET},
452 {"pool", pool_items, R_POOL},
453 {"messages", msgs_items, R_MSGS},
454 {"counter", counter_items, R_COUNTER},
455 {"console", con_items, R_CONSOLE},
456 {"jobdefs", job_items, R_JOBDEFS},
457 {"device", NULL, R_DEVICE}, /* info obtained from SD */
462 /* Keywords (RHS) permitted in Job Level records
464 * level_name level job_type
466 struct s_jl joblevels[] = {
467 {"Full", L_FULL, JT_BACKUP},
468 {"Base", L_BASE, JT_BACKUP},
469 {"Incremental", L_INCREMENTAL, JT_BACKUP},
470 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
471 {"Since", L_SINCE, JT_BACKUP},
472 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
473 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
474 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
475 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
476 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
477 {"Data", L_VERIFY_DATA, JT_VERIFY},
478 {" ", L_NONE, JT_ADMIN},
479 {" ", L_NONE, JT_RESTORE},
483 /* Keywords (RHS) permitted in Job type records
487 struct s_jt jobtypes[] = {
488 {"backup", JT_BACKUP},
490 {"verify", JT_VERIFY},
491 {"restore", JT_RESTORE},
492 {"migrate", JT_MIGRATE},
498 /* Keywords (RHS) permitted in Selection type records
502 struct s_jt migtypes[] = {
503 {"smallestvolume", MT_SMALLEST_VOL},
504 {"oldestvolume", MT_OLDEST_VOL},
505 {"pooloccupancy", MT_POOL_OCCUPANCY},
506 {"pooltime", MT_POOL_TIME},
507 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
508 {"client", MT_CLIENT},
509 {"volume", MT_VOLUME},
511 {"sqlquery", MT_SQLQUERY},
517 /* Options permitted in Restore replace= */
518 struct s_kw ReplaceOptions[] = {
519 {"always", REPLACE_ALWAYS},
520 {"ifnewer", REPLACE_IFNEWER},
521 {"ifolder", REPLACE_IFOLDER},
522 {"never", REPLACE_NEVER},
526 char *CAT::display(POOLMEM *dst) {
527 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
528 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
530 name(), NPRTB(db_name),
531 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
532 NPRTB(db_address), db_port, NPRTB(db_socket));
536 const char *level_to_str(int level)
539 static char level_no[30];
540 const char *str = level_no;
542 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
543 for (i=0; joblevels[i].level_name; i++) {
544 if (level == (int)joblevels[i].level) {
545 str = joblevels[i].level_name;
552 /* Dump contents of resource */
553 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
555 URES *res = (URES *)reshdr;
557 char ed1[100], ed2[100], ed3[100];
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 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
605 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
606 res->res_client.MaxConcurrentJobs);
607 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
608 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
609 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
610 res->res_client.AutoPrune);
611 if (res->res_client.max_bandwidth) {
612 sendit(sock, _(" MaximumBandwidth=%lld\n"),
613 res->res_client.max_bandwidth);
615 if (res->res_client.catalog) {
616 sendit(sock, _(" --> "));
617 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
624 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
625 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
626 " poolid=%s volname=%s MediaType=%s\n"),
627 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
628 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
629 dev->offline, dev->autochanger,
630 edit_uint64(dev->PoolId, ed1),
631 dev->VolumeName, dev->MediaType);
635 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
636 " DeviceName=%s MediaType=%s StorageId=%s\n"),
637 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
638 res->res_store.MaxConcurrentJobs,
639 res->res_store.dev_name(),
640 res->res_store.media_type,
641 edit_int64(res->res_store.StorageId, ed1));
645 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
646 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
647 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
648 res->res_cat.db_port, res->res_cat.db_name,
649 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
650 res->res_cat.mult_db_connections);
655 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
656 type == R_JOB ? _("Job") : _("JobDefs"),
657 res->res_job.hdr.name, res->res_job.JobType,
658 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
659 res->res_job.enabled);
660 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
661 res->res_job.MaxConcurrentJobs,
662 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
663 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
664 res->res_job.spool_data, res->res_job.write_part_after_job);
665 if (res->res_job.spool_size) {
666 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
668 if (res->res_job.JobType == JT_BACKUP) {
669 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
671 if (res->res_job.max_bandwidth) {
672 sendit(sock, _(" MaximumBandwidth=%lld\n"),
673 res->res_job.max_bandwidth);
675 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
676 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
678 if (res->res_job.client) {
679 sendit(sock, _(" --> "));
680 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
682 if (res->res_job.fileset) {
683 sendit(sock, _(" --> "));
684 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
686 if (res->res_job.schedule) {
687 sendit(sock, _(" --> "));
688 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
690 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
691 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
693 if (res->res_job.RegexWhere) {
694 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
696 if (res->res_job.RestoreBootstrap) {
697 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
699 if (res->res_job.WriteBootstrap) {
700 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
702 if (res->res_job.PluginOptions) {
703 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
705 if (res->res_job.MaxRunTime) {
706 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
708 if (res->res_job.MaxWaitTime) {
709 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
711 if (res->res_job.MaxStartDelay) {
712 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
714 if (res->res_job.storage) {
716 foreach_alist(store, res->res_job.storage) {
717 sendit(sock, _(" --> "));
718 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
721 if (res->res_job.base) {
723 foreach_alist(job, res->res_job.base) {
724 sendit(sock, _(" --> Base %s\n"), job->name());
727 if (res->res_job.RunScripts) {
729 foreach_alist(script, res->res_job.RunScripts) {
730 sendit(sock, _(" --> RunScript\n"));
731 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
732 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
733 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
734 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
735 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
736 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
739 if (res->res_job.pool) {
740 sendit(sock, _(" --> "));
741 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
743 if (res->res_job.full_pool) {
744 sendit(sock, _(" --> "));
745 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
747 if (res->res_job.inc_pool) {
748 sendit(sock, _(" --> "));
749 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
751 if (res->res_job.diff_pool) {
752 sendit(sock, _(" --> "));
753 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
755 if (res->res_job.verify_job) {
756 sendit(sock, _(" --> "));
757 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
759 if (res->res_job.run_cmds) {
761 foreach_alist(runcmd, res->res_job.run_cmds) {
762 sendit(sock, _(" --> Run=%s\n"), runcmd);
765 if (res->res_job.selection_pattern) {
766 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
768 if (res->res_job.messages) {
769 sendit(sock, _(" --> "));
770 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
777 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
778 for (i=0; i<res->res_fs.num_includes; i++) {
779 INCEXE *incexe = res->res_fs.include_items[i];
780 for (j=0; j<incexe->num_opts; j++) {
781 FOPTS *fo = incexe->opts_list[j];
782 sendit(sock, " O %s\n", fo->opts);
784 bool enhanced_wild = false;
785 for (k=0; fo->opts[k]!='\0'; k++) {
786 if (fo->opts[k]=='W') {
787 enhanced_wild = true;
792 for (k=0; k<fo->regex.size(); k++) {
793 sendit(sock, " R %s\n", fo->regex.get(k));
795 for (k=0; k<fo->regexdir.size(); k++) {
796 sendit(sock, " RD %s\n", fo->regexdir.get(k));
798 for (k=0; k<fo->regexfile.size(); k++) {
799 sendit(sock, " RF %s\n", fo->regexfile.get(k));
801 for (k=0; k<fo->wild.size(); k++) {
802 sendit(sock, " W %s\n", fo->wild.get(k));
804 for (k=0; k<fo->wilddir.size(); k++) {
805 sendit(sock, " WD %s\n", fo->wilddir.get(k));
807 for (k=0; k<fo->wildfile.size(); k++) {
808 sendit(sock, " WF %s\n", fo->wildfile.get(k));
810 for (k=0; k<fo->wildbase.size(); k++) {
811 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
813 for (k=0; k<fo->base.size(); k++) {
814 sendit(sock, " B %s\n", fo->base.get(k));
816 for (k=0; k<fo->fstype.size(); k++) {
817 sendit(sock, " X %s\n", fo->fstype.get(k));
819 for (k=0; k<fo->drivetype.size(); k++) {
820 sendit(sock, " XD %s\n", fo->drivetype.get(k));
823 sendit(sock, " G %s\n", fo->plugin);
826 sendit(sock, " D %s\n", fo->reader);
829 sendit(sock, " T %s\n", fo->writer);
831 sendit(sock, " N\n");
833 if (incexe->ignoredir) {
834 sendit(sock, " Z %s\n", incexe->ignoredir);
836 for (j=0; j<incexe->name_list.size(); j++) {
837 sendit(sock, " I %s\n", incexe->name_list.get(j));
839 if (incexe->name_list.size()) {
840 sendit(sock, " N\n");
842 for (j=0; j<incexe->plugin_list.size(); j++) {
843 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
845 if (incexe->plugin_list.size()) {
846 sendit(sock, " N\n");
851 for (i=0; i<res->res_fs.num_excludes; i++) {
852 INCEXE *incexe = res->res_fs.exclude_items[i];
853 for (j=0; j<incexe->name_list.size(); j++) {
854 sendit(sock, " E %s\n", incexe->name_list.get(j));
856 if (incexe->name_list.size()) {
857 sendit(sock, " N\n");
864 if (res->res_sch.run) {
866 RUN *run = res->res_sch.run;
867 char buf[1000], num[30];
868 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
873 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
874 bstrncpy(buf, _(" hour="), sizeof(buf));
875 for (i=0; i<24; i++) {
876 if (bit_is_set(i, run->hour)) {
877 bsnprintf(num, sizeof(num), "%d ", i);
878 bstrncat(buf, num, sizeof(buf));
881 bstrncat(buf, "\n", sizeof(buf));
883 bstrncpy(buf, _(" mday="), sizeof(buf));
884 for (i=0; i<31; i++) {
885 if (bit_is_set(i, run->mday)) {
886 bsnprintf(num, sizeof(num), "%d ", i);
887 bstrncat(buf, num, sizeof(buf));
890 bstrncat(buf, "\n", sizeof(buf));
892 bstrncpy(buf, _(" month="), sizeof(buf));
893 for (i=0; i<12; i++) {
894 if (bit_is_set(i, run->month)) {
895 bsnprintf(num, sizeof(num), "%d ", i);
896 bstrncat(buf, num, sizeof(buf));
899 bstrncat(buf, "\n", sizeof(buf));
901 bstrncpy(buf, _(" wday="), sizeof(buf));
902 for (i=0; i<7; i++) {
903 if (bit_is_set(i, run->wday)) {
904 bsnprintf(num, sizeof(num), "%d ", i);
905 bstrncat(buf, num, sizeof(buf));
908 bstrncat(buf, "\n", sizeof(buf));
910 bstrncpy(buf, _(" wom="), sizeof(buf));
911 for (i=0; i<5; i++) {
912 if (bit_is_set(i, run->wom)) {
913 bsnprintf(num, sizeof(num), "%d ", i);
914 bstrncat(buf, num, sizeof(buf));
917 bstrncat(buf, "\n", sizeof(buf));
919 bstrncpy(buf, _(" woy="), sizeof(buf));
920 for (i=0; i<54; i++) {
921 if (bit_is_set(i, run->woy)) {
922 bsnprintf(num, sizeof(num), "%d ", i);
923 bstrncat(buf, num, sizeof(buf));
926 bstrncat(buf, "\n", sizeof(buf));
928 sendit(sock, _(" mins=%d\n"), run->minute);
930 sendit(sock, _(" --> "));
931 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
934 sendit(sock, _(" --> "));
935 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
938 sendit(sock, _(" --> "));
939 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
941 /* If another Run record is chained in, go print it */
947 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
952 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
953 res->res_pool.pool_type);
954 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
955 res->res_pool.use_catalog, res->res_pool.use_volume_once,
956 res->res_pool.catalog_files);
957 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
958 res->res_pool.max_volumes, res->res_pool.AutoPrune,
959 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
960 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
961 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
962 res->res_pool.Recycle,
963 NPRT(res->res_pool.label_format));
964 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
965 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
966 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
967 res->res_pool.recycle_oldest_volume,
968 res->res_pool.purge_oldest_volume,
969 res->res_pool.action_on_purge);
970 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
971 res->res_pool.MaxVolJobs,
972 res->res_pool.MaxVolFiles,
973 edit_uint64(res->res_pool.MaxVolBytes, ed1));
974 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
975 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
976 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
977 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
978 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
979 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
980 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
981 if (res->res_pool.NextPool) {
982 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
984 if (res->res_pool.RecyclePool) {
985 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
987 if (res->res_pool.ScratchPool) {
988 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
990 if (res->res_pool.catalog) {
991 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
993 if (res->res_pool.storage) {
995 foreach_alist(store, res->res_pool.storage) {
996 sendit(sock, _(" --> "));
997 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1000 if (res->res_pool.CopyPool) {
1002 foreach_alist(copy, res->res_pool.CopyPool) {
1003 sendit(sock, _(" --> "));
1004 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1011 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1012 if (res->res_msgs.mail_cmd)
1013 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1014 if (res->res_msgs.operator_cmd)
1015 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1019 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1022 if (recurse && res->res_dir.hdr.next) {
1023 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1028 * Free all the members of an INCEXE structure
1030 static void free_incexe(INCEXE *incexe)
1032 incexe->name_list.destroy();
1033 incexe->plugin_list.destroy();
1034 for (int i=0; i<incexe->num_opts; i++) {
1035 FOPTS *fopt = incexe->opts_list[i];
1036 fopt->regex.destroy();
1037 fopt->regexdir.destroy();
1038 fopt->regexfile.destroy();
1039 fopt->wild.destroy();
1040 fopt->wilddir.destroy();
1041 fopt->wildfile.destroy();
1042 fopt->wildbase.destroy();
1043 fopt->base.destroy();
1044 fopt->fstype.destroy();
1045 fopt->drivetype.destroy();
1057 if (incexe->opts_list) {
1058 free(incexe->opts_list);
1060 if (incexe->ignoredir) {
1061 free(incexe->ignoredir);
1067 * Free memory of resource -- called when daemon terminates.
1068 * NB, we don't need to worry about freeing any references
1069 * to other resources as they will be freed when that
1070 * resource chain is traversed. Mainly we worry about freeing
1071 * allocated strings (names).
1073 void free_resource(RES *sres, int type)
1076 RES *nres; /* next resource if linked */
1077 URES *res = (URES *)sres;
1082 /* common stuff -- free the resource name and description */
1083 nres = (RES *)res->res_dir.hdr.next;
1084 if (res->res_dir.hdr.name) {
1085 free(res->res_dir.hdr.name);
1087 if (res->res_dir.hdr.desc) {
1088 free(res->res_dir.hdr.desc);
1093 if (res->res_dir.working_directory) {
1094 free(res->res_dir.working_directory);
1096 if (res->res_dir.scripts_directory) {
1097 free((char *)res->res_dir.scripts_directory);
1099 if (res->res_dir.plugin_directory) {
1100 free((char *)res->res_dir.plugin_directory);
1102 if (res->res_dir.pid_directory) {
1103 free(res->res_dir.pid_directory);
1105 if (res->res_dir.subsys_directory) {
1106 free(res->res_dir.subsys_directory);
1108 if (res->res_dir.password) {
1109 free(res->res_dir.password);
1111 if (res->res_dir.query_file) {
1112 free(res->res_dir.query_file);
1114 if (res->res_dir.DIRaddrs) {
1115 free_addresses(res->res_dir.DIRaddrs);
1117 if (res->res_dir.DIRsrc_addr) {
1118 free_addresses(res->res_dir.DIRsrc_addr);
1120 if (res->res_dir.tls_ctx) {
1121 free_tls_context(res->res_dir.tls_ctx);
1123 if (res->res_dir.tls_ca_certfile) {
1124 free(res->res_dir.tls_ca_certfile);
1126 if (res->res_dir.tls_ca_certdir) {
1127 free(res->res_dir.tls_ca_certdir);
1129 if (res->res_dir.tls_certfile) {
1130 free(res->res_dir.tls_certfile);
1132 if (res->res_dir.tls_keyfile) {
1133 free(res->res_dir.tls_keyfile);
1135 if (res->res_dir.tls_dhfile) {
1136 free(res->res_dir.tls_dhfile);
1138 if (res->res_dir.tls_allowed_cns) {
1139 delete res->res_dir.tls_allowed_cns;
1141 if (res->res_dir.verid) {
1142 free(res->res_dir.verid);
1149 if (res->res_con.password) {
1150 free(res->res_con.password);
1152 if (res->res_con.tls_ctx) {
1153 free_tls_context(res->res_con.tls_ctx);
1155 if (res->res_con.tls_ca_certfile) {
1156 free(res->res_con.tls_ca_certfile);
1158 if (res->res_con.tls_ca_certdir) {
1159 free(res->res_con.tls_ca_certdir);
1161 if (res->res_con.tls_certfile) {
1162 free(res->res_con.tls_certfile);
1164 if (res->res_con.tls_keyfile) {
1165 free(res->res_con.tls_keyfile);
1167 if (res->res_con.tls_dhfile) {
1168 free(res->res_con.tls_dhfile);
1170 if (res->res_con.tls_allowed_cns) {
1171 delete res->res_con.tls_allowed_cns;
1173 for (int i=0; i<Num_ACL; i++) {
1174 if (res->res_con.ACL_lists[i]) {
1175 delete res->res_con.ACL_lists[i];
1176 res->res_con.ACL_lists[i] = NULL;
1181 if (res->res_client.address) {
1182 free(res->res_client.address);
1184 if (res->res_client.password) {
1185 free(res->res_client.password);
1187 if (res->res_client.tls_ctx) {
1188 free_tls_context(res->res_client.tls_ctx);
1190 if (res->res_client.tls_ca_certfile) {
1191 free(res->res_client.tls_ca_certfile);
1193 if (res->res_client.tls_ca_certdir) {
1194 free(res->res_client.tls_ca_certdir);
1196 if (res->res_client.tls_certfile) {
1197 free(res->res_client.tls_certfile);
1199 if (res->res_client.tls_keyfile) {
1200 free(res->res_client.tls_keyfile);
1202 if (res->res_client.tls_allowed_cns) {
1203 delete res->res_client.tls_allowed_cns;
1207 if (res->res_store.address) {
1208 free(res->res_store.address);
1210 if (res->res_store.password) {
1211 free(res->res_store.password);
1213 if (res->res_store.media_type) {
1214 free(res->res_store.media_type);
1216 if (res->res_store.device) {
1217 delete res->res_store.device;
1219 if (res->res_store.tls_ctx) {
1220 free_tls_context(res->res_store.tls_ctx);
1222 if (res->res_store.tls_ca_certfile) {
1223 free(res->res_store.tls_ca_certfile);
1225 if (res->res_store.tls_ca_certdir) {
1226 free(res->res_store.tls_ca_certdir);
1228 if (res->res_store.tls_certfile) {
1229 free(res->res_store.tls_certfile);
1231 if (res->res_store.tls_keyfile) {
1232 free(res->res_store.tls_keyfile);
1236 if (res->res_cat.db_address) {
1237 free(res->res_cat.db_address);
1239 if (res->res_cat.db_socket) {
1240 free(res->res_cat.db_socket);
1242 if (res->res_cat.db_user) {
1243 free(res->res_cat.db_user);
1245 if (res->res_cat.db_name) {
1246 free(res->res_cat.db_name);
1248 if (res->res_cat.db_driver) {
1249 free(res->res_cat.db_driver);
1251 if (res->res_cat.db_password) {
1252 free(res->res_cat.db_password);
1256 if ((num=res->res_fs.num_includes)) {
1257 while (--num >= 0) {
1258 free_incexe(res->res_fs.include_items[num]);
1260 free(res->res_fs.include_items);
1262 res->res_fs.num_includes = 0;
1263 if ((num=res->res_fs.num_excludes)) {
1264 while (--num >= 0) {
1265 free_incexe(res->res_fs.exclude_items[num]);
1267 free(res->res_fs.exclude_items);
1269 res->res_fs.num_excludes = 0;
1272 if (res->res_pool.pool_type) {
1273 free(res->res_pool.pool_type);
1275 if (res->res_pool.label_format) {
1276 free(res->res_pool.label_format);
1278 if (res->res_pool.cleaning_prefix) {
1279 free(res->res_pool.cleaning_prefix);
1281 if (res->res_pool.storage) {
1282 delete res->res_pool.storage;
1286 if (res->res_sch.run) {
1288 nrun = res->res_sch.run;
1298 if (res->res_job.RestoreWhere) {
1299 free(res->res_job.RestoreWhere);
1301 if (res->res_job.RegexWhere) {
1302 free(res->res_job.RegexWhere);
1304 if (res->res_job.strip_prefix) {
1305 free(res->res_job.strip_prefix);
1307 if (res->res_job.add_prefix) {
1308 free(res->res_job.add_prefix);
1310 if (res->res_job.add_suffix) {
1311 free(res->res_job.add_suffix);
1313 if (res->res_job.RestoreBootstrap) {
1314 free(res->res_job.RestoreBootstrap);
1316 if (res->res_job.WriteBootstrap) {
1317 free(res->res_job.WriteBootstrap);
1319 if (res->res_job.PluginOptions) {
1320 free(res->res_job.PluginOptions);
1322 if (res->res_job.selection_pattern) {
1323 free(res->res_job.selection_pattern);
1325 if (res->res_job.run_cmds) {
1326 delete res->res_job.run_cmds;
1328 if (res->res_job.storage) {
1329 delete res->res_job.storage;
1331 if (res->res_job.base) {
1332 delete res->res_job.base;
1334 if (res->res_job.RunScripts) {
1335 free_runscripts(res->res_job.RunScripts);
1336 delete res->res_job.RunScripts;
1340 if (res->res_msgs.mail_cmd) {
1341 free(res->res_msgs.mail_cmd);
1343 if (res->res_msgs.operator_cmd) {
1344 free(res->res_msgs.operator_cmd);
1346 free_msgs_res((MSGS *)res); /* free message resource */
1350 printf(_("Unknown resource type %d in free_resource.\n"), type);
1352 /* Common stuff again -- free the resource, recurse to next one */
1357 free_resource(nres, type);
1362 * Save the new resource by chaining it into the head list for
1363 * the resource. If this is pass 2, we update any resource
1364 * pointers because they may not have been defined until
1367 void save_resource(int type, RES_ITEM *items, int pass)
1370 int rindex = type - r_first;
1374 /* Check Job requirements after applying JobDefs */
1375 if (type != R_JOB && type != R_JOBDEFS) {
1377 * Ensure that all required items are present
1379 for (i=0; items[i].name; i++) {
1380 if (items[i].flags & ITEM_REQUIRED) {
1381 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1382 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1383 items[i].name, resources[rindex]);
1386 /* If this triggers, take a look at lib/parse_conf.h */
1387 if (i >= MAX_RES_ITEMS) {
1388 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1391 } else if (type == R_JOB) {
1393 * Ensure that the name item is present
1395 if (items[0].flags & ITEM_REQUIRED) {
1396 if (!bit_is_set(0, 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[0].name, resources[rindex]);
1404 * During pass 2 in each "store" routine, we looked up pointers
1405 * to all the resources referrenced in the current resource, now we
1406 * must copy their addresses from the static record to the allocated
1411 /* Resources not containing a resource */
1419 * Resources containing another resource or alist. First
1420 * look up the resource which contains another resource. It
1421 * was written during pass 1. Then stuff in the pointers to
1422 * the resources it contains, which were inserted this pass.
1423 * Finally, it will all be stored back.
1426 /* Find resource saved in pass 1 */
1427 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1428 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1430 /* Explicitly copy resource pointers from this pass (res_all) */
1431 res->res_pool.NextPool = res_all.res_pool.NextPool;
1432 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1433 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1434 res->res_pool.storage = res_all.res_pool.storage;
1435 res->res_pool.catalog = res_all.res_pool.catalog;
1438 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1439 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1441 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1444 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1445 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1447 res->res_dir.messages = res_all.res_dir.messages;
1448 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1451 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1452 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1453 res_all.res_dir.hdr.name);
1455 /* we must explicitly copy the device alist pointer */
1456 res->res_store.device = res_all.res_store.device;
1460 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1461 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1462 res_all.res_dir.hdr.name);
1464 res->res_job.messages = res_all.res_job.messages;
1465 res->res_job.schedule = res_all.res_job.schedule;
1466 res->res_job.client = res_all.res_job.client;
1467 res->res_job.fileset = res_all.res_job.fileset;
1468 res->res_job.storage = res_all.res_job.storage;
1469 res->res_job.base = res_all.res_job.base;
1470 res->res_job.pool = res_all.res_job.pool;
1471 res->res_job.full_pool = res_all.res_job.full_pool;
1472 res->res_job.inc_pool = res_all.res_job.inc_pool;
1473 res->res_job.diff_pool = res_all.res_job.diff_pool;
1474 res->res_job.verify_job = res_all.res_job.verify_job;
1475 res->res_job.jobdefs = res_all.res_job.jobdefs;
1476 res->res_job.run_cmds = res_all.res_job.run_cmds;
1477 res->res_job.RunScripts = res_all.res_job.RunScripts;
1479 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1480 * is not very useful)
1481 * We have to set_bit(index, res_all.hdr.item_present);
1482 * or something like that
1485 /* we take RegexWhere before all other options */
1486 if (!res->res_job.RegexWhere
1488 (res->res_job.strip_prefix ||
1489 res->res_job.add_suffix ||
1490 res->res_job.add_prefix))
1492 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1493 res->res_job.add_prefix,
1494 res->res_job.add_suffix);
1495 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1496 bregexp_build_where(res->res_job.RegexWhere, len,
1497 res->res_job.strip_prefix,
1498 res->res_job.add_prefix,
1499 res->res_job.add_suffix);
1500 /* TODO: test bregexp */
1503 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1504 free(res->res_job.RestoreWhere);
1505 res->res_job.RestoreWhere = NULL;
1510 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1511 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1513 res->res_counter.Catalog = res_all.res_counter.Catalog;
1514 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1518 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1519 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1521 res->res_client.catalog = res_all.res_client.catalog;
1522 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1526 * Schedule is a bit different in that it contains a RUN record
1527 * chain which isn't a "named" resource. This chain was linked
1528 * in by run_conf.c during pass 2, so here we jam the pointer
1529 * into the Schedule resource.
1531 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1532 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1534 res->res_sch.run = res_all.res_sch.run;
1537 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1541 /* Note, the resource name was already saved during pass 1,
1542 * so here, we can just release it.
1544 if (res_all.res_dir.hdr.name) {
1545 free(res_all.res_dir.hdr.name);
1546 res_all.res_dir.hdr.name = NULL;
1548 if (res_all.res_dir.hdr.desc) {
1549 free(res_all.res_dir.hdr.desc);
1550 res_all.res_dir.hdr.desc = NULL;
1556 * The following code is only executed during pass 1
1560 size = sizeof(DIRRES);
1563 size = sizeof(CONRES);
1566 size =sizeof(CLIENT);
1569 size = sizeof(STORE);
1579 size = sizeof(FILESET);
1582 size = sizeof(SCHED);
1585 size = sizeof(POOL);
1588 size = sizeof(MSGS);
1591 size = sizeof(COUNTER);
1597 printf(_("Unknown resource type %d in save_resource.\n"), type);
1603 res = (URES *)malloc(size);
1604 memcpy(res, &res_all, size);
1605 if (!res_head[rindex]) {
1606 res_head[rindex] = (RES *)res; /* store first entry */
1607 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1608 res->res_dir.hdr.name, rindex);
1611 if (res->res_dir.hdr.name == NULL) {
1612 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1615 /* Add new res to end of chain */
1616 for (last=next=res_head[rindex]; next; next=next->next) {
1618 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1619 Emsg2(M_ERROR_TERM, 0,
1620 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1621 resources[rindex].name, res->res_dir.hdr.name);
1624 last->next = (RES *)res;
1625 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1626 res->res_dir.hdr.name, rindex, pass);
1631 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1633 uint32_t *destination = (uint32_t*)item->value;
1634 lex_get_token(lc, T_NAME);
1635 if (strcasecmp(lc->str, "truncate") == 0) {
1636 *destination = (*destination) | ON_PURGE_TRUNCATE;
1638 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1642 set_bit(index, res_all.hdr.item_present);
1646 * Store Device. Note, the resource is created upon the
1647 * first reference. The details of the resource are obtained
1648 * later from the SD.
1650 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1654 int rindex = R_DEVICE - r_first;
1655 int size = sizeof(DEVICE);
1659 token = lex_get_token(lc, T_NAME);
1660 if (!res_head[rindex]) {
1661 res = (URES *)malloc(size);
1662 memset(res, 0, size);
1663 res->res_dev.hdr.name = bstrdup(lc->str);
1664 res_head[rindex] = (RES *)res; /* store first entry */
1665 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1666 res->res_dir.hdr.name, rindex);
1669 /* See if it is already defined */
1670 for (next=res_head[rindex]; next->next; next=next->next) {
1671 if (strcmp(next->name, lc->str) == 0) {
1677 res = (URES *)malloc(size);
1678 memset(res, 0, size);
1679 res->res_dev.hdr.name = bstrdup(lc->str);
1680 next->next = (RES *)res;
1681 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1682 res->res_dir.hdr.name, rindex, pass);
1687 set_bit(index, res_all.hdr.item_present);
1689 store_alist_res(lc, item, index, pass);
1694 * Store Migration/Copy type
1697 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1701 token = lex_get_token(lc, T_NAME);
1702 /* Store the type both pass 1 and pass 2 */
1703 for (i=0; migtypes[i].type_name; i++) {
1704 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1705 *(uint32_t *)(item->value) = migtypes[i].job_type;
1711 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1714 set_bit(index, res_all.hdr.item_present);
1720 * Store JobType (backup, verify, restore)
1723 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1727 token = lex_get_token(lc, T_NAME);
1728 /* Store the type both pass 1 and pass 2 */
1729 for (i=0; jobtypes[i].type_name; i++) {
1730 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1731 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1737 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1740 set_bit(index, res_all.hdr.item_present);
1744 * Store Job Level (Full, Incremental, ...)
1747 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1751 token = lex_get_token(lc, T_NAME);
1752 /* Store the level pass 2 so that type is defined */
1753 for (i=0; joblevels[i].level_name; i++) {
1754 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1755 *(uint32_t *)(item->value) = joblevels[i].level;
1761 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1764 set_bit(index, res_all.hdr.item_present);
1768 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1771 token = lex_get_token(lc, T_NAME);
1772 /* Scan Replacement options */
1773 for (i=0; ReplaceOptions[i].name; i++) {
1774 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1775 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1781 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1784 set_bit(index, res_all.hdr.item_present);
1788 * Store ACL (access control list)
1791 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1796 token = lex_get_token(lc, T_STRING);
1798 if (((alist **)item->value)[item->code] == NULL) {
1799 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1800 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1802 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1803 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1805 token = lex_get_token(lc, T_ALL);
1806 if (token == T_COMMA) {
1807 continue; /* get another ACL */
1811 set_bit(index, res_all.hdr.item_present);
1814 /* We build RunScripts items here */
1815 static RUNSCRIPT res_runscript;
1817 /* Store a runscript->when in a bit field */
1818 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1820 lex_get_token(lc, T_NAME);
1822 if (strcasecmp(lc->str, "before") == 0) {
1823 *(uint32_t *)(item->value) = SCRIPT_Before ;
1824 } else if (strcasecmp(lc->str, "after") == 0) {
1825 *(uint32_t *)(item->value) = SCRIPT_After;
1826 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1827 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1828 } else if (strcasecmp(lc->str, "always") == 0) {
1829 *(uint32_t *)(item->value) = SCRIPT_Any;
1831 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1836 /* Store a runscript->target
1839 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1841 lex_get_token(lc, T_STRING);
1844 if (strcmp(lc->str, "%c") == 0) {
1845 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1846 } else if (strcasecmp(lc->str, "yes") == 0) {
1847 ((RUNSCRIPT*) item->value)->set_target("%c");
1848 } else if (strcasecmp(lc->str, "no") == 0) {
1849 ((RUNSCRIPT*) item->value)->set_target("");
1851 RES *res = GetResWithName(R_CLIENT, lc->str);
1853 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1854 lc->str, lc->line_no, lc->line);
1857 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1864 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1866 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1868 lex_get_token(lc, T_STRING);
1871 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1872 POOLMEM *c = get_pool_memory(PM_FNAME);
1873 /* Each runscript command takes 2 entries in commands list */
1874 pm_strcpy(c, lc->str);
1875 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1876 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1881 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1883 lex_get_token(lc, T_STRING);
1884 alist **runscripts = (alist **)(item->value) ;
1887 RUNSCRIPT *script = new_runscript();
1888 script->set_job_code_callback(job_code_callback_filesetname);
1890 script->set_command(lc->str);
1892 /* TODO: remove all script->old_proto with bacula 1.42 */
1894 if (strcmp(item->name, "runbeforejob") == 0) {
1895 script->when = SCRIPT_Before;
1896 script->fail_on_error = true;
1897 script->set_target("");
1899 } else if (strcmp(item->name, "runafterjob") == 0) {
1900 script->when = SCRIPT_After;
1901 script->on_success = true;
1902 script->on_failure = false;
1903 script->set_target("");
1905 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1906 script->old_proto = true;
1907 script->when = SCRIPT_After;
1908 script->set_target("%c");
1909 script->on_success = true;
1910 script->on_failure = false;
1912 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1913 script->old_proto = true;
1914 script->when = SCRIPT_Before;
1915 script->set_target("%c");
1916 script->fail_on_error = true;
1918 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1919 script->when = SCRIPT_After;
1920 script->on_failure = true;
1921 script->on_success = false;
1922 script->set_target("");
1925 if (*runscripts == NULL) {
1926 *runscripts = New(alist(10, not_owned_by_alist));
1929 (*runscripts)->append(script);
1936 /* Store a bool in a bit field without modifing res_all.hdr
1937 * We can also add an option to store_bool to skip res_all.hdr
1939 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1941 lex_get_token(lc, T_NAME);
1942 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1943 *(bool *)(item->value) = true;
1944 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1945 *(bool *)(item->value) = false;
1947 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1953 * new RunScript items
1954 * name handler value code flags default_value
1956 static RES_ITEM runscript_items[] = {
1957 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1958 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1959 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1960 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1961 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1962 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1963 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1964 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1965 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1966 {NULL, NULL, {0}, 0, 0, 0}
1970 * Store RunScript info
1972 * Note, when this routine is called, we are inside a Job
1973 * resource. We treat the RunScript like a sort of
1974 * mini-resource within the Job resource.
1976 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1980 alist **runscripts = (alist **)(item->value) ;
1982 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1984 token = lex_get_token(lc, T_SKIP_EOL);
1986 if (token != T_BOB) {
1987 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1989 /* setting on_success, on_failure, fail_on_error */
1990 res_runscript.reset_default();
1993 res_runscript.commands = New(alist(10, not_owned_by_alist));
1996 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1997 if (token == T_EOB) {
2000 if (token != T_IDENTIFIER) {
2001 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2003 for (i=0; runscript_items[i].name; i++) {
2004 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2005 token = lex_get_token(lc, T_SKIP_EOL);
2006 if (token != T_EQUALS) {
2007 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2010 /* Call item handler */
2011 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2018 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2023 /* run on client by default */
2024 if (res_runscript.target == NULL) {
2025 res_runscript.set_target("%c");
2027 if (*runscripts == NULL) {
2028 *runscripts = New(alist(10, not_owned_by_alist));
2031 * commands list contains 2 values per command
2032 * - POOLMEM command string (ex: /bin/true)
2033 * - int command type (ex: SHELL_CMD)
2035 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2036 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2037 t = (intptr_t)res_runscript.commands->pop();
2038 RUNSCRIPT *script = new_runscript();
2039 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2040 script->command = c;
2041 script->cmd_type = t;
2042 /* target is taken from res_runscript, each runscript object have
2045 script->target = NULL;
2046 script->set_target(res_runscript.target);
2048 (*runscripts)->append(script);
2051 delete res_runscript.commands;
2052 /* setting on_success, on_failure... cleanup target field */
2053 res_runscript.reset_default(true);
2057 set_bit(index, res_all.hdr.item_present);
2060 /* callback function for edit_job_codes */
2061 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2063 if (param[0] == 'f' && jcr->fileset) {
2064 return jcr->fileset->name();
2066 } else if (param[0] == 'h' && jcr->client) {
2067 return jcr->client->address;
2072 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2074 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2075 r_first, r_last, resources, res_head);
2076 return config->parse_config();