2 * Main configuration file parser for Bacula Directors,
3 * some parts may be split into separate files such as
4 * the schedule configuration (run_config.c).
6 * Note, the configuration file parser consists of three parts
8 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
10 * 2. The generic config scanner in lib/parse_config.c and
12 * These files contain the parser code, some utility
13 * routines, and the common store routines (name, int,
16 * 3. The daemon specific file, which contains the Resource
17 * definitions as well as any specific store routines
18 * for the resource records.
20 * Kern Sibbald, January MM
25 Copyright (C) 2000-2006 Kern Sibbald
27 This program is free software; you can redistribute it and/or
28 modify it under the terms of the GNU General Public License
29 version 2 as amended with additional clauses defined in the
30 file LICENSE in the main source directory.
32 This program is distributed in the hope that it will be useful,
33 but WITHOUT ANY WARRANTY; without even the implied warranty of
34 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 the file LICENSE for additional details.
42 /* Define the first and last resource ID record
43 * types. Note, these should be unique for each
44 * daemon though not a requirement.
46 int r_first = R_FIRST;
48 static RES *sres_head[R_LAST - R_FIRST + 1];
49 RES **res_head = sres_head;
51 /* Imported subroutines */
52 extern void store_run(LEX *lc, RES_ITEM *item, int index, int pass);
53 extern void store_finc(LEX *lc, RES_ITEM *item, int index, int pass);
54 extern void store_inc(LEX *lc, RES_ITEM *item, int index, int pass);
57 /* Forward referenced subroutines */
59 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
60 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
61 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
62 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
63 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
64 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
65 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
66 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
67 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
68 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
70 /* We build the current resource here as we are
71 * scanning the resource configuration definition,
72 * then move it to allocated memory when the resource
76 extern "C" { // work around visual compiler mangling variables
82 int res_all_size = sizeof(res_all);
85 /* Definition of records permitted within each
86 * resource with the routine to process the record
87 * information. NOTE! quoted names must be in lower case.
92 * name handler value code flags default_value
94 static RES_ITEM dir_items[] = {
95 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
96 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
97 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
98 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
99 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
100 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
101 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
102 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
103 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
104 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
105 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
106 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
107 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
108 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
109 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
110 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
111 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
112 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
113 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
114 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
115 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
116 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
117 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
118 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
119 {NULL, NULL, {0}, 0, 0, 0}
125 * name handler value code flags default_value
127 static RES_ITEM con_items[] = {
128 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
129 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
130 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
131 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
132 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
133 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
134 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
135 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
136 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
137 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
138 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
139 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
140 {"whereacl", store_acl, ITEM(res_con.ACL_lists), Where_ACL, 0, 0},
141 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
142 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
143 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
144 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
145 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
146 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
147 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
148 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
149 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
150 {NULL, NULL, {0}, 0, 0, 0}
155 * Client or File daemon resource
157 * name handler value code flags default_value
160 static RES_ITEM cli_items[] = {
161 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
162 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
163 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
164 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
165 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
166 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
167 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
168 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
169 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
170 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
171 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
172 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
173 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
174 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
175 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
176 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
177 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
178 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
179 {NULL, NULL, {0}, 0, 0, 0}
182 /* Storage daemon resource
184 * name handler value code flags default_value
186 static RES_ITEM store_items[] = {
187 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
188 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
189 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
190 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
191 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
192 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
193 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
194 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
195 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
196 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
197 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
198 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
199 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
200 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
201 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
202 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
203 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
204 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
205 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
206 {NULL, NULL, {0}, 0, 0, 0}
210 * Catalog Resource Directives
212 * name handler value code flags default_value
214 static RES_ITEM cat_items[] = {
215 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
216 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
217 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
218 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
219 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
220 /* keep this password as store_str for the moment */
221 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
222 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
223 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
224 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
225 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
226 /* Turned off for the moment */
227 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
228 {NULL, NULL, {0}, 0, 0, 0}
232 * Job Resource Directives
234 * name handler value code flags default_value
236 RES_ITEM job_items[] = {
237 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
238 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
239 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
240 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
241 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
242 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
243 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
244 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
245 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
246 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
247 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
248 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
249 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
250 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
251 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
252 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
253 {"nextpool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
254 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
255 /* Root of where to restore files */
256 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
257 /* Where to find bootstrap during restore */
258 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
259 /* Where to write bootstrap file during backup */
260 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
261 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
262 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
263 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
264 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
265 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
266 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
267 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
268 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
269 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
270 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
271 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
272 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
273 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
274 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
275 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
276 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
277 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
278 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
279 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
280 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
281 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
282 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
283 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
284 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
285 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
286 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
287 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
288 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
289 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, false},
290 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
291 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
292 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
293 {NULL, NULL, {0}, 0, 0, 0}
298 * name handler value code flags default_value
300 static RES_ITEM fs_items[] = {
301 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
302 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
303 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
304 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
305 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
306 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, false},
307 {NULL, NULL, {0}, 0, 0, 0}
310 /* Schedule -- see run_conf.c */
313 * name handler value code flags default_value
315 static RES_ITEM sch_items[] = {
316 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
317 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
318 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
319 {NULL, NULL, {0}, 0, 0, 0}
324 * name handler value code flags default_value
326 static RES_ITEM pool_items[] = {
327 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
328 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
329 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
330 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
331 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
332 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
333 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
334 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
335 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
336 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
337 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
338 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
339 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
340 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
341 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
342 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
343 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
344 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
345 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
346 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
347 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
348 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
349 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
350 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
351 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
352 {NULL, NULL, {0}, 0, 0, 0}
357 * name handler value code flags default_value
359 static RES_ITEM counter_items[] = {
360 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
361 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
362 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
363 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
364 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
365 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
366 {NULL, NULL, {0}, 0, 0, 0}
370 /* Message resource */
371 extern RES_ITEM msgs_items[];
374 * This is the master resource definition.
375 * It must have one item for each of the resources.
377 * NOTE!!! keep it in the same order as the R_codes
378 * or eliminate all resources[rindex].name
380 * name items rcode res_head
382 RES_TABLE resources[] = {
383 {"director", dir_items, R_DIRECTOR},
384 {"client", cli_items, R_CLIENT},
385 {"job", job_items, R_JOB},
386 {"storage", store_items, R_STORAGE},
387 {"catalog", cat_items, R_CATALOG},
388 {"schedule", sch_items, R_SCHEDULE},
389 {"fileset", fs_items, R_FILESET},
390 {"pool", pool_items, R_POOL},
391 {"messages", msgs_items, R_MSGS},
392 {"counter", counter_items, R_COUNTER},
393 {"console", con_items, R_CONSOLE},
394 {"jobdefs", job_items, R_JOBDEFS},
395 {"device", NULL, R_DEVICE}, /* info obtained from SD */
400 /* Keywords (RHS) permitted in Job Level records
402 * level_name level job_type
404 struct s_jl joblevels[] = {
405 {"Full", L_FULL, JT_BACKUP},
406 {"Base", L_BASE, JT_BACKUP},
407 {"Incremental", L_INCREMENTAL, JT_BACKUP},
408 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
409 {"Since", L_SINCE, JT_BACKUP},
410 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
411 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
412 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
413 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
414 {"Data", L_VERIFY_DATA, JT_VERIFY},
415 {" ", L_NONE, JT_ADMIN},
416 {" ", L_NONE, JT_RESTORE},
420 /* Keywords (RHS) permitted in Job type records
424 struct s_jt jobtypes[] = {
425 {"backup", JT_BACKUP},
427 {"verify", JT_VERIFY},
428 {"restore", JT_RESTORE},
429 {"migrate", JT_MIGRATE},
434 /* Keywords (RHS) permitted in Selection type records
438 struct s_jt migtypes[] = {
439 {"smallestvolume", MT_SMALLEST_VOL},
440 {"oldestvolume", MT_OLDEST_VOL},
441 {"pooloccupancy", MT_POOL_OCCUPANCY},
442 {"pooltime", MT_POOL_TIME},
443 {"client", MT_CLIENT},
444 {"volume", MT_VOLUME},
446 {"sqlquery", MT_SQLQUERY},
452 /* Options permitted in Restore replace= */
453 struct s_kw ReplaceOptions[] = {
454 {"always", REPLACE_ALWAYS},
455 {"ifnewer", REPLACE_IFNEWER},
456 {"ifolder", REPLACE_IFOLDER},
457 {"never", REPLACE_NEVER},
461 const char *level_to_str(int level)
464 static char level_no[30];
465 const char *str = level_no;
467 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
468 for (i=0; joblevels[i].level_name; i++) {
469 if (level == joblevels[i].level) {
470 str = joblevels[i].level_name;
477 /* Dump contents of resource */
478 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
480 URES *res = (URES *)reshdr;
482 char ed1[100], ed2[100], ed3[100];
486 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
489 if (type < 0) { /* no recursion */
495 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
496 reshdr->name, res->res_dir.MaxConcurrentJobs,
497 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
498 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
499 if (res->res_dir.query_file) {
500 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
502 if (res->res_dir.messages) {
503 sendit(sock, _(" --> "));
504 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
508 sendit(sock, _("Console: name=%s SSL=%d\n"),
509 res->res_con.hdr.name, res->res_con.tls_enable);
512 if (res->res_counter.WrapCounter) {
513 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
514 res->res_counter.hdr.name, res->res_counter.MinValue,
515 res->res_counter.MaxValue, res->res_counter.CurrentValue,
516 res->res_counter.WrapCounter->hdr.name);
518 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
519 res->res_counter.hdr.name, res->res_counter.MinValue,
520 res->res_counter.MaxValue);
522 if (res->res_counter.Catalog) {
523 sendit(sock, _(" --> "));
524 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
529 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
530 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
531 res->res_client.MaxConcurrentJobs);
532 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
533 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
534 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
535 res->res_client.AutoPrune);
536 if (res->res_client.catalog) {
537 sendit(sock, _(" --> "));
538 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
544 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
545 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
546 " poolid=%s volname=%s MediaType=%s\n"),
547 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
548 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
549 dev->offline, dev->autochanger,
550 edit_uint64(dev->PoolId, ed1),
551 dev->VolumeName, dev->MediaType);
554 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
555 " DeviceName=%s MediaType=%s StorageId=%s\n"),
556 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
557 res->res_store.MaxConcurrentJobs,
558 res->res_store.dev_name(),
559 res->res_store.media_type,
560 edit_int64(res->res_store.StorageId, ed1));
563 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
564 " db_user=%s MutliDBConn=%d\n"),
565 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
566 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
567 res->res_cat.mult_db_connections);
571 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
572 type == R_JOB ? _("Job") : _("JobDefs"),
573 res->res_job.hdr.name, res->res_job.JobType,
574 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
575 res->res_job.enabled);
576 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
577 res->res_job.MaxConcurrentJobs,
578 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
579 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
580 res->res_job.spool_data, res->res_job.write_part_after_job);
581 if (res->res_job.JobType == JT_MIGRATE) {
582 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
584 if (res->res_job.client) {
585 sendit(sock, _(" --> "));
586 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
588 if (res->res_job.fileset) {
589 sendit(sock, _(" --> "));
590 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
592 if (res->res_job.schedule) {
593 sendit(sock, _(" --> "));
594 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
596 if (res->res_job.RestoreWhere) {
597 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
599 if (res->res_job.RestoreBootstrap) {
600 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
602 if (res->res_job.WriteBootstrap) {
603 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
605 if (res->res_job.storage) {
607 foreach_alist(store, res->res_job.storage) {
608 sendit(sock, _(" --> "));
609 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
612 if (res->res_job.RunScripts) {
614 foreach_alist(script, res->res_job.RunScripts) {
615 sendit(sock, _(" --> RunScript\n"));
616 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
617 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
618 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
619 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
620 sendit(sock, _(" --> AbortJobOnError=%u\n"), script->abort_on_error);
621 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
624 if (res->res_job.pool) {
625 sendit(sock, _(" --> "));
626 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
628 if (res->res_job.full_pool) {
629 sendit(sock, _(" --> "));
630 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
632 if (res->res_job.inc_pool) {
633 sendit(sock, _(" --> "));
634 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
636 if (res->res_job.diff_pool) {
637 sendit(sock, _(" --> "));
638 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
640 if (res->res_job.verify_job) {
641 sendit(sock, _(" --> "));
642 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
644 if (res->res_job.run_cmds) {
646 foreach_alist(runcmd, res->res_job.run_cmds) {
647 sendit(sock, _(" --> Run=%s\n"), runcmd);
650 if (res->res_job.selection_pattern) {
651 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
653 if (res->res_job.messages) {
654 sendit(sock, _(" --> "));
655 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
661 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
662 for (i=0; i<res->res_fs.num_includes; i++) {
663 INCEXE *incexe = res->res_fs.include_items[i];
664 for (j=0; j<incexe->num_opts; j++) {
665 FOPTS *fo = incexe->opts_list[j];
666 sendit(sock, " O %s\n", fo->opts);
668 bool enhanced_wild = false;
669 for (k=0; fo->opts[k]!='\0'; k++) {
670 if (fo->opts[k]=='W') {
671 enhanced_wild = true;
676 for (k=0; k<fo->regex.size(); k++) {
677 sendit(sock, " R %s\n", fo->regex.get(k));
679 for (k=0; k<fo->regexdir.size(); k++) {
680 sendit(sock, " RD %s\n", fo->regexdir.get(k));
682 for (k=0; k<fo->regexfile.size(); k++) {
683 sendit(sock, " RF %s\n", fo->regexfile.get(k));
685 for (k=0; k<fo->wild.size(); k++) {
686 sendit(sock, " W %s\n", fo->wild.get(k));
688 for (k=0; k<fo->wilddir.size(); k++) {
689 sendit(sock, " WD %s\n", fo->wilddir.get(k));
691 for (k=0; k<fo->wildfile.size(); k++) {
692 sendit(sock, " WF %s\n", fo->wildfile.get(k));
694 for (k=0; k<fo->wildbase.size(); k++) {
695 sendit(sock, " W%c %s\n", enhanced_wild ? 'B' : 'F', fo->wildbase.get(k));
697 for (k=0; k<fo->base.size(); k++) {
698 sendit(sock, " B %s\n", fo->base.get(k));
700 for (k=0; k<fo->fstype.size(); k++) {
701 sendit(sock, " X %s\n", fo->fstype.get(k));
703 for (k=0; k<fo->drivetype.size(); k++) {
704 sendit(sock, " XD %s\n", fo->drivetype.get(k));
707 sendit(sock, " D %s\n", fo->reader);
710 sendit(sock, " T %s\n", fo->writer);
712 sendit(sock, " N\n");
714 for (j=0; j<incexe->name_list.size(); j++) {
715 sendit(sock, " I %s\n", incexe->name_list.get(j));
717 if (incexe->name_list.size()) {
718 sendit(sock, " N\n");
722 for (i=0; i<res->res_fs.num_excludes; i++) {
723 INCEXE *incexe = res->res_fs.exclude_items[i];
724 for (j=0; j<incexe->name_list.size(); j++) {
725 sendit(sock, " E %s\n", incexe->name_list.get(j));
727 if (incexe->name_list.size()) {
728 sendit(sock, " N\n");
734 if (res->res_sch.run) {
736 RUN *run = res->res_sch.run;
737 char buf[1000], num[30];
738 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
743 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
744 bstrncpy(buf, _(" hour="), sizeof(buf));
745 for (i=0; i<24; i++) {
746 if (bit_is_set(i, run->hour)) {
747 bsnprintf(num, sizeof(num), "%d ", i);
748 bstrncat(buf, num, sizeof(buf));
751 bstrncat(buf, "\n", sizeof(buf));
753 bstrncpy(buf, _(" mday="), sizeof(buf));
754 for (i=0; i<31; i++) {
755 if (bit_is_set(i, run->mday)) {
756 bsnprintf(num, sizeof(num), "%d ", i);
757 bstrncat(buf, num, sizeof(buf));
760 bstrncat(buf, "\n", sizeof(buf));
762 bstrncpy(buf, _(" month="), sizeof(buf));
763 for (i=0; i<12; i++) {
764 if (bit_is_set(i, run->month)) {
765 bsnprintf(num, sizeof(num), "%d ", i);
766 bstrncat(buf, num, sizeof(buf));
769 bstrncat(buf, "\n", sizeof(buf));
771 bstrncpy(buf, _(" wday="), sizeof(buf));
772 for (i=0; i<7; i++) {
773 if (bit_is_set(i, run->wday)) {
774 bsnprintf(num, sizeof(num), "%d ", i);
775 bstrncat(buf, num, sizeof(buf));
778 bstrncat(buf, "\n", sizeof(buf));
780 bstrncpy(buf, _(" wom="), sizeof(buf));
781 for (i=0; i<5; i++) {
782 if (bit_is_set(i, run->wom)) {
783 bsnprintf(num, sizeof(num), "%d ", i);
784 bstrncat(buf, num, sizeof(buf));
787 bstrncat(buf, "\n", sizeof(buf));
789 bstrncpy(buf, _(" woy="), sizeof(buf));
790 for (i=0; i<54; i++) {
791 if (bit_is_set(i, run->woy)) {
792 bsnprintf(num, sizeof(num), "%d ", i);
793 bstrncat(buf, num, sizeof(buf));
796 bstrncat(buf, "\n", sizeof(buf));
798 sendit(sock, _(" mins=%d\n"), run->minute);
800 sendit(sock, _(" --> "));
801 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
804 sendit(sock, _(" --> "));
805 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
808 sendit(sock, _(" --> "));
809 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
811 /* If another Run record is chained in, go print it */
817 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
821 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
822 res->res_pool.pool_type);
823 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
824 res->res_pool.use_catalog, res->res_pool.use_volume_once,
825 res->res_pool.catalog_files);
826 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
827 res->res_pool.max_volumes, res->res_pool.AutoPrune,
828 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
829 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
830 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
831 res->res_pool.Recycle,
832 NPRT(res->res_pool.label_format));
833 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
834 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
835 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
836 res->res_pool.recycle_oldest_volume,
837 res->res_pool.purge_oldest_volume,
838 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
839 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
840 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
841 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
842 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
843 if (res->res_pool.NextPool) {
844 sendit(sock, _(" --> "));
845 dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
847 if (res->res_pool.storage) {
849 foreach_alist(store, res->res_pool.storage) {
850 sendit(sock, _(" --> "));
851 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
856 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
857 if (res->res_msgs.mail_cmd)
858 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
859 if (res->res_msgs.operator_cmd)
860 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
863 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
866 if (recurse && res->res_dir.hdr.next) {
867 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
872 * Free all the members of an INCEXE structure
874 static void free_incexe(INCEXE *incexe)
876 incexe->name_list.destroy();
877 for (int i=0; i<incexe->num_opts; i++) {
878 FOPTS *fopt = incexe->opts_list[i];
879 fopt->regex.destroy();
880 fopt->regexdir.destroy();
881 fopt->regexfile.destroy();
882 fopt->wild.destroy();
883 fopt->wilddir.destroy();
884 fopt->wildfile.destroy();
885 fopt->wildbase.destroy();
886 fopt->base.destroy();
887 fopt->fstype.destroy();
888 fopt->drivetype.destroy();
897 if (incexe->opts_list) {
898 free(incexe->opts_list);
904 * Free memory of resource -- called when daemon terminates.
905 * NB, we don't need to worry about freeing any references
906 * to other resources as they will be freed when that
907 * resource chain is traversed. Mainly we worry about freeing
908 * allocated strings (names).
910 void free_resource(RES *sres, int type)
913 RES *nres; /* next resource if linked */
914 URES *res = (URES *)sres;
919 /* common stuff -- free the resource name and description */
920 nres = (RES *)res->res_dir.hdr.next;
921 if (res->res_dir.hdr.name) {
922 free(res->res_dir.hdr.name);
924 if (res->res_dir.hdr.desc) {
925 free(res->res_dir.hdr.desc);
930 if (res->res_dir.working_directory) {
931 free(res->res_dir.working_directory);
933 if (res->res_dir.scripts_directory) {
934 free((char *)res->res_dir.scripts_directory);
936 if (res->res_dir.pid_directory) {
937 free(res->res_dir.pid_directory);
939 if (res->res_dir.subsys_directory) {
940 free(res->res_dir.subsys_directory);
942 if (res->res_dir.password) {
943 free(res->res_dir.password);
945 if (res->res_dir.query_file) {
946 free(res->res_dir.query_file);
948 if (res->res_dir.DIRaddrs) {
949 free_addresses(res->res_dir.DIRaddrs);
951 if (res->res_dir.tls_ctx) {
952 free_tls_context(res->res_dir.tls_ctx);
954 if (res->res_dir.tls_ca_certfile) {
955 free(res->res_dir.tls_ca_certfile);
957 if (res->res_dir.tls_ca_certdir) {
958 free(res->res_dir.tls_ca_certdir);
960 if (res->res_dir.tls_certfile) {
961 free(res->res_dir.tls_certfile);
963 if (res->res_dir.tls_keyfile) {
964 free(res->res_dir.tls_keyfile);
966 if (res->res_dir.tls_dhfile) {
967 free(res->res_dir.tls_dhfile);
969 if (res->res_dir.tls_allowed_cns) {
970 delete res->res_dir.tls_allowed_cns;
977 if (res->res_con.password) {
978 free(res->res_con.password);
980 if (res->res_con.tls_ctx) {
981 free_tls_context(res->res_con.tls_ctx);
983 if (res->res_con.tls_ca_certfile) {
984 free(res->res_con.tls_ca_certfile);
986 if (res->res_con.tls_ca_certdir) {
987 free(res->res_con.tls_ca_certdir);
989 if (res->res_con.tls_certfile) {
990 free(res->res_con.tls_certfile);
992 if (res->res_con.tls_keyfile) {
993 free(res->res_con.tls_keyfile);
995 if (res->res_con.tls_dhfile) {
996 free(res->res_con.tls_dhfile);
998 if (res->res_con.tls_allowed_cns) {
999 delete res->res_con.tls_allowed_cns;
1001 for (int i=0; i<Num_ACL; i++) {
1002 if (res->res_con.ACL_lists[i]) {
1003 delete res->res_con.ACL_lists[i];
1004 res->res_con.ACL_lists[i] = NULL;
1009 if (res->res_client.address) {
1010 free(res->res_client.address);
1012 if (res->res_client.password) {
1013 free(res->res_client.password);
1015 if (res->res_client.tls_ctx) {
1016 free_tls_context(res->res_client.tls_ctx);
1018 if (res->res_client.tls_ca_certfile) {
1019 free(res->res_client.tls_ca_certfile);
1021 if (res->res_client.tls_ca_certdir) {
1022 free(res->res_client.tls_ca_certdir);
1024 if (res->res_client.tls_certfile) {
1025 free(res->res_client.tls_certfile);
1027 if (res->res_client.tls_keyfile) {
1028 free(res->res_client.tls_keyfile);
1032 if (res->res_store.address) {
1033 free(res->res_store.address);
1035 if (res->res_store.password) {
1036 free(res->res_store.password);
1038 if (res->res_store.media_type) {
1039 free(res->res_store.media_type);
1041 if (res->res_store.device) {
1042 delete res->res_store.device;
1044 if (res->res_store.tls_ctx) {
1045 free_tls_context(res->res_store.tls_ctx);
1047 if (res->res_store.tls_ca_certfile) {
1048 free(res->res_store.tls_ca_certfile);
1050 if (res->res_store.tls_ca_certdir) {
1051 free(res->res_store.tls_ca_certdir);
1053 if (res->res_store.tls_certfile) {
1054 free(res->res_store.tls_certfile);
1056 if (res->res_store.tls_keyfile) {
1057 free(res->res_store.tls_keyfile);
1061 if (res->res_cat.db_address) {
1062 free(res->res_cat.db_address);
1064 if (res->res_cat.db_socket) {
1065 free(res->res_cat.db_socket);
1067 if (res->res_cat.db_user) {
1068 free(res->res_cat.db_user);
1070 if (res->res_cat.db_name) {
1071 free(res->res_cat.db_name);
1073 if (res->res_cat.db_password) {
1074 free(res->res_cat.db_password);
1078 if ((num=res->res_fs.num_includes)) {
1079 while (--num >= 0) {
1080 free_incexe(res->res_fs.include_items[num]);
1082 free(res->res_fs.include_items);
1084 res->res_fs.num_includes = 0;
1085 if ((num=res->res_fs.num_excludes)) {
1086 while (--num >= 0) {
1087 free_incexe(res->res_fs.exclude_items[num]);
1089 free(res->res_fs.exclude_items);
1091 res->res_fs.num_excludes = 0;
1094 if (res->res_pool.pool_type) {
1095 free(res->res_pool.pool_type);
1097 if (res->res_pool.label_format) {
1098 free(res->res_pool.label_format);
1100 if (res->res_pool.cleaning_prefix) {
1101 free(res->res_pool.cleaning_prefix);
1103 if (res->res_pool.storage) {
1104 delete res->res_pool.storage;
1108 if (res->res_sch.run) {
1110 nrun = res->res_sch.run;
1120 if (res->res_job.RestoreWhere) {
1121 free(res->res_job.RestoreWhere);
1123 if (res->res_job.RestoreBootstrap) {
1124 free(res->res_job.RestoreBootstrap);
1126 if (res->res_job.WriteBootstrap) {
1127 free(res->res_job.WriteBootstrap);
1129 if (res->res_job.selection_pattern) {
1130 free(res->res_job.selection_pattern);
1132 if (res->res_job.run_cmds) {
1133 delete res->res_job.run_cmds;
1135 if (res->res_job.storage) {
1136 delete res->res_job.storage;
1138 if (res->res_job.RunScripts) {
1139 free_runscripts(res->res_job.RunScripts);
1140 delete res->res_job.RunScripts;
1144 if (res->res_msgs.mail_cmd) {
1145 free(res->res_msgs.mail_cmd);
1147 if (res->res_msgs.operator_cmd) {
1148 free(res->res_msgs.operator_cmd);
1150 free_msgs_res((MSGS *)res); /* free message resource */
1154 printf(_("Unknown resource type %d in free_resource.\n"), type);
1156 /* Common stuff again -- free the resource, recurse to next one */
1161 free_resource(nres, type);
1166 * Save the new resource by chaining it into the head list for
1167 * the resource. If this is pass 2, we update any resource
1168 * pointers because they may not have been defined until
1171 void save_resource(int type, RES_ITEM *items, int pass)
1174 int rindex = type - r_first;
1178 /* Check Job requirements after applying JobDefs */
1179 if (type != R_JOB && type != R_JOBDEFS) {
1181 * Ensure that all required items are present
1183 for (i=0; items[i].name; i++) {
1184 if (items[i].flags & ITEM_REQUIRED) {
1185 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1186 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1187 items[i].name, resources[rindex]);
1190 /* If this triggers, take a look at lib/parse_conf.h */
1191 if (i >= MAX_RES_ITEMS) {
1192 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1195 } else if (type == R_JOB) {
1197 * Ensure that the name item is present
1199 if (items[0].flags & ITEM_REQUIRED) {
1200 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1201 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1202 items[0].name, resources[rindex]);
1208 * During pass 2 in each "store" routine, we looked up pointers
1209 * to all the resources referrenced in the current resource, now we
1210 * must copy their addresses from the static record to the allocated
1215 /* Resources not containing a resource */
1223 * Resources containing another resource or alist. First
1224 * look up the resource which contains another resource. It
1225 * was written during pass 1. Then stuff in the pointers to
1226 * the resources it contains, which were inserted this pass.
1227 * Finally, it will all be stored back.
1230 /* Find resource saved in pass 1 */
1231 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1232 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1234 /* Explicitly copy resource pointers from this pass (res_all) */
1235 res->res_pool.NextPool = res_all.res_pool.NextPool;
1236 res->res_pool.storage = res_all.res_pool.storage;
1239 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1240 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1242 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1245 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1246 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1248 res->res_dir.messages = res_all.res_dir.messages;
1249 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1252 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1253 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1254 res_all.res_dir.hdr.name);
1256 /* we must explicitly copy the device alist pointer */
1257 res->res_store.device = res_all.res_store.device;
1261 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1262 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1263 res_all.res_dir.hdr.name);
1265 res->res_job.messages = res_all.res_job.messages;
1266 res->res_job.schedule = res_all.res_job.schedule;
1267 res->res_job.client = res_all.res_job.client;
1268 res->res_job.fileset = res_all.res_job.fileset;
1269 res->res_job.storage = res_all.res_job.storage;
1270 res->res_job.pool = res_all.res_job.pool;
1271 res->res_job.full_pool = res_all.res_job.full_pool;
1272 res->res_job.inc_pool = res_all.res_job.inc_pool;
1273 res->res_job.diff_pool = res_all.res_job.diff_pool;
1274 res->res_job.verify_job = res_all.res_job.verify_job;
1275 res->res_job.jobdefs = res_all.res_job.jobdefs;
1276 res->res_job.run_cmds = res_all.res_job.run_cmds;
1277 res->res_job.RunScripts = res_all.res_job.RunScripts;
1280 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1281 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1283 res->res_counter.Catalog = res_all.res_counter.Catalog;
1284 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1288 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1289 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1291 res->res_client.catalog = res_all.res_client.catalog;
1295 * Schedule is a bit different in that it contains a RUN record
1296 * chain which isn't a "named" resource. This chain was linked
1297 * in by run_conf.c during pass 2, so here we jam the pointer
1298 * into the Schedule resource.
1300 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1301 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1303 res->res_sch.run = res_all.res_sch.run;
1306 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1310 /* Note, the resource name was already saved during pass 1,
1311 * so here, we can just release it.
1313 if (res_all.res_dir.hdr.name) {
1314 free(res_all.res_dir.hdr.name);
1315 res_all.res_dir.hdr.name = NULL;
1317 if (res_all.res_dir.hdr.desc) {
1318 free(res_all.res_dir.hdr.desc);
1319 res_all.res_dir.hdr.desc = NULL;
1325 * The following code is only executed during pass 1
1329 size = sizeof(DIRRES);
1332 size = sizeof(CONRES);
1335 size =sizeof(CLIENT);
1338 size = sizeof(STORE);
1348 size = sizeof(FILESET);
1351 size = sizeof(SCHED);
1354 size = sizeof(POOL);
1357 size = sizeof(MSGS);
1360 size = sizeof(COUNTER);
1366 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1372 res = (URES *)malloc(size);
1373 memcpy(res, &res_all, size);
1374 if (!res_head[rindex]) {
1375 res_head[rindex] = (RES *)res; /* store first entry */
1376 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1377 res->res_dir.hdr.name, rindex);
1380 if (res->res_dir.hdr.name == NULL) {
1381 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1384 /* Add new res to end of chain */
1385 for (next=res_head[rindex]; next->next; next=next->next) {
1386 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1387 Emsg2(M_ERROR_TERM, 0,
1388 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1389 resources[rindex].name, res->res_dir.hdr.name);
1392 next->next = (RES *)res;
1393 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1394 res->res_dir.hdr.name, rindex, pass);
1400 * Store Device. Note, the resource is created upon the
1401 * first reference. The details of the resource are obtained
1402 * later from the SD.
1404 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1408 int rindex = R_DEVICE - r_first;
1409 int size = sizeof(DEVICE);
1413 token = lex_get_token(lc, T_NAME);
1414 if (!res_head[rindex]) {
1415 res = (URES *)malloc(size);
1416 memset(res, 0, size);
1417 res->res_dev.hdr.name = bstrdup(lc->str);
1418 res_head[rindex] = (RES *)res; /* store first entry */
1419 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1420 res->res_dir.hdr.name, rindex);
1423 /* See if it is already defined */
1424 for (next=res_head[rindex]; next->next; next=next->next) {
1425 if (strcmp(next->name, lc->str) == 0) {
1431 res = (URES *)malloc(size);
1432 memset(res, 0, size);
1433 res->res_dev.hdr.name = bstrdup(lc->str);
1434 next->next = (RES *)res;
1435 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1436 res->res_dir.hdr.name, rindex, pass);
1441 set_bit(index, res_all.hdr.item_present);
1443 store_alist_res(lc, item, index, pass);
1448 * Store JobType (backup, verify, restore)
1451 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1455 token = lex_get_token(lc, T_NAME);
1456 /* Store the type both pass 1 and pass 2 */
1457 for (i=0; migtypes[i].type_name; i++) {
1458 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1459 *(int *)(item->value) = migtypes[i].job_type;
1465 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1468 set_bit(index, res_all.hdr.item_present);
1474 * Store JobType (backup, verify, restore)
1477 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1481 token = lex_get_token(lc, T_NAME);
1482 /* Store the type both pass 1 and pass 2 */
1483 for (i=0; jobtypes[i].type_name; i++) {
1484 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1485 *(int *)(item->value) = jobtypes[i].job_type;
1491 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1494 set_bit(index, res_all.hdr.item_present);
1498 * Store Job Level (Full, Incremental, ...)
1501 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1505 token = lex_get_token(lc, T_NAME);
1506 /* Store the level pass 2 so that type is defined */
1507 for (i=0; joblevels[i].level_name; i++) {
1508 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1509 *(int *)(item->value) = joblevels[i].level;
1515 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1518 set_bit(index, res_all.hdr.item_present);
1522 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1525 token = lex_get_token(lc, T_NAME);
1526 /* Scan Replacement options */
1527 for (i=0; ReplaceOptions[i].name; i++) {
1528 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1529 *(int *)(item->value) = ReplaceOptions[i].token;
1535 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1538 set_bit(index, res_all.hdr.item_present);
1542 * Store ACL (access control list)
1545 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1550 token = lex_get_token(lc, T_STRING);
1552 if (((alist **)item->value)[item->code] == NULL) {
1553 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1554 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1556 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1557 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1559 token = lex_get_token(lc, T_ALL);
1560 if (token == T_COMMA) {
1561 continue; /* get another ACL */
1565 set_bit(index, res_all.hdr.item_present);
1568 /* We build RunScripts items here */
1569 static RUNSCRIPT res_runscript;
1571 /* Store a runscript->when in a bit field */
1572 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1574 lex_get_token(lc, T_NAME);
1576 if (strcasecmp(lc->str, "before") == 0) {
1577 *(int *)(item->value) = SCRIPT_Before ;
1578 } else if (strcasecmp(lc->str, "after") == 0) {
1579 *(int *)(item->value) = SCRIPT_After;
1580 } else if (strcasecmp(lc->str, "always") == 0) {
1581 *(int *)(item->value) = SCRIPT_Any;
1583 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1588 /* Store a runscript->target
1591 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1593 lex_get_token(lc, T_STRING);
1596 if (strcmp(lc->str, "%c") == 0) {
1597 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1598 } else if (strcmp(lc->str, "yes") == 0) {
1599 ((RUNSCRIPT*) item->value)->set_target("%c");
1600 } else if (strcmp(lc->str, "no") == 0) {
1601 /* store nothing, run on director */
1603 RES *res = GetResWithName(R_CLIENT, lc->str);
1605 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1606 lc->str, lc->line_no, lc->line);
1609 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1615 /* Store a runscript->command in a bit field
1618 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1620 lex_get_token(lc, T_STRING);
1623 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1628 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1630 lex_get_token(lc, T_STRING);
1631 alist **runscripts = (alist **)(item->value) ;
1634 RUNSCRIPT *script = new_runscript();
1636 script->set_command(lc->str);
1638 /* TODO: remove all script->old_proto with bacula 1.42 */
1640 if (strcmp(item->name, "runbeforejob") == 0) {
1641 script->when = SCRIPT_Before;
1642 script->abort_on_error = true;
1644 } else if (strcmp(item->name, "runafterjob") == 0) {
1645 script->when = SCRIPT_After;
1646 script->on_success = true;
1647 script->on_failure = false;
1649 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1650 script->old_proto = true;
1651 script->when = SCRIPT_After;
1652 script->set_target("%c");
1653 script->on_success = true;
1654 script->on_failure = false;
1656 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1657 script->old_proto = true;
1658 script->when = SCRIPT_Before;
1659 script->set_target("%c");
1660 script->abort_on_error = true;
1662 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1663 script->when = SCRIPT_After;
1664 script->on_failure = true;
1665 script->on_success = false;
1668 if (*runscripts == NULL) {
1669 *runscripts = New(alist(10, not_owned_by_alist));
1672 (*runscripts)->append(script);
1680 * new RunScript items
1681 * name handler value code flags default_value
1683 static RES_ITEM runscript_items[] = {
1684 {"command", store_runscript_cmd, {(char **)&res_runscript}, 0, ITEM_REQUIRED, 0},
1685 {"target", store_runscript_target, {(char **)&res_runscript}, 0, 0, 0},
1686 {"runsonsuccess", store_bool, {(char **)&res_runscript.on_success}, 0, 0, 0},
1687 {"runsonfailure", store_bool, {(char **)&res_runscript.on_failure}, 0, 0, 0},
1688 {"abortjobonerror", store_bool, {(char **)&res_runscript.abort_on_error}, 0, 0, 0},
1689 {"runswhen", store_runscript_when, {(char **)&res_runscript.when}, 0, 0, 0},
1690 {"runsonclient", store_runscript_target, {(char **)&res_runscript}, 0, 0, 0}, /* TODO */
1691 {NULL, NULL, {0}, 0, 0, 0}
1695 * Store RunScript info
1697 * Note, when this routine is called, we are inside a Job
1698 * resource. We treat the RunScript like a sort of
1699 * mini-resource within the Job resource.
1701 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1704 alist **runscripts = (alist **)(item->value) ;
1706 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1708 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1710 token = lex_get_token(lc, T_SKIP_EOL);
1712 if (token != T_BOB) {
1713 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1716 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1717 if (token == T_EOB) {
1720 if (token != T_IDENTIFIER) {
1721 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1723 for (i=0; runscript_items[i].name; i++) {
1724 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1725 token = lex_get_token(lc, T_SKIP_EOL);
1726 if (token != T_EQUALS) {
1727 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1730 /* Call item handler */
1731 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1738 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1743 if (res_runscript.command == NULL) {
1744 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1745 "command", "runscript");
1748 /* run on client by default */
1749 if (res_runscript.target == NULL) {
1750 res_runscript.set_target("%c");
1753 RUNSCRIPT *script = new_runscript();
1754 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1756 if (*runscripts == NULL) {
1757 *runscripts = New(alist(10, not_owned_by_alist));
1760 (*runscripts)->append(script);
1765 set_bit(index, res_all.hdr.item_present);