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 {NULL, NULL, {0}, 0, 0, 0}
196 /* Storage daemon resource
198 * name handler value code flags default_value
200 static RES_ITEM store_items[] = {
201 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
202 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
203 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
204 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
205 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
206 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
207 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
208 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
209 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
210 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
211 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
212 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
213 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
214 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
215 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
216 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
217 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
218 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
219 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
220 {NULL, NULL, {0}, 0, 0, 0}
224 * Catalog Resource Directives
226 * name handler value code flags default_value
228 static RES_ITEM cat_items[] = {
229 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
230 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
231 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
232 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
233 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
234 /* keep this password as store_str for the moment */
235 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
236 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
237 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
238 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
239 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
240 /* Turned off for the moment */
241 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
242 {NULL, NULL, {0}, 0, 0, 0}
246 * Job Resource Directives
248 * name handler value code flags default_value
250 RES_ITEM job_items[] = {
251 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
252 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
253 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
254 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
255 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
256 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
257 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
258 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
259 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
260 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
261 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
262 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
263 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
264 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
265 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
266 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
267 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
268 /* Root of where to restore files */
269 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
270 /* Where to find bootstrap during restore */
271 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
272 /* Where to write bootstrap file during backup */
273 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
274 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
275 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
276 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
277 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
278 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
279 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
280 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
281 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
282 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
283 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
284 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
285 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
286 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
287 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
288 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
289 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
290 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
291 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
292 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
293 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
294 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
295 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
296 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
297 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
298 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
299 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
300 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
301 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
302 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, true},
303 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
304 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
305 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
306 {NULL, NULL, {0}, 0, 0, 0}
311 * name handler value code flags default_value
313 static RES_ITEM fs_items[] = {
314 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
315 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
316 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
317 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
318 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
319 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, true},
320 {NULL, NULL, {0}, 0, 0, 0}
323 /* Schedule -- see run_conf.c */
326 * name handler value code flags default_value
328 static RES_ITEM sch_items[] = {
329 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
330 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
331 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
332 {NULL, NULL, {0}, 0, 0, 0}
337 * name handler value code flags default_value
339 static RES_ITEM pool_items[] = {
340 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
341 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
342 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
343 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
344 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
345 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
346 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
347 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
348 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
349 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
350 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
351 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
352 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
353 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
354 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
355 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
356 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
357 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
358 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
359 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
360 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
361 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
362 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
363 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
364 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
365 {"recyclepool", store_res, ITEM(res_pool.RecyclePool), R_POOL, 0, 0},
366 {NULL, NULL, {0}, 0, 0, 0}
371 * name handler value code flags default_value
373 static RES_ITEM counter_items[] = {
374 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
375 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
376 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
377 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
378 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
379 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
380 {NULL, NULL, {0}, 0, 0, 0}
384 /* Message resource */
385 extern RES_ITEM msgs_items[];
388 * This is the master resource definition.
389 * It must have one item for each of the resources.
391 * NOTE!!! keep it in the same order as the R_codes
392 * or eliminate all resources[rindex].name
394 * name items rcode res_head
396 RES_TABLE resources[] = {
397 {"director", dir_items, R_DIRECTOR},
398 {"client", cli_items, R_CLIENT},
399 {"job", job_items, R_JOB},
400 {"storage", store_items, R_STORAGE},
401 {"catalog", cat_items, R_CATALOG},
402 {"schedule", sch_items, R_SCHEDULE},
403 {"fileset", fs_items, R_FILESET},
404 {"pool", pool_items, R_POOL},
405 {"messages", msgs_items, R_MSGS},
406 {"counter", counter_items, R_COUNTER},
407 {"console", con_items, R_CONSOLE},
408 {"jobdefs", job_items, R_JOBDEFS},
409 {"device", NULL, R_DEVICE}, /* info obtained from SD */
414 /* Keywords (RHS) permitted in Job Level records
416 * level_name level job_type
418 struct s_jl joblevels[] = {
419 {"Full", L_FULL, JT_BACKUP},
420 {"Base", L_BASE, JT_BACKUP},
421 {"Incremental", L_INCREMENTAL, JT_BACKUP},
422 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
423 {"Since", L_SINCE, JT_BACKUP},
424 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
425 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
426 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
427 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
428 {"Data", L_VERIFY_DATA, JT_VERIFY},
429 {" ", L_NONE, JT_ADMIN},
430 {" ", L_NONE, JT_RESTORE},
434 /* Keywords (RHS) permitted in Job type records
438 struct s_jt jobtypes[] = {
439 {"backup", JT_BACKUP},
441 {"verify", JT_VERIFY},
442 {"restore", JT_RESTORE},
443 {"migrate", JT_MIGRATE},
448 /* Keywords (RHS) permitted in Selection type records
452 struct s_jt migtypes[] = {
453 {"smallestvolume", MT_SMALLEST_VOL},
454 {"oldestvolume", MT_OLDEST_VOL},
455 {"pooloccupancy", MT_POOL_OCCUPANCY},
456 {"pooltime", MT_POOL_TIME},
457 {"client", MT_CLIENT},
458 {"volume", MT_VOLUME},
460 {"sqlquery", MT_SQLQUERY},
466 /* Options permitted in Restore replace= */
467 struct s_kw ReplaceOptions[] = {
468 {"always", REPLACE_ALWAYS},
469 {"ifnewer", REPLACE_IFNEWER},
470 {"ifolder", REPLACE_IFOLDER},
471 {"never", REPLACE_NEVER},
475 const char *level_to_str(int level)
478 static char level_no[30];
479 const char *str = level_no;
481 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
482 for (i=0; joblevels[i].level_name; i++) {
483 if (level == joblevels[i].level) {
484 str = joblevels[i].level_name;
491 /* Dump contents of resource */
492 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
494 URES *res = (URES *)reshdr;
496 char ed1[100], ed2[100], ed3[100];
500 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
503 if (type < 0) { /* no recursion */
509 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
510 reshdr->name, res->res_dir.MaxConcurrentJobs,
511 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
512 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
513 if (res->res_dir.query_file) {
514 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
516 if (res->res_dir.messages) {
517 sendit(sock, _(" --> "));
518 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
522 sendit(sock, _("Console: name=%s SSL=%d\n"),
523 res->res_con.hdr.name, res->res_con.tls_enable);
526 if (res->res_counter.WrapCounter) {
527 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
528 res->res_counter.hdr.name, res->res_counter.MinValue,
529 res->res_counter.MaxValue, res->res_counter.CurrentValue,
530 res->res_counter.WrapCounter->hdr.name);
532 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
533 res->res_counter.hdr.name, res->res_counter.MinValue,
534 res->res_counter.MaxValue);
536 if (res->res_counter.Catalog) {
537 sendit(sock, _(" --> "));
538 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
543 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
544 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
545 res->res_client.MaxConcurrentJobs);
546 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
547 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
548 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
549 res->res_client.AutoPrune);
550 if (res->res_client.catalog) {
551 sendit(sock, _(" --> "));
552 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
558 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
559 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
560 " poolid=%s volname=%s MediaType=%s\n"),
561 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
562 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
563 dev->offline, dev->autochanger,
564 edit_uint64(dev->PoolId, ed1),
565 dev->VolumeName, dev->MediaType);
568 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
569 " DeviceName=%s MediaType=%s StorageId=%s\n"),
570 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
571 res->res_store.MaxConcurrentJobs,
572 res->res_store.dev_name(),
573 res->res_store.media_type,
574 edit_int64(res->res_store.StorageId, ed1));
577 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
578 " db_user=%s MutliDBConn=%d\n"),
579 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
580 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
581 res->res_cat.mult_db_connections);
585 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
586 type == R_JOB ? _("Job") : _("JobDefs"),
587 res->res_job.hdr.name, res->res_job.JobType,
588 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
589 res->res_job.enabled);
590 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
591 res->res_job.MaxConcurrentJobs,
592 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
593 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
594 res->res_job.spool_data, res->res_job.write_part_after_job);
595 if (res->res_job.JobType == JT_MIGRATE) {
596 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
598 if (res->res_job.client) {
599 sendit(sock, _(" --> "));
600 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
602 if (res->res_job.fileset) {
603 sendit(sock, _(" --> "));
604 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
606 if (res->res_job.schedule) {
607 sendit(sock, _(" --> "));
608 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
610 if (res->res_job.RestoreWhere) {
611 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
613 if (res->res_job.RestoreBootstrap) {
614 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
616 if (res->res_job.WriteBootstrap) {
617 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
619 if (res->res_job.storage) {
621 foreach_alist(store, res->res_job.storage) {
622 sendit(sock, _(" --> "));
623 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
626 if (res->res_job.RunScripts) {
628 foreach_alist(script, res->res_job.RunScripts) {
629 sendit(sock, _(" --> RunScript\n"));
630 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
631 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
632 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
633 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
634 sendit(sock, _(" --> AbortJobOnError=%u\n"), script->abort_on_error);
635 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
638 if (res->res_job.pool) {
639 sendit(sock, _(" --> "));
640 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
642 if (res->res_job.full_pool) {
643 sendit(sock, _(" --> "));
644 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
646 if (res->res_job.inc_pool) {
647 sendit(sock, _(" --> "));
648 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
650 if (res->res_job.diff_pool) {
651 sendit(sock, _(" --> "));
652 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
654 if (res->res_job.verify_job) {
655 sendit(sock, _(" --> "));
656 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
658 if (res->res_job.run_cmds) {
660 foreach_alist(runcmd, res->res_job.run_cmds) {
661 sendit(sock, _(" --> Run=%s\n"), runcmd);
664 if (res->res_job.selection_pattern) {
665 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
667 if (res->res_job.messages) {
668 sendit(sock, _(" --> "));
669 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
675 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
676 for (i=0; i<res->res_fs.num_includes; i++) {
677 INCEXE *incexe = res->res_fs.include_items[i];
678 for (j=0; j<incexe->num_opts; j++) {
679 FOPTS *fo = incexe->opts_list[j];
680 sendit(sock, " O %s\n", fo->opts);
682 bool enhanced_wild = false;
683 for (k=0; fo->opts[k]!='\0'; k++) {
684 if (fo->opts[k]=='W') {
685 enhanced_wild = true;
690 for (k=0; k<fo->regex.size(); k++) {
691 sendit(sock, " R %s\n", fo->regex.get(k));
693 for (k=0; k<fo->regexdir.size(); k++) {
694 sendit(sock, " RD %s\n", fo->regexdir.get(k));
696 for (k=0; k<fo->regexfile.size(); k++) {
697 sendit(sock, " RF %s\n", fo->regexfile.get(k));
699 for (k=0; k<fo->wild.size(); k++) {
700 sendit(sock, " W %s\n", fo->wild.get(k));
702 for (k=0; k<fo->wilddir.size(); k++) {
703 sendit(sock, " WD %s\n", fo->wilddir.get(k));
705 for (k=0; k<fo->wildfile.size(); k++) {
706 sendit(sock, " WF %s\n", fo->wildfile.get(k));
708 for (k=0; k<fo->wildbase.size(); k++) {
709 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
711 for (k=0; k<fo->base.size(); k++) {
712 sendit(sock, " B %s\n", fo->base.get(k));
714 for (k=0; k<fo->fstype.size(); k++) {
715 sendit(sock, " X %s\n", fo->fstype.get(k));
717 for (k=0; k<fo->drivetype.size(); k++) {
718 sendit(sock, " XD %s\n", fo->drivetype.get(k));
721 sendit(sock, " D %s\n", fo->reader);
724 sendit(sock, " T %s\n", fo->writer);
726 sendit(sock, " N\n");
728 for (j=0; j<incexe->name_list.size(); j++) {
729 sendit(sock, " I %s\n", incexe->name_list.get(j));
731 if (incexe->name_list.size()) {
732 sendit(sock, " N\n");
736 for (i=0; i<res->res_fs.num_excludes; i++) {
737 INCEXE *incexe = res->res_fs.exclude_items[i];
738 for (j=0; j<incexe->name_list.size(); j++) {
739 sendit(sock, " E %s\n", incexe->name_list.get(j));
741 if (incexe->name_list.size()) {
742 sendit(sock, " N\n");
748 if (res->res_sch.run) {
750 RUN *run = res->res_sch.run;
751 char buf[1000], num[30];
752 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
757 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
758 bstrncpy(buf, _(" hour="), sizeof(buf));
759 for (i=0; i<24; i++) {
760 if (bit_is_set(i, run->hour)) {
761 bsnprintf(num, sizeof(num), "%d ", i);
762 bstrncat(buf, num, sizeof(buf));
765 bstrncat(buf, "\n", sizeof(buf));
767 bstrncpy(buf, _(" mday="), sizeof(buf));
768 for (i=0; i<31; i++) {
769 if (bit_is_set(i, run->mday)) {
770 bsnprintf(num, sizeof(num), "%d ", i);
771 bstrncat(buf, num, sizeof(buf));
774 bstrncat(buf, "\n", sizeof(buf));
776 bstrncpy(buf, _(" month="), sizeof(buf));
777 for (i=0; i<12; i++) {
778 if (bit_is_set(i, run->month)) {
779 bsnprintf(num, sizeof(num), "%d ", i);
780 bstrncat(buf, num, sizeof(buf));
783 bstrncat(buf, "\n", sizeof(buf));
785 bstrncpy(buf, _(" wday="), sizeof(buf));
786 for (i=0; i<7; i++) {
787 if (bit_is_set(i, run->wday)) {
788 bsnprintf(num, sizeof(num), "%d ", i);
789 bstrncat(buf, num, sizeof(buf));
792 bstrncat(buf, "\n", sizeof(buf));
794 bstrncpy(buf, _(" wom="), sizeof(buf));
795 for (i=0; i<5; i++) {
796 if (bit_is_set(i, run->wom)) {
797 bsnprintf(num, sizeof(num), "%d ", i);
798 bstrncat(buf, num, sizeof(buf));
801 bstrncat(buf, "\n", sizeof(buf));
803 bstrncpy(buf, _(" woy="), sizeof(buf));
804 for (i=0; i<54; i++) {
805 if (bit_is_set(i, run->woy)) {
806 bsnprintf(num, sizeof(num), "%d ", i);
807 bstrncat(buf, num, sizeof(buf));
810 bstrncat(buf, "\n", sizeof(buf));
812 sendit(sock, _(" mins=%d\n"), run->minute);
814 sendit(sock, _(" --> "));
815 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
818 sendit(sock, _(" --> "));
819 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
822 sendit(sock, _(" --> "));
823 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
825 /* If another Run record is chained in, go print it */
831 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
835 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
836 res->res_pool.pool_type);
837 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
838 res->res_pool.use_catalog, res->res_pool.use_volume_once,
839 res->res_pool.catalog_files);
840 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
841 res->res_pool.max_volumes, res->res_pool.AutoPrune,
842 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
843 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
844 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
845 res->res_pool.Recycle,
846 NPRT(res->res_pool.label_format));
847 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
848 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
849 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
850 res->res_pool.recycle_oldest_volume,
851 res->res_pool.purge_oldest_volume,
852 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
853 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
854 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
855 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
856 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
857 if (res->res_pool.NextPool) {
858 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
860 if (res->res_pool.RecyclePool) {
861 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
863 if (res->res_pool.storage) {
865 foreach_alist(store, res->res_pool.storage) {
866 sendit(sock, _(" --> "));
867 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
872 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
873 if (res->res_msgs.mail_cmd)
874 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
875 if (res->res_msgs.operator_cmd)
876 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
879 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
882 if (recurse && res->res_dir.hdr.next) {
883 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
888 * Free all the members of an INCEXE structure
890 static void free_incexe(INCEXE *incexe)
892 incexe->name_list.destroy();
893 for (int i=0; i<incexe->num_opts; i++) {
894 FOPTS *fopt = incexe->opts_list[i];
895 fopt->regex.destroy();
896 fopt->regexdir.destroy();
897 fopt->regexfile.destroy();
898 fopt->wild.destroy();
899 fopt->wilddir.destroy();
900 fopt->wildfile.destroy();
901 fopt->wildbase.destroy();
902 fopt->base.destroy();
903 fopt->fstype.destroy();
904 fopt->drivetype.destroy();
913 if (incexe->opts_list) {
914 free(incexe->opts_list);
920 * Free memory of resource -- called when daemon terminates.
921 * NB, we don't need to worry about freeing any references
922 * to other resources as they will be freed when that
923 * resource chain is traversed. Mainly we worry about freeing
924 * allocated strings (names).
926 void free_resource(RES *sres, int type)
929 RES *nres; /* next resource if linked */
930 URES *res = (URES *)sres;
935 /* common stuff -- free the resource name and description */
936 nres = (RES *)res->res_dir.hdr.next;
937 if (res->res_dir.hdr.name) {
938 free(res->res_dir.hdr.name);
940 if (res->res_dir.hdr.desc) {
941 free(res->res_dir.hdr.desc);
946 if (res->res_dir.working_directory) {
947 free(res->res_dir.working_directory);
949 if (res->res_dir.scripts_directory) {
950 free((char *)res->res_dir.scripts_directory);
952 if (res->res_dir.pid_directory) {
953 free(res->res_dir.pid_directory);
955 if (res->res_dir.subsys_directory) {
956 free(res->res_dir.subsys_directory);
958 if (res->res_dir.password) {
959 free(res->res_dir.password);
961 if (res->res_dir.query_file) {
962 free(res->res_dir.query_file);
964 if (res->res_dir.DIRaddrs) {
965 free_addresses(res->res_dir.DIRaddrs);
967 if (res->res_dir.tls_ctx) {
968 free_tls_context(res->res_dir.tls_ctx);
970 if (res->res_dir.tls_ca_certfile) {
971 free(res->res_dir.tls_ca_certfile);
973 if (res->res_dir.tls_ca_certdir) {
974 free(res->res_dir.tls_ca_certdir);
976 if (res->res_dir.tls_certfile) {
977 free(res->res_dir.tls_certfile);
979 if (res->res_dir.tls_keyfile) {
980 free(res->res_dir.tls_keyfile);
982 if (res->res_dir.tls_dhfile) {
983 free(res->res_dir.tls_dhfile);
985 if (res->res_dir.tls_allowed_cns) {
986 delete res->res_dir.tls_allowed_cns;
993 if (res->res_con.password) {
994 free(res->res_con.password);
996 if (res->res_con.tls_ctx) {
997 free_tls_context(res->res_con.tls_ctx);
999 if (res->res_con.tls_ca_certfile) {
1000 free(res->res_con.tls_ca_certfile);
1002 if (res->res_con.tls_ca_certdir) {
1003 free(res->res_con.tls_ca_certdir);
1005 if (res->res_con.tls_certfile) {
1006 free(res->res_con.tls_certfile);
1008 if (res->res_con.tls_keyfile) {
1009 free(res->res_con.tls_keyfile);
1011 if (res->res_con.tls_dhfile) {
1012 free(res->res_con.tls_dhfile);
1014 if (res->res_con.tls_allowed_cns) {
1015 delete res->res_con.tls_allowed_cns;
1017 for (int i=0; i<Num_ACL; i++) {
1018 if (res->res_con.ACL_lists[i]) {
1019 delete res->res_con.ACL_lists[i];
1020 res->res_con.ACL_lists[i] = NULL;
1025 if (res->res_client.address) {
1026 free(res->res_client.address);
1028 if (res->res_client.password) {
1029 free(res->res_client.password);
1031 if (res->res_client.tls_ctx) {
1032 free_tls_context(res->res_client.tls_ctx);
1034 if (res->res_client.tls_ca_certfile) {
1035 free(res->res_client.tls_ca_certfile);
1037 if (res->res_client.tls_ca_certdir) {
1038 free(res->res_client.tls_ca_certdir);
1040 if (res->res_client.tls_certfile) {
1041 free(res->res_client.tls_certfile);
1043 if (res->res_client.tls_keyfile) {
1044 free(res->res_client.tls_keyfile);
1048 if (res->res_store.address) {
1049 free(res->res_store.address);
1051 if (res->res_store.password) {
1052 free(res->res_store.password);
1054 if (res->res_store.media_type) {
1055 free(res->res_store.media_type);
1057 if (res->res_store.device) {
1058 delete res->res_store.device;
1060 if (res->res_store.tls_ctx) {
1061 free_tls_context(res->res_store.tls_ctx);
1063 if (res->res_store.tls_ca_certfile) {
1064 free(res->res_store.tls_ca_certfile);
1066 if (res->res_store.tls_ca_certdir) {
1067 free(res->res_store.tls_ca_certdir);
1069 if (res->res_store.tls_certfile) {
1070 free(res->res_store.tls_certfile);
1072 if (res->res_store.tls_keyfile) {
1073 free(res->res_store.tls_keyfile);
1077 if (res->res_cat.db_address) {
1078 free(res->res_cat.db_address);
1080 if (res->res_cat.db_socket) {
1081 free(res->res_cat.db_socket);
1083 if (res->res_cat.db_user) {
1084 free(res->res_cat.db_user);
1086 if (res->res_cat.db_name) {
1087 free(res->res_cat.db_name);
1089 if (res->res_cat.db_password) {
1090 free(res->res_cat.db_password);
1094 if ((num=res->res_fs.num_includes)) {
1095 while (--num >= 0) {
1096 free_incexe(res->res_fs.include_items[num]);
1098 free(res->res_fs.include_items);
1100 res->res_fs.num_includes = 0;
1101 if ((num=res->res_fs.num_excludes)) {
1102 while (--num >= 0) {
1103 free_incexe(res->res_fs.exclude_items[num]);
1105 free(res->res_fs.exclude_items);
1107 res->res_fs.num_excludes = 0;
1110 if (res->res_pool.pool_type) {
1111 free(res->res_pool.pool_type);
1113 if (res->res_pool.label_format) {
1114 free(res->res_pool.label_format);
1116 if (res->res_pool.cleaning_prefix) {
1117 free(res->res_pool.cleaning_prefix);
1119 if (res->res_pool.storage) {
1120 delete res->res_pool.storage;
1124 if (res->res_sch.run) {
1126 nrun = res->res_sch.run;
1136 if (res->res_job.RestoreWhere) {
1137 free(res->res_job.RestoreWhere);
1139 if (res->res_job.RestoreBootstrap) {
1140 free(res->res_job.RestoreBootstrap);
1142 if (res->res_job.WriteBootstrap) {
1143 free(res->res_job.WriteBootstrap);
1145 if (res->res_job.selection_pattern) {
1146 free(res->res_job.selection_pattern);
1148 if (res->res_job.run_cmds) {
1149 delete res->res_job.run_cmds;
1151 if (res->res_job.storage) {
1152 delete res->res_job.storage;
1154 if (res->res_job.RunScripts) {
1155 free_runscripts(res->res_job.RunScripts);
1156 delete res->res_job.RunScripts;
1160 if (res->res_msgs.mail_cmd) {
1161 free(res->res_msgs.mail_cmd);
1163 if (res->res_msgs.operator_cmd) {
1164 free(res->res_msgs.operator_cmd);
1166 free_msgs_res((MSGS *)res); /* free message resource */
1170 printf(_("Unknown resource type %d in free_resource.\n"), type);
1172 /* Common stuff again -- free the resource, recurse to next one */
1177 free_resource(nres, type);
1182 * Save the new resource by chaining it into the head list for
1183 * the resource. If this is pass 2, we update any resource
1184 * pointers because they may not have been defined until
1187 void save_resource(int type, RES_ITEM *items, int pass)
1190 int rindex = type - r_first;
1194 /* Check Job requirements after applying JobDefs */
1195 if (type != R_JOB && type != R_JOBDEFS) {
1197 * Ensure that all required items are present
1199 for (i=0; items[i].name; i++) {
1200 if (items[i].flags & ITEM_REQUIRED) {
1201 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1202 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1203 items[i].name, resources[rindex]);
1206 /* If this triggers, take a look at lib/parse_conf.h */
1207 if (i >= MAX_RES_ITEMS) {
1208 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1211 } else if (type == R_JOB) {
1213 * Ensure that the name item is present
1215 if (items[0].flags & ITEM_REQUIRED) {
1216 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1217 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1218 items[0].name, resources[rindex]);
1224 * During pass 2 in each "store" routine, we looked up pointers
1225 * to all the resources referrenced in the current resource, now we
1226 * must copy their addresses from the static record to the allocated
1231 /* Resources not containing a resource */
1239 * Resources containing another resource or alist. First
1240 * look up the resource which contains another resource. It
1241 * was written during pass 1. Then stuff in the pointers to
1242 * the resources it contains, which were inserted this pass.
1243 * Finally, it will all be stored back.
1246 /* Find resource saved in pass 1 */
1247 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1248 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1250 /* Explicitly copy resource pointers from this pass (res_all) */
1251 res->res_pool.NextPool = res_all.res_pool.NextPool;
1252 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1253 res->res_pool.storage = res_all.res_pool.storage;
1256 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1257 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1259 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1262 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1263 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1265 res->res_dir.messages = res_all.res_dir.messages;
1266 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1269 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1270 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1271 res_all.res_dir.hdr.name);
1273 /* we must explicitly copy the device alist pointer */
1274 res->res_store.device = res_all.res_store.device;
1278 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1279 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1280 res_all.res_dir.hdr.name);
1282 res->res_job.messages = res_all.res_job.messages;
1283 res->res_job.schedule = res_all.res_job.schedule;
1284 res->res_job.client = res_all.res_job.client;
1285 res->res_job.fileset = res_all.res_job.fileset;
1286 res->res_job.storage = res_all.res_job.storage;
1287 res->res_job.pool = res_all.res_job.pool;
1288 res->res_job.full_pool = res_all.res_job.full_pool;
1289 res->res_job.inc_pool = res_all.res_job.inc_pool;
1290 res->res_job.diff_pool = res_all.res_job.diff_pool;
1291 res->res_job.verify_job = res_all.res_job.verify_job;
1292 res->res_job.jobdefs = res_all.res_job.jobdefs;
1293 res->res_job.run_cmds = res_all.res_job.run_cmds;
1294 res->res_job.RunScripts = res_all.res_job.RunScripts;
1297 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1298 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1300 res->res_counter.Catalog = res_all.res_counter.Catalog;
1301 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1305 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1306 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1308 res->res_client.catalog = res_all.res_client.catalog;
1312 * Schedule is a bit different in that it contains a RUN record
1313 * chain which isn't a "named" resource. This chain was linked
1314 * in by run_conf.c during pass 2, so here we jam the pointer
1315 * into the Schedule resource.
1317 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1318 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1320 res->res_sch.run = res_all.res_sch.run;
1323 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1327 /* Note, the resource name was already saved during pass 1,
1328 * so here, we can just release it.
1330 if (res_all.res_dir.hdr.name) {
1331 free(res_all.res_dir.hdr.name);
1332 res_all.res_dir.hdr.name = NULL;
1334 if (res_all.res_dir.hdr.desc) {
1335 free(res_all.res_dir.hdr.desc);
1336 res_all.res_dir.hdr.desc = NULL;
1342 * The following code is only executed during pass 1
1346 size = sizeof(DIRRES);
1349 size = sizeof(CONRES);
1352 size =sizeof(CLIENT);
1355 size = sizeof(STORE);
1365 size = sizeof(FILESET);
1368 size = sizeof(SCHED);
1371 size = sizeof(POOL);
1374 size = sizeof(MSGS);
1377 size = sizeof(COUNTER);
1383 printf(_("Unknown resource type %d in save_resource.\n"), type);
1389 res = (URES *)malloc(size);
1390 memcpy(res, &res_all, size);
1391 if (!res_head[rindex]) {
1392 res_head[rindex] = (RES *)res; /* store first entry */
1393 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1394 res->res_dir.hdr.name, rindex);
1397 if (res->res_dir.hdr.name == NULL) {
1398 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1401 /* Add new res to end of chain */
1402 for (last=next=res_head[rindex]; next; next=next->next) {
1404 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1405 Emsg2(M_ERROR_TERM, 0,
1406 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1407 resources[rindex].name, res->res_dir.hdr.name);
1410 last->next = (RES *)res;
1411 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1412 res->res_dir.hdr.name, rindex, pass);
1418 * Store Device. Note, the resource is created upon the
1419 * first reference. The details of the resource are obtained
1420 * later from the SD.
1422 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1426 int rindex = R_DEVICE - r_first;
1427 int size = sizeof(DEVICE);
1431 token = lex_get_token(lc, T_NAME);
1432 if (!res_head[rindex]) {
1433 res = (URES *)malloc(size);
1434 memset(res, 0, size);
1435 res->res_dev.hdr.name = bstrdup(lc->str);
1436 res_head[rindex] = (RES *)res; /* store first entry */
1437 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1438 res->res_dir.hdr.name, rindex);
1441 /* See if it is already defined */
1442 for (next=res_head[rindex]; next->next; next=next->next) {
1443 if (strcmp(next->name, lc->str) == 0) {
1449 res = (URES *)malloc(size);
1450 memset(res, 0, size);
1451 res->res_dev.hdr.name = bstrdup(lc->str);
1452 next->next = (RES *)res;
1453 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1454 res->res_dir.hdr.name, rindex, pass);
1459 set_bit(index, res_all.hdr.item_present);
1461 store_alist_res(lc, item, index, pass);
1466 * Store JobType (backup, verify, restore)
1469 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1473 token = lex_get_token(lc, T_NAME);
1474 /* Store the type both pass 1 and pass 2 */
1475 for (i=0; migtypes[i].type_name; i++) {
1476 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1477 *(int *)(item->value) = migtypes[i].job_type;
1483 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1486 set_bit(index, res_all.hdr.item_present);
1492 * Store JobType (backup, verify, restore)
1495 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1499 token = lex_get_token(lc, T_NAME);
1500 /* Store the type both pass 1 and pass 2 */
1501 for (i=0; jobtypes[i].type_name; i++) {
1502 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1503 *(int *)(item->value) = jobtypes[i].job_type;
1509 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1512 set_bit(index, res_all.hdr.item_present);
1516 * Store Job Level (Full, Incremental, ...)
1519 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1523 token = lex_get_token(lc, T_NAME);
1524 /* Store the level pass 2 so that type is defined */
1525 for (i=0; joblevels[i].level_name; i++) {
1526 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1527 *(int *)(item->value) = joblevels[i].level;
1533 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1536 set_bit(index, res_all.hdr.item_present);
1540 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1543 token = lex_get_token(lc, T_NAME);
1544 /* Scan Replacement options */
1545 for (i=0; ReplaceOptions[i].name; i++) {
1546 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1547 *(int *)(item->value) = ReplaceOptions[i].token;
1553 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1556 set_bit(index, res_all.hdr.item_present);
1560 * Store ACL (access control list)
1563 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1568 token = lex_get_token(lc, T_STRING);
1570 if (((alist **)item->value)[item->code] == NULL) {
1571 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1572 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1574 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1575 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1577 token = lex_get_token(lc, T_ALL);
1578 if (token == T_COMMA) {
1579 continue; /* get another ACL */
1583 set_bit(index, res_all.hdr.item_present);
1586 /* We build RunScripts items here */
1587 static RUNSCRIPT res_runscript;
1589 /* Store a runscript->when in a bit field */
1590 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1592 lex_get_token(lc, T_NAME);
1594 if (strcasecmp(lc->str, "before") == 0) {
1595 *(int *)(item->value) = SCRIPT_Before ;
1596 } else if (strcasecmp(lc->str, "after") == 0) {
1597 *(int *)(item->value) = SCRIPT_After;
1598 } else if (strcasecmp(lc->str, "always") == 0) {
1599 *(int *)(item->value) = SCRIPT_Any;
1601 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1606 /* Store a runscript->target
1609 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1611 lex_get_token(lc, T_STRING);
1614 if (strcmp(lc->str, "%c") == 0) {
1615 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1616 } else if (strcasecmp(lc->str, "yes") == 0) {
1617 ((RUNSCRIPT*) item->value)->set_target("%c");
1618 } else if (strcasecmp(lc->str, "no") == 0) {
1619 ((RUNSCRIPT*) item->value)->set_target("");
1621 RES *res = GetResWithName(R_CLIENT, lc->str);
1623 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1624 lc->str, lc->line_no, lc->line);
1627 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1633 /* Store a runscript->command in a bit field
1636 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1638 lex_get_token(lc, T_STRING);
1641 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1646 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1648 lex_get_token(lc, T_STRING);
1649 alist **runscripts = (alist **)(item->value) ;
1652 RUNSCRIPT *script = new_runscript();
1654 script->set_command(lc->str);
1656 /* TODO: remove all script->old_proto with bacula 1.42 */
1658 if (strcmp(item->name, "runbeforejob") == 0) {
1659 script->when = SCRIPT_Before;
1660 script->abort_on_error = true;
1661 script->set_target("");
1663 } else if (strcmp(item->name, "runafterjob") == 0) {
1664 script->when = SCRIPT_After;
1665 script->on_success = true;
1666 script->on_failure = false;
1667 script->set_target("");
1669 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1670 script->old_proto = true;
1671 script->when = SCRIPT_After;
1672 script->set_target("%c");
1673 script->on_success = true;
1674 script->on_failure = false;
1676 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1677 script->old_proto = true;
1678 script->when = SCRIPT_Before;
1679 script->set_target("%c");
1680 script->abort_on_error = true;
1682 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1683 script->when = SCRIPT_After;
1684 script->on_failure = true;
1685 script->on_success = false;
1686 script->set_target("");
1689 if (*runscripts == NULL) {
1690 *runscripts = New(alist(10, not_owned_by_alist));
1693 (*runscripts)->append(script);
1700 /* Store a bool in a bit field without modifing res_all.hdr
1701 * We can also add an option to store_bool to skip res_all.hdr
1703 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1705 lex_get_token(lc, T_NAME);
1706 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1707 *(bool *)(item->value) = true;
1708 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1709 *(bool *)(item->value) = false;
1711 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1717 * new RunScript items
1718 * name handler value code flags default_value
1720 static RES_ITEM runscript_items[] = {
1721 {"command", store_runscript_cmd, {(char **)&res_runscript}, 0, ITEM_REQUIRED, 0},
1722 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1723 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1724 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1725 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.abort_on_error},0, 0, 0},
1726 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1727 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1728 {NULL, NULL, {0}, 0, 0, 0}
1732 * Store RunScript info
1734 * Note, when this routine is called, we are inside a Job
1735 * resource. We treat the RunScript like a sort of
1736 * mini-resource within the Job resource.
1738 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1741 alist **runscripts = (alist **)(item->value) ;
1743 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1745 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1747 token = lex_get_token(lc, T_SKIP_EOL);
1749 if (token != T_BOB) {
1750 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1753 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1754 if (token == T_EOB) {
1757 if (token != T_IDENTIFIER) {
1758 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1760 for (i=0; runscript_items[i].name; i++) {
1761 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1762 token = lex_get_token(lc, T_SKIP_EOL);
1763 if (token != T_EQUALS) {
1764 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1767 /* Call item handler */
1768 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1775 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1780 if (res_runscript.command == NULL) {
1781 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1782 "command", "runscript");
1785 /* run on client by default */
1786 if (res_runscript.target == NULL) {
1787 res_runscript.set_target("%c");
1790 RUNSCRIPT *script = new_runscript();
1791 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1793 if (*runscripts == NULL) {
1794 *runscripts = New(alist(10, not_owned_by_alist));
1797 (*runscripts)->append(script);
1802 set_bit(index, res_all.hdr.item_present);