2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation plus additions
11 that are listed in the file LICENSE.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Main configuration file parser for Bacula Directors,
30 * some parts may be split into separate files such as
31 * the schedule configuration (run_config.c).
33 * Note, the configuration file parser consists of three parts
35 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
37 * 2. The generic config scanner in lib/parse_config.c and
39 * These files contain the parser code, some utility
40 * routines, and the common store routines (name, int,
43 * 3. The daemon specific file, which contains the Resource
44 * definitions as well as any specific store routines
45 * for the resource records.
47 * Kern Sibbald, January MM
56 /* Define the first and last resource ID record
57 * types. Note, these should be unique for each
58 * daemon though not a requirement.
60 int r_first = R_FIRST;
62 static RES *sres_head[R_LAST - R_FIRST + 1];
63 RES **res_head = sres_head;
65 /* Imported subroutines */
66 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
67 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
68 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
71 /* Forward referenced subroutines */
73 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
74 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
75 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
76 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
77 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
78 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
79 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
80 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
81 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
82 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
84 /* We build the current resource here as we are
85 * scanning the resource configuration definition,
86 * then move it to allocated memory when the resource
90 extern "C" { // work around visual compiler mangling variables
96 int res_all_size = sizeof(res_all);
99 /* Definition of records permitted within each
100 * resource with the routine to process the record
101 * information. NOTE! quoted names must be in lower case.
106 * name handler value code flags default_value
108 static RES_ITEM dir_items[] = {
109 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
110 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
111 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
112 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
113 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
114 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
115 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
116 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
117 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
118 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
119 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
120 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
121 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
122 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
123 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
124 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
125 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
126 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
127 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
128 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
129 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
130 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
131 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
132 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
133 {NULL, NULL, {0}, 0, 0, 0}
139 * name handler value code flags default_value
141 static RES_ITEM con_items[] = {
142 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
143 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
144 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
145 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
146 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
147 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
148 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
149 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
150 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
151 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
152 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
153 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
154 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
155 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
156 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
157 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
158 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
159 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
160 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
161 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
162 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
163 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
164 {NULL, NULL, {0}, 0, 0, 0}
169 * Client or File daemon resource
171 * name handler value code flags default_value
174 static RES_ITEM cli_items[] = {
175 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
176 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
177 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
178 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
179 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
180 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
181 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
182 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
183 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
184 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
185 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
186 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
187 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
188 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
189 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
190 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
191 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
192 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
193 {"tlsallowedcn", store_alist_str, ITEM(res_client.tls_allowed_cns), 0, 0, 0},
194 {NULL, NULL, {0}, 0, 0, 0}
197 /* Storage daemon resource
199 * name handler value code flags default_value
201 static RES_ITEM store_items[] = {
202 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
203 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
204 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
205 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
206 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
207 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
208 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
209 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
210 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
211 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
212 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
213 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
214 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
215 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
216 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
217 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
218 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
219 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
220 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
221 {NULL, NULL, {0}, 0, 0, 0}
225 * Catalog Resource Directives
227 * name handler value code flags default_value
229 static RES_ITEM cat_items[] = {
230 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
231 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
232 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
233 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
234 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
235 /* keep this password as store_str for the moment */
236 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
237 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
238 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
239 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
240 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
241 /* Turned off for the moment */
242 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
243 {NULL, NULL, {0}, 0, 0, 0}
247 * Job Resource Directives
249 * name handler value code flags default_value
251 RES_ITEM job_items[] = {
252 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
253 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
254 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
255 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
256 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
257 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
258 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
259 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
260 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
261 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
262 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
263 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
264 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
265 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
266 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
267 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
268 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
269 /* Root of where to restore files */
270 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
271 /* Where to find bootstrap during restore */
272 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
273 /* Where to write bootstrap file during backup */
274 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
275 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
276 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
277 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
278 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
279 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
280 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
281 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
282 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
283 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
284 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
285 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
286 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
287 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
288 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
289 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
290 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
291 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
292 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
293 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
294 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
295 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
296 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
297 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
298 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
299 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
300 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
301 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
302 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
303 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
304 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
305 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
306 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
307 {NULL, NULL, {0}, 0, 0, 0}
312 * name handler value code flags default_value
314 static RES_ITEM fs_items[] = {
315 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
316 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
317 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
318 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
319 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
320 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
321 {NULL, NULL, {0}, 0, 0, 0}
324 /* Schedule -- see run_conf.c */
327 * name handler value code flags default_value
329 static RES_ITEM sch_items[] = {
330 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
331 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
332 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
333 {NULL, NULL, {0}, 0, 0, 0}
338 * name handler value code flags default_value
340 static RES_ITEM pool_items[] = {
341 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
342 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
343 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
344 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
345 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
346 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
347 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
348 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
349 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
350 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
351 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
352 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
353 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
354 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
355 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
356 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
357 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
358 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
359 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
360 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
361 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
362 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
363 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
364 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
365 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
366 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
367 {NULL, NULL, {0}, 0, 0, 0}
372 * name handler value code flags default_value
374 static RES_ITEM counter_items[] = {
375 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
376 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
377 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
378 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
379 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
380 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
381 {NULL, NULL, {0}, 0, 0, 0}
385 /* Message resource */
386 extern RES_ITEM msgs_items[];
389 * This is the master resource definition.
390 * It must have one item for each of the resources.
392 * NOTE!!! keep it in the same order as the R_codes
393 * or eliminate all resources[rindex].name
395 * name items rcode res_head
397 RES_TABLE resources[] = {
398 {"director", dir_items, R_DIRECTOR},
399 {"client", cli_items, R_CLIENT},
400 {"job", job_items, R_JOB},
401 {"storage", store_items, R_STORAGE},
402 {"catalog", cat_items, R_CATALOG},
403 {"schedule", sch_items, R_SCHEDULE},
404 {"fileset", fs_items, R_FILESET},
405 {"pool", pool_items, R_POOL},
406 {"messages", msgs_items, R_MSGS},
407 {"counter", counter_items, R_COUNTER},
408 {"console", con_items, R_CONSOLE},
409 {"jobdefs", job_items, R_JOBDEFS},
410 {"device", NULL, R_DEVICE}, /* info obtained from SD */
415 /* Keywords (RHS) permitted in Job Level records
417 * level_name level job_type
419 struct s_jl joblevels[] = {
420 {"Full", L_FULL, JT_BACKUP},
421 {"Base", L_BASE, JT_BACKUP},
422 {"Incremental", L_INCREMENTAL, JT_BACKUP},
423 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
424 {"Since", L_SINCE, JT_BACKUP},
425 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
426 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
427 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
428 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
429 {"Data", L_VERIFY_DATA, JT_VERIFY},
430 {" ", L_NONE, JT_ADMIN},
431 {" ", L_NONE, JT_RESTORE},
435 /* Keywords (RHS) permitted in Job type records
439 struct s_jt jobtypes[] = {
440 {"backup", JT_BACKUP},
442 {"verify", JT_VERIFY},
443 {"restore", JT_RESTORE},
444 {"migrate", JT_MIGRATE},
449 /* Keywords (RHS) permitted in Selection type records
453 struct s_jt migtypes[] = {
454 {"smallestvolume", MT_SMALLEST_VOL},
455 {"oldestvolume", MT_OLDEST_VOL},
456 {"pooloccupancy", MT_POOL_OCCUPANCY},
457 {"pooltime", MT_POOL_TIME},
458 {"client", MT_CLIENT},
459 {"volume", MT_VOLUME},
461 {"sqlquery", MT_SQLQUERY},
467 /* Options permitted in Restore replace= */
468 struct s_kw ReplaceOptions[] = {
469 {"always", REPLACE_ALWAYS},
470 {"ifnewer", REPLACE_IFNEWER},
471 {"ifolder", REPLACE_IFOLDER},
472 {"never", REPLACE_NEVER},
476 const char *level_to_str(int level)
479 static char level_no[30];
480 const char *str = level_no;
482 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
483 for (i=0; joblevels[i].level_name; i++) {
484 if (level == joblevels[i].level) {
485 str = joblevels[i].level_name;
492 /* Dump contents of resource */
493 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
495 URES *res = (URES *)reshdr;
497 char ed1[100], ed2[100], ed3[100];
501 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
504 if (type < 0) { /* no recursion */
510 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
511 reshdr->name, res->res_dir.MaxConcurrentJobs,
512 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
513 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
514 if (res->res_dir.query_file) {
515 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
517 if (res->res_dir.messages) {
518 sendit(sock, _(" --> "));
519 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
523 sendit(sock, _("Console: name=%s SSL=%d\n"),
524 res->res_con.hdr.name, res->res_con.tls_enable);
527 if (res->res_counter.WrapCounter) {
528 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
529 res->res_counter.hdr.name, res->res_counter.MinValue,
530 res->res_counter.MaxValue, res->res_counter.CurrentValue,
531 res->res_counter.WrapCounter->hdr.name);
533 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
534 res->res_counter.hdr.name, res->res_counter.MinValue,
535 res->res_counter.MaxValue);
537 if (res->res_counter.Catalog) {
538 sendit(sock, _(" --> "));
539 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
544 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
545 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
546 res->res_client.MaxConcurrentJobs);
547 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
548 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
549 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
550 res->res_client.AutoPrune);
551 if (res->res_client.catalog) {
552 sendit(sock, _(" --> "));
553 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
559 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
560 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
561 " poolid=%s volname=%s MediaType=%s\n"),
562 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
563 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
564 dev->offline, dev->autochanger,
565 edit_uint64(dev->PoolId, ed1),
566 dev->VolumeName, dev->MediaType);
569 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
570 " DeviceName=%s MediaType=%s StorageId=%s\n"),
571 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
572 res->res_store.MaxConcurrentJobs,
573 res->res_store.dev_name(),
574 res->res_store.media_type,
575 edit_int64(res->res_store.StorageId, ed1));
578 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
579 " db_user=%s MutliDBConn=%d\n"),
580 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
581 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
582 res->res_cat.mult_db_connections);
586 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
587 type == R_JOB ? _("Job") : _("JobDefs"),
588 res->res_job.hdr.name, res->res_job.JobType,
589 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
590 res->res_job.enabled);
591 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
592 res->res_job.MaxConcurrentJobs,
593 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
594 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
595 res->res_job.spool_data, res->res_job.write_part_after_job);
596 if (res->res_job.JobType == JT_MIGRATE) {
597 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
599 if (res->res_job.client) {
600 sendit(sock, _(" --> "));
601 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
603 if (res->res_job.fileset) {
604 sendit(sock, _(" --> "));
605 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
607 if (res->res_job.schedule) {
608 sendit(sock, _(" --> "));
609 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
611 if (res->res_job.RestoreWhere) {
612 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
614 if (res->res_job.RestoreBootstrap) {
615 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
617 if (res->res_job.WriteBootstrap) {
618 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
620 if (res->res_job.storage) {
622 foreach_alist(store, res->res_job.storage) {
623 sendit(sock, _(" --> "));
624 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
627 if (res->res_job.RunScripts) {
629 foreach_alist(script, res->res_job.RunScripts) {
630 sendit(sock, _(" --> RunScript\n"));
631 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
632 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
633 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
634 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
635 sendit(sock, _(" --> AbortJobOnError=%u\n"), script->abort_on_error);
636 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
639 if (res->res_job.pool) {
640 sendit(sock, _(" --> "));
641 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
643 if (res->res_job.full_pool) {
644 sendit(sock, _(" --> "));
645 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
647 if (res->res_job.inc_pool) {
648 sendit(sock, _(" --> "));
649 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
651 if (res->res_job.diff_pool) {
652 sendit(sock, _(" --> "));
653 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
655 if (res->res_job.verify_job) {
656 sendit(sock, _(" --> "));
657 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
659 if (res->res_job.run_cmds) {
661 foreach_alist(runcmd, res->res_job.run_cmds) {
662 sendit(sock, _(" --> Run=%s\n"), runcmd);
665 if (res->res_job.selection_pattern) {
666 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
668 if (res->res_job.messages) {
669 sendit(sock, _(" --> "));
670 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
676 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
677 for (i=0; i<res->res_fs.num_includes; i++) {
678 INCEXE *incexe = res->res_fs.include_items[i];
679 for (j=0; j<incexe->num_opts; j++) {
680 FOPTS *fo = incexe->opts_list[j];
681 sendit(sock, " O %s\n", fo->opts);
683 bool enhanced_wild = false;
684 for (k=0; fo->opts[k]!='\0'; k++) {
685 if (fo->opts[k]=='W') {
686 enhanced_wild = true;
691 for (k=0; k<fo->regex.size(); k++) {
692 sendit(sock, " R %s\n", fo->regex.get(k));
694 for (k=0; k<fo->regexdir.size(); k++) {
695 sendit(sock, " RD %s\n", fo->regexdir.get(k));
697 for (k=0; k<fo->regexfile.size(); k++) {
698 sendit(sock, " RF %s\n", fo->regexfile.get(k));
700 for (k=0; k<fo->wild.size(); k++) {
701 sendit(sock, " W %s\n", fo->wild.get(k));
703 for (k=0; k<fo->wilddir.size(); k++) {
704 sendit(sock, " WD %s\n", fo->wilddir.get(k));
706 for (k=0; k<fo->wildfile.size(); k++) {
707 sendit(sock, " WF %s\n", fo->wildfile.get(k));
709 for (k=0; k<fo->wildbase.size(); k++) {
710 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
712 for (k=0; k<fo->base.size(); k++) {
713 sendit(sock, " B %s\n", fo->base.get(k));
715 for (k=0; k<fo->fstype.size(); k++) {
716 sendit(sock, " X %s\n", fo->fstype.get(k));
718 for (k=0; k<fo->drivetype.size(); k++) {
719 sendit(sock, " XD %s\n", fo->drivetype.get(k));
722 sendit(sock, " D %s\n", fo->reader);
725 sendit(sock, " T %s\n", fo->writer);
727 sendit(sock, " N\n");
729 for (j=0; j<incexe->name_list.size(); j++) {
730 sendit(sock, " I %s\n", incexe->name_list.get(j));
732 if (incexe->name_list.size()) {
733 sendit(sock, " N\n");
737 for (i=0; i<res->res_fs.num_excludes; i++) {
738 INCEXE *incexe = res->res_fs.exclude_items[i];
739 for (j=0; j<incexe->name_list.size(); j++) {
740 sendit(sock, " E %s\n", incexe->name_list.get(j));
742 if (incexe->name_list.size()) {
743 sendit(sock, " N\n");
749 if (res->res_sch.run) {
751 RUN *run = res->res_sch.run;
752 char buf[1000], num[30];
753 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
758 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
759 bstrncpy(buf, _(" hour="), sizeof(buf));
760 for (i=0; i<24; i++) {
761 if (bit_is_set(i, run->hour)) {
762 bsnprintf(num, sizeof(num), "%d ", i);
763 bstrncat(buf, num, sizeof(buf));
766 bstrncat(buf, "\n", sizeof(buf));
768 bstrncpy(buf, _(" mday="), sizeof(buf));
769 for (i=0; i<31; i++) {
770 if (bit_is_set(i, run->mday)) {
771 bsnprintf(num, sizeof(num), "%d ", i);
772 bstrncat(buf, num, sizeof(buf));
775 bstrncat(buf, "\n", sizeof(buf));
777 bstrncpy(buf, _(" month="), sizeof(buf));
778 for (i=0; i<12; i++) {
779 if (bit_is_set(i, run->month)) {
780 bsnprintf(num, sizeof(num), "%d ", i);
781 bstrncat(buf, num, sizeof(buf));
784 bstrncat(buf, "\n", sizeof(buf));
786 bstrncpy(buf, _(" wday="), sizeof(buf));
787 for (i=0; i<7; i++) {
788 if (bit_is_set(i, run->wday)) {
789 bsnprintf(num, sizeof(num), "%d ", i);
790 bstrncat(buf, num, sizeof(buf));
793 bstrncat(buf, "\n", sizeof(buf));
795 bstrncpy(buf, _(" wom="), sizeof(buf));
796 for (i=0; i<5; i++) {
797 if (bit_is_set(i, run->wom)) {
798 bsnprintf(num, sizeof(num), "%d ", i);
799 bstrncat(buf, num, sizeof(buf));
802 bstrncat(buf, "\n", sizeof(buf));
804 bstrncpy(buf, _(" woy="), sizeof(buf));
805 for (i=0; i<54; i++) {
806 if (bit_is_set(i, run->woy)) {
807 bsnprintf(num, sizeof(num), "%d ", i);
808 bstrncat(buf, num, sizeof(buf));
811 bstrncat(buf, "\n", sizeof(buf));
813 sendit(sock, _(" mins=%d\n"), run->minute);
815 sendit(sock, _(" --> "));
816 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
819 sendit(sock, _(" --> "));
820 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
823 sendit(sock, _(" --> "));
824 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
826 /* If another Run record is chained in, go print it */
832 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
836 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
837 res->res_pool.pool_type);
838 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
839 res->res_pool.use_catalog, res->res_pool.use_volume_once,
840 res->res_pool.catalog_files);
841 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
842 res->res_pool.max_volumes, res->res_pool.AutoPrune,
843 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
844 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
845 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
846 res->res_pool.Recycle,
847 NPRT(res->res_pool.label_format));
848 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
849 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
850 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d\n"),
851 res->res_pool.recycle_oldest_volume,
852 res->res_pool.purge_oldest_volume);
853 sendit(sock, _(" MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
854 res->res_pool.MaxVolJobs,
855 res->res_pool.MaxVolFiles,
856 edit_uint64(res->res_pool.MaxVolFiles, ed1));
857 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
858 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
859 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
860 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
861 if (res->res_pool.NextPool) {
862 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
864 if (res->res_pool.RecyclePool) {
865 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
867 if (res->res_pool.storage) {
869 foreach_alist(store, res->res_pool.storage) {
870 sendit(sock, _(" --> "));
871 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
876 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
877 if (res->res_msgs.mail_cmd)
878 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
879 if (res->res_msgs.operator_cmd)
880 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
883 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
886 if (recurse && res->res_dir.hdr.next) {
887 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
892 * Free all the members of an INCEXE structure
894 static void free_incexe(INCEXE *incexe)
896 incexe->name_list.destroy();
897 for (int i=0; i<incexe->num_opts; i++) {
898 FOPTS *fopt = incexe->opts_list[i];
899 fopt->regex.destroy();
900 fopt->regexdir.destroy();
901 fopt->regexfile.destroy();
902 fopt->wild.destroy();
903 fopt->wilddir.destroy();
904 fopt->wildfile.destroy();
905 fopt->wildbase.destroy();
906 fopt->base.destroy();
907 fopt->fstype.destroy();
908 fopt->drivetype.destroy();
917 if (incexe->opts_list) {
918 free(incexe->opts_list);
924 * Free memory of resource -- called when daemon terminates.
925 * NB, we don't need to worry about freeing any references
926 * to other resources as they will be freed when that
927 * resource chain is traversed. Mainly we worry about freeing
928 * allocated strings (names).
930 void free_resource(RES *sres, int type)
933 RES *nres; /* next resource if linked */
934 URES *res = (URES *)sres;
939 /* common stuff -- free the resource name and description */
940 nres = (RES *)res->res_dir.hdr.next;
941 if (res->res_dir.hdr.name) {
942 free(res->res_dir.hdr.name);
944 if (res->res_dir.hdr.desc) {
945 free(res->res_dir.hdr.desc);
950 if (res->res_dir.working_directory) {
951 free(res->res_dir.working_directory);
953 if (res->res_dir.scripts_directory) {
954 free((char *)res->res_dir.scripts_directory);
956 if (res->res_dir.pid_directory) {
957 free(res->res_dir.pid_directory);
959 if (res->res_dir.subsys_directory) {
960 free(res->res_dir.subsys_directory);
962 if (res->res_dir.password) {
963 free(res->res_dir.password);
965 if (res->res_dir.query_file) {
966 free(res->res_dir.query_file);
968 if (res->res_dir.DIRaddrs) {
969 free_addresses(res->res_dir.DIRaddrs);
971 if (res->res_dir.tls_ctx) {
972 free_tls_context(res->res_dir.tls_ctx);
974 if (res->res_dir.tls_ca_certfile) {
975 free(res->res_dir.tls_ca_certfile);
977 if (res->res_dir.tls_ca_certdir) {
978 free(res->res_dir.tls_ca_certdir);
980 if (res->res_dir.tls_certfile) {
981 free(res->res_dir.tls_certfile);
983 if (res->res_dir.tls_keyfile) {
984 free(res->res_dir.tls_keyfile);
986 if (res->res_dir.tls_dhfile) {
987 free(res->res_dir.tls_dhfile);
989 if (res->res_dir.tls_allowed_cns) {
990 delete res->res_dir.tls_allowed_cns;
997 if (res->res_con.password) {
998 free(res->res_con.password);
1000 if (res->res_con.tls_ctx) {
1001 free_tls_context(res->res_con.tls_ctx);
1003 if (res->res_con.tls_ca_certfile) {
1004 free(res->res_con.tls_ca_certfile);
1006 if (res->res_con.tls_ca_certdir) {
1007 free(res->res_con.tls_ca_certdir);
1009 if (res->res_con.tls_certfile) {
1010 free(res->res_con.tls_certfile);
1012 if (res->res_con.tls_keyfile) {
1013 free(res->res_con.tls_keyfile);
1015 if (res->res_con.tls_dhfile) {
1016 free(res->res_con.tls_dhfile);
1018 if (res->res_con.tls_allowed_cns) {
1019 delete res->res_con.tls_allowed_cns;
1021 for (int i=0; i<Num_ACL; i++) {
1022 if (res->res_con.ACL_lists[i]) {
1023 delete res->res_con.ACL_lists[i];
1024 res->res_con.ACL_lists[i] = NULL;
1029 if (res->res_client.address) {
1030 free(res->res_client.address);
1032 if (res->res_client.password) {
1033 free(res->res_client.password);
1035 if (res->res_client.tls_ctx) {
1036 free_tls_context(res->res_client.tls_ctx);
1038 if (res->res_client.tls_ca_certfile) {
1039 free(res->res_client.tls_ca_certfile);
1041 if (res->res_client.tls_ca_certdir) {
1042 free(res->res_client.tls_ca_certdir);
1044 if (res->res_client.tls_certfile) {
1045 free(res->res_client.tls_certfile);
1047 if (res->res_client.tls_keyfile) {
1048 free(res->res_client.tls_keyfile);
1050 if (res->res_client.tls_allowed_cns) {
1051 delete res->res_client.tls_allowed_cns;
1055 if (res->res_store.address) {
1056 free(res->res_store.address);
1058 if (res->res_store.password) {
1059 free(res->res_store.password);
1061 if (res->res_store.media_type) {
1062 free(res->res_store.media_type);
1064 if (res->res_store.device) {
1065 delete res->res_store.device;
1067 if (res->res_store.tls_ctx) {
1068 free_tls_context(res->res_store.tls_ctx);
1070 if (res->res_store.tls_ca_certfile) {
1071 free(res->res_store.tls_ca_certfile);
1073 if (res->res_store.tls_ca_certdir) {
1074 free(res->res_store.tls_ca_certdir);
1076 if (res->res_store.tls_certfile) {
1077 free(res->res_store.tls_certfile);
1079 if (res->res_store.tls_keyfile) {
1080 free(res->res_store.tls_keyfile);
1084 if (res->res_cat.db_address) {
1085 free(res->res_cat.db_address);
1087 if (res->res_cat.db_socket) {
1088 free(res->res_cat.db_socket);
1090 if (res->res_cat.db_user) {
1091 free(res->res_cat.db_user);
1093 if (res->res_cat.db_name) {
1094 free(res->res_cat.db_name);
1096 if (res->res_cat.db_password) {
1097 free(res->res_cat.db_password);
1101 if ((num=res->res_fs.num_includes)) {
1102 while (--num >= 0) {
1103 free_incexe(res->res_fs.include_items[num]);
1105 free(res->res_fs.include_items);
1107 res->res_fs.num_includes = 0;
1108 if ((num=res->res_fs.num_excludes)) {
1109 while (--num >= 0) {
1110 free_incexe(res->res_fs.exclude_items[num]);
1112 free(res->res_fs.exclude_items);
1114 res->res_fs.num_excludes = 0;
1117 if (res->res_pool.pool_type) {
1118 free(res->res_pool.pool_type);
1120 if (res->res_pool.label_format) {
1121 free(res->res_pool.label_format);
1123 if (res->res_pool.cleaning_prefix) {
1124 free(res->res_pool.cleaning_prefix);
1126 if (res->res_pool.storage) {
1127 delete res->res_pool.storage;
1131 if (res->res_sch.run) {
1133 nrun = res->res_sch.run;
1143 if (res->res_job.RestoreWhere) {
1144 free(res->res_job.RestoreWhere);
1146 if (res->res_job.RestoreBootstrap) {
1147 free(res->res_job.RestoreBootstrap);
1149 if (res->res_job.WriteBootstrap) {
1150 free(res->res_job.WriteBootstrap);
1152 if (res->res_job.selection_pattern) {
1153 free(res->res_job.selection_pattern);
1155 if (res->res_job.run_cmds) {
1156 delete res->res_job.run_cmds;
1158 if (res->res_job.storage) {
1159 delete res->res_job.storage;
1161 if (res->res_job.RunScripts) {
1162 free_runscripts(res->res_job.RunScripts);
1163 delete res->res_job.RunScripts;
1167 if (res->res_msgs.mail_cmd) {
1168 free(res->res_msgs.mail_cmd);
1170 if (res->res_msgs.operator_cmd) {
1171 free(res->res_msgs.operator_cmd);
1173 free_msgs_res((MSGS *)res); /* free message resource */
1177 printf(_("Unknown resource type %d in free_resource.\n"), type);
1179 /* Common stuff again -- free the resource, recurse to next one */
1184 free_resource(nres, type);
1189 * Save the new resource by chaining it into the head list for
1190 * the resource. If this is pass 2, we update any resource
1191 * pointers because they may not have been defined until
1194 void save_resource(int type, RES_ITEM *items, int pass)
1197 int rindex = type - r_first;
1201 /* Check Job requirements after applying JobDefs */
1202 if (type != R_JOB && type != R_JOBDEFS) {
1204 * Ensure that all required items are present
1206 for (i=0; items[i].name; i++) {
1207 if (items[i].flags & ITEM_REQUIRED) {
1208 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1209 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1210 items[i].name, resources[rindex]);
1213 /* If this triggers, take a look at lib/parse_conf.h */
1214 if (i >= MAX_RES_ITEMS) {
1215 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1218 } else if (type == R_JOB) {
1220 * Ensure that the name item is present
1222 if (items[0].flags & ITEM_REQUIRED) {
1223 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1224 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1225 items[0].name, resources[rindex]);
1231 * During pass 2 in each "store" routine, we looked up pointers
1232 * to all the resources referrenced in the current resource, now we
1233 * must copy their addresses from the static record to the allocated
1238 /* Resources not containing a resource */
1246 * Resources containing another resource or alist. First
1247 * look up the resource which contains another resource. It
1248 * was written during pass 1. Then stuff in the pointers to
1249 * the resources it contains, which were inserted this pass.
1250 * Finally, it will all be stored back.
1253 /* Find resource saved in pass 1 */
1254 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1255 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1257 /* Explicitly copy resource pointers from this pass (res_all) */
1258 res->res_pool.NextPool = res_all.res_pool.NextPool;
1259 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1260 res->res_pool.storage = res_all.res_pool.storage;
1263 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1264 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1266 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1269 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1270 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1272 res->res_dir.messages = res_all.res_dir.messages;
1273 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1276 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1277 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1278 res_all.res_dir.hdr.name);
1280 /* we must explicitly copy the device alist pointer */
1281 res->res_store.device = res_all.res_store.device;
1285 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1286 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1287 res_all.res_dir.hdr.name);
1289 res->res_job.messages = res_all.res_job.messages;
1290 res->res_job.schedule = res_all.res_job.schedule;
1291 res->res_job.client = res_all.res_job.client;
1292 res->res_job.fileset = res_all.res_job.fileset;
1293 res->res_job.storage = res_all.res_job.storage;
1294 res->res_job.pool = res_all.res_job.pool;
1295 res->res_job.full_pool = res_all.res_job.full_pool;
1296 res->res_job.inc_pool = res_all.res_job.inc_pool;
1297 res->res_job.diff_pool = res_all.res_job.diff_pool;
1298 res->res_job.verify_job = res_all.res_job.verify_job;
1299 res->res_job.jobdefs = res_all.res_job.jobdefs;
1300 res->res_job.run_cmds = res_all.res_job.run_cmds;
1301 res->res_job.RunScripts = res_all.res_job.RunScripts;
1304 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1305 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1307 res->res_counter.Catalog = res_all.res_counter.Catalog;
1308 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1312 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1313 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1315 res->res_client.catalog = res_all.res_client.catalog;
1316 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1320 * Schedule is a bit different in that it contains a RUN record
1321 * chain which isn't a "named" resource. This chain was linked
1322 * in by run_conf.c during pass 2, so here we jam the pointer
1323 * into the Schedule resource.
1325 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1326 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1328 res->res_sch.run = res_all.res_sch.run;
1331 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1335 /* Note, the resource name was already saved during pass 1,
1336 * so here, we can just release it.
1338 if (res_all.res_dir.hdr.name) {
1339 free(res_all.res_dir.hdr.name);
1340 res_all.res_dir.hdr.name = NULL;
1342 if (res_all.res_dir.hdr.desc) {
1343 free(res_all.res_dir.hdr.desc);
1344 res_all.res_dir.hdr.desc = NULL;
1350 * The following code is only executed during pass 1
1354 size = sizeof(DIRRES);
1357 size = sizeof(CONRES);
1360 size =sizeof(CLIENT);
1363 size = sizeof(STORE);
1373 size = sizeof(FILESET);
1376 size = sizeof(SCHED);
1379 size = sizeof(POOL);
1382 size = sizeof(MSGS);
1385 size = sizeof(COUNTER);
1391 printf(_("Unknown resource type %d in save_resource.\n"), type);
1397 res = (URES *)malloc(size);
1398 memcpy(res, &res_all, size);
1399 if (!res_head[rindex]) {
1400 res_head[rindex] = (RES *)res; /* store first entry */
1401 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1402 res->res_dir.hdr.name, rindex);
1405 if (res->res_dir.hdr.name == NULL) {
1406 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1409 /* Add new res to end of chain */
1410 for (last=next=res_head[rindex]; next; next=next->next) {
1412 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1413 Emsg2(M_ERROR_TERM, 0,
1414 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1415 resources[rindex].name, res->res_dir.hdr.name);
1418 last->next = (RES *)res;
1419 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1420 res->res_dir.hdr.name, rindex, pass);
1426 * Store Device. Note, the resource is created upon the
1427 * first reference. The details of the resource are obtained
1428 * later from the SD.
1430 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1434 int rindex = R_DEVICE - r_first;
1435 int size = sizeof(DEVICE);
1439 token = lex_get_token(lc, T_NAME);
1440 if (!res_head[rindex]) {
1441 res = (URES *)malloc(size);
1442 memset(res, 0, size);
1443 res->res_dev.hdr.name = bstrdup(lc->str);
1444 res_head[rindex] = (RES *)res; /* store first entry */
1445 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1446 res->res_dir.hdr.name, rindex);
1449 /* See if it is already defined */
1450 for (next=res_head[rindex]; next->next; next=next->next) {
1451 if (strcmp(next->name, lc->str) == 0) {
1457 res = (URES *)malloc(size);
1458 memset(res, 0, size);
1459 res->res_dev.hdr.name = bstrdup(lc->str);
1460 next->next = (RES *)res;
1461 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1462 res->res_dir.hdr.name, rindex, pass);
1467 set_bit(index, res_all.hdr.item_present);
1469 store_alist_res(lc, item, index, pass);
1474 * Store JobType (backup, verify, restore)
1477 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1481 token = lex_get_token(lc, T_NAME);
1482 /* Store the type both pass 1 and pass 2 */
1483 for (i=0; migtypes[i].type_name; i++) {
1484 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1485 *(int *)(item->value) = migtypes[i].job_type;
1491 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1494 set_bit(index, res_all.hdr.item_present);
1500 * Store JobType (backup, verify, restore)
1503 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1507 token = lex_get_token(lc, T_NAME);
1508 /* Store the type both pass 1 and pass 2 */
1509 for (i=0; jobtypes[i].type_name; i++) {
1510 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1511 *(int *)(item->value) = jobtypes[i].job_type;
1517 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1520 set_bit(index, res_all.hdr.item_present);
1524 * Store Job Level (Full, Incremental, ...)
1527 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1531 token = lex_get_token(lc, T_NAME);
1532 /* Store the level pass 2 so that type is defined */
1533 for (i=0; joblevels[i].level_name; i++) {
1534 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1535 *(int *)(item->value) = joblevels[i].level;
1541 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1544 set_bit(index, res_all.hdr.item_present);
1548 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1551 token = lex_get_token(lc, T_NAME);
1552 /* Scan Replacement options */
1553 for (i=0; ReplaceOptions[i].name; i++) {
1554 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1555 *(int *)(item->value) = ReplaceOptions[i].token;
1561 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1564 set_bit(index, res_all.hdr.item_present);
1568 * Store ACL (access control list)
1571 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1576 token = lex_get_token(lc, T_STRING);
1578 if (((alist **)item->value)[item->code] == NULL) {
1579 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1580 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1582 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1583 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1585 token = lex_get_token(lc, T_ALL);
1586 if (token == T_COMMA) {
1587 continue; /* get another ACL */
1591 set_bit(index, res_all.hdr.item_present);
1594 /* We build RunScripts items here */
1595 static RUNSCRIPT res_runscript;
1597 /* Store a runscript->when in a bit field */
1598 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1600 lex_get_token(lc, T_NAME);
1602 if (strcasecmp(lc->str, "before") == 0) {
1603 *(int *)(item->value) = SCRIPT_Before ;
1604 } else if (strcasecmp(lc->str, "after") == 0) {
1605 *(int *)(item->value) = SCRIPT_After;
1606 } else if (strcasecmp(lc->str, "always") == 0) {
1607 *(int *)(item->value) = SCRIPT_Any;
1609 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1614 /* Store a runscript->target
1617 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1619 lex_get_token(lc, T_STRING);
1622 if (strcmp(lc->str, "%c") == 0) {
1623 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1624 } else if (strcasecmp(lc->str, "yes") == 0) {
1625 ((RUNSCRIPT*) item->value)->set_target("%c");
1626 } else if (strcasecmp(lc->str, "no") == 0) {
1627 ((RUNSCRIPT*) item->value)->set_target("");
1629 RES *res = GetResWithName(R_CLIENT, lc->str);
1631 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1632 lc->str, lc->line_no, lc->line);
1635 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1641 /* Store a runscript->command in a bit field
1644 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1646 lex_get_token(lc, T_STRING);
1649 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1654 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1656 lex_get_token(lc, T_STRING);
1657 alist **runscripts = (alist **)(item->value) ;
1660 RUNSCRIPT *script = new_runscript();
1662 script->set_command(lc->str);
1664 /* TODO: remove all script->old_proto with bacula 1.42 */
1666 if (strcmp(item->name, "runbeforejob") == 0) {
1667 script->when = SCRIPT_Before;
1668 script->abort_on_error = true;
1669 script->set_target("");
1671 } else if (strcmp(item->name, "runafterjob") == 0) {
1672 script->when = SCRIPT_After;
1673 script->on_success = true;
1674 script->on_failure = false;
1675 script->set_target("");
1677 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1678 script->old_proto = true;
1679 script->when = SCRIPT_After;
1680 script->set_target("%c");
1681 script->on_success = true;
1682 script->on_failure = false;
1684 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1685 script->old_proto = true;
1686 script->when = SCRIPT_Before;
1687 script->set_target("%c");
1688 script->abort_on_error = true;
1690 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1691 script->when = SCRIPT_After;
1692 script->on_failure = true;
1693 script->on_success = false;
1694 script->set_target("");
1697 if (*runscripts == NULL) {
1698 *runscripts = New(alist(10, not_owned_by_alist));
1701 (*runscripts)->append(script);
1708 /* Store a bool in a bit field without modifing res_all.hdr
1709 * We can also add an option to store_bool to skip res_all.hdr
1711 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1713 lex_get_token(lc, T_NAME);
1714 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1715 *(bool *)(item->value) = true;
1716 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1717 *(bool *)(item->value) = false;
1719 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1725 * new RunScript items
1726 * name handler value code flags default_value
1728 static RES_ITEM runscript_items[] = {
1729 {"command", store_runscript_cmd, {(char **)&res_runscript}, 0, ITEM_REQUIRED, 0},
1730 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1731 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1732 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1733 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.abort_on_error},0, 0, 0},
1734 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1735 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1736 {NULL, NULL, {0}, 0, 0, 0}
1740 * Store RunScript info
1742 * Note, when this routine is called, we are inside a Job
1743 * resource. We treat the RunScript like a sort of
1744 * mini-resource within the Job resource.
1746 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1749 alist **runscripts = (alist **)(item->value) ;
1751 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1753 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1755 token = lex_get_token(lc, T_SKIP_EOL);
1757 if (token != T_BOB) {
1758 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1761 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1762 if (token == T_EOB) {
1765 if (token != T_IDENTIFIER) {
1766 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1768 for (i=0; runscript_items[i].name; i++) {
1769 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1770 token = lex_get_token(lc, T_SKIP_EOL);
1771 if (token != T_EQUALS) {
1772 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1775 /* Call item handler */
1776 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1783 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1788 if (res_runscript.command == NULL) {
1789 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1790 "command", "runscript");
1793 /* run on client by default */
1794 if (res_runscript.target == NULL) {
1795 res_runscript.set_target("%c");
1798 RUNSCRIPT *script = new_runscript();
1799 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1801 if (*runscripts == NULL) {
1802 *runscripts = New(alist(10, not_owned_by_alist));
1805 (*runscripts)->append(script);
1810 set_bit(index, res_all.hdr.item_present);