2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2010 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 {"rescheduleincompletejobs", store_bool, ITEM(res_job.RescheduleIncompleteJobs), 0, ITEM_DEFAULT, true},
332 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
333 {"rescheduletimes", store_pint32, ITEM(res_job.RescheduleTimes), 0, 0, 5},
334 {"priority", store_pint32, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
335 {"allowmixedpriority", store_bool, ITEM(res_job.allow_mixed_priority), 0, ITEM_DEFAULT, false},
336 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
337 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
338 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
339 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
340 {"accurate", store_bool, ITEM(res_job.accurate), 0,0,0},
341 {"allowduplicatejobs", store_bool, ITEM(res_job.AllowDuplicateJobs), 0, ITEM_DEFAULT, true},
342 {"allowhigherduplicates", store_bool, ITEM(res_job.AllowHigherDuplicates), 0, ITEM_DEFAULT, true},
343 {"cancellowerlevelduplicates", store_bool, ITEM(res_job.CancelLowerLevelDuplicates), 0, ITEM_DEFAULT, false},
344 {"cancelqueuedduplicates", store_bool, ITEM(res_job.CancelQueuedDuplicates), 0, ITEM_DEFAULT, false},
345 {"cancelrunningduplicates", store_bool, ITEM(res_job.CancelRunningDuplicates), 0, ITEM_DEFAULT, false},
346 {"pluginoptions", store_str, ITEM(res_job.PluginOptions), 0, 0, 0},
347 {"base", store_alist_res, ITEM(res_job.base), R_JOB, 0, 0},
348 {NULL, NULL, {0}, 0, 0, 0}
353 * name handler value code flags default_value
355 static RES_ITEM fs_items[] = {
356 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
357 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
358 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
359 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
360 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
361 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
362 {NULL, NULL, {0}, 0, 0, 0}
365 /* Schedule -- see run_conf.c */
368 * name handler value code flags default_value
370 static RES_ITEM sch_items[] = {
371 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
372 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
373 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
374 {NULL, NULL, {0}, 0, 0, 0}
379 * name handler value code flags default_value
381 static RES_ITEM pool_items[] = {
382 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
383 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
384 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
385 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
386 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
387 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
388 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
389 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
390 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
391 {"actiononpurge", store_actiononpurge, ITEM(res_pool.action_on_purge), 0, 0, 0},
392 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
393 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
394 {"maximumvolumes", store_pint32, ITEM(res_pool.max_volumes), 0, 0, 0},
395 {"maximumvolumejobs", store_pint32, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
396 {"maximumvolumefiles", store_pint32, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
397 {"maximumvolumebytes", store_size64, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
398 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
399 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
400 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
401 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
402 {"migrationhighbytes", store_size64, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
403 {"migrationlowbytes", store_size64, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
404 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
405 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
406 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
407 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
408 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
409 {"scratchpool", store_res, ITEM(res_pool.ScratchPool), R_POOL, 0, 0},
410 {"copypool", store_alist_res, ITEM(res_pool.CopyPool), R_POOL, 0, 0},
411 {"catalog", store_res, ITEM(res_pool.catalog), R_CATALOG, 0, 0},
412 {"fileretention", store_time, ITEM(res_pool.FileRetention), 0, 0, 0},
413 {"jobretention", store_time, ITEM(res_pool.JobRetention), 0, 0, 0},
415 {NULL, NULL, {0}, 0, 0, 0}
420 * name handler value code flags default_value
422 static RES_ITEM counter_items[] = {
423 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
424 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
425 {"minimum", store_int32, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
426 {"maximum", store_pint32, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
427 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
428 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
429 {NULL, NULL, {0}, 0, 0, 0}
433 /* Message resource */
434 extern RES_ITEM msgs_items[];
437 * This is the master resource definition.
438 * It must have one item for each of the resources.
440 * NOTE!!! keep it in the same order as the R_codes
441 * or eliminate all resources[rindex].name
443 * name items rcode res_head
445 RES_TABLE resources[] = {
446 {"director", dir_items, R_DIRECTOR},
447 {"client", cli_items, R_CLIENT},
448 {"job", job_items, R_JOB},
449 {"storage", store_items, R_STORAGE},
450 {"catalog", cat_items, R_CATALOG},
451 {"schedule", sch_items, R_SCHEDULE},
452 {"fileset", fs_items, R_FILESET},
453 {"pool", pool_items, R_POOL},
454 {"messages", msgs_items, R_MSGS},
455 {"counter", counter_items, R_COUNTER},
456 {"console", con_items, R_CONSOLE},
457 {"jobdefs", job_items, R_JOBDEFS},
458 {"device", NULL, R_DEVICE}, /* info obtained from SD */
463 /* Keywords (RHS) permitted in Job Level records
465 * level_name level job_type
467 struct s_jl joblevels[] = {
468 {"Full", L_FULL, JT_BACKUP},
469 {"Base", L_BASE, JT_BACKUP},
470 {"Incremental", L_INCREMENTAL, JT_BACKUP},
471 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
472 {"Since", L_SINCE, JT_BACKUP},
473 {"VirtualFull", L_VIRTUAL_FULL, JT_BACKUP},
474 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
475 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
476 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
477 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
478 {"Data", L_VERIFY_DATA, JT_VERIFY},
479 {" ", L_NONE, JT_ADMIN},
480 {" ", L_NONE, JT_RESTORE},
484 /* Keywords (RHS) permitted in Job type records
488 struct s_jt jobtypes[] = {
489 {"backup", JT_BACKUP},
491 {"verify", JT_VERIFY},
492 {"restore", JT_RESTORE},
493 {"migrate", JT_MIGRATE},
499 /* Keywords (RHS) permitted in Selection type records
503 struct s_jt migtypes[] = {
504 {"smallestvolume", MT_SMALLEST_VOL},
505 {"oldestvolume", MT_OLDEST_VOL},
506 {"pooloccupancy", MT_POOL_OCCUPANCY},
507 {"pooltime", MT_POOL_TIME},
508 {"pooluncopiedjobs", MT_POOL_UNCOPIED_JOBS},
509 {"client", MT_CLIENT},
510 {"volume", MT_VOLUME},
512 {"sqlquery", MT_SQLQUERY},
518 /* Options permitted in Restore replace= */
519 struct s_kw ReplaceOptions[] = {
520 {"always", REPLACE_ALWAYS},
521 {"ifnewer", REPLACE_IFNEWER},
522 {"ifolder", REPLACE_IFOLDER},
523 {"never", REPLACE_NEVER},
527 char *CAT::display(POOLMEM *dst) {
528 Mmsg(dst,"catalog=%s\ndb_name=%s\ndb_driver=%s\ndb_user=%s\n"
529 "db_password=%s\ndb_address=%s\ndb_port=%i\n"
531 name(), NPRTB(db_name),
532 NPRTB(db_driver), NPRTB(db_user), NPRTB(db_password),
533 NPRTB(db_address), db_port, NPRTB(db_socket));
537 const char *level_to_str(int level)
540 static char level_no[30];
541 const char *str = level_no;
543 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
544 for (i=0; joblevels[i].level_name; i++) {
545 if (level == (int)joblevels[i].level) {
546 str = joblevels[i].level_name;
553 /* Dump contents of resource */
554 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
556 URES *res = (URES *)reshdr;
558 char ed1[100], ed2[100], ed3[100];
562 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
565 if (type < 0) { /* no recursion */
571 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
572 reshdr->name, res->res_dir.MaxConcurrentJobs,
573 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
574 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
575 if (res->res_dir.query_file) {
576 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
578 if (res->res_dir.messages) {
579 sendit(sock, _(" --> "));
580 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
584 sendit(sock, _("Console: name=%s SSL=%d\n"),
585 res->res_con.hdr.name, res->res_con.tls_enable);
588 if (res->res_counter.WrapCounter) {
589 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
590 res->res_counter.hdr.name, res->res_counter.MinValue,
591 res->res_counter.MaxValue, res->res_counter.CurrentValue,
592 res->res_counter.WrapCounter->hdr.name);
594 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
595 res->res_counter.hdr.name, res->res_counter.MinValue,
596 res->res_counter.MaxValue);
598 if (res->res_counter.Catalog) {
599 sendit(sock, _(" --> "));
600 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
605 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
606 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
607 res->res_client.MaxConcurrentJobs);
608 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
609 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
610 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
611 res->res_client.AutoPrune);
612 if (res->res_client.max_bandwidth) {
613 sendit(sock, _(" MaximumBandwidth=%lld\n"),
614 res->res_client.max_bandwidth);
616 if (res->res_client.catalog) {
617 sendit(sock, _(" --> "));
618 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
625 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
626 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
627 " poolid=%s volname=%s MediaType=%s\n"),
628 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
629 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
630 dev->offline, dev->autochanger,
631 edit_uint64(dev->PoolId, ed1),
632 dev->VolumeName, dev->MediaType);
636 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
637 " DeviceName=%s MediaType=%s StorageId=%s\n"),
638 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
639 res->res_store.MaxConcurrentJobs,
640 res->res_store.dev_name(),
641 res->res_store.media_type,
642 edit_int64(res->res_store.StorageId, ed1));
646 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
647 " db_driver=%s db_user=%s MutliDBConn=%d\n"),
648 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
649 res->res_cat.db_port, res->res_cat.db_name,
650 NPRT(res->res_cat.db_driver), NPRT(res->res_cat.db_user),
651 res->res_cat.mult_db_connections);
656 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
657 type == R_JOB ? _("Job") : _("JobDefs"),
658 res->res_job.hdr.name, res->res_job.JobType,
659 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
660 res->res_job.enabled);
661 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
662 res->res_job.MaxConcurrentJobs,
663 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
664 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
665 res->res_job.spool_data, res->res_job.write_part_after_job);
666 if (res->res_job.spool_size) {
667 sendit(sock, _(" SpoolSize=%s\n"), edit_uint64(res->res_job.spool_size, ed1));
669 if (res->res_job.JobType == JT_BACKUP) {
670 sendit(sock, _(" Accurate=%d\n"), res->res_job.accurate);
672 if (res->res_job.max_bandwidth) {
673 sendit(sock, _(" MaximumBandwidth=%lld\n"),
674 res->res_job.max_bandwidth);
676 if (res->res_job.JobType == JT_MIGRATE || res->res_job.JobType == JT_COPY) {
677 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
679 if (res->res_job.client) {
680 sendit(sock, _(" --> "));
681 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
683 if (res->res_job.fileset) {
684 sendit(sock, _(" --> "));
685 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
687 if (res->res_job.schedule) {
688 sendit(sock, _(" --> "));
689 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
691 if (res->res_job.RestoreWhere && !res->res_job.RegexWhere) {
692 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
694 if (res->res_job.RegexWhere) {
695 sendit(sock, _(" --> RegexWhere=%s\n"), NPRT(res->res_job.RegexWhere));
697 if (res->res_job.RestoreBootstrap) {
698 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
700 if (res->res_job.WriteBootstrap) {
701 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
703 if (res->res_job.PluginOptions) {
704 sendit(sock, _(" --> PluginOptions=%s\n"), NPRT(res->res_job.PluginOptions));
706 if (res->res_job.MaxRunTime) {
707 sendit(sock, _(" --> MaxRunTime=%u\n"), res->res_job.MaxRunTime);
709 if (res->res_job.MaxWaitTime) {
710 sendit(sock, _(" --> MaxWaitTime=%u\n"), res->res_job.MaxWaitTime);
712 if (res->res_job.MaxStartDelay) {
713 sendit(sock, _(" --> MaxStartDelay=%u\n"), res->res_job.MaxStartDelay);
715 if (res->res_job.storage) {
717 foreach_alist(store, res->res_job.storage) {
718 sendit(sock, _(" --> "));
719 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
722 if (res->res_job.base) {
724 foreach_alist(job, res->res_job.base) {
725 sendit(sock, _(" --> Base %s\n"), job->name());
728 if (res->res_job.RunScripts) {
730 foreach_alist(script, res->res_job.RunScripts) {
731 sendit(sock, _(" --> RunScript\n"));
732 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
733 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
734 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
735 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
736 sendit(sock, _(" --> FailJobOnError=%u\n"), script->fail_on_error);
737 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
740 if (res->res_job.pool) {
741 sendit(sock, _(" --> "));
742 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
744 if (res->res_job.full_pool) {
745 sendit(sock, _(" --> "));
746 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
748 if (res->res_job.inc_pool) {
749 sendit(sock, _(" --> "));
750 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
752 if (res->res_job.diff_pool) {
753 sendit(sock, _(" --> "));
754 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
756 if (res->res_job.verify_job) {
757 sendit(sock, _(" --> "));
758 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
760 if (res->res_job.run_cmds) {
762 foreach_alist(runcmd, res->res_job.run_cmds) {
763 sendit(sock, _(" --> Run=%s\n"), runcmd);
766 if (res->res_job.selection_pattern) {
767 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
769 if (res->res_job.messages) {
770 sendit(sock, _(" --> "));
771 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
778 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
779 for (i=0; i<res->res_fs.num_includes; i++) {
780 INCEXE *incexe = res->res_fs.include_items[i];
781 for (j=0; j<incexe->num_opts; j++) {
782 FOPTS *fo = incexe->opts_list[j];
783 sendit(sock, " O %s\n", fo->opts);
785 bool enhanced_wild = false;
786 for (k=0; fo->opts[k]!='\0'; k++) {
787 if (fo->opts[k]=='W') {
788 enhanced_wild = true;
793 for (k=0; k<fo->regex.size(); k++) {
794 sendit(sock, " R %s\n", fo->regex.get(k));
796 for (k=0; k<fo->regexdir.size(); k++) {
797 sendit(sock, " RD %s\n", fo->regexdir.get(k));
799 for (k=0; k<fo->regexfile.size(); k++) {
800 sendit(sock, " RF %s\n", fo->regexfile.get(k));
802 for (k=0; k<fo->wild.size(); k++) {
803 sendit(sock, " W %s\n", fo->wild.get(k));
805 for (k=0; k<fo->wilddir.size(); k++) {
806 sendit(sock, " WD %s\n", fo->wilddir.get(k));
808 for (k=0; k<fo->wildfile.size(); k++) {
809 sendit(sock, " WF %s\n", fo->wildfile.get(k));
811 for (k=0; k<fo->wildbase.size(); k++) {
812 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
814 for (k=0; k<fo->base.size(); k++) {
815 sendit(sock, " B %s\n", fo->base.get(k));
817 for (k=0; k<fo->fstype.size(); k++) {
818 sendit(sock, " X %s\n", fo->fstype.get(k));
820 for (k=0; k<fo->drivetype.size(); k++) {
821 sendit(sock, " XD %s\n", fo->drivetype.get(k));
824 sendit(sock, " G %s\n", fo->plugin);
827 sendit(sock, " D %s\n", fo->reader);
830 sendit(sock, " T %s\n", fo->writer);
832 sendit(sock, " N\n");
834 if (incexe->ignoredir) {
835 sendit(sock, " Z %s\n", incexe->ignoredir);
837 for (j=0; j<incexe->name_list.size(); j++) {
838 sendit(sock, " I %s\n", incexe->name_list.get(j));
840 if (incexe->name_list.size()) {
841 sendit(sock, " N\n");
843 for (j=0; j<incexe->plugin_list.size(); j++) {
844 sendit(sock, " P %s\n", incexe->plugin_list.get(j));
846 if (incexe->plugin_list.size()) {
847 sendit(sock, " N\n");
852 for (i=0; i<res->res_fs.num_excludes; i++) {
853 INCEXE *incexe = res->res_fs.exclude_items[i];
854 for (j=0; j<incexe->name_list.size(); j++) {
855 sendit(sock, " E %s\n", incexe->name_list.get(j));
857 if (incexe->name_list.size()) {
858 sendit(sock, " N\n");
865 if (res->res_sch.run) {
867 RUN *run = res->res_sch.run;
868 char buf[1000], num[30];
869 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
874 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
875 bstrncpy(buf, _(" hour="), sizeof(buf));
876 for (i=0; i<24; i++) {
877 if (bit_is_set(i, run->hour)) {
878 bsnprintf(num, sizeof(num), "%d ", i);
879 bstrncat(buf, num, sizeof(buf));
882 bstrncat(buf, "\n", sizeof(buf));
884 bstrncpy(buf, _(" mday="), sizeof(buf));
885 for (i=0; i<31; i++) {
886 if (bit_is_set(i, run->mday)) {
887 bsnprintf(num, sizeof(num), "%d ", i);
888 bstrncat(buf, num, sizeof(buf));
891 bstrncat(buf, "\n", sizeof(buf));
893 bstrncpy(buf, _(" month="), sizeof(buf));
894 for (i=0; i<12; i++) {
895 if (bit_is_set(i, run->month)) {
896 bsnprintf(num, sizeof(num), "%d ", i);
897 bstrncat(buf, num, sizeof(buf));
900 bstrncat(buf, "\n", sizeof(buf));
902 bstrncpy(buf, _(" wday="), sizeof(buf));
903 for (i=0; i<7; i++) {
904 if (bit_is_set(i, run->wday)) {
905 bsnprintf(num, sizeof(num), "%d ", i);
906 bstrncat(buf, num, sizeof(buf));
909 bstrncat(buf, "\n", sizeof(buf));
911 bstrncpy(buf, _(" wom="), sizeof(buf));
912 for (i=0; i<5; i++) {
913 if (bit_is_set(i, run->wom)) {
914 bsnprintf(num, sizeof(num), "%d ", i);
915 bstrncat(buf, num, sizeof(buf));
918 bstrncat(buf, "\n", sizeof(buf));
920 bstrncpy(buf, _(" woy="), sizeof(buf));
921 for (i=0; i<54; i++) {
922 if (bit_is_set(i, run->woy)) {
923 bsnprintf(num, sizeof(num), "%d ", i);
924 bstrncat(buf, num, sizeof(buf));
927 bstrncat(buf, "\n", sizeof(buf));
929 sendit(sock, _(" mins=%d\n"), run->minute);
931 sendit(sock, _(" --> "));
932 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
935 sendit(sock, _(" --> "));
936 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
939 sendit(sock, _(" --> "));
940 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
942 /* If another Run record is chained in, go print it */
948 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
953 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
954 res->res_pool.pool_type);
955 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
956 res->res_pool.use_catalog, res->res_pool.use_volume_once,
957 res->res_pool.catalog_files);
958 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
959 res->res_pool.max_volumes, res->res_pool.AutoPrune,
960 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
961 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
962 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
963 res->res_pool.Recycle,
964 NPRT(res->res_pool.label_format));
965 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
966 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
967 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d ActionOnPurge=%d\n"),
968 res->res_pool.recycle_oldest_volume,
969 res->res_pool.purge_oldest_volume,
970 res->res_pool.action_on_purge);
971 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
972 res->res_pool.MaxVolJobs,
973 res->res_pool.MaxVolFiles,
974 edit_uint64(res->res_pool.MaxVolBytes, ed1));
975 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
976 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
977 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
978 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
979 sendit(sock, _(" JobRetention=%s FileRetention=%s\n"),
980 edit_utime(res->res_pool.JobRetention, ed1, sizeof(ed1)),
981 edit_utime(res->res_pool.FileRetention, ed2, sizeof(ed2)));
982 if (res->res_pool.NextPool) {
983 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
985 if (res->res_pool.RecyclePool) {
986 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
988 if (res->res_pool.ScratchPool) {
989 sendit(sock, _(" ScratchPool=%s\n"), res->res_pool.ScratchPool->name());
991 if (res->res_pool.catalog) {
992 sendit(sock, _(" Catalog=%s\n"), res->res_pool.catalog->name());
994 if (res->res_pool.storage) {
996 foreach_alist(store, res->res_pool.storage) {
997 sendit(sock, _(" --> "));
998 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
1001 if (res->res_pool.CopyPool) {
1003 foreach_alist(copy, res->res_pool.CopyPool) {
1004 sendit(sock, _(" --> "));
1005 dump_resource(-R_POOL, (RES *)copy, sendit, sock);
1012 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
1013 if (res->res_msgs.mail_cmd)
1014 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
1015 if (res->res_msgs.operator_cmd)
1016 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
1020 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
1023 if (recurse && res->res_dir.hdr.next) {
1024 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
1029 * Free all the members of an INCEXE structure
1031 static void free_incexe(INCEXE *incexe)
1033 incexe->name_list.destroy();
1034 incexe->plugin_list.destroy();
1035 for (int i=0; i<incexe->num_opts; i++) {
1036 FOPTS *fopt = incexe->opts_list[i];
1037 fopt->regex.destroy();
1038 fopt->regexdir.destroy();
1039 fopt->regexfile.destroy();
1040 fopt->wild.destroy();
1041 fopt->wilddir.destroy();
1042 fopt->wildfile.destroy();
1043 fopt->wildbase.destroy();
1044 fopt->base.destroy();
1045 fopt->fstype.destroy();
1046 fopt->drivetype.destroy();
1058 if (incexe->opts_list) {
1059 free(incexe->opts_list);
1061 if (incexe->ignoredir) {
1062 free(incexe->ignoredir);
1068 * Free memory of resource -- called when daemon terminates.
1069 * NB, we don't need to worry about freeing any references
1070 * to other resources as they will be freed when that
1071 * resource chain is traversed. Mainly we worry about freeing
1072 * allocated strings (names).
1074 void free_resource(RES *sres, int type)
1077 RES *nres; /* next resource if linked */
1078 URES *res = (URES *)sres;
1083 /* common stuff -- free the resource name and description */
1084 nres = (RES *)res->res_dir.hdr.next;
1085 if (res->res_dir.hdr.name) {
1086 free(res->res_dir.hdr.name);
1088 if (res->res_dir.hdr.desc) {
1089 free(res->res_dir.hdr.desc);
1094 if (res->res_dir.working_directory) {
1095 free(res->res_dir.working_directory);
1097 if (res->res_dir.scripts_directory) {
1098 free((char *)res->res_dir.scripts_directory);
1100 if (res->res_dir.plugin_directory) {
1101 free((char *)res->res_dir.plugin_directory);
1103 if (res->res_dir.pid_directory) {
1104 free(res->res_dir.pid_directory);
1106 if (res->res_dir.subsys_directory) {
1107 free(res->res_dir.subsys_directory);
1109 if (res->res_dir.password) {
1110 free(res->res_dir.password);
1112 if (res->res_dir.query_file) {
1113 free(res->res_dir.query_file);
1115 if (res->res_dir.DIRaddrs) {
1116 free_addresses(res->res_dir.DIRaddrs);
1118 if (res->res_dir.DIRsrc_addr) {
1119 free_addresses(res->res_dir.DIRsrc_addr);
1121 if (res->res_dir.tls_ctx) {
1122 free_tls_context(res->res_dir.tls_ctx);
1124 if (res->res_dir.tls_ca_certfile) {
1125 free(res->res_dir.tls_ca_certfile);
1127 if (res->res_dir.tls_ca_certdir) {
1128 free(res->res_dir.tls_ca_certdir);
1130 if (res->res_dir.tls_certfile) {
1131 free(res->res_dir.tls_certfile);
1133 if (res->res_dir.tls_keyfile) {
1134 free(res->res_dir.tls_keyfile);
1136 if (res->res_dir.tls_dhfile) {
1137 free(res->res_dir.tls_dhfile);
1139 if (res->res_dir.tls_allowed_cns) {
1140 delete res->res_dir.tls_allowed_cns;
1142 if (res->res_dir.verid) {
1143 free(res->res_dir.verid);
1150 if (res->res_con.password) {
1151 free(res->res_con.password);
1153 if (res->res_con.tls_ctx) {
1154 free_tls_context(res->res_con.tls_ctx);
1156 if (res->res_con.tls_ca_certfile) {
1157 free(res->res_con.tls_ca_certfile);
1159 if (res->res_con.tls_ca_certdir) {
1160 free(res->res_con.tls_ca_certdir);
1162 if (res->res_con.tls_certfile) {
1163 free(res->res_con.tls_certfile);
1165 if (res->res_con.tls_keyfile) {
1166 free(res->res_con.tls_keyfile);
1168 if (res->res_con.tls_dhfile) {
1169 free(res->res_con.tls_dhfile);
1171 if (res->res_con.tls_allowed_cns) {
1172 delete res->res_con.tls_allowed_cns;
1174 for (int i=0; i<Num_ACL; i++) {
1175 if (res->res_con.ACL_lists[i]) {
1176 delete res->res_con.ACL_lists[i];
1177 res->res_con.ACL_lists[i] = NULL;
1182 if (res->res_client.address) {
1183 free(res->res_client.address);
1185 if (res->res_client.password) {
1186 free(res->res_client.password);
1188 if (res->res_client.tls_ctx) {
1189 free_tls_context(res->res_client.tls_ctx);
1191 if (res->res_client.tls_ca_certfile) {
1192 free(res->res_client.tls_ca_certfile);
1194 if (res->res_client.tls_ca_certdir) {
1195 free(res->res_client.tls_ca_certdir);
1197 if (res->res_client.tls_certfile) {
1198 free(res->res_client.tls_certfile);
1200 if (res->res_client.tls_keyfile) {
1201 free(res->res_client.tls_keyfile);
1203 if (res->res_client.tls_allowed_cns) {
1204 delete res->res_client.tls_allowed_cns;
1208 if (res->res_store.address) {
1209 free(res->res_store.address);
1211 if (res->res_store.password) {
1212 free(res->res_store.password);
1214 if (res->res_store.media_type) {
1215 free(res->res_store.media_type);
1217 if (res->res_store.device) {
1218 delete res->res_store.device;
1220 if (res->res_store.tls_ctx) {
1221 free_tls_context(res->res_store.tls_ctx);
1223 if (res->res_store.tls_ca_certfile) {
1224 free(res->res_store.tls_ca_certfile);
1226 if (res->res_store.tls_ca_certdir) {
1227 free(res->res_store.tls_ca_certdir);
1229 if (res->res_store.tls_certfile) {
1230 free(res->res_store.tls_certfile);
1232 if (res->res_store.tls_keyfile) {
1233 free(res->res_store.tls_keyfile);
1237 if (res->res_cat.db_address) {
1238 free(res->res_cat.db_address);
1240 if (res->res_cat.db_socket) {
1241 free(res->res_cat.db_socket);
1243 if (res->res_cat.db_user) {
1244 free(res->res_cat.db_user);
1246 if (res->res_cat.db_name) {
1247 free(res->res_cat.db_name);
1249 if (res->res_cat.db_driver) {
1250 free(res->res_cat.db_driver);
1252 if (res->res_cat.db_password) {
1253 free(res->res_cat.db_password);
1257 if ((num=res->res_fs.num_includes)) {
1258 while (--num >= 0) {
1259 free_incexe(res->res_fs.include_items[num]);
1261 free(res->res_fs.include_items);
1263 res->res_fs.num_includes = 0;
1264 if ((num=res->res_fs.num_excludes)) {
1265 while (--num >= 0) {
1266 free_incexe(res->res_fs.exclude_items[num]);
1268 free(res->res_fs.exclude_items);
1270 res->res_fs.num_excludes = 0;
1273 if (res->res_pool.pool_type) {
1274 free(res->res_pool.pool_type);
1276 if (res->res_pool.label_format) {
1277 free(res->res_pool.label_format);
1279 if (res->res_pool.cleaning_prefix) {
1280 free(res->res_pool.cleaning_prefix);
1282 if (res->res_pool.storage) {
1283 delete res->res_pool.storage;
1287 if (res->res_sch.run) {
1289 nrun = res->res_sch.run;
1299 if (res->res_job.RestoreWhere) {
1300 free(res->res_job.RestoreWhere);
1302 if (res->res_job.RegexWhere) {
1303 free(res->res_job.RegexWhere);
1305 if (res->res_job.strip_prefix) {
1306 free(res->res_job.strip_prefix);
1308 if (res->res_job.add_prefix) {
1309 free(res->res_job.add_prefix);
1311 if (res->res_job.add_suffix) {
1312 free(res->res_job.add_suffix);
1314 if (res->res_job.RestoreBootstrap) {
1315 free(res->res_job.RestoreBootstrap);
1317 if (res->res_job.WriteBootstrap) {
1318 free(res->res_job.WriteBootstrap);
1320 if (res->res_job.PluginOptions) {
1321 free(res->res_job.PluginOptions);
1323 if (res->res_job.selection_pattern) {
1324 free(res->res_job.selection_pattern);
1326 if (res->res_job.run_cmds) {
1327 delete res->res_job.run_cmds;
1329 if (res->res_job.storage) {
1330 delete res->res_job.storage;
1332 if (res->res_job.base) {
1333 delete res->res_job.base;
1335 if (res->res_job.RunScripts) {
1336 free_runscripts(res->res_job.RunScripts);
1337 delete res->res_job.RunScripts;
1341 if (res->res_msgs.mail_cmd) {
1342 free(res->res_msgs.mail_cmd);
1344 if (res->res_msgs.operator_cmd) {
1345 free(res->res_msgs.operator_cmd);
1347 free_msgs_res((MSGS *)res); /* free message resource */
1351 printf(_("Unknown resource type %d in free_resource.\n"), type);
1353 /* Common stuff again -- free the resource, recurse to next one */
1358 free_resource(nres, type);
1363 * Save the new resource by chaining it into the head list for
1364 * the resource. If this is pass 2, we update any resource
1365 * pointers because they may not have been defined until
1368 void save_resource(int type, RES_ITEM *items, int pass)
1371 int rindex = type - r_first;
1375 /* Check Job requirements after applying JobDefs */
1376 if (type != R_JOB && type != R_JOBDEFS) {
1378 * Ensure that all required items are present
1380 for (i=0; items[i].name; i++) {
1381 if (items[i].flags & ITEM_REQUIRED) {
1382 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1383 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1384 items[i].name, resources[rindex]);
1387 /* If this triggers, take a look at lib/parse_conf.h */
1388 if (i >= MAX_RES_ITEMS) {
1389 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1392 } else if (type == R_JOB) {
1394 * Ensure that the name item is present
1396 if (items[0].flags & ITEM_REQUIRED) {
1397 if (!bit_is_set(0, 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[0].name, resources[rindex]);
1405 * During pass 2 in each "store" routine, we looked up pointers
1406 * to all the resources referrenced in the current resource, now we
1407 * must copy their addresses from the static record to the allocated
1412 /* Resources not containing a resource */
1420 * Resources containing another resource or alist. First
1421 * look up the resource which contains another resource. It
1422 * was written during pass 1. Then stuff in the pointers to
1423 * the resources it contains, which were inserted this pass.
1424 * Finally, it will all be stored back.
1427 /* Find resource saved in pass 1 */
1428 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1429 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1431 /* Explicitly copy resource pointers from this pass (res_all) */
1432 res->res_pool.NextPool = res_all.res_pool.NextPool;
1433 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1434 res->res_pool.ScratchPool = res_all.res_pool.ScratchPool;
1435 res->res_pool.storage = res_all.res_pool.storage;
1436 res->res_pool.catalog = res_all.res_pool.catalog;
1439 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1440 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1442 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1445 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1446 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1448 res->res_dir.messages = res_all.res_dir.messages;
1449 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1452 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1453 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1454 res_all.res_dir.hdr.name);
1456 /* we must explicitly copy the device alist pointer */
1457 res->res_store.device = res_all.res_store.device;
1461 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1462 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1463 res_all.res_dir.hdr.name);
1465 res->res_job.messages = res_all.res_job.messages;
1466 res->res_job.schedule = res_all.res_job.schedule;
1467 res->res_job.client = res_all.res_job.client;
1468 res->res_job.fileset = res_all.res_job.fileset;
1469 res->res_job.storage = res_all.res_job.storage;
1470 res->res_job.base = res_all.res_job.base;
1471 res->res_job.pool = res_all.res_job.pool;
1472 res->res_job.full_pool = res_all.res_job.full_pool;
1473 res->res_job.inc_pool = res_all.res_job.inc_pool;
1474 res->res_job.diff_pool = res_all.res_job.diff_pool;
1475 res->res_job.verify_job = res_all.res_job.verify_job;
1476 res->res_job.jobdefs = res_all.res_job.jobdefs;
1477 res->res_job.run_cmds = res_all.res_job.run_cmds;
1478 res->res_job.RunScripts = res_all.res_job.RunScripts;
1480 /* TODO: JobDefs where/regexwhere doesn't work well (but this
1481 * is not very useful)
1482 * We have to set_bit(index, res_all.hdr.item_present);
1483 * or something like that
1486 /* we take RegexWhere before all other options */
1487 if (!res->res_job.RegexWhere
1489 (res->res_job.strip_prefix ||
1490 res->res_job.add_suffix ||
1491 res->res_job.add_prefix))
1493 int len = bregexp_get_build_where_size(res->res_job.strip_prefix,
1494 res->res_job.add_prefix,
1495 res->res_job.add_suffix);
1496 res->res_job.RegexWhere = (char *) bmalloc (len * sizeof(char));
1497 bregexp_build_where(res->res_job.RegexWhere, len,
1498 res->res_job.strip_prefix,
1499 res->res_job.add_prefix,
1500 res->res_job.add_suffix);
1501 /* TODO: test bregexp */
1504 if (res->res_job.RegexWhere && res->res_job.RestoreWhere) {
1505 free(res->res_job.RestoreWhere);
1506 res->res_job.RestoreWhere = NULL;
1511 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1512 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1514 res->res_counter.Catalog = res_all.res_counter.Catalog;
1515 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1519 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1520 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1522 res->res_client.catalog = res_all.res_client.catalog;
1523 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1527 * Schedule is a bit different in that it contains a RUN record
1528 * chain which isn't a "named" resource. This chain was linked
1529 * in by run_conf.c during pass 2, so here we jam the pointer
1530 * into the Schedule resource.
1532 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1533 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1535 res->res_sch.run = res_all.res_sch.run;
1538 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1542 /* Note, the resource name was already saved during pass 1,
1543 * so here, we can just release it.
1545 if (res_all.res_dir.hdr.name) {
1546 free(res_all.res_dir.hdr.name);
1547 res_all.res_dir.hdr.name = NULL;
1549 if (res_all.res_dir.hdr.desc) {
1550 free(res_all.res_dir.hdr.desc);
1551 res_all.res_dir.hdr.desc = NULL;
1557 * The following code is only executed during pass 1
1561 size = sizeof(DIRRES);
1564 size = sizeof(CONRES);
1567 size =sizeof(CLIENT);
1570 size = sizeof(STORE);
1580 size = sizeof(FILESET);
1583 size = sizeof(SCHED);
1586 size = sizeof(POOL);
1589 size = sizeof(MSGS);
1592 size = sizeof(COUNTER);
1598 printf(_("Unknown resource type %d in save_resource.\n"), type);
1604 res = (URES *)malloc(size);
1605 memcpy(res, &res_all, size);
1606 if (!res_head[rindex]) {
1607 res_head[rindex] = (RES *)res; /* store first entry */
1608 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1609 res->res_dir.hdr.name, rindex);
1612 if (res->res_dir.hdr.name == NULL) {
1613 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1616 /* Add new res to end of chain */
1617 for (last=next=res_head[rindex]; next; next=next->next) {
1619 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1620 Emsg2(M_ERROR_TERM, 0,
1621 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1622 resources[rindex].name, res->res_dir.hdr.name);
1625 last->next = (RES *)res;
1626 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1627 res->res_dir.hdr.name, rindex, pass);
1632 static void store_actiononpurge(LEX *lc, RES_ITEM *item, int index, int pass)
1634 uint32_t *destination = (uint32_t*)item->value;
1635 lex_get_token(lc, T_NAME);
1636 if (strcasecmp(lc->str, "truncate") == 0) {
1637 *destination = (*destination) | ON_PURGE_TRUNCATE;
1639 scan_err2(lc, _("Expected one of: %s, got: %s"), "Truncate", lc->str);
1643 set_bit(index, res_all.hdr.item_present);
1647 * Store Device. Note, the resource is created upon the
1648 * first reference. The details of the resource are obtained
1649 * later from the SD.
1651 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1655 int rindex = R_DEVICE - r_first;
1656 int size = sizeof(DEVICE);
1660 token = lex_get_token(lc, T_NAME);
1661 if (!res_head[rindex]) {
1662 res = (URES *)malloc(size);
1663 memset(res, 0, size);
1664 res->res_dev.hdr.name = bstrdup(lc->str);
1665 res_head[rindex] = (RES *)res; /* store first entry */
1666 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1667 res->res_dir.hdr.name, rindex);
1670 /* See if it is already defined */
1671 for (next=res_head[rindex]; next->next; next=next->next) {
1672 if (strcmp(next->name, lc->str) == 0) {
1678 res = (URES *)malloc(size);
1679 memset(res, 0, size);
1680 res->res_dev.hdr.name = bstrdup(lc->str);
1681 next->next = (RES *)res;
1682 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1683 res->res_dir.hdr.name, rindex, pass);
1688 set_bit(index, res_all.hdr.item_present);
1690 store_alist_res(lc, item, index, pass);
1695 * Store Migration/Copy type
1698 void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1702 token = lex_get_token(lc, T_NAME);
1703 /* Store the type both pass 1 and pass 2 */
1704 for (i=0; migtypes[i].type_name; i++) {
1705 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1706 *(uint32_t *)(item->value) = migtypes[i].job_type;
1712 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1715 set_bit(index, res_all.hdr.item_present);
1721 * Store JobType (backup, verify, restore)
1724 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1728 token = lex_get_token(lc, T_NAME);
1729 /* Store the type both pass 1 and pass 2 */
1730 for (i=0; jobtypes[i].type_name; i++) {
1731 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1732 *(uint32_t *)(item->value) = jobtypes[i].job_type;
1738 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1741 set_bit(index, res_all.hdr.item_present);
1745 * Store Job Level (Full, Incremental, ...)
1748 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1752 token = lex_get_token(lc, T_NAME);
1753 /* Store the level pass 2 so that type is defined */
1754 for (i=0; joblevels[i].level_name; i++) {
1755 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1756 *(uint32_t *)(item->value) = joblevels[i].level;
1762 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1765 set_bit(index, res_all.hdr.item_present);
1769 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1772 token = lex_get_token(lc, T_NAME);
1773 /* Scan Replacement options */
1774 for (i=0; ReplaceOptions[i].name; i++) {
1775 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1776 *(uint32_t *)(item->value) = ReplaceOptions[i].token;
1782 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1785 set_bit(index, res_all.hdr.item_present);
1789 * Store ACL (access control list)
1792 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1797 token = lex_get_token(lc, T_STRING);
1799 if (((alist **)item->value)[item->code] == NULL) {
1800 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1801 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1803 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1804 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1806 token = lex_get_token(lc, T_ALL);
1807 if (token == T_COMMA) {
1808 continue; /* get another ACL */
1812 set_bit(index, res_all.hdr.item_present);
1815 /* We build RunScripts items here */
1816 static RUNSCRIPT res_runscript;
1818 /* Store a runscript->when in a bit field */
1819 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1821 lex_get_token(lc, T_NAME);
1823 if (strcasecmp(lc->str, "before") == 0) {
1824 *(uint32_t *)(item->value) = SCRIPT_Before ;
1825 } else if (strcasecmp(lc->str, "after") == 0) {
1826 *(uint32_t *)(item->value) = SCRIPT_After;
1827 } else if (strcasecmp(lc->str, "aftervss") == 0) {
1828 *(uint32_t *)(item->value) = SCRIPT_AfterVSS;
1829 } else if (strcasecmp(lc->str, "always") == 0) {
1830 *(uint32_t *)(item->value) = SCRIPT_Any;
1832 scan_err2(lc, _("Expect %s, got: %s"), "Before, After, AfterVSS or Always", lc->str);
1837 /* Store a runscript->target
1840 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1842 lex_get_token(lc, T_STRING);
1845 if (strcmp(lc->str, "%c") == 0) {
1846 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1847 } else if (strcasecmp(lc->str, "yes") == 0) {
1848 ((RUNSCRIPT*) item->value)->set_target("%c");
1849 } else if (strcasecmp(lc->str, "no") == 0) {
1850 ((RUNSCRIPT*) item->value)->set_target("");
1852 RES *res = GetResWithName(R_CLIENT, lc->str);
1854 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1855 lc->str, lc->line_no, lc->line);
1858 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1865 * Store a runscript->command as a string and runscript->cmd_type as a pointer
1867 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1869 lex_get_token(lc, T_STRING);
1872 Dmsg2(1, "runscript cmd=%s type=%c\n", lc->str, item->code);
1873 POOLMEM *c = get_pool_memory(PM_FNAME);
1874 /* Each runscript command takes 2 entries in commands list */
1875 pm_strcpy(c, lc->str);
1876 ((RUNSCRIPT*) item->value)->commands->prepend(c); /* command line */
1877 ((RUNSCRIPT*) item->value)->commands->prepend((void *)(intptr_t)item->code); /* command type */
1882 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1884 lex_get_token(lc, T_STRING);
1885 alist **runscripts = (alist **)(item->value) ;
1888 RUNSCRIPT *script = new_runscript();
1889 script->set_job_code_callback(job_code_callback_filesetname);
1891 script->set_command(lc->str);
1893 /* TODO: remove all script->old_proto with bacula 1.42 */
1895 if (strcmp(item->name, "runbeforejob") == 0) {
1896 script->when = SCRIPT_Before;
1897 script->fail_on_error = true;
1898 script->set_target("");
1900 } else if (strcmp(item->name, "runafterjob") == 0) {
1901 script->when = SCRIPT_After;
1902 script->on_success = true;
1903 script->on_failure = false;
1904 script->set_target("");
1906 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1907 script->old_proto = true;
1908 script->when = SCRIPT_After;
1909 script->set_target("%c");
1910 script->on_success = true;
1911 script->on_failure = false;
1913 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1914 script->old_proto = true;
1915 script->when = SCRIPT_Before;
1916 script->set_target("%c");
1917 script->fail_on_error = true;
1919 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1920 script->when = SCRIPT_After;
1921 script->on_failure = true;
1922 script->on_success = false;
1923 script->set_target("");
1926 if (*runscripts == NULL) {
1927 *runscripts = New(alist(10, not_owned_by_alist));
1930 (*runscripts)->append(script);
1937 /* Store a bool in a bit field without modifing res_all.hdr
1938 * We can also add an option to store_bool to skip res_all.hdr
1940 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1942 lex_get_token(lc, T_NAME);
1943 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1944 *(bool *)(item->value) = true;
1945 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1946 *(bool *)(item->value) = false;
1948 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1954 * new RunScript items
1955 * name handler value code flags default_value
1957 static RES_ITEM runscript_items[] = {
1958 {"command", store_runscript_cmd, {(char **)&res_runscript}, SHELL_CMD, 0, 0},
1959 {"console", store_runscript_cmd, {(char **)&res_runscript}, CONSOLE_CMD, 0, 0},
1960 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1961 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1962 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1963 {"failjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1964 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.fail_on_error},0, 0, 0},
1965 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1966 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1967 {NULL, NULL, {0}, 0, 0, 0}
1971 * Store RunScript info
1973 * Note, when this routine is called, we are inside a Job
1974 * resource. We treat the RunScript like a sort of
1975 * mini-resource within the Job resource.
1977 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1981 alist **runscripts = (alist **)(item->value) ;
1983 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1985 token = lex_get_token(lc, T_SKIP_EOL);
1987 if (token != T_BOB) {
1988 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1990 /* setting on_success, on_failure, fail_on_error */
1991 res_runscript.reset_default();
1994 res_runscript.commands = New(alist(10, not_owned_by_alist));
1997 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1998 if (token == T_EOB) {
2001 if (token != T_IDENTIFIER) {
2002 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
2004 for (i=0; runscript_items[i].name; i++) {
2005 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
2006 token = lex_get_token(lc, T_SKIP_EOL);
2007 if (token != T_EQUALS) {
2008 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
2011 /* Call item handler */
2012 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
2019 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
2024 /* run on client by default */
2025 if (res_runscript.target == NULL) {
2026 res_runscript.set_target("%c");
2028 if (*runscripts == NULL) {
2029 *runscripts = New(alist(10, not_owned_by_alist));
2032 * commands list contains 2 values per command
2033 * - POOLMEM command string (ex: /bin/true)
2034 * - int command type (ex: SHELL_CMD)
2036 res_runscript.set_job_code_callback(job_code_callback_filesetname);
2037 while ((c=(char*)res_runscript.commands->pop()) != NULL) {
2038 t = (intptr_t)res_runscript.commands->pop();
2039 RUNSCRIPT *script = new_runscript();
2040 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
2041 script->command = c;
2042 script->cmd_type = t;
2043 /* target is taken from res_runscript, each runscript object have
2046 script->target = NULL;
2047 script->set_target(res_runscript.target);
2049 (*runscripts)->append(script);
2052 delete res_runscript.commands;
2053 /* setting on_success, on_failure... cleanup target field */
2054 res_runscript.reset_default(true);
2058 set_bit(index, res_all.hdr.item_present);
2061 /* callback function for edit_job_codes */
2062 extern "C" char *job_code_callback_filesetname(JCR *jcr, const char* param)
2064 if (param[0] == 'f' && jcr->fileset) {
2065 return jcr->fileset->name();
2067 } else if (param[0] == 'h' && jcr->client) {
2068 return jcr->client->address;
2073 bool parse_dir_config(CONFIG *config, const char *configfile, int exit_code)
2075 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
2076 r_first, r_last, resources, res_head);
2077 return config->parse_config();