2 * Main configuration file parser for Bacula Directors,
3 * some parts may be split into separate files such as
4 * the schedule configuration (run_config.c).
6 * Note, the configuration file parser consists of three parts
8 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
10 * 2. The generic config scanner in lib/parse_config.c and
12 * These files contain the parser code, some utility
13 * routines, and the common store routines (name, int,
16 * 3. The daemon specific file, which contains the Resource
17 * definitions as well as any specific store routines
18 * for the resource records.
20 * Kern Sibbald, January MM
25 Bacula® - The Network Backup Solution
27 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
29 The main author of Bacula is Kern Sibbald, with contributions from
30 many others, a complete list can be found in the file AUTHORS.
31 This program is Free Software; you can redistribute it and/or
32 modify it under the terms of version two of the GNU General Public
33 License as published by the Free Software Foundation plus additions
34 that are listed in the file LICENSE.
36 This program is distributed in the hope that it will be useful, but
37 WITHOUT ANY WARRANTY; without even the implied warranty of
38 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
39 General Public License for more details.
41 You should have received a copy of the GNU General Public License
42 along with this program; if not, write to the Free Software
43 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
46 Bacula® is a registered trademark of John Walker.
47 The licensor of Bacula is the Free Software Foundation Europe
48 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
49 Switzerland, email:ftf@fsfeurope.org.
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 int r_first = R_FIRST;
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 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
77 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
83 /* We build the current resource here as we are
84 * scanning the resource configuration definition,
85 * then move it to allocated memory when the resource
89 extern "C" { // work around visual compiler mangling variables
95 int res_all_size = sizeof(res_all);
98 /* Definition of records permitted within each
99 * resource with the routine to process the record
100 * information. NOTE! quoted names must be in lower case.
105 * name handler value code flags default_value
107 static RES_ITEM dir_items[] = {
108 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
109 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
110 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
111 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
112 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
115 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
116 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
117 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
118 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
119 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
120 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
121 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
122 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
123 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
124 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
125 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
126 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
127 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
128 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
129 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
130 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
131 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
132 {NULL, NULL, {0}, 0, 0, 0}
138 * name handler value code flags default_value
140 static RES_ITEM con_items[] = {
141 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
142 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
143 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
144 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
145 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
146 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
147 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
148 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
149 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
150 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
151 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
152 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
153 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
154 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
155 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
156 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
157 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
158 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
159 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
160 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
161 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
162 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
163 {NULL, NULL, {0}, 0, 0, 0}
168 * Client or File daemon resource
170 * name handler value code flags default_value
173 static RES_ITEM cli_items[] = {
174 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
175 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
176 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
177 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
178 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
179 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
180 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
181 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
182 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
183 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
184 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
185 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
186 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
187 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
188 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
189 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
190 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
191 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
192 {NULL, NULL, {0}, 0, 0, 0}
195 /* Storage daemon resource
197 * name handler value code flags default_value
199 static RES_ITEM store_items[] = {
200 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
201 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
202 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
203 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
204 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
205 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
206 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
207 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
208 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
209 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
210 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
211 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
212 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
213 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
214 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
215 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
216 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
217 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
218 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
219 {NULL, NULL, {0}, 0, 0, 0}
223 * Catalog Resource Directives
225 * name handler value code flags default_value
227 static RES_ITEM cat_items[] = {
228 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
229 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
230 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
231 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
232 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
233 /* keep this password as store_str for the moment */
234 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
235 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
236 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
237 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
238 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
239 /* Turned off for the moment */
240 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
241 {NULL, NULL, {0}, 0, 0, 0}
245 * Job Resource Directives
247 * name handler value code flags default_value
249 RES_ITEM job_items[] = {
250 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
251 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
252 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
253 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
254 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
255 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
256 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
257 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
258 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
259 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
260 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
261 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
262 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
263 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
264 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
265 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
266 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
267 /* Root of where to restore files */
268 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
269 /* Where to find bootstrap during restore */
270 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
271 /* Where to write bootstrap file during backup */
272 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
273 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
274 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
275 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
276 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
277 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
278 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
279 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
280 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
281 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
282 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
283 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
284 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
285 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
286 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
287 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
288 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
289 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
290 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
291 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
292 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
293 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
294 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
295 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
296 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
297 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
298 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
299 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
300 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
301 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
302 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
303 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
304 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
305 {NULL, NULL, {0}, 0, 0, 0}
310 * name handler value code flags default_value
312 static RES_ITEM fs_items[] = {
313 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
314 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
315 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
316 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
317 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
318 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
319 {NULL, NULL, {0}, 0, 0, 0}
322 /* Schedule -- see run_conf.c */
325 * name handler value code flags default_value
327 static RES_ITEM sch_items[] = {
328 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
329 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
330 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
331 {NULL, NULL, {0}, 0, 0, 0}
336 * name handler value code flags default_value
338 static RES_ITEM pool_items[] = {
339 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
340 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
341 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
342 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
343 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
344 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
345 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
346 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
347 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
348 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
349 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
350 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
351 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
352 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
353 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
354 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
355 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
356 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
357 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
358 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
359 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
360 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
361 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
362 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
363 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
364 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
365 {NULL, NULL, {0}, 0, 0, 0}
370 * name handler value code flags default_value
372 static RES_ITEM counter_items[] = {
373 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
374 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
375 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
376 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
377 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
378 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
379 {NULL, NULL, {0}, 0, 0, 0}
383 /* Message resource */
384 extern RES_ITEM msgs_items[];
387 * This is the master resource definition.
388 * It must have one item for each of the resources.
390 * NOTE!!! keep it in the same order as the R_codes
391 * or eliminate all resources[rindex].name
393 * name items rcode res_head
395 RES_TABLE resources[] = {
396 {"director", dir_items, R_DIRECTOR},
397 {"client", cli_items, R_CLIENT},
398 {"job", job_items, R_JOB},
399 {"storage", store_items, R_STORAGE},
400 {"catalog", cat_items, R_CATALOG},
401 {"schedule", sch_items, R_SCHEDULE},
402 {"fileset", fs_items, R_FILESET},
403 {"pool", pool_items, R_POOL},
404 {"messages", msgs_items, R_MSGS},
405 {"counter", counter_items, R_COUNTER},
406 {"console", con_items, R_CONSOLE},
407 {"jobdefs", job_items, R_JOBDEFS},
408 {"device", NULL, R_DEVICE}, /* info obtained from SD */
413 /* Keywords (RHS) permitted in Job Level records
415 * level_name level job_type
417 struct s_jl joblevels[] = {
418 {"Full", L_FULL, JT_BACKUP},
419 {"Base", L_BASE, JT_BACKUP},
420 {"Incremental", L_INCREMENTAL, JT_BACKUP},
421 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
422 {"Since", L_SINCE, JT_BACKUP},
423 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
424 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
425 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
426 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
427 {"Data", L_VERIFY_DATA, JT_VERIFY},
428 {" ", L_NONE, JT_ADMIN},
429 {" ", L_NONE, JT_RESTORE},
433 /* Keywords (RHS) permitted in Job type records
437 struct s_jt jobtypes[] = {
438 {"backup", JT_BACKUP},
440 {"verify", JT_VERIFY},
441 {"restore", JT_RESTORE},
442 {"migrate", JT_MIGRATE},
447 /* Keywords (RHS) permitted in Selection type records
451 struct s_jt migtypes[] = {
452 {"smallestvolume", MT_SMALLEST_VOL},
453 {"oldestvolume", MT_OLDEST_VOL},
454 {"pooloccupancy", MT_POOL_OCCUPANCY},
455 {"pooltime", MT_POOL_TIME},
456 {"client", MT_CLIENT},
457 {"volume", MT_VOLUME},
459 {"sqlquery", MT_SQLQUERY},
465 /* Options permitted in Restore replace= */
466 struct s_kw ReplaceOptions[] = {
467 {"always", REPLACE_ALWAYS},
468 {"ifnewer", REPLACE_IFNEWER},
469 {"ifolder", REPLACE_IFOLDER},
470 {"never", REPLACE_NEVER},
474 const char *level_to_str(int level)
477 static char level_no[30];
478 const char *str = level_no;
480 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
481 for (i=0; joblevels[i].level_name; i++) {
482 if (level == joblevels[i].level) {
483 str = joblevels[i].level_name;
490 /* Dump contents of resource */
491 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
493 URES *res = (URES *)reshdr;
495 char ed1[100], ed2[100], ed3[100];
499 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
502 if (type < 0) { /* no recursion */
508 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
509 reshdr->name, res->res_dir.MaxConcurrentJobs,
510 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
511 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
512 if (res->res_dir.query_file) {
513 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
515 if (res->res_dir.messages) {
516 sendit(sock, _(" --> "));
517 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
521 sendit(sock, _("Console: name=%s SSL=%d\n"),
522 res->res_con.hdr.name, res->res_con.tls_enable);
525 if (res->res_counter.WrapCounter) {
526 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
527 res->res_counter.hdr.name, res->res_counter.MinValue,
528 res->res_counter.MaxValue, res->res_counter.CurrentValue,
529 res->res_counter.WrapCounter->hdr.name);
531 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
532 res->res_counter.hdr.name, res->res_counter.MinValue,
533 res->res_counter.MaxValue);
535 if (res->res_counter.Catalog) {
536 sendit(sock, _(" --> "));
537 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
542 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
543 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
544 res->res_client.MaxConcurrentJobs);
545 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
546 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
547 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
548 res->res_client.AutoPrune);
549 if (res->res_client.catalog) {
550 sendit(sock, _(" --> "));
551 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
557 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
558 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
559 " poolid=%s volname=%s MediaType=%s\n"),
560 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
561 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
562 dev->offline, dev->autochanger,
563 edit_uint64(dev->PoolId, ed1),
564 dev->VolumeName, dev->MediaType);
567 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
568 " DeviceName=%s MediaType=%s StorageId=%s\n"),
569 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
570 res->res_store.MaxConcurrentJobs,
571 res->res_store.dev_name(),
572 res->res_store.media_type,
573 edit_int64(res->res_store.StorageId, ed1));
576 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
577 " db_user=%s MutliDBConn=%d\n"),
578 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
579 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
580 res->res_cat.mult_db_connections);
584 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
585 type == R_JOB ? _("Job") : _("JobDefs"),
586 res->res_job.hdr.name, res->res_job.JobType,
587 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
588 res->res_job.enabled);
589 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
590 res->res_job.MaxConcurrentJobs,
591 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
592 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
593 res->res_job.spool_data, res->res_job.write_part_after_job);
594 if (res->res_job.JobType == JT_MIGRATE) {
595 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
597 if (res->res_job.client) {
598 sendit(sock, _(" --> "));
599 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
601 if (res->res_job.fileset) {
602 sendit(sock, _(" --> "));
603 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
605 if (res->res_job.schedule) {
606 sendit(sock, _(" --> "));
607 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
609 if (res->res_job.RestoreWhere) {
610 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
612 if (res->res_job.RestoreBootstrap) {
613 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
615 if (res->res_job.WriteBootstrap) {
616 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
618 if (res->res_job.storage) {
620 foreach_alist(store, res->res_job.storage) {
621 sendit(sock, _(" --> "));
622 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
625 if (res->res_job.RunScripts) {
627 foreach_alist(script, res->res_job.RunScripts) {
628 sendit(sock, _(" --> RunScript\n"));
629 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
630 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
631 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
632 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
633 sendit(sock, _(" --> AbortJobOnError=%u\n"), script->abort_on_error);
634 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
637 if (res->res_job.pool) {
638 sendit(sock, _(" --> "));
639 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
641 if (res->res_job.full_pool) {
642 sendit(sock, _(" --> "));
643 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
645 if (res->res_job.inc_pool) {
646 sendit(sock, _(" --> "));
647 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
649 if (res->res_job.diff_pool) {
650 sendit(sock, _(" --> "));
651 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
653 if (res->res_job.verify_job) {
654 sendit(sock, _(" --> "));
655 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
657 if (res->res_job.run_cmds) {
659 foreach_alist(runcmd, res->res_job.run_cmds) {
660 sendit(sock, _(" --> Run=%s\n"), runcmd);
663 if (res->res_job.selection_pattern) {
664 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
666 if (res->res_job.messages) {
667 sendit(sock, _(" --> "));
668 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
674 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
675 for (i=0; i<res->res_fs.num_includes; i++) {
676 INCEXE *incexe = res->res_fs.include_items[i];
677 for (j=0; j<incexe->num_opts; j++) {
678 FOPTS *fo = incexe->opts_list[j];
679 sendit(sock, " O %s\n", fo->opts);
681 bool enhanced_wild = false;
682 for (k=0; fo->opts[k]!='\0'; k++) {
683 if (fo->opts[k]=='W') {
684 enhanced_wild = true;
689 for (k=0; k<fo->regex.size(); k++) {
690 sendit(sock, " R %s\n", fo->regex.get(k));
692 for (k=0; k<fo->regexdir.size(); k++) {
693 sendit(sock, " RD %s\n", fo->regexdir.get(k));
695 for (k=0; k<fo->regexfile.size(); k++) {
696 sendit(sock, " RF %s\n", fo->regexfile.get(k));
698 for (k=0; k<fo->wild.size(); k++) {
699 sendit(sock, " W %s\n", fo->wild.get(k));
701 for (k=0; k<fo->wilddir.size(); k++) {
702 sendit(sock, " WD %s\n", fo->wilddir.get(k));
704 for (k=0; k<fo->wildfile.size(); k++) {
705 sendit(sock, " WF %s\n", fo->wildfile.get(k));
707 for (k=0; k<fo->wildbase.size(); k++) {
708 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
710 for (k=0; k<fo->base.size(); k++) {
711 sendit(sock, " B %s\n", fo->base.get(k));
713 for (k=0; k<fo->fstype.size(); k++) {
714 sendit(sock, " X %s\n", fo->fstype.get(k));
716 for (k=0; k<fo->drivetype.size(); k++) {
717 sendit(sock, " XD %s\n", fo->drivetype.get(k));
720 sendit(sock, " D %s\n", fo->reader);
723 sendit(sock, " T %s\n", fo->writer);
725 sendit(sock, " N\n");
727 for (j=0; j<incexe->name_list.size(); j++) {
728 sendit(sock, " I %s\n", incexe->name_list.get(j));
730 if (incexe->name_list.size()) {
731 sendit(sock, " N\n");
735 for (i=0; i<res->res_fs.num_excludes; i++) {
736 INCEXE *incexe = res->res_fs.exclude_items[i];
737 for (j=0; j<incexe->name_list.size(); j++) {
738 sendit(sock, " E %s\n", incexe->name_list.get(j));
740 if (incexe->name_list.size()) {
741 sendit(sock, " N\n");
747 if (res->res_sch.run) {
749 RUN *run = res->res_sch.run;
750 char buf[1000], num[30];
751 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
756 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
757 bstrncpy(buf, _(" hour="), sizeof(buf));
758 for (i=0; i<24; i++) {
759 if (bit_is_set(i, run->hour)) {
760 bsnprintf(num, sizeof(num), "%d ", i);
761 bstrncat(buf, num, sizeof(buf));
764 bstrncat(buf, "\n", sizeof(buf));
766 bstrncpy(buf, _(" mday="), sizeof(buf));
767 for (i=0; i<31; i++) {
768 if (bit_is_set(i, run->mday)) {
769 bsnprintf(num, sizeof(num), "%d ", i);
770 bstrncat(buf, num, sizeof(buf));
773 bstrncat(buf, "\n", sizeof(buf));
775 bstrncpy(buf, _(" month="), sizeof(buf));
776 for (i=0; i<12; i++) {
777 if (bit_is_set(i, run->month)) {
778 bsnprintf(num, sizeof(num), "%d ", i);
779 bstrncat(buf, num, sizeof(buf));
782 bstrncat(buf, "\n", sizeof(buf));
784 bstrncpy(buf, _(" wday="), sizeof(buf));
785 for (i=0; i<7; i++) {
786 if (bit_is_set(i, run->wday)) {
787 bsnprintf(num, sizeof(num), "%d ", i);
788 bstrncat(buf, num, sizeof(buf));
791 bstrncat(buf, "\n", sizeof(buf));
793 bstrncpy(buf, _(" wom="), sizeof(buf));
794 for (i=0; i<5; i++) {
795 if (bit_is_set(i, run->wom)) {
796 bsnprintf(num, sizeof(num), "%d ", i);
797 bstrncat(buf, num, sizeof(buf));
800 bstrncat(buf, "\n", sizeof(buf));
802 bstrncpy(buf, _(" woy="), sizeof(buf));
803 for (i=0; i<54; i++) {
804 if (bit_is_set(i, run->woy)) {
805 bsnprintf(num, sizeof(num), "%d ", i);
806 bstrncat(buf, num, sizeof(buf));
809 bstrncat(buf, "\n", sizeof(buf));
811 sendit(sock, _(" mins=%d\n"), run->minute);
813 sendit(sock, _(" --> "));
814 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
817 sendit(sock, _(" --> "));
818 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
821 sendit(sock, _(" --> "));
822 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
824 /* If another Run record is chained in, go print it */
830 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
834 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
835 res->res_pool.pool_type);
836 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
837 res->res_pool.use_catalog, res->res_pool.use_volume_once,
838 res->res_pool.catalog_files);
839 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
840 res->res_pool.max_volumes, res->res_pool.AutoPrune,
841 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
842 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
843 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
844 res->res_pool.Recycle,
845 NPRT(res->res_pool.label_format));
846 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
847 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
848 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
849 res->res_pool.recycle_oldest_volume,
850 res->res_pool.purge_oldest_volume,
851 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
852 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
853 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
854 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
855 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
856 if (res->res_pool.NextPool) {
857 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
859 if (res->res_pool.RecyclePool) {
860 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
862 if (res->res_pool.storage) {
864 foreach_alist(store, res->res_pool.storage) {
865 sendit(sock, _(" --> "));
866 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
871 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
872 if (res->res_msgs.mail_cmd)
873 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
874 if (res->res_msgs.operator_cmd)
875 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
878 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
881 if (recurse && res->res_dir.hdr.next) {
882 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
887 * Free all the members of an INCEXE structure
889 static void free_incexe(INCEXE *incexe)
891 incexe->name_list.destroy();
892 for (int i=0; i<incexe->num_opts; i++) {
893 FOPTS *fopt = incexe->opts_list[i];
894 fopt->regex.destroy();
895 fopt->regexdir.destroy();
896 fopt->regexfile.destroy();
897 fopt->wild.destroy();
898 fopt->wilddir.destroy();
899 fopt->wildfile.destroy();
900 fopt->wildbase.destroy();
901 fopt->base.destroy();
902 fopt->fstype.destroy();
903 fopt->drivetype.destroy();
912 if (incexe->opts_list) {
913 free(incexe->opts_list);
919 * Free memory of resource -- called when daemon terminates.
920 * NB, we don't need to worry about freeing any references
921 * to other resources as they will be freed when that
922 * resource chain is traversed. Mainly we worry about freeing
923 * allocated strings (names).
925 void free_resource(RES *sres, int type)
928 RES *nres; /* next resource if linked */
929 URES *res = (URES *)sres;
934 /* common stuff -- free the resource name and description */
935 nres = (RES *)res->res_dir.hdr.next;
936 if (res->res_dir.hdr.name) {
937 free(res->res_dir.hdr.name);
939 if (res->res_dir.hdr.desc) {
940 free(res->res_dir.hdr.desc);
945 if (res->res_dir.working_directory) {
946 free(res->res_dir.working_directory);
948 if (res->res_dir.scripts_directory) {
949 free((char *)res->res_dir.scripts_directory);
951 if (res->res_dir.pid_directory) {
952 free(res->res_dir.pid_directory);
954 if (res->res_dir.subsys_directory) {
955 free(res->res_dir.subsys_directory);
957 if (res->res_dir.password) {
958 free(res->res_dir.password);
960 if (res->res_dir.query_file) {
961 free(res->res_dir.query_file);
963 if (res->res_dir.DIRaddrs) {
964 free_addresses(res->res_dir.DIRaddrs);
966 if (res->res_dir.tls_ctx) {
967 free_tls_context(res->res_dir.tls_ctx);
969 if (res->res_dir.tls_ca_certfile) {
970 free(res->res_dir.tls_ca_certfile);
972 if (res->res_dir.tls_ca_certdir) {
973 free(res->res_dir.tls_ca_certdir);
975 if (res->res_dir.tls_certfile) {
976 free(res->res_dir.tls_certfile);
978 if (res->res_dir.tls_keyfile) {
979 free(res->res_dir.tls_keyfile);
981 if (res->res_dir.tls_dhfile) {
982 free(res->res_dir.tls_dhfile);
984 if (res->res_dir.tls_allowed_cns) {
985 delete res->res_dir.tls_allowed_cns;
992 if (res->res_con.password) {
993 free(res->res_con.password);
995 if (res->res_con.tls_ctx) {
996 free_tls_context(res->res_con.tls_ctx);
998 if (res->res_con.tls_ca_certfile) {
999 free(res->res_con.tls_ca_certfile);
1001 if (res->res_con.tls_ca_certdir) {
1002 free(res->res_con.tls_ca_certdir);
1004 if (res->res_con.tls_certfile) {
1005 free(res->res_con.tls_certfile);
1007 if (res->res_con.tls_keyfile) {
1008 free(res->res_con.tls_keyfile);
1010 if (res->res_con.tls_dhfile) {
1011 free(res->res_con.tls_dhfile);
1013 if (res->res_con.tls_allowed_cns) {
1014 delete res->res_con.tls_allowed_cns;
1016 for (int i=0; i<Num_ACL; i++) {
1017 if (res->res_con.ACL_lists[i]) {
1018 delete res->res_con.ACL_lists[i];
1019 res->res_con.ACL_lists[i] = NULL;
1024 if (res->res_client.address) {
1025 free(res->res_client.address);
1027 if (res->res_client.password) {
1028 free(res->res_client.password);
1030 if (res->res_client.tls_ctx) {
1031 free_tls_context(res->res_client.tls_ctx);
1033 if (res->res_client.tls_ca_certfile) {
1034 free(res->res_client.tls_ca_certfile);
1036 if (res->res_client.tls_ca_certdir) {
1037 free(res->res_client.tls_ca_certdir);
1039 if (res->res_client.tls_certfile) {
1040 free(res->res_client.tls_certfile);
1042 if (res->res_client.tls_keyfile) {
1043 free(res->res_client.tls_keyfile);
1047 if (res->res_store.address) {
1048 free(res->res_store.address);
1050 if (res->res_store.password) {
1051 free(res->res_store.password);
1053 if (res->res_store.media_type) {
1054 free(res->res_store.media_type);
1056 if (res->res_store.device) {
1057 delete res->res_store.device;
1059 if (res->res_store.tls_ctx) {
1060 free_tls_context(res->res_store.tls_ctx);
1062 if (res->res_store.tls_ca_certfile) {
1063 free(res->res_store.tls_ca_certfile);
1065 if (res->res_store.tls_ca_certdir) {
1066 free(res->res_store.tls_ca_certdir);
1068 if (res->res_store.tls_certfile) {
1069 free(res->res_store.tls_certfile);
1071 if (res->res_store.tls_keyfile) {
1072 free(res->res_store.tls_keyfile);
1076 if (res->res_cat.db_address) {
1077 free(res->res_cat.db_address);
1079 if (res->res_cat.db_socket) {
1080 free(res->res_cat.db_socket);
1082 if (res->res_cat.db_user) {
1083 free(res->res_cat.db_user);
1085 if (res->res_cat.db_name) {
1086 free(res->res_cat.db_name);
1088 if (res->res_cat.db_password) {
1089 free(res->res_cat.db_password);
1093 if ((num=res->res_fs.num_includes)) {
1094 while (--num >= 0) {
1095 free_incexe(res->res_fs.include_items[num]);
1097 free(res->res_fs.include_items);
1099 res->res_fs.num_includes = 0;
1100 if ((num=res->res_fs.num_excludes)) {
1101 while (--num >= 0) {
1102 free_incexe(res->res_fs.exclude_items[num]);
1104 free(res->res_fs.exclude_items);
1106 res->res_fs.num_excludes = 0;
1109 if (res->res_pool.pool_type) {
1110 free(res->res_pool.pool_type);
1112 if (res->res_pool.label_format) {
1113 free(res->res_pool.label_format);
1115 if (res->res_pool.cleaning_prefix) {
1116 free(res->res_pool.cleaning_prefix);
1118 if (res->res_pool.storage) {
1119 delete res->res_pool.storage;
1123 if (res->res_sch.run) {
1125 nrun = res->res_sch.run;
1135 if (res->res_job.RestoreWhere) {
1136 free(res->res_job.RestoreWhere);
1138 if (res->res_job.RestoreBootstrap) {
1139 free(res->res_job.RestoreBootstrap);
1141 if (res->res_job.WriteBootstrap) {
1142 free(res->res_job.WriteBootstrap);
1144 if (res->res_job.selection_pattern) {
1145 free(res->res_job.selection_pattern);
1147 if (res->res_job.run_cmds) {
1148 delete res->res_job.run_cmds;
1150 if (res->res_job.storage) {
1151 delete res->res_job.storage;
1153 if (res->res_job.RunScripts) {
1154 free_runscripts(res->res_job.RunScripts);
1155 delete res->res_job.RunScripts;
1159 if (res->res_msgs.mail_cmd) {
1160 free(res->res_msgs.mail_cmd);
1162 if (res->res_msgs.operator_cmd) {
1163 free(res->res_msgs.operator_cmd);
1165 free_msgs_res((MSGS *)res); /* free message resource */
1169 printf(_("Unknown resource type %d in free_resource.\n"), type);
1171 /* Common stuff again -- free the resource, recurse to next one */
1176 free_resource(nres, type);
1181 * Save the new resource by chaining it into the head list for
1182 * the resource. If this is pass 2, we update any resource
1183 * pointers because they may not have been defined until
1186 void save_resource(int type, RES_ITEM *items, int pass)
1189 int rindex = type - r_first;
1193 /* Check Job requirements after applying JobDefs */
1194 if (type != R_JOB && type != R_JOBDEFS) {
1196 * Ensure that all required items are present
1198 for (i=0; items[i].name; i++) {
1199 if (items[i].flags & ITEM_REQUIRED) {
1200 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1201 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1202 items[i].name, resources[rindex]);
1205 /* If this triggers, take a look at lib/parse_conf.h */
1206 if (i >= MAX_RES_ITEMS) {
1207 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1210 } else if (type == R_JOB) {
1212 * Ensure that the name item is present
1214 if (items[0].flags & ITEM_REQUIRED) {
1215 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1216 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1217 items[0].name, resources[rindex]);
1223 * During pass 2 in each "store" routine, we looked up pointers
1224 * to all the resources referrenced in the current resource, now we
1225 * must copy their addresses from the static record to the allocated
1230 /* Resources not containing a resource */
1238 * Resources containing another resource or alist. First
1239 * look up the resource which contains another resource. It
1240 * was written during pass 1. Then stuff in the pointers to
1241 * the resources it contains, which were inserted this pass.
1242 * Finally, it will all be stored back.
1245 /* Find resource saved in pass 1 */
1246 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1247 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1249 /* Explicitly copy resource pointers from this pass (res_all) */
1250 res->res_pool.NextPool = res_all.res_pool.NextPool;
1251 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1252 res->res_pool.storage = res_all.res_pool.storage;
1255 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1256 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1258 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1261 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1262 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1264 res->res_dir.messages = res_all.res_dir.messages;
1265 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1268 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1269 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1270 res_all.res_dir.hdr.name);
1272 /* we must explicitly copy the device alist pointer */
1273 res->res_store.device = res_all.res_store.device;
1277 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1278 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1279 res_all.res_dir.hdr.name);
1281 res->res_job.messages = res_all.res_job.messages;
1282 res->res_job.schedule = res_all.res_job.schedule;
1283 res->res_job.client = res_all.res_job.client;
1284 res->res_job.fileset = res_all.res_job.fileset;
1285 res->res_job.storage = res_all.res_job.storage;
1286 res->res_job.pool = res_all.res_job.pool;
1287 res->res_job.full_pool = res_all.res_job.full_pool;
1288 res->res_job.inc_pool = res_all.res_job.inc_pool;
1289 res->res_job.diff_pool = res_all.res_job.diff_pool;
1290 res->res_job.verify_job = res_all.res_job.verify_job;
1291 res->res_job.jobdefs = res_all.res_job.jobdefs;
1292 res->res_job.run_cmds = res_all.res_job.run_cmds;
1293 res->res_job.RunScripts = res_all.res_job.RunScripts;
1296 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1297 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1299 res->res_counter.Catalog = res_all.res_counter.Catalog;
1300 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1304 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1305 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1307 res->res_client.catalog = res_all.res_client.catalog;
1311 * Schedule is a bit different in that it contains a RUN record
1312 * chain which isn't a "named" resource. This chain was linked
1313 * in by run_conf.c during pass 2, so here we jam the pointer
1314 * into the Schedule resource.
1316 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1317 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1319 res->res_sch.run = res_all.res_sch.run;
1322 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1326 /* Note, the resource name was already saved during pass 1,
1327 * so here, we can just release it.
1329 if (res_all.res_dir.hdr.name) {
1330 free(res_all.res_dir.hdr.name);
1331 res_all.res_dir.hdr.name = NULL;
1333 if (res_all.res_dir.hdr.desc) {
1334 free(res_all.res_dir.hdr.desc);
1335 res_all.res_dir.hdr.desc = NULL;
1341 * The following code is only executed during pass 1
1345 size = sizeof(DIRRES);
1348 size = sizeof(CONRES);
1351 size =sizeof(CLIENT);
1354 size = sizeof(STORE);
1364 size = sizeof(FILESET);
1367 size = sizeof(SCHED);
1370 size = sizeof(POOL);
1373 size = sizeof(MSGS);
1376 size = sizeof(COUNTER);
1382 printf(_("Unknown resource type %d in save_resource.\n"), type);
1388 res = (URES *)malloc(size);
1389 memcpy(res, &res_all, size);
1390 if (!res_head[rindex]) {
1391 res_head[rindex] = (RES *)res; /* store first entry */
1392 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1393 res->res_dir.hdr.name, rindex);
1396 if (res->res_dir.hdr.name == NULL) {
1397 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1400 /* Add new res to end of chain */
1401 for (last=next=res_head[rindex]; next; next=next->next) {
1403 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1404 Emsg2(M_ERROR_TERM, 0,
1405 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1406 resources[rindex].name, res->res_dir.hdr.name);
1409 last->next = (RES *)res;
1410 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1411 res->res_dir.hdr.name, rindex, pass);
1417 * Store Device. Note, the resource is created upon the
1418 * first reference. The details of the resource are obtained
1419 * later from the SD.
1421 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1425 int rindex = R_DEVICE - r_first;
1426 int size = sizeof(DEVICE);
1430 token = lex_get_token(lc, T_NAME);
1431 if (!res_head[rindex]) {
1432 res = (URES *)malloc(size);
1433 memset(res, 0, size);
1434 res->res_dev.hdr.name = bstrdup(lc->str);
1435 res_head[rindex] = (RES *)res; /* store first entry */
1436 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1437 res->res_dir.hdr.name, rindex);
1440 /* See if it is already defined */
1441 for (next=res_head[rindex]; next->next; next=next->next) {
1442 if (strcmp(next->name, lc->str) == 0) {
1448 res = (URES *)malloc(size);
1449 memset(res, 0, size);
1450 res->res_dev.hdr.name = bstrdup(lc->str);
1451 next->next = (RES *)res;
1452 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1453 res->res_dir.hdr.name, rindex, pass);
1458 set_bit(index, res_all.hdr.item_present);
1460 store_alist_res(lc, item, index, pass);
1465 * Store JobType (backup, verify, restore)
1468 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1472 token = lex_get_token(lc, T_NAME);
1473 /* Store the type both pass 1 and pass 2 */
1474 for (i=0; migtypes[i].type_name; i++) {
1475 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1476 *(int *)(item->value) = migtypes[i].job_type;
1482 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1485 set_bit(index, res_all.hdr.item_present);
1491 * Store JobType (backup, verify, restore)
1494 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1498 token = lex_get_token(lc, T_NAME);
1499 /* Store the type both pass 1 and pass 2 */
1500 for (i=0; jobtypes[i].type_name; i++) {
1501 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1502 *(int *)(item->value) = jobtypes[i].job_type;
1508 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1511 set_bit(index, res_all.hdr.item_present);
1515 * Store Job Level (Full, Incremental, ...)
1518 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1522 token = lex_get_token(lc, T_NAME);
1523 /* Store the level pass 2 so that type is defined */
1524 for (i=0; joblevels[i].level_name; i++) {
1525 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1526 *(int *)(item->value) = joblevels[i].level;
1532 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1535 set_bit(index, res_all.hdr.item_present);
1539 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1542 token = lex_get_token(lc, T_NAME);
1543 /* Scan Replacement options */
1544 for (i=0; ReplaceOptions[i].name; i++) {
1545 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1546 *(int *)(item->value) = ReplaceOptions[i].token;
1552 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1555 set_bit(index, res_all.hdr.item_present);
1559 * Store ACL (access control list)
1562 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1567 token = lex_get_token(lc, T_STRING);
1569 if (((alist **)item->value)[item->code] == NULL) {
1570 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1571 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1573 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1574 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1576 token = lex_get_token(lc, T_ALL);
1577 if (token == T_COMMA) {
1578 continue; /* get another ACL */
1582 set_bit(index, res_all.hdr.item_present);
1585 /* We build RunScripts items here */
1586 static RUNSCRIPT res_runscript;
1588 /* Store a runscript->when in a bit field */
1589 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1591 lex_get_token(lc, T_NAME);
1593 if (strcasecmp(lc->str, "before") == 0) {
1594 *(int *)(item->value) = SCRIPT_Before ;
1595 } else if (strcasecmp(lc->str, "after") == 0) {
1596 *(int *)(item->value) = SCRIPT_After;
1597 } else if (strcasecmp(lc->str, "always") == 0) {
1598 *(int *)(item->value) = SCRIPT_Any;
1600 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1605 /* Store a runscript->target
1608 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1610 lex_get_token(lc, T_STRING);
1613 if (strcmp(lc->str, "%c") == 0) {
1614 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1615 } else if (strcasecmp(lc->str, "yes") == 0) {
1616 ((RUNSCRIPT*) item->value)->set_target("%c");
1617 } else if (strcasecmp(lc->str, "no") == 0) {
1618 ((RUNSCRIPT*) item->value)->set_target("");
1620 RES *res = GetResWithName(R_CLIENT, lc->str);
1622 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1623 lc->str, lc->line_no, lc->line);
1626 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1632 /* Store a runscript->command in a bit field
1635 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1637 lex_get_token(lc, T_STRING);
1640 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1645 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1647 lex_get_token(lc, T_STRING);
1648 alist **runscripts = (alist **)(item->value) ;
1651 RUNSCRIPT *script = new_runscript();
1653 script->set_command(lc->str);
1655 /* TODO: remove all script->old_proto with bacula 1.42 */
1657 if (strcmp(item->name, "runbeforejob") == 0) {
1658 script->when = SCRIPT_Before;
1659 script->abort_on_error = true;
1660 script->set_target("");
1662 } else if (strcmp(item->name, "runafterjob") == 0) {
1663 script->when = SCRIPT_After;
1664 script->on_success = true;
1665 script->on_failure = false;
1666 script->set_target("");
1668 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1669 script->old_proto = true;
1670 script->when = SCRIPT_After;
1671 script->set_target("%c");
1672 script->on_success = true;
1673 script->on_failure = false;
1675 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1676 script->old_proto = true;
1677 script->when = SCRIPT_Before;
1678 script->set_target("%c");
1679 script->abort_on_error = true;
1681 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1682 script->when = SCRIPT_After;
1683 script->on_failure = true;
1684 script->on_success = false;
1685 script->set_target("");
1688 if (*runscripts == NULL) {
1689 *runscripts = New(alist(10, not_owned_by_alist));
1692 (*runscripts)->append(script);
1699 /* Store a bool in a bit field without modifing res_all.hdr
1700 * We can also add an option to store_bool to skip res_all.hdr
1702 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1704 lex_get_token(lc, T_NAME);
1705 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1706 *(bool *)(item->value) = true;
1707 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1708 *(bool *)(item->value) = false;
1710 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1716 * new RunScript items
1717 * name handler value code flags default_value
1719 static RES_ITEM runscript_items[] = {
1720 {"command", store_runscript_cmd, {(char **)&res_runscript}, 0, ITEM_REQUIRED, 0},
1721 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1722 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1723 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1724 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.abort_on_error},0, 0, 0},
1725 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1726 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1727 {NULL, NULL, {0}, 0, 0, 0}
1731 * Store RunScript info
1733 * Note, when this routine is called, we are inside a Job
1734 * resource. We treat the RunScript like a sort of
1735 * mini-resource within the Job resource.
1737 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1740 alist **runscripts = (alist **)(item->value) ;
1742 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1744 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1746 token = lex_get_token(lc, T_SKIP_EOL);
1748 if (token != T_BOB) {
1749 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1752 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1753 if (token == T_EOB) {
1756 if (token != T_IDENTIFIER) {
1757 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1759 for (i=0; runscript_items[i].name; i++) {
1760 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1761 token = lex_get_token(lc, T_SKIP_EOL);
1762 if (token != T_EQUALS) {
1763 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1766 /* Call item handler */
1767 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1774 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1779 if (res_runscript.command == NULL) {
1780 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1781 "command", "runscript");
1784 /* run on client by default */
1785 if (res_runscript.target == NULL) {
1786 res_runscript.set_target("%c");
1789 RUNSCRIPT *script = new_runscript();
1790 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1792 if (*runscripts == NULL) {
1793 *runscripts = New(alist(10, not_owned_by_alist));
1796 (*runscripts)->append(script);
1801 set_bit(index, res_all.hdr.item_present);