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 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
304 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 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, false},
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 {NULL, NULL, {0}, 0, 0, 0}
369 * name handler value code flags default_value
371 static RES_ITEM counter_items[] = {
372 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
373 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
374 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
375 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
376 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
377 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
378 {NULL, NULL, {0}, 0, 0, 0}
382 /* Message resource */
383 extern RES_ITEM msgs_items[];
386 * This is the master resource definition.
387 * It must have one item for each of the resources.
389 * NOTE!!! keep it in the same order as the R_codes
390 * or eliminate all resources[rindex].name
392 * name items rcode res_head
394 RES_TABLE resources[] = {
395 {"director", dir_items, R_DIRECTOR},
396 {"client", cli_items, R_CLIENT},
397 {"job", job_items, R_JOB},
398 {"storage", store_items, R_STORAGE},
399 {"catalog", cat_items, R_CATALOG},
400 {"schedule", sch_items, R_SCHEDULE},
401 {"fileset", fs_items, R_FILESET},
402 {"pool", pool_items, R_POOL},
403 {"messages", msgs_items, R_MSGS},
404 {"counter", counter_items, R_COUNTER},
405 {"console", con_items, R_CONSOLE},
406 {"jobdefs", job_items, R_JOBDEFS},
407 {"device", NULL, R_DEVICE}, /* info obtained from SD */
412 /* Keywords (RHS) permitted in Job Level records
414 * level_name level job_type
416 struct s_jl joblevels[] = {
417 {"Full", L_FULL, JT_BACKUP},
418 {"Base", L_BASE, JT_BACKUP},
419 {"Incremental", L_INCREMENTAL, JT_BACKUP},
420 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
421 {"Since", L_SINCE, JT_BACKUP},
422 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
423 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
424 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
425 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
426 {"Data", L_VERIFY_DATA, JT_VERIFY},
427 {" ", L_NONE, JT_ADMIN},
428 {" ", L_NONE, JT_RESTORE},
432 /* Keywords (RHS) permitted in Job type records
436 struct s_jt jobtypes[] = {
437 {"backup", JT_BACKUP},
439 {"verify", JT_VERIFY},
440 {"restore", JT_RESTORE},
441 {"migrate", JT_MIGRATE},
446 /* Keywords (RHS) permitted in Selection type records
450 struct s_jt migtypes[] = {
451 {"smallestvolume", MT_SMALLEST_VOL},
452 {"oldestvolume", MT_OLDEST_VOL},
453 {"pooloccupancy", MT_POOL_OCCUPANCY},
454 {"pooltime", MT_POOL_TIME},
455 {"client", MT_CLIENT},
456 {"volume", MT_VOLUME},
458 {"sqlquery", MT_SQLQUERY},
464 /* Options permitted in Restore replace= */
465 struct s_kw ReplaceOptions[] = {
466 {"always", REPLACE_ALWAYS},
467 {"ifnewer", REPLACE_IFNEWER},
468 {"ifolder", REPLACE_IFOLDER},
469 {"never", REPLACE_NEVER},
473 const char *level_to_str(int level)
476 static char level_no[30];
477 const char *str = level_no;
479 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
480 for (i=0; joblevels[i].level_name; i++) {
481 if (level == joblevels[i].level) {
482 str = joblevels[i].level_name;
489 /* Dump contents of resource */
490 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
492 URES *res = (URES *)reshdr;
494 char ed1[100], ed2[100], ed3[100];
498 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
501 if (type < 0) { /* no recursion */
507 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
508 reshdr->name, res->res_dir.MaxConcurrentJobs,
509 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
510 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
511 if (res->res_dir.query_file) {
512 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
514 if (res->res_dir.messages) {
515 sendit(sock, _(" --> "));
516 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
520 sendit(sock, _("Console: name=%s SSL=%d\n"),
521 res->res_con.hdr.name, res->res_con.tls_enable);
524 if (res->res_counter.WrapCounter) {
525 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
526 res->res_counter.hdr.name, res->res_counter.MinValue,
527 res->res_counter.MaxValue, res->res_counter.CurrentValue,
528 res->res_counter.WrapCounter->hdr.name);
530 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
531 res->res_counter.hdr.name, res->res_counter.MinValue,
532 res->res_counter.MaxValue);
534 if (res->res_counter.Catalog) {
535 sendit(sock, _(" --> "));
536 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
541 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
542 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
543 res->res_client.MaxConcurrentJobs);
544 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
545 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
546 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
547 res->res_client.AutoPrune);
548 if (res->res_client.catalog) {
549 sendit(sock, _(" --> "));
550 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
556 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
557 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
558 " poolid=%s volname=%s MediaType=%s\n"),
559 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
560 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
561 dev->offline, dev->autochanger,
562 edit_uint64(dev->PoolId, ed1),
563 dev->VolumeName, dev->MediaType);
566 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
567 " DeviceName=%s MediaType=%s StorageId=%s\n"),
568 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
569 res->res_store.MaxConcurrentJobs,
570 res->res_store.dev_name(),
571 res->res_store.media_type,
572 edit_int64(res->res_store.StorageId, ed1));
575 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
576 " db_user=%s MutliDBConn=%d\n"),
577 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
578 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
579 res->res_cat.mult_db_connections);
583 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
584 type == R_JOB ? _("Job") : _("JobDefs"),
585 res->res_job.hdr.name, res->res_job.JobType,
586 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
587 res->res_job.enabled);
588 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
589 res->res_job.MaxConcurrentJobs,
590 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
591 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
592 res->res_job.spool_data, res->res_job.write_part_after_job);
593 if (res->res_job.JobType == JT_MIGRATE) {
594 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
596 if (res->res_job.client) {
597 sendit(sock, _(" --> "));
598 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
600 if (res->res_job.fileset) {
601 sendit(sock, _(" --> "));
602 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
604 if (res->res_job.schedule) {
605 sendit(sock, _(" --> "));
606 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
608 if (res->res_job.RestoreWhere) {
609 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
611 if (res->res_job.RestoreBootstrap) {
612 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
614 if (res->res_job.WriteBootstrap) {
615 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
617 if (res->res_job.storage) {
619 foreach_alist(store, res->res_job.storage) {
620 sendit(sock, _(" --> "));
621 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
624 if (res->res_job.RunScripts) {
626 foreach_alist(script, res->res_job.RunScripts) {
627 sendit(sock, _(" --> RunScript\n"));
628 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
629 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
630 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
631 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
632 sendit(sock, _(" --> AbortJobOnError=%u\n"), script->abort_on_error);
633 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
636 if (res->res_job.pool) {
637 sendit(sock, _(" --> "));
638 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
640 if (res->res_job.full_pool) {
641 sendit(sock, _(" --> "));
642 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
644 if (res->res_job.inc_pool) {
645 sendit(sock, _(" --> "));
646 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
648 if (res->res_job.diff_pool) {
649 sendit(sock, _(" --> "));
650 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
652 if (res->res_job.verify_job) {
653 sendit(sock, _(" --> "));
654 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
656 if (res->res_job.run_cmds) {
658 foreach_alist(runcmd, res->res_job.run_cmds) {
659 sendit(sock, _(" --> Run=%s\n"), runcmd);
662 if (res->res_job.selection_pattern) {
663 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
665 if (res->res_job.messages) {
666 sendit(sock, _(" --> "));
667 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
673 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
674 for (i=0; i<res->res_fs.num_includes; i++) {
675 INCEXE *incexe = res->res_fs.include_items[i];
676 for (j=0; j<incexe->num_opts; j++) {
677 FOPTS *fo = incexe->opts_list[j];
678 sendit(sock, " O %s\n", fo->opts);
680 bool enhanced_wild = false;
681 for (k=0; fo->opts[k]!='\0'; k++) {
682 if (fo->opts[k]=='W') {
683 enhanced_wild = true;
688 for (k=0; k<fo->regex.size(); k++) {
689 sendit(sock, " R %s\n", fo->regex.get(k));
691 for (k=0; k<fo->regexdir.size(); k++) {
692 sendit(sock, " RD %s\n", fo->regexdir.get(k));
694 for (k=0; k<fo->regexfile.size(); k++) {
695 sendit(sock, " RF %s\n", fo->regexfile.get(k));
697 for (k=0; k<fo->wild.size(); k++) {
698 sendit(sock, " W %s\n", fo->wild.get(k));
700 for (k=0; k<fo->wilddir.size(); k++) {
701 sendit(sock, " WD %s\n", fo->wilddir.get(k));
703 for (k=0; k<fo->wildfile.size(); k++) {
704 sendit(sock, " WF %s\n", fo->wildfile.get(k));
706 for (k=0; k<fo->wildbase.size(); k++) {
707 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
709 for (k=0; k<fo->base.size(); k++) {
710 sendit(sock, " B %s\n", fo->base.get(k));
712 for (k=0; k<fo->fstype.size(); k++) {
713 sendit(sock, " X %s\n", fo->fstype.get(k));
715 for (k=0; k<fo->drivetype.size(); k++) {
716 sendit(sock, " XD %s\n", fo->drivetype.get(k));
719 sendit(sock, " D %s\n", fo->reader);
722 sendit(sock, " T %s\n", fo->writer);
724 sendit(sock, " N\n");
726 for (j=0; j<incexe->name_list.size(); j++) {
727 sendit(sock, " I %s\n", incexe->name_list.get(j));
729 if (incexe->name_list.size()) {
730 sendit(sock, " N\n");
734 for (i=0; i<res->res_fs.num_excludes; i++) {
735 INCEXE *incexe = res->res_fs.exclude_items[i];
736 for (j=0; j<incexe->name_list.size(); j++) {
737 sendit(sock, " E %s\n", incexe->name_list.get(j));
739 if (incexe->name_list.size()) {
740 sendit(sock, " N\n");
746 if (res->res_sch.run) {
748 RUN *run = res->res_sch.run;
749 char buf[1000], num[30];
750 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
755 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
756 bstrncpy(buf, _(" hour="), sizeof(buf));
757 for (i=0; i<24; i++) {
758 if (bit_is_set(i, run->hour)) {
759 bsnprintf(num, sizeof(num), "%d ", i);
760 bstrncat(buf, num, sizeof(buf));
763 bstrncat(buf, "\n", sizeof(buf));
765 bstrncpy(buf, _(" mday="), sizeof(buf));
766 for (i=0; i<31; i++) {
767 if (bit_is_set(i, run->mday)) {
768 bsnprintf(num, sizeof(num), "%d ", i);
769 bstrncat(buf, num, sizeof(buf));
772 bstrncat(buf, "\n", sizeof(buf));
774 bstrncpy(buf, _(" month="), sizeof(buf));
775 for (i=0; i<12; i++) {
776 if (bit_is_set(i, run->month)) {
777 bsnprintf(num, sizeof(num), "%d ", i);
778 bstrncat(buf, num, sizeof(buf));
781 bstrncat(buf, "\n", sizeof(buf));
783 bstrncpy(buf, _(" wday="), sizeof(buf));
784 for (i=0; i<7; i++) {
785 if (bit_is_set(i, run->wday)) {
786 bsnprintf(num, sizeof(num), "%d ", i);
787 bstrncat(buf, num, sizeof(buf));
790 bstrncat(buf, "\n", sizeof(buf));
792 bstrncpy(buf, _(" wom="), sizeof(buf));
793 for (i=0; i<5; i++) {
794 if (bit_is_set(i, run->wom)) {
795 bsnprintf(num, sizeof(num), "%d ", i);
796 bstrncat(buf, num, sizeof(buf));
799 bstrncat(buf, "\n", sizeof(buf));
801 bstrncpy(buf, _(" woy="), sizeof(buf));
802 for (i=0; i<54; i++) {
803 if (bit_is_set(i, run->woy)) {
804 bsnprintf(num, sizeof(num), "%d ", i);
805 bstrncat(buf, num, sizeof(buf));
808 bstrncat(buf, "\n", sizeof(buf));
810 sendit(sock, _(" mins=%d\n"), run->minute);
812 sendit(sock, _(" --> "));
813 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
816 sendit(sock, _(" --> "));
817 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
820 sendit(sock, _(" --> "));
821 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
823 /* If another Run record is chained in, go print it */
829 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
833 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
834 res->res_pool.pool_type);
835 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
836 res->res_pool.use_catalog, res->res_pool.use_volume_once,
837 res->res_pool.catalog_files);
838 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
839 res->res_pool.max_volumes, res->res_pool.AutoPrune,
840 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
841 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
842 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
843 res->res_pool.Recycle,
844 NPRT(res->res_pool.label_format));
845 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
846 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
847 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
848 res->res_pool.recycle_oldest_volume,
849 res->res_pool.purge_oldest_volume,
850 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
851 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
852 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
853 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
854 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
855 if (res->res_pool.NextPool) {
856 sendit(sock, _(" --> "));
857 dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
859 if (res->res_pool.storage) {
861 foreach_alist(store, res->res_pool.storage) {
862 sendit(sock, _(" --> "));
863 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
868 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
869 if (res->res_msgs.mail_cmd)
870 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
871 if (res->res_msgs.operator_cmd)
872 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
875 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
878 if (recurse && res->res_dir.hdr.next) {
879 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
884 * Free all the members of an INCEXE structure
886 static void free_incexe(INCEXE *incexe)
888 incexe->name_list.destroy();
889 for (int i=0; i<incexe->num_opts; i++) {
890 FOPTS *fopt = incexe->opts_list[i];
891 fopt->regex.destroy();
892 fopt->regexdir.destroy();
893 fopt->regexfile.destroy();
894 fopt->wild.destroy();
895 fopt->wilddir.destroy();
896 fopt->wildfile.destroy();
897 fopt->wildbase.destroy();
898 fopt->base.destroy();
899 fopt->fstype.destroy();
900 fopt->drivetype.destroy();
909 if (incexe->opts_list) {
910 free(incexe->opts_list);
916 * Free memory of resource -- called when daemon terminates.
917 * NB, we don't need to worry about freeing any references
918 * to other resources as they will be freed when that
919 * resource chain is traversed. Mainly we worry about freeing
920 * allocated strings (names).
922 void free_resource(RES *sres, int type)
925 RES *nres; /* next resource if linked */
926 URES *res = (URES *)sres;
931 /* common stuff -- free the resource name and description */
932 nres = (RES *)res->res_dir.hdr.next;
933 if (res->res_dir.hdr.name) {
934 free(res->res_dir.hdr.name);
936 if (res->res_dir.hdr.desc) {
937 free(res->res_dir.hdr.desc);
942 if (res->res_dir.working_directory) {
943 free(res->res_dir.working_directory);
945 if (res->res_dir.scripts_directory) {
946 free((char *)res->res_dir.scripts_directory);
948 if (res->res_dir.pid_directory) {
949 free(res->res_dir.pid_directory);
951 if (res->res_dir.subsys_directory) {
952 free(res->res_dir.subsys_directory);
954 if (res->res_dir.password) {
955 free(res->res_dir.password);
957 if (res->res_dir.query_file) {
958 free(res->res_dir.query_file);
960 if (res->res_dir.DIRaddrs) {
961 free_addresses(res->res_dir.DIRaddrs);
963 if (res->res_dir.tls_ctx) {
964 free_tls_context(res->res_dir.tls_ctx);
966 if (res->res_dir.tls_ca_certfile) {
967 free(res->res_dir.tls_ca_certfile);
969 if (res->res_dir.tls_ca_certdir) {
970 free(res->res_dir.tls_ca_certdir);
972 if (res->res_dir.tls_certfile) {
973 free(res->res_dir.tls_certfile);
975 if (res->res_dir.tls_keyfile) {
976 free(res->res_dir.tls_keyfile);
978 if (res->res_dir.tls_dhfile) {
979 free(res->res_dir.tls_dhfile);
981 if (res->res_dir.tls_allowed_cns) {
982 delete res->res_dir.tls_allowed_cns;
989 if (res->res_con.password) {
990 free(res->res_con.password);
992 if (res->res_con.tls_ctx) {
993 free_tls_context(res->res_con.tls_ctx);
995 if (res->res_con.tls_ca_certfile) {
996 free(res->res_con.tls_ca_certfile);
998 if (res->res_con.tls_ca_certdir) {
999 free(res->res_con.tls_ca_certdir);
1001 if (res->res_con.tls_certfile) {
1002 free(res->res_con.tls_certfile);
1004 if (res->res_con.tls_keyfile) {
1005 free(res->res_con.tls_keyfile);
1007 if (res->res_con.tls_dhfile) {
1008 free(res->res_con.tls_dhfile);
1010 if (res->res_con.tls_allowed_cns) {
1011 delete res->res_con.tls_allowed_cns;
1013 for (int i=0; i<Num_ACL; i++) {
1014 if (res->res_con.ACL_lists[i]) {
1015 delete res->res_con.ACL_lists[i];
1016 res->res_con.ACL_lists[i] = NULL;
1021 if (res->res_client.address) {
1022 free(res->res_client.address);
1024 if (res->res_client.password) {
1025 free(res->res_client.password);
1027 if (res->res_client.tls_ctx) {
1028 free_tls_context(res->res_client.tls_ctx);
1030 if (res->res_client.tls_ca_certfile) {
1031 free(res->res_client.tls_ca_certfile);
1033 if (res->res_client.tls_ca_certdir) {
1034 free(res->res_client.tls_ca_certdir);
1036 if (res->res_client.tls_certfile) {
1037 free(res->res_client.tls_certfile);
1039 if (res->res_client.tls_keyfile) {
1040 free(res->res_client.tls_keyfile);
1044 if (res->res_store.address) {
1045 free(res->res_store.address);
1047 if (res->res_store.password) {
1048 free(res->res_store.password);
1050 if (res->res_store.media_type) {
1051 free(res->res_store.media_type);
1053 if (res->res_store.device) {
1054 delete res->res_store.device;
1056 if (res->res_store.tls_ctx) {
1057 free_tls_context(res->res_store.tls_ctx);
1059 if (res->res_store.tls_ca_certfile) {
1060 free(res->res_store.tls_ca_certfile);
1062 if (res->res_store.tls_ca_certdir) {
1063 free(res->res_store.tls_ca_certdir);
1065 if (res->res_store.tls_certfile) {
1066 free(res->res_store.tls_certfile);
1068 if (res->res_store.tls_keyfile) {
1069 free(res->res_store.tls_keyfile);
1073 if (res->res_cat.db_address) {
1074 free(res->res_cat.db_address);
1076 if (res->res_cat.db_socket) {
1077 free(res->res_cat.db_socket);
1079 if (res->res_cat.db_user) {
1080 free(res->res_cat.db_user);
1082 if (res->res_cat.db_name) {
1083 free(res->res_cat.db_name);
1085 if (res->res_cat.db_password) {
1086 free(res->res_cat.db_password);
1090 if ((num=res->res_fs.num_includes)) {
1091 while (--num >= 0) {
1092 free_incexe(res->res_fs.include_items[num]);
1094 free(res->res_fs.include_items);
1096 res->res_fs.num_includes = 0;
1097 if ((num=res->res_fs.num_excludes)) {
1098 while (--num >= 0) {
1099 free_incexe(res->res_fs.exclude_items[num]);
1101 free(res->res_fs.exclude_items);
1103 res->res_fs.num_excludes = 0;
1106 if (res->res_pool.pool_type) {
1107 free(res->res_pool.pool_type);
1109 if (res->res_pool.label_format) {
1110 free(res->res_pool.label_format);
1112 if (res->res_pool.cleaning_prefix) {
1113 free(res->res_pool.cleaning_prefix);
1115 if (res->res_pool.storage) {
1116 delete res->res_pool.storage;
1120 if (res->res_sch.run) {
1122 nrun = res->res_sch.run;
1132 if (res->res_job.RestoreWhere) {
1133 free(res->res_job.RestoreWhere);
1135 if (res->res_job.RestoreBootstrap) {
1136 free(res->res_job.RestoreBootstrap);
1138 if (res->res_job.WriteBootstrap) {
1139 free(res->res_job.WriteBootstrap);
1141 if (res->res_job.selection_pattern) {
1142 free(res->res_job.selection_pattern);
1144 if (res->res_job.run_cmds) {
1145 delete res->res_job.run_cmds;
1147 if (res->res_job.storage) {
1148 delete res->res_job.storage;
1150 if (res->res_job.RunScripts) {
1151 free_runscripts(res->res_job.RunScripts);
1152 delete res->res_job.RunScripts;
1156 if (res->res_msgs.mail_cmd) {
1157 free(res->res_msgs.mail_cmd);
1159 if (res->res_msgs.operator_cmd) {
1160 free(res->res_msgs.operator_cmd);
1162 free_msgs_res((MSGS *)res); /* free message resource */
1166 printf(_("Unknown resource type %d in free_resource.\n"), type);
1168 /* Common stuff again -- free the resource, recurse to next one */
1173 free_resource(nres, type);
1178 * Save the new resource by chaining it into the head list for
1179 * the resource. If this is pass 2, we update any resource
1180 * pointers because they may not have been defined until
1183 void save_resource(int type, RES_ITEM *items, int pass)
1186 int rindex = type - r_first;
1190 /* Check Job requirements after applying JobDefs */
1191 if (type != R_JOB && type != R_JOBDEFS) {
1193 * Ensure that all required items are present
1195 for (i=0; items[i].name; i++) {
1196 if (items[i].flags & ITEM_REQUIRED) {
1197 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1198 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1199 items[i].name, resources[rindex]);
1202 /* If this triggers, take a look at lib/parse_conf.h */
1203 if (i >= MAX_RES_ITEMS) {
1204 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1207 } else if (type == R_JOB) {
1209 * Ensure that the name item is present
1211 if (items[0].flags & ITEM_REQUIRED) {
1212 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1213 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1214 items[0].name, resources[rindex]);
1220 * During pass 2 in each "store" routine, we looked up pointers
1221 * to all the resources referrenced in the current resource, now we
1222 * must copy their addresses from the static record to the allocated
1227 /* Resources not containing a resource */
1235 * Resources containing another resource or alist. First
1236 * look up the resource which contains another resource. It
1237 * was written during pass 1. Then stuff in the pointers to
1238 * the resources it contains, which were inserted this pass.
1239 * Finally, it will all be stored back.
1242 /* Find resource saved in pass 1 */
1243 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1244 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1246 /* Explicitly copy resource pointers from this pass (res_all) */
1247 res->res_pool.NextPool = res_all.res_pool.NextPool;
1248 res->res_pool.storage = res_all.res_pool.storage;
1251 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1252 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1254 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1257 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1258 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1260 res->res_dir.messages = res_all.res_dir.messages;
1261 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1264 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1265 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1266 res_all.res_dir.hdr.name);
1268 /* we must explicitly copy the device alist pointer */
1269 res->res_store.device = res_all.res_store.device;
1273 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1274 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1275 res_all.res_dir.hdr.name);
1277 res->res_job.messages = res_all.res_job.messages;
1278 res->res_job.schedule = res_all.res_job.schedule;
1279 res->res_job.client = res_all.res_job.client;
1280 res->res_job.fileset = res_all.res_job.fileset;
1281 res->res_job.storage = res_all.res_job.storage;
1282 res->res_job.pool = res_all.res_job.pool;
1283 res->res_job.full_pool = res_all.res_job.full_pool;
1284 res->res_job.inc_pool = res_all.res_job.inc_pool;
1285 res->res_job.diff_pool = res_all.res_job.diff_pool;
1286 res->res_job.verify_job = res_all.res_job.verify_job;
1287 res->res_job.jobdefs = res_all.res_job.jobdefs;
1288 res->res_job.run_cmds = res_all.res_job.run_cmds;
1289 res->res_job.RunScripts = res_all.res_job.RunScripts;
1292 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1293 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1295 res->res_counter.Catalog = res_all.res_counter.Catalog;
1296 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1300 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1301 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1303 res->res_client.catalog = res_all.res_client.catalog;
1307 * Schedule is a bit different in that it contains a RUN record
1308 * chain which isn't a "named" resource. This chain was linked
1309 * in by run_conf.c during pass 2, so here we jam the pointer
1310 * into the Schedule resource.
1312 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1313 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1315 res->res_sch.run = res_all.res_sch.run;
1318 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1322 /* Note, the resource name was already saved during pass 1,
1323 * so here, we can just release it.
1325 if (res_all.res_dir.hdr.name) {
1326 free(res_all.res_dir.hdr.name);
1327 res_all.res_dir.hdr.name = NULL;
1329 if (res_all.res_dir.hdr.desc) {
1330 free(res_all.res_dir.hdr.desc);
1331 res_all.res_dir.hdr.desc = NULL;
1337 * The following code is only executed during pass 1
1341 size = sizeof(DIRRES);
1344 size = sizeof(CONRES);
1347 size =sizeof(CLIENT);
1350 size = sizeof(STORE);
1360 size = sizeof(FILESET);
1363 size = sizeof(SCHED);
1366 size = sizeof(POOL);
1369 size = sizeof(MSGS);
1372 size = sizeof(COUNTER);
1378 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1384 res = (URES *)malloc(size);
1385 memcpy(res, &res_all, size);
1386 if (!res_head[rindex]) {
1387 res_head[rindex] = (RES *)res; /* store first entry */
1388 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1389 res->res_dir.hdr.name, rindex);
1392 if (res->res_dir.hdr.name == NULL) {
1393 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1396 /* Add new res to end of chain */
1397 for (next=res_head[rindex]; next->next; next=next->next) {
1398 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1399 Emsg2(M_ERROR_TERM, 0,
1400 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1401 resources[rindex].name, res->res_dir.hdr.name);
1404 next->next = (RES *)res;
1405 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1406 res->res_dir.hdr.name, rindex, pass);
1412 * Store Device. Note, the resource is created upon the
1413 * first reference. The details of the resource are obtained
1414 * later from the SD.
1416 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1420 int rindex = R_DEVICE - r_first;
1421 int size = sizeof(DEVICE);
1425 token = lex_get_token(lc, T_NAME);
1426 if (!res_head[rindex]) {
1427 res = (URES *)malloc(size);
1428 memset(res, 0, size);
1429 res->res_dev.hdr.name = bstrdup(lc->str);
1430 res_head[rindex] = (RES *)res; /* store first entry */
1431 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1432 res->res_dir.hdr.name, rindex);
1435 /* See if it is already defined */
1436 for (next=res_head[rindex]; next->next; next=next->next) {
1437 if (strcmp(next->name, lc->str) == 0) {
1443 res = (URES *)malloc(size);
1444 memset(res, 0, size);
1445 res->res_dev.hdr.name = bstrdup(lc->str);
1446 next->next = (RES *)res;
1447 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1448 res->res_dir.hdr.name, rindex, pass);
1453 set_bit(index, res_all.hdr.item_present);
1455 store_alist_res(lc, item, index, pass);
1460 * Store JobType (backup, verify, restore)
1463 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1467 token = lex_get_token(lc, T_NAME);
1468 /* Store the type both pass 1 and pass 2 */
1469 for (i=0; migtypes[i].type_name; i++) {
1470 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1471 *(int *)(item->value) = migtypes[i].job_type;
1477 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1480 set_bit(index, res_all.hdr.item_present);
1486 * Store JobType (backup, verify, restore)
1489 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1493 token = lex_get_token(lc, T_NAME);
1494 /* Store the type both pass 1 and pass 2 */
1495 for (i=0; jobtypes[i].type_name; i++) {
1496 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1497 *(int *)(item->value) = jobtypes[i].job_type;
1503 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1506 set_bit(index, res_all.hdr.item_present);
1510 * Store Job Level (Full, Incremental, ...)
1513 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1517 token = lex_get_token(lc, T_NAME);
1518 /* Store the level pass 2 so that type is defined */
1519 for (i=0; joblevels[i].level_name; i++) {
1520 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1521 *(int *)(item->value) = joblevels[i].level;
1527 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1530 set_bit(index, res_all.hdr.item_present);
1534 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1537 token = lex_get_token(lc, T_NAME);
1538 /* Scan Replacement options */
1539 for (i=0; ReplaceOptions[i].name; i++) {
1540 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1541 *(int *)(item->value) = ReplaceOptions[i].token;
1547 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1550 set_bit(index, res_all.hdr.item_present);
1554 * Store ACL (access control list)
1557 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1562 token = lex_get_token(lc, T_STRING);
1564 if (((alist **)item->value)[item->code] == NULL) {
1565 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1566 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1568 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1569 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1571 token = lex_get_token(lc, T_ALL);
1572 if (token == T_COMMA) {
1573 continue; /* get another ACL */
1577 set_bit(index, res_all.hdr.item_present);
1580 /* We build RunScripts items here */
1581 static RUNSCRIPT res_runscript;
1583 /* Store a runscript->when in a bit field */
1584 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1586 lex_get_token(lc, T_NAME);
1588 if (strcasecmp(lc->str, "before") == 0) {
1589 *(int *)(item->value) = SCRIPT_Before ;
1590 } else if (strcasecmp(lc->str, "after") == 0) {
1591 *(int *)(item->value) = SCRIPT_After;
1592 } else if (strcasecmp(lc->str, "always") == 0) {
1593 *(int *)(item->value) = SCRIPT_Any;
1595 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1600 /* Store a runscript->target
1603 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1605 lex_get_token(lc, T_STRING);
1608 if (strcmp(lc->str, "%c") == 0) {
1609 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1610 } else if (strcmp(lc->str, "yes") == 0) {
1611 ((RUNSCRIPT*) item->value)->set_target("%c");
1612 } else if (strcmp(lc->str, "no") == 0) {
1613 ((RUNSCRIPT*) item->value)->set_target("");
1615 RES *res = GetResWithName(R_CLIENT, lc->str);
1617 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1618 lc->str, lc->line_no, lc->line);
1621 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1627 /* Store a runscript->command in a bit field
1630 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1632 lex_get_token(lc, T_STRING);
1635 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1640 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1642 lex_get_token(lc, T_STRING);
1643 alist **runscripts = (alist **)(item->value) ;
1646 RUNSCRIPT *script = new_runscript();
1648 script->set_command(lc->str);
1650 /* TODO: remove all script->old_proto with bacula 1.42 */
1652 if (strcmp(item->name, "runbeforejob") == 0) {
1653 script->when = SCRIPT_Before;
1654 script->abort_on_error = true;
1655 script->set_target("");
1657 } else if (strcmp(item->name, "runafterjob") == 0) {
1658 script->when = SCRIPT_After;
1659 script->on_success = true;
1660 script->on_failure = false;
1661 script->set_target("");
1663 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1664 script->old_proto = true;
1665 script->when = SCRIPT_After;
1666 script->set_target("%c");
1667 script->on_success = true;
1668 script->on_failure = false;
1670 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1671 script->old_proto = true;
1672 script->when = SCRIPT_Before;
1673 script->set_target("%c");
1674 script->abort_on_error = true;
1676 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1677 script->when = SCRIPT_After;
1678 script->on_failure = true;
1679 script->on_success = false;
1680 script->set_target("");
1683 if (*runscripts == NULL) {
1684 *runscripts = New(alist(10, not_owned_by_alist));
1687 (*runscripts)->append(script);
1695 * new RunScript items
1696 * name handler value code flags default_value
1698 static RES_ITEM runscript_items[] = {
1699 {"command", store_runscript_cmd, {(char **)&res_runscript}, 0, ITEM_REQUIRED, 0},
1700 {"target", store_runscript_target, {(char **)&res_runscript}, 0, 0, 0},
1701 {"runsonsuccess", store_bool, {(char **)&res_runscript.on_success}, 0, 0, 0},
1702 {"runsonfailure", store_bool, {(char **)&res_runscript.on_failure}, 0, 0, 0},
1703 {"abortjobonerror", store_bool, {(char **)&res_runscript.abort_on_error}, 0, 0, 0},
1704 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1705 {"runsonclient", store_runscript_target, {(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1706 {NULL, NULL, {0}, 0, 0, 0}
1710 * Store RunScript info
1712 * Note, when this routine is called, we are inside a Job
1713 * resource. We treat the RunScript like a sort of
1714 * mini-resource within the Job resource.
1716 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1719 alist **runscripts = (alist **)(item->value) ;
1721 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1723 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1725 token = lex_get_token(lc, T_SKIP_EOL);
1727 if (token != T_BOB) {
1728 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1731 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1732 if (token == T_EOB) {
1735 if (token != T_IDENTIFIER) {
1736 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1738 for (i=0; runscript_items[i].name; i++) {
1739 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1740 token = lex_get_token(lc, T_SKIP_EOL);
1741 if (token != T_EQUALS) {
1742 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1745 /* Call item handler */
1746 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1753 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1758 if (res_runscript.command == NULL) {
1759 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1760 "command", "runscript");
1763 /* run on client by default */
1764 if (res_runscript.target == NULL) {
1765 res_runscript.set_target("%c");
1768 RUNSCRIPT *script = new_runscript();
1769 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1771 if (*runscripts == NULL) {
1772 *runscripts = New(alist(10, not_owned_by_alist));
1775 (*runscripts)->append(script);
1780 set_bit(index, res_all.hdr.item_present);