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 MaxVolJobs=%d MaxVolFiles=%d\n"),
851 res->res_pool.recycle_oldest_volume,
852 res->res_pool.purge_oldest_volume,
853 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
854 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
855 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
856 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
857 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
858 if (res->res_pool.NextPool) {
859 sendit(sock, _(" NextPool=%s\n"), res->res_pool.NextPool->name());
861 if (res->res_pool.RecyclePool) {
862 sendit(sock, _(" RecyclePool=%s\n"), res->res_pool.RecyclePool->name());
864 if (res->res_pool.storage) {
866 foreach_alist(store, res->res_pool.storage) {
867 sendit(sock, _(" --> "));
868 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
873 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
874 if (res->res_msgs.mail_cmd)
875 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
876 if (res->res_msgs.operator_cmd)
877 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
880 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
883 if (recurse && res->res_dir.hdr.next) {
884 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
889 * Free all the members of an INCEXE structure
891 static void free_incexe(INCEXE *incexe)
893 incexe->name_list.destroy();
894 for (int i=0; i<incexe->num_opts; i++) {
895 FOPTS *fopt = incexe->opts_list[i];
896 fopt->regex.destroy();
897 fopt->regexdir.destroy();
898 fopt->regexfile.destroy();
899 fopt->wild.destroy();
900 fopt->wilddir.destroy();
901 fopt->wildfile.destroy();
902 fopt->wildbase.destroy();
903 fopt->base.destroy();
904 fopt->fstype.destroy();
905 fopt->drivetype.destroy();
914 if (incexe->opts_list) {
915 free(incexe->opts_list);
921 * Free memory of resource -- called when daemon terminates.
922 * NB, we don't need to worry about freeing any references
923 * to other resources as they will be freed when that
924 * resource chain is traversed. Mainly we worry about freeing
925 * allocated strings (names).
927 void free_resource(RES *sres, int type)
930 RES *nres; /* next resource if linked */
931 URES *res = (URES *)sres;
936 /* common stuff -- free the resource name and description */
937 nres = (RES *)res->res_dir.hdr.next;
938 if (res->res_dir.hdr.name) {
939 free(res->res_dir.hdr.name);
941 if (res->res_dir.hdr.desc) {
942 free(res->res_dir.hdr.desc);
947 if (res->res_dir.working_directory) {
948 free(res->res_dir.working_directory);
950 if (res->res_dir.scripts_directory) {
951 free((char *)res->res_dir.scripts_directory);
953 if (res->res_dir.pid_directory) {
954 free(res->res_dir.pid_directory);
956 if (res->res_dir.subsys_directory) {
957 free(res->res_dir.subsys_directory);
959 if (res->res_dir.password) {
960 free(res->res_dir.password);
962 if (res->res_dir.query_file) {
963 free(res->res_dir.query_file);
965 if (res->res_dir.DIRaddrs) {
966 free_addresses(res->res_dir.DIRaddrs);
968 if (res->res_dir.tls_ctx) {
969 free_tls_context(res->res_dir.tls_ctx);
971 if (res->res_dir.tls_ca_certfile) {
972 free(res->res_dir.tls_ca_certfile);
974 if (res->res_dir.tls_ca_certdir) {
975 free(res->res_dir.tls_ca_certdir);
977 if (res->res_dir.tls_certfile) {
978 free(res->res_dir.tls_certfile);
980 if (res->res_dir.tls_keyfile) {
981 free(res->res_dir.tls_keyfile);
983 if (res->res_dir.tls_dhfile) {
984 free(res->res_dir.tls_dhfile);
986 if (res->res_dir.tls_allowed_cns) {
987 delete res->res_dir.tls_allowed_cns;
994 if (res->res_con.password) {
995 free(res->res_con.password);
997 if (res->res_con.tls_ctx) {
998 free_tls_context(res->res_con.tls_ctx);
1000 if (res->res_con.tls_ca_certfile) {
1001 free(res->res_con.tls_ca_certfile);
1003 if (res->res_con.tls_ca_certdir) {
1004 free(res->res_con.tls_ca_certdir);
1006 if (res->res_con.tls_certfile) {
1007 free(res->res_con.tls_certfile);
1009 if (res->res_con.tls_keyfile) {
1010 free(res->res_con.tls_keyfile);
1012 if (res->res_con.tls_dhfile) {
1013 free(res->res_con.tls_dhfile);
1015 if (res->res_con.tls_allowed_cns) {
1016 delete res->res_con.tls_allowed_cns;
1018 for (int i=0; i<Num_ACL; i++) {
1019 if (res->res_con.ACL_lists[i]) {
1020 delete res->res_con.ACL_lists[i];
1021 res->res_con.ACL_lists[i] = NULL;
1026 if (res->res_client.address) {
1027 free(res->res_client.address);
1029 if (res->res_client.password) {
1030 free(res->res_client.password);
1032 if (res->res_client.tls_ctx) {
1033 free_tls_context(res->res_client.tls_ctx);
1035 if (res->res_client.tls_ca_certfile) {
1036 free(res->res_client.tls_ca_certfile);
1038 if (res->res_client.tls_ca_certdir) {
1039 free(res->res_client.tls_ca_certdir);
1041 if (res->res_client.tls_certfile) {
1042 free(res->res_client.tls_certfile);
1044 if (res->res_client.tls_keyfile) {
1045 free(res->res_client.tls_keyfile);
1047 if (res->res_client.tls_allowed_cns) {
1048 delete res->res_client.tls_allowed_cns;
1052 if (res->res_store.address) {
1053 free(res->res_store.address);
1055 if (res->res_store.password) {
1056 free(res->res_store.password);
1058 if (res->res_store.media_type) {
1059 free(res->res_store.media_type);
1061 if (res->res_store.device) {
1062 delete res->res_store.device;
1064 if (res->res_store.tls_ctx) {
1065 free_tls_context(res->res_store.tls_ctx);
1067 if (res->res_store.tls_ca_certfile) {
1068 free(res->res_store.tls_ca_certfile);
1070 if (res->res_store.tls_ca_certdir) {
1071 free(res->res_store.tls_ca_certdir);
1073 if (res->res_store.tls_certfile) {
1074 free(res->res_store.tls_certfile);
1076 if (res->res_store.tls_keyfile) {
1077 free(res->res_store.tls_keyfile);
1081 if (res->res_cat.db_address) {
1082 free(res->res_cat.db_address);
1084 if (res->res_cat.db_socket) {
1085 free(res->res_cat.db_socket);
1087 if (res->res_cat.db_user) {
1088 free(res->res_cat.db_user);
1090 if (res->res_cat.db_name) {
1091 free(res->res_cat.db_name);
1093 if (res->res_cat.db_password) {
1094 free(res->res_cat.db_password);
1098 if ((num=res->res_fs.num_includes)) {
1099 while (--num >= 0) {
1100 free_incexe(res->res_fs.include_items[num]);
1102 free(res->res_fs.include_items);
1104 res->res_fs.num_includes = 0;
1105 if ((num=res->res_fs.num_excludes)) {
1106 while (--num >= 0) {
1107 free_incexe(res->res_fs.exclude_items[num]);
1109 free(res->res_fs.exclude_items);
1111 res->res_fs.num_excludes = 0;
1114 if (res->res_pool.pool_type) {
1115 free(res->res_pool.pool_type);
1117 if (res->res_pool.label_format) {
1118 free(res->res_pool.label_format);
1120 if (res->res_pool.cleaning_prefix) {
1121 free(res->res_pool.cleaning_prefix);
1123 if (res->res_pool.storage) {
1124 delete res->res_pool.storage;
1128 if (res->res_sch.run) {
1130 nrun = res->res_sch.run;
1140 if (res->res_job.RestoreWhere) {
1141 free(res->res_job.RestoreWhere);
1143 if (res->res_job.RestoreBootstrap) {
1144 free(res->res_job.RestoreBootstrap);
1146 if (res->res_job.WriteBootstrap) {
1147 free(res->res_job.WriteBootstrap);
1149 if (res->res_job.selection_pattern) {
1150 free(res->res_job.selection_pattern);
1152 if (res->res_job.run_cmds) {
1153 delete res->res_job.run_cmds;
1155 if (res->res_job.storage) {
1156 delete res->res_job.storage;
1158 if (res->res_job.RunScripts) {
1159 free_runscripts(res->res_job.RunScripts);
1160 delete res->res_job.RunScripts;
1164 if (res->res_msgs.mail_cmd) {
1165 free(res->res_msgs.mail_cmd);
1167 if (res->res_msgs.operator_cmd) {
1168 free(res->res_msgs.operator_cmd);
1170 free_msgs_res((MSGS *)res); /* free message resource */
1174 printf(_("Unknown resource type %d in free_resource.\n"), type);
1176 /* Common stuff again -- free the resource, recurse to next one */
1181 free_resource(nres, type);
1186 * Save the new resource by chaining it into the head list for
1187 * the resource. If this is pass 2, we update any resource
1188 * pointers because they may not have been defined until
1191 void save_resource(int type, RES_ITEM *items, int pass)
1194 int rindex = type - r_first;
1198 /* Check Job requirements after applying JobDefs */
1199 if (type != R_JOB && type != R_JOBDEFS) {
1201 * Ensure that all required items are present
1203 for (i=0; items[i].name; i++) {
1204 if (items[i].flags & ITEM_REQUIRED) {
1205 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1206 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1207 items[i].name, resources[rindex]);
1210 /* If this triggers, take a look at lib/parse_conf.h */
1211 if (i >= MAX_RES_ITEMS) {
1212 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1215 } else if (type == R_JOB) {
1217 * Ensure that the name item is present
1219 if (items[0].flags & ITEM_REQUIRED) {
1220 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1221 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1222 items[0].name, resources[rindex]);
1228 * During pass 2 in each "store" routine, we looked up pointers
1229 * to all the resources referrenced in the current resource, now we
1230 * must copy their addresses from the static record to the allocated
1235 /* Resources not containing a resource */
1243 * Resources containing another resource or alist. First
1244 * look up the resource which contains another resource. It
1245 * was written during pass 1. Then stuff in the pointers to
1246 * the resources it contains, which were inserted this pass.
1247 * Finally, it will all be stored back.
1250 /* Find resource saved in pass 1 */
1251 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1252 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1254 /* Explicitly copy resource pointers from this pass (res_all) */
1255 res->res_pool.NextPool = res_all.res_pool.NextPool;
1256 res->res_pool.RecyclePool = res_all.res_pool.RecyclePool;
1257 res->res_pool.storage = res_all.res_pool.storage;
1260 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1261 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1263 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1266 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1267 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1269 res->res_dir.messages = res_all.res_dir.messages;
1270 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1273 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1274 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1275 res_all.res_dir.hdr.name);
1277 /* we must explicitly copy the device alist pointer */
1278 res->res_store.device = res_all.res_store.device;
1282 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1283 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1284 res_all.res_dir.hdr.name);
1286 res->res_job.messages = res_all.res_job.messages;
1287 res->res_job.schedule = res_all.res_job.schedule;
1288 res->res_job.client = res_all.res_job.client;
1289 res->res_job.fileset = res_all.res_job.fileset;
1290 res->res_job.storage = res_all.res_job.storage;
1291 res->res_job.pool = res_all.res_job.pool;
1292 res->res_job.full_pool = res_all.res_job.full_pool;
1293 res->res_job.inc_pool = res_all.res_job.inc_pool;
1294 res->res_job.diff_pool = res_all.res_job.diff_pool;
1295 res->res_job.verify_job = res_all.res_job.verify_job;
1296 res->res_job.jobdefs = res_all.res_job.jobdefs;
1297 res->res_job.run_cmds = res_all.res_job.run_cmds;
1298 res->res_job.RunScripts = res_all.res_job.RunScripts;
1301 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1302 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1304 res->res_counter.Catalog = res_all.res_counter.Catalog;
1305 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1309 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1310 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1312 res->res_client.catalog = res_all.res_client.catalog;
1313 res->res_client.tls_allowed_cns = res_all.res_client.tls_allowed_cns;
1317 * Schedule is a bit different in that it contains a RUN record
1318 * chain which isn't a "named" resource. This chain was linked
1319 * in by run_conf.c during pass 2, so here we jam the pointer
1320 * into the Schedule resource.
1322 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1323 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1325 res->res_sch.run = res_all.res_sch.run;
1328 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1332 /* Note, the resource name was already saved during pass 1,
1333 * so here, we can just release it.
1335 if (res_all.res_dir.hdr.name) {
1336 free(res_all.res_dir.hdr.name);
1337 res_all.res_dir.hdr.name = NULL;
1339 if (res_all.res_dir.hdr.desc) {
1340 free(res_all.res_dir.hdr.desc);
1341 res_all.res_dir.hdr.desc = NULL;
1347 * The following code is only executed during pass 1
1351 size = sizeof(DIRRES);
1354 size = sizeof(CONRES);
1357 size =sizeof(CLIENT);
1360 size = sizeof(STORE);
1370 size = sizeof(FILESET);
1373 size = sizeof(SCHED);
1376 size = sizeof(POOL);
1379 size = sizeof(MSGS);
1382 size = sizeof(COUNTER);
1388 printf(_("Unknown resource type %d in save_resource.\n"), type);
1394 res = (URES *)malloc(size);
1395 memcpy(res, &res_all, size);
1396 if (!res_head[rindex]) {
1397 res_head[rindex] = (RES *)res; /* store first entry */
1398 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1399 res->res_dir.hdr.name, rindex);
1402 if (res->res_dir.hdr.name == NULL) {
1403 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1406 /* Add new res to end of chain */
1407 for (last=next=res_head[rindex]; next; next=next->next) {
1409 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1410 Emsg2(M_ERROR_TERM, 0,
1411 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1412 resources[rindex].name, res->res_dir.hdr.name);
1415 last->next = (RES *)res;
1416 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1417 res->res_dir.hdr.name, rindex, pass);
1423 * Store Device. Note, the resource is created upon the
1424 * first reference. The details of the resource are obtained
1425 * later from the SD.
1427 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1431 int rindex = R_DEVICE - r_first;
1432 int size = sizeof(DEVICE);
1436 token = lex_get_token(lc, T_NAME);
1437 if (!res_head[rindex]) {
1438 res = (URES *)malloc(size);
1439 memset(res, 0, size);
1440 res->res_dev.hdr.name = bstrdup(lc->str);
1441 res_head[rindex] = (RES *)res; /* store first entry */
1442 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1443 res->res_dir.hdr.name, rindex);
1446 /* See if it is already defined */
1447 for (next=res_head[rindex]; next->next; next=next->next) {
1448 if (strcmp(next->name, lc->str) == 0) {
1454 res = (URES *)malloc(size);
1455 memset(res, 0, size);
1456 res->res_dev.hdr.name = bstrdup(lc->str);
1457 next->next = (RES *)res;
1458 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1459 res->res_dir.hdr.name, rindex, pass);
1464 set_bit(index, res_all.hdr.item_present);
1466 store_alist_res(lc, item, index, pass);
1471 * Store JobType (backup, verify, restore)
1474 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1478 token = lex_get_token(lc, T_NAME);
1479 /* Store the type both pass 1 and pass 2 */
1480 for (i=0; migtypes[i].type_name; i++) {
1481 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1482 *(int *)(item->value) = migtypes[i].job_type;
1488 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1491 set_bit(index, res_all.hdr.item_present);
1497 * Store JobType (backup, verify, restore)
1500 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1504 token = lex_get_token(lc, T_NAME);
1505 /* Store the type both pass 1 and pass 2 */
1506 for (i=0; jobtypes[i].type_name; i++) {
1507 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1508 *(int *)(item->value) = jobtypes[i].job_type;
1514 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1517 set_bit(index, res_all.hdr.item_present);
1521 * Store Job Level (Full, Incremental, ...)
1524 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1528 token = lex_get_token(lc, T_NAME);
1529 /* Store the level pass 2 so that type is defined */
1530 for (i=0; joblevels[i].level_name; i++) {
1531 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1532 *(int *)(item->value) = joblevels[i].level;
1538 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1541 set_bit(index, res_all.hdr.item_present);
1545 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1548 token = lex_get_token(lc, T_NAME);
1549 /* Scan Replacement options */
1550 for (i=0; ReplaceOptions[i].name; i++) {
1551 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1552 *(int *)(item->value) = ReplaceOptions[i].token;
1558 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1561 set_bit(index, res_all.hdr.item_present);
1565 * Store ACL (access control list)
1568 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1573 token = lex_get_token(lc, T_STRING);
1575 if (((alist **)item->value)[item->code] == NULL) {
1576 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1577 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1579 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1580 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1582 token = lex_get_token(lc, T_ALL);
1583 if (token == T_COMMA) {
1584 continue; /* get another ACL */
1588 set_bit(index, res_all.hdr.item_present);
1591 /* We build RunScripts items here */
1592 static RUNSCRIPT res_runscript;
1594 /* Store a runscript->when in a bit field */
1595 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1597 lex_get_token(lc, T_NAME);
1599 if (strcasecmp(lc->str, "before") == 0) {
1600 *(int *)(item->value) = SCRIPT_Before ;
1601 } else if (strcasecmp(lc->str, "after") == 0) {
1602 *(int *)(item->value) = SCRIPT_After;
1603 } else if (strcasecmp(lc->str, "always") == 0) {
1604 *(int *)(item->value) = SCRIPT_Any;
1606 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1611 /* Store a runscript->target
1614 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1616 lex_get_token(lc, T_STRING);
1619 if (strcmp(lc->str, "%c") == 0) {
1620 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1621 } else if (strcasecmp(lc->str, "yes") == 0) {
1622 ((RUNSCRIPT*) item->value)->set_target("%c");
1623 } else if (strcasecmp(lc->str, "no") == 0) {
1624 ((RUNSCRIPT*) item->value)->set_target("");
1626 RES *res = GetResWithName(R_CLIENT, lc->str);
1628 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1629 lc->str, lc->line_no, lc->line);
1632 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1638 /* Store a runscript->command in a bit field
1641 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1643 lex_get_token(lc, T_STRING);
1646 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1651 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1653 lex_get_token(lc, T_STRING);
1654 alist **runscripts = (alist **)(item->value) ;
1657 RUNSCRIPT *script = new_runscript();
1659 script->set_command(lc->str);
1661 /* TODO: remove all script->old_proto with bacula 1.42 */
1663 if (strcmp(item->name, "runbeforejob") == 0) {
1664 script->when = SCRIPT_Before;
1665 script->abort_on_error = true;
1666 script->set_target("");
1668 } else if (strcmp(item->name, "runafterjob") == 0) {
1669 script->when = SCRIPT_After;
1670 script->on_success = true;
1671 script->on_failure = false;
1672 script->set_target("");
1674 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1675 script->old_proto = true;
1676 script->when = SCRIPT_After;
1677 script->set_target("%c");
1678 script->on_success = true;
1679 script->on_failure = false;
1681 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1682 script->old_proto = true;
1683 script->when = SCRIPT_Before;
1684 script->set_target("%c");
1685 script->abort_on_error = true;
1687 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1688 script->when = SCRIPT_After;
1689 script->on_failure = true;
1690 script->on_success = false;
1691 script->set_target("");
1694 if (*runscripts == NULL) {
1695 *runscripts = New(alist(10, not_owned_by_alist));
1698 (*runscripts)->append(script);
1705 /* Store a bool in a bit field without modifing res_all.hdr
1706 * We can also add an option to store_bool to skip res_all.hdr
1708 void store_runscript_bool(LEX *lc, RES_ITEM *item, int index, int pass)
1710 lex_get_token(lc, T_NAME);
1711 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
1712 *(bool *)(item->value) = true;
1713 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
1714 *(bool *)(item->value) = false;
1716 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
1722 * new RunScript items
1723 * name handler value code flags default_value
1725 static RES_ITEM runscript_items[] = {
1726 {"command", store_runscript_cmd, {(char **)&res_runscript}, 0, ITEM_REQUIRED, 0},
1727 {"target", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0},
1728 {"runsonsuccess", store_runscript_bool, {(char **)&res_runscript.on_success},0, 0, 0},
1729 {"runsonfailure", store_runscript_bool, {(char **)&res_runscript.on_failure},0, 0, 0},
1730 {"abortjobonerror",store_runscript_bool, {(char **)&res_runscript.abort_on_error},0, 0, 0},
1731 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1732 {"runsonclient", store_runscript_target,{(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1733 {NULL, NULL, {0}, 0, 0, 0}
1737 * Store RunScript info
1739 * Note, when this routine is called, we are inside a Job
1740 * resource. We treat the RunScript like a sort of
1741 * mini-resource within the Job resource.
1743 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1746 alist **runscripts = (alist **)(item->value) ;
1748 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1750 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1752 token = lex_get_token(lc, T_SKIP_EOL);
1754 if (token != T_BOB) {
1755 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1758 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1759 if (token == T_EOB) {
1762 if (token != T_IDENTIFIER) {
1763 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1765 for (i=0; runscript_items[i].name; i++) {
1766 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1767 token = lex_get_token(lc, T_SKIP_EOL);
1768 if (token != T_EQUALS) {
1769 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1772 /* Call item handler */
1773 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1780 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1785 if (res_runscript.command == NULL) {
1786 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1787 "command", "runscript");
1790 /* run on client by default */
1791 if (res_runscript.target == NULL) {
1792 res_runscript.set_target("%c");
1795 RUNSCRIPT *script = new_runscript();
1796 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1798 if (*runscripts == NULL) {
1799 *runscripts = New(alist(10, not_owned_by_alist));
1802 (*runscripts)->append(script);
1807 set_bit(index, res_all.hdr.item_present);