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 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
141 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
142 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
143 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
144 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
145 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
146 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
147 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
148 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
149 {NULL, NULL, {0}, 0, 0, 0}
154 * Client or File daemon resource
156 * name handler value code flags default_value
159 static RES_ITEM cli_items[] = {
160 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
161 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
162 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
163 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
164 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
165 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
166 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
167 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
168 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
169 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
170 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
171 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
172 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
173 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
174 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
175 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
176 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
177 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
178 {NULL, NULL, {0}, 0, 0, 0}
181 /* Storage daemon resource
183 * name handler value code flags default_value
185 static RES_ITEM store_items[] = {
186 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
187 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
188 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
189 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
190 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
191 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
192 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
193 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
194 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
195 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
196 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
197 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
198 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
199 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
200 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
201 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
202 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
203 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
204 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
205 {NULL, NULL, {0}, 0, 0, 0}
209 * Catalog Resource Directives
211 * name handler value code flags default_value
213 static RES_ITEM cat_items[] = {
214 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
215 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
216 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
217 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
218 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
219 /* keep this password as store_str for the moment */
220 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
221 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
222 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
223 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
224 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
225 /* Turned off for the moment */
226 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
227 {NULL, NULL, {0}, 0, 0, 0}
231 * Job Resource Directives
233 * name handler value code flags default_value
235 RES_ITEM job_items[] = {
236 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
237 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
238 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
239 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
240 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
241 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
242 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
243 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
244 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
245 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
246 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
247 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
248 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
249 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
250 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
251 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
252 {"nextpool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
253 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
254 /* Root of where to restore files */
255 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
256 /* Where to find bootstrap during restore */
257 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
258 /* Where to write bootstrap file during backup */
259 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
260 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
261 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
262 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
263 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
264 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
265 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
266 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
267 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
268 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
269 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
270 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
271 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
272 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
273 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
274 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
275 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
276 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
277 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
278 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
279 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
280 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
281 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
282 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
283 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
284 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
285 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
286 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
287 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
288 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, false},
289 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
290 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
291 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
292 {NULL, NULL, {0}, 0, 0, 0}
297 * name handler value code flags default_value
299 static RES_ITEM fs_items[] = {
300 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
301 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
302 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
303 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
304 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
305 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, false},
306 {NULL, NULL, {0}, 0, 0, 0}
309 /* Schedule -- see run_conf.c */
312 * name handler value code flags default_value
314 static RES_ITEM sch_items[] = {
315 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
316 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
317 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
318 {NULL, NULL, {0}, 0, 0, 0}
323 * name handler value code flags default_value
325 static RES_ITEM pool_items[] = {
326 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
327 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
328 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
329 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
330 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
331 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
332 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
333 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
334 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
335 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
336 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
337 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
338 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
339 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
340 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
341 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
342 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
343 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
344 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
345 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
346 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
347 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
348 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
349 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
350 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
351 {NULL, NULL, {0}, 0, 0, 0}
356 * name handler value code flags default_value
358 static RES_ITEM counter_items[] = {
359 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
360 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
361 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
362 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
363 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
364 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
365 {NULL, NULL, {0}, 0, 0, 0}
369 /* Message resource */
370 extern RES_ITEM msgs_items[];
373 * This is the master resource definition.
374 * It must have one item for each of the resources.
376 * NOTE!!! keep it in the same order as the R_codes
377 * or eliminate all resources[rindex].name
379 * name items rcode res_head
381 RES_TABLE resources[] = {
382 {"director", dir_items, R_DIRECTOR},
383 {"client", cli_items, R_CLIENT},
384 {"job", job_items, R_JOB},
385 {"storage", store_items, R_STORAGE},
386 {"catalog", cat_items, R_CATALOG},
387 {"schedule", sch_items, R_SCHEDULE},
388 {"fileset", fs_items, R_FILESET},
389 {"pool", pool_items, R_POOL},
390 {"messages", msgs_items, R_MSGS},
391 {"counter", counter_items, R_COUNTER},
392 {"console", con_items, R_CONSOLE},
393 {"jobdefs", job_items, R_JOBDEFS},
394 {"device", NULL, R_DEVICE}, /* info obtained from SD */
399 /* Keywords (RHS) permitted in Job Level records
401 * level_name level job_type
403 struct s_jl joblevels[] = {
404 {"Full", L_FULL, JT_BACKUP},
405 {"Base", L_BASE, JT_BACKUP},
406 {"Incremental", L_INCREMENTAL, JT_BACKUP},
407 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
408 {"Since", L_SINCE, JT_BACKUP},
409 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
410 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
411 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
412 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
413 {"Data", L_VERIFY_DATA, JT_VERIFY},
414 {" ", L_NONE, JT_ADMIN},
415 {" ", L_NONE, JT_RESTORE},
419 /* Keywords (RHS) permitted in Job type records
423 struct s_jt jobtypes[] = {
424 {"backup", JT_BACKUP},
426 {"verify", JT_VERIFY},
427 {"restore", JT_RESTORE},
428 {"migrate", JT_MIGRATE},
433 /* Keywords (RHS) permitted in Selection type records
437 struct s_jt migtypes[] = {
438 {"smallestvolume", MT_SMALLEST_VOL},
439 {"oldestvolume", MT_OLDEST_VOL},
440 {"pooloccupancy", MT_POOL_OCCUPANCY},
441 {"pooltime", MT_POOL_TIME},
442 {"client", MT_CLIENT},
443 {"volume", MT_VOLUME},
445 {"sqlquery", MT_SQLQUERY},
451 /* Options permitted in Restore replace= */
452 struct s_kw ReplaceOptions[] = {
453 {"always", REPLACE_ALWAYS},
454 {"ifnewer", REPLACE_IFNEWER},
455 {"ifolder", REPLACE_IFOLDER},
456 {"never", REPLACE_NEVER},
460 const char *level_to_str(int level)
463 static char level_no[30];
464 const char *str = level_no;
466 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
467 for (i=0; joblevels[i].level_name; i++) {
468 if (level == joblevels[i].level) {
469 str = joblevels[i].level_name;
476 /* Dump contents of resource */
477 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
479 URES *res = (URES *)reshdr;
481 char ed1[100], ed2[100], ed3[100];
485 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
488 if (type < 0) { /* no recursion */
494 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
495 reshdr->name, res->res_dir.MaxConcurrentJobs,
496 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
497 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
498 if (res->res_dir.query_file) {
499 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
501 if (res->res_dir.messages) {
502 sendit(sock, _(" --> "));
503 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
507 sendit(sock, _("Console: name=%s SSL=%d\n"),
508 res->res_con.hdr.name, res->res_con.tls_enable);
511 if (res->res_counter.WrapCounter) {
512 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
513 res->res_counter.hdr.name, res->res_counter.MinValue,
514 res->res_counter.MaxValue, res->res_counter.CurrentValue,
515 res->res_counter.WrapCounter->hdr.name);
517 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
518 res->res_counter.hdr.name, res->res_counter.MinValue,
519 res->res_counter.MaxValue);
521 if (res->res_counter.Catalog) {
522 sendit(sock, _(" --> "));
523 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
528 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
529 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
530 res->res_client.MaxConcurrentJobs);
531 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
532 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
533 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
534 res->res_client.AutoPrune);
535 if (res->res_client.catalog) {
536 sendit(sock, _(" --> "));
537 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
543 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
544 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
545 " poolid=%s volname=%s MediaType=%s\n"),
546 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
547 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
548 dev->offline, dev->autochanger,
549 edit_uint64(dev->PoolId, ed1),
550 dev->VolumeName, dev->MediaType);
553 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
554 " DeviceName=%s MediaType=%s StorageId=%s\n"),
555 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
556 res->res_store.MaxConcurrentJobs,
557 res->res_store.dev_name(),
558 res->res_store.media_type,
559 edit_int64(res->res_store.StorageId, ed1));
562 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
563 " db_user=%s MutliDBConn=%d\n"),
564 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
565 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
566 res->res_cat.mult_db_connections);
570 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
571 type == R_JOB ? _("Job") : _("JobDefs"),
572 res->res_job.hdr.name, res->res_job.JobType,
573 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
574 res->res_job.enabled);
575 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
576 res->res_job.MaxConcurrentJobs,
577 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
578 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
579 res->res_job.spool_data, res->res_job.write_part_after_job);
580 if (res->res_job.JobType == JT_MIGRATE) {
581 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
583 if (res->res_job.client) {
584 sendit(sock, _(" --> "));
585 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
587 if (res->res_job.fileset) {
588 sendit(sock, _(" --> "));
589 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
591 if (res->res_job.schedule) {
592 sendit(sock, _(" --> "));
593 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
595 if (res->res_job.RestoreWhere) {
596 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
598 if (res->res_job.RestoreBootstrap) {
599 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
601 if (res->res_job.WriteBootstrap) {
602 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
604 if (res->res_job.storage) {
606 foreach_alist(store, res->res_job.storage) {
607 sendit(sock, _(" --> "));
608 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
611 if (res->res_job.RunScripts) {
613 foreach_alist(script, res->res_job.RunScripts) {
614 sendit(sock, _(" --> RunScript\n"));
615 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
616 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
617 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
618 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
619 sendit(sock, _(" --> AbortJobOnError=%u\n"), script->abort_on_error);
620 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
623 if (res->res_job.pool) {
624 sendit(sock, _(" --> "));
625 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
627 if (res->res_job.full_pool) {
628 sendit(sock, _(" --> "));
629 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
631 if (res->res_job.inc_pool) {
632 sendit(sock, _(" --> "));
633 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
635 if (res->res_job.diff_pool) {
636 sendit(sock, _(" --> "));
637 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
639 if (res->res_job.verify_job) {
640 sendit(sock, _(" --> "));
641 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
643 if (res->res_job.run_cmds) {
645 foreach_alist(runcmd, res->res_job.run_cmds) {
646 sendit(sock, _(" --> Run=%s\n"), runcmd);
649 if (res->res_job.selection_pattern) {
650 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
652 if (res->res_job.messages) {
653 sendit(sock, _(" --> "));
654 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
660 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
661 for (i=0; i<res->res_fs.num_includes; i++) {
662 INCEXE *incexe = res->res_fs.include_items[i];
663 for (j=0; j<incexe->num_opts; j++) {
664 FOPTS *fo = incexe->opts_list[j];
665 sendit(sock, " O %s\n", fo->opts);
666 for (k=0; k<fo->regex.size(); k++) {
667 sendit(sock, " R %s\n", fo->regex.get(k));
669 for (k=0; k<fo->regexdir.size(); k++) {
670 sendit(sock, " RD %s\n", fo->regexdir.get(k));
672 for (k=0; k<fo->regexfile.size(); k++) {
673 sendit(sock, " RF %s\n", fo->regexfile.get(k));
675 for (k=0; k<fo->wild.size(); k++) {
676 sendit(sock, " W %s\n", fo->wild.get(k));
678 for (k=0; k<fo->wilddir.size(); k++) {
679 sendit(sock, " WD %s\n", fo->wilddir.get(k));
681 for (k=0; k<fo->wildfile.size(); k++) {
682 sendit(sock, " WF %s\n", fo->wildfile.get(k));
684 for (k=0; k<fo->base.size(); k++) {
685 sendit(sock, " B %s\n", fo->base.get(k));
687 for (k=0; k<fo->fstype.size(); k++) {
688 sendit(sock, " X %s\n", fo->fstype.get(k));
691 sendit(sock, " D %s\n", fo->reader);
694 sendit(sock, " T %s\n", fo->writer);
696 sendit(sock, " N\n");
698 for (j=0; j<incexe->name_list.size(); j++) {
699 sendit(sock, " I %s\n", incexe->name_list.get(j));
701 if (incexe->name_list.size()) {
702 sendit(sock, " N\n");
706 for (i=0; i<res->res_fs.num_excludes; i++) {
707 INCEXE *incexe = res->res_fs.exclude_items[i];
708 for (j=0; j<incexe->name_list.size(); j++) {
709 sendit(sock, " E %s\n", incexe->name_list.get(j));
711 if (incexe->name_list.size()) {
712 sendit(sock, " N\n");
718 if (res->res_sch.run) {
720 RUN *run = res->res_sch.run;
721 char buf[1000], num[30];
722 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
727 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
728 bstrncpy(buf, _(" hour="), sizeof(buf));
729 for (i=0; i<24; i++) {
730 if (bit_is_set(i, run->hour)) {
731 bsnprintf(num, sizeof(num), "%d ", i);
732 bstrncat(buf, num, sizeof(buf));
735 bstrncat(buf, "\n", sizeof(buf));
737 bstrncpy(buf, _(" mday="), sizeof(buf));
738 for (i=0; i<31; i++) {
739 if (bit_is_set(i, run->mday)) {
740 bsnprintf(num, sizeof(num), "%d ", i);
741 bstrncat(buf, num, sizeof(buf));
744 bstrncat(buf, "\n", sizeof(buf));
746 bstrncpy(buf, _(" month="), sizeof(buf));
747 for (i=0; i<12; i++) {
748 if (bit_is_set(i, run->month)) {
749 bsnprintf(num, sizeof(num), "%d ", i);
750 bstrncat(buf, num, sizeof(buf));
753 bstrncat(buf, "\n", sizeof(buf));
755 bstrncpy(buf, _(" wday="), sizeof(buf));
756 for (i=0; i<7; i++) {
757 if (bit_is_set(i, run->wday)) {
758 bsnprintf(num, sizeof(num), "%d ", i);
759 bstrncat(buf, num, sizeof(buf));
762 bstrncat(buf, "\n", sizeof(buf));
764 bstrncpy(buf, _(" wom="), sizeof(buf));
765 for (i=0; i<5; i++) {
766 if (bit_is_set(i, run->wom)) {
767 bsnprintf(num, sizeof(num), "%d ", i);
768 bstrncat(buf, num, sizeof(buf));
771 bstrncat(buf, "\n", sizeof(buf));
773 bstrncpy(buf, _(" woy="), sizeof(buf));
774 for (i=0; i<54; i++) {
775 if (bit_is_set(i, run->woy)) {
776 bsnprintf(num, sizeof(num), "%d ", i);
777 bstrncat(buf, num, sizeof(buf));
780 bstrncat(buf, "\n", sizeof(buf));
782 sendit(sock, _(" mins=%d\n"), run->minute);
784 sendit(sock, _(" --> "));
785 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
788 sendit(sock, _(" --> "));
789 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
792 sendit(sock, _(" --> "));
793 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
795 /* If another Run record is chained in, go print it */
801 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
805 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
806 res->res_pool.pool_type);
807 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
808 res->res_pool.use_catalog, res->res_pool.use_volume_once,
809 res->res_pool.catalog_files);
810 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
811 res->res_pool.max_volumes, res->res_pool.AutoPrune,
812 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
813 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
814 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
815 res->res_pool.Recycle,
816 NPRT(res->res_pool.label_format));
817 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
818 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
819 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
820 res->res_pool.recycle_oldest_volume,
821 res->res_pool.purge_oldest_volume,
822 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
823 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
824 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
825 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
826 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
827 if (res->res_pool.NextPool) {
828 sendit(sock, _(" --> "));
829 dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
831 if (res->res_pool.storage) {
833 foreach_alist(store, res->res_pool.storage) {
834 sendit(sock, _(" --> "));
835 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
840 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
841 if (res->res_msgs.mail_cmd)
842 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
843 if (res->res_msgs.operator_cmd)
844 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
847 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
850 if (recurse && res->res_dir.hdr.next) {
851 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
856 * Free all the members of an INCEXE structure
858 static void free_incexe(INCEXE *incexe)
860 incexe->name_list.destroy();
861 for (int i=0; i<incexe->num_opts; i++) {
862 FOPTS *fopt = incexe->opts_list[i];
863 fopt->regex.destroy();
864 fopt->regexdir.destroy();
865 fopt->regexfile.destroy();
866 fopt->wild.destroy();
867 fopt->wilddir.destroy();
868 fopt->wildfile.destroy();
869 fopt->base.destroy();
870 fopt->fstype.destroy();
879 if (incexe->opts_list) {
880 free(incexe->opts_list);
886 * Free memory of resource -- called when daemon terminates.
887 * NB, we don't need to worry about freeing any references
888 * to other resources as they will be freed when that
889 * resource chain is traversed. Mainly we worry about freeing
890 * allocated strings (names).
892 void free_resource(RES *sres, int type)
895 RES *nres; /* next resource if linked */
896 URES *res = (URES *)sres;
901 /* common stuff -- free the resource name and description */
902 nres = (RES *)res->res_dir.hdr.next;
903 if (res->res_dir.hdr.name) {
904 free(res->res_dir.hdr.name);
906 if (res->res_dir.hdr.desc) {
907 free(res->res_dir.hdr.desc);
912 if (res->res_dir.working_directory) {
913 free(res->res_dir.working_directory);
915 if (res->res_dir.scripts_directory) {
916 free((char *)res->res_dir.scripts_directory);
918 if (res->res_dir.pid_directory) {
919 free(res->res_dir.pid_directory);
921 if (res->res_dir.subsys_directory) {
922 free(res->res_dir.subsys_directory);
924 if (res->res_dir.password) {
925 free(res->res_dir.password);
927 if (res->res_dir.query_file) {
928 free(res->res_dir.query_file);
930 if (res->res_dir.DIRaddrs) {
931 free_addresses(res->res_dir.DIRaddrs);
933 if (res->res_dir.tls_ctx) {
934 free_tls_context(res->res_dir.tls_ctx);
936 if (res->res_dir.tls_ca_certfile) {
937 free(res->res_dir.tls_ca_certfile);
939 if (res->res_dir.tls_ca_certdir) {
940 free(res->res_dir.tls_ca_certdir);
942 if (res->res_dir.tls_certfile) {
943 free(res->res_dir.tls_certfile);
945 if (res->res_dir.tls_keyfile) {
946 free(res->res_dir.tls_keyfile);
948 if (res->res_dir.tls_dhfile) {
949 free(res->res_dir.tls_dhfile);
951 if (res->res_dir.tls_allowed_cns) {
952 delete res->res_dir.tls_allowed_cns;
959 if (res->res_con.password) {
960 free(res->res_con.password);
962 if (res->res_con.tls_ctx) {
963 free_tls_context(res->res_con.tls_ctx);
965 if (res->res_con.tls_ca_certfile) {
966 free(res->res_con.tls_ca_certfile);
968 if (res->res_con.tls_ca_certdir) {
969 free(res->res_con.tls_ca_certdir);
971 if (res->res_con.tls_certfile) {
972 free(res->res_con.tls_certfile);
974 if (res->res_con.tls_keyfile) {
975 free(res->res_con.tls_keyfile);
977 if (res->res_con.tls_dhfile) {
978 free(res->res_con.tls_dhfile);
980 if (res->res_con.tls_allowed_cns) {
981 delete res->res_con.tls_allowed_cns;
983 for (int i=0; i<Num_ACL; i++) {
984 if (res->res_con.ACL_lists[i]) {
985 delete res->res_con.ACL_lists[i];
986 res->res_con.ACL_lists[i] = NULL;
991 if (res->res_client.address) {
992 free(res->res_client.address);
994 if (res->res_client.password) {
995 free(res->res_client.password);
997 if (res->res_client.tls_ctx) {
998 free_tls_context(res->res_client.tls_ctx);
1000 if (res->res_client.tls_ca_certfile) {
1001 free(res->res_client.tls_ca_certfile);
1003 if (res->res_client.tls_ca_certdir) {
1004 free(res->res_client.tls_ca_certdir);
1006 if (res->res_client.tls_certfile) {
1007 free(res->res_client.tls_certfile);
1009 if (res->res_client.tls_keyfile) {
1010 free(res->res_client.tls_keyfile);
1014 if (res->res_store.address) {
1015 free(res->res_store.address);
1017 if (res->res_store.password) {
1018 free(res->res_store.password);
1020 if (res->res_store.media_type) {
1021 free(res->res_store.media_type);
1023 if (res->res_store.device) {
1024 delete res->res_store.device;
1026 if (res->res_store.tls_ctx) {
1027 free_tls_context(res->res_store.tls_ctx);
1029 if (res->res_store.tls_ca_certfile) {
1030 free(res->res_store.tls_ca_certfile);
1032 if (res->res_store.tls_ca_certdir) {
1033 free(res->res_store.tls_ca_certdir);
1035 if (res->res_store.tls_certfile) {
1036 free(res->res_store.tls_certfile);
1038 if (res->res_store.tls_keyfile) {
1039 free(res->res_store.tls_keyfile);
1043 if (res->res_cat.db_address) {
1044 free(res->res_cat.db_address);
1046 if (res->res_cat.db_socket) {
1047 free(res->res_cat.db_socket);
1049 if (res->res_cat.db_user) {
1050 free(res->res_cat.db_user);
1052 if (res->res_cat.db_name) {
1053 free(res->res_cat.db_name);
1055 if (res->res_cat.db_password) {
1056 free(res->res_cat.db_password);
1060 if ((num=res->res_fs.num_includes)) {
1061 while (--num >= 0) {
1062 free_incexe(res->res_fs.include_items[num]);
1064 free(res->res_fs.include_items);
1066 res->res_fs.num_includes = 0;
1067 if ((num=res->res_fs.num_excludes)) {
1068 while (--num >= 0) {
1069 free_incexe(res->res_fs.exclude_items[num]);
1071 free(res->res_fs.exclude_items);
1073 res->res_fs.num_excludes = 0;
1076 if (res->res_pool.pool_type) {
1077 free(res->res_pool.pool_type);
1079 if (res->res_pool.label_format) {
1080 free(res->res_pool.label_format);
1082 if (res->res_pool.cleaning_prefix) {
1083 free(res->res_pool.cleaning_prefix);
1085 if (res->res_pool.storage) {
1086 delete res->res_pool.storage;
1090 if (res->res_sch.run) {
1092 nrun = res->res_sch.run;
1102 if (res->res_job.RestoreWhere) {
1103 free(res->res_job.RestoreWhere);
1105 if (res->res_job.RestoreBootstrap) {
1106 free(res->res_job.RestoreBootstrap);
1108 if (res->res_job.WriteBootstrap) {
1109 free(res->res_job.WriteBootstrap);
1111 if (res->res_job.selection_pattern) {
1112 free(res->res_job.selection_pattern);
1114 if (res->res_job.run_cmds) {
1115 delete res->res_job.run_cmds;
1117 if (res->res_job.storage) {
1118 delete res->res_job.storage;
1120 if (res->res_job.RunScripts) {
1121 free_runscripts(res->res_job.RunScripts);
1122 delete res->res_job.RunScripts;
1126 if (res->res_msgs.mail_cmd) {
1127 free(res->res_msgs.mail_cmd);
1129 if (res->res_msgs.operator_cmd) {
1130 free(res->res_msgs.operator_cmd);
1132 free_msgs_res((MSGS *)res); /* free message resource */
1136 printf(_("Unknown resource type %d in free_resource.\n"), type);
1138 /* Common stuff again -- free the resource, recurse to next one */
1143 free_resource(nres, type);
1148 * Save the new resource by chaining it into the head list for
1149 * the resource. If this is pass 2, we update any resource
1150 * pointers because they may not have been defined until
1153 void save_resource(int type, RES_ITEM *items, int pass)
1156 int rindex = type - r_first;
1160 /* Check Job requirements after applying JobDefs */
1161 if (type != R_JOB && type != R_JOBDEFS) {
1163 * Ensure that all required items are present
1165 for (i=0; items[i].name; i++) {
1166 if (items[i].flags & ITEM_REQUIRED) {
1167 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1168 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1169 items[i].name, resources[rindex]);
1172 /* If this triggers, take a look at lib/parse_conf.h */
1173 if (i >= MAX_RES_ITEMS) {
1174 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1177 } else if (type == R_JOB) {
1179 * Ensure that the name item is present
1181 if (items[0].flags & ITEM_REQUIRED) {
1182 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1183 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1184 items[0].name, resources[rindex]);
1190 * During pass 2 in each "store" routine, we looked up pointers
1191 * to all the resources referrenced in the current resource, now we
1192 * must copy their addresses from the static record to the allocated
1197 /* Resources not containing a resource */
1205 * Resources containing another resource or alist. First
1206 * look up the resource which contains another resource. It
1207 * was written during pass 1. Then stuff in the pointers to
1208 * the resources it contains, which were inserted this pass.
1209 * Finally, it will all be stored back.
1212 /* Find resource saved in pass 1 */
1213 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1214 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1216 /* Explicitly copy resource pointers from this pass (res_all) */
1217 res->res_pool.NextPool = res_all.res_pool.NextPool;
1218 res->res_pool.storage = res_all.res_pool.storage;
1221 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1222 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1224 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1227 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1228 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1230 res->res_dir.messages = res_all.res_dir.messages;
1231 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1234 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1235 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1236 res_all.res_dir.hdr.name);
1238 /* we must explicitly copy the device alist pointer */
1239 res->res_store.device = res_all.res_store.device;
1243 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1244 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1245 res_all.res_dir.hdr.name);
1247 res->res_job.messages = res_all.res_job.messages;
1248 res->res_job.schedule = res_all.res_job.schedule;
1249 res->res_job.client = res_all.res_job.client;
1250 res->res_job.fileset = res_all.res_job.fileset;
1251 res->res_job.storage = res_all.res_job.storage;
1252 res->res_job.pool = res_all.res_job.pool;
1253 res->res_job.full_pool = res_all.res_job.full_pool;
1254 res->res_job.inc_pool = res_all.res_job.inc_pool;
1255 res->res_job.diff_pool = res_all.res_job.diff_pool;
1256 res->res_job.verify_job = res_all.res_job.verify_job;
1257 res->res_job.jobdefs = res_all.res_job.jobdefs;
1258 res->res_job.run_cmds = res_all.res_job.run_cmds;
1259 res->res_job.RunScripts = res_all.res_job.RunScripts;
1262 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1263 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1265 res->res_counter.Catalog = res_all.res_counter.Catalog;
1266 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1270 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1271 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1273 res->res_client.catalog = res_all.res_client.catalog;
1277 * Schedule is a bit different in that it contains a RUN record
1278 * chain which isn't a "named" resource. This chain was linked
1279 * in by run_conf.c during pass 2, so here we jam the pointer
1280 * into the Schedule resource.
1282 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1283 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1285 res->res_sch.run = res_all.res_sch.run;
1288 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1292 /* Note, the resource name was already saved during pass 1,
1293 * so here, we can just release it.
1295 if (res_all.res_dir.hdr.name) {
1296 free(res_all.res_dir.hdr.name);
1297 res_all.res_dir.hdr.name = NULL;
1299 if (res_all.res_dir.hdr.desc) {
1300 free(res_all.res_dir.hdr.desc);
1301 res_all.res_dir.hdr.desc = NULL;
1307 * The following code is only executed during pass 1
1311 size = sizeof(DIRRES);
1314 size = sizeof(CONRES);
1317 size =sizeof(CLIENT);
1320 size = sizeof(STORE);
1330 size = sizeof(FILESET);
1333 size = sizeof(SCHED);
1336 size = sizeof(POOL);
1339 size = sizeof(MSGS);
1342 size = sizeof(COUNTER);
1348 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1354 res = (URES *)malloc(size);
1355 memcpy(res, &res_all, size);
1356 if (!res_head[rindex]) {
1357 res_head[rindex] = (RES *)res; /* store first entry */
1358 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1359 res->res_dir.hdr.name, rindex);
1362 if (res->res_dir.hdr.name == NULL) {
1363 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1366 /* Add new res to end of chain */
1367 for (next=res_head[rindex]; next->next; next=next->next) {
1368 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1369 Emsg2(M_ERROR_TERM, 0,
1370 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1371 resources[rindex].name, res->res_dir.hdr.name);
1374 next->next = (RES *)res;
1375 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1376 res->res_dir.hdr.name, rindex, pass);
1382 * Store Device. Note, the resource is created upon the
1383 * first reference. The details of the resource are obtained
1384 * later from the SD.
1386 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1390 int rindex = R_DEVICE - r_first;
1391 int size = sizeof(DEVICE);
1395 token = lex_get_token(lc, T_NAME);
1396 if (!res_head[rindex]) {
1397 res = (URES *)malloc(size);
1398 memset(res, 0, size);
1399 res->res_dev.hdr.name = bstrdup(lc->str);
1400 res_head[rindex] = (RES *)res; /* store first entry */
1401 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1402 res->res_dir.hdr.name, rindex);
1405 /* See if it is already defined */
1406 for (next=res_head[rindex]; next->next; next=next->next) {
1407 if (strcmp(next->name, lc->str) == 0) {
1413 res = (URES *)malloc(size);
1414 memset(res, 0, size);
1415 res->res_dev.hdr.name = bstrdup(lc->str);
1416 next->next = (RES *)res;
1417 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1418 res->res_dir.hdr.name, rindex, pass);
1423 set_bit(index, res_all.hdr.item_present);
1425 store_alist_res(lc, item, index, pass);
1430 * Store JobType (backup, verify, restore)
1433 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1437 token = lex_get_token(lc, T_NAME);
1438 /* Store the type both pass 1 and pass 2 */
1439 for (i=0; migtypes[i].type_name; i++) {
1440 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1441 *(int *)(item->value) = migtypes[i].job_type;
1447 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1450 set_bit(index, res_all.hdr.item_present);
1456 * Store JobType (backup, verify, restore)
1459 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1463 token = lex_get_token(lc, T_NAME);
1464 /* Store the type both pass 1 and pass 2 */
1465 for (i=0; jobtypes[i].type_name; i++) {
1466 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1467 *(int *)(item->value) = jobtypes[i].job_type;
1473 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1476 set_bit(index, res_all.hdr.item_present);
1480 * Store Job Level (Full, Incremental, ...)
1483 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1487 token = lex_get_token(lc, T_NAME);
1488 /* Store the level pass 2 so that type is defined */
1489 for (i=0; joblevels[i].level_name; i++) {
1490 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1491 *(int *)(item->value) = joblevels[i].level;
1497 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1500 set_bit(index, res_all.hdr.item_present);
1504 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1507 token = lex_get_token(lc, T_NAME);
1508 /* Scan Replacement options */
1509 for (i=0; ReplaceOptions[i].name; i++) {
1510 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1511 *(int *)(item->value) = ReplaceOptions[i].token;
1517 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1520 set_bit(index, res_all.hdr.item_present);
1524 * Store ACL (access control list)
1527 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1532 token = lex_get_token(lc, T_NAME);
1534 if (((alist **)item->value)[item->code] == NULL) {
1535 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1536 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1538 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1539 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1541 token = lex_get_token(lc, T_ALL);
1542 if (token == T_COMMA) {
1543 continue; /* get another ACL */
1547 set_bit(index, res_all.hdr.item_present);
1551 /* Store a runscript->when in a bit field */
1552 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1554 lex_get_token(lc, T_NAME);
1556 if (strcasecmp(lc->str, "before") == 0) {
1557 *(int *)(item->value) = SCRIPT_Before ;
1558 } else if (strcasecmp(lc->str, "after") == 0) {
1559 *(int *)(item->value) = SCRIPT_After;
1560 } else if (strcasecmp(lc->str, "always") == 0) {
1561 *(int *)(item->value) = SCRIPT_Any;
1563 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1568 /* Store a runscript->target
1571 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1573 lex_get_token(lc, T_STRING);
1576 if (strcmp(lc->str, "%c") == 0) {
1577 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1578 } else if (strcmp(lc->str, "yes") == 0) {
1579 ((RUNSCRIPT*) item->value)->set_target("%c");
1580 } else if (strcmp(lc->str, "no") == 0) {
1581 /* store nothing, run on director */
1583 RES *res = GetResWithName(R_CLIENT, lc->str);
1585 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1586 lc->str, lc->line_no, lc->line);
1589 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1595 /* Store a runscript->command in a bit field
1598 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1600 lex_get_token(lc, T_STRING);
1603 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1608 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1610 lex_get_token(lc, T_STRING);
1611 alist **runscripts = (alist **)(item->value) ;
1614 RUNSCRIPT *script = new_runscript();
1616 script->set_command(lc->str);
1618 if (strcmp(item->name, "runbeforejob") == 0) {
1619 script->when = SCRIPT_Before;
1620 script->abort_on_error = true;
1622 } else if (strcmp(item->name, "runafterjob") == 0) {
1623 script->when = SCRIPT_After;
1624 script->on_success = true;
1625 script->on_failure = false;
1627 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1628 script->when = SCRIPT_After;
1629 script->set_target("%c");
1630 script->on_success = true;
1631 script->on_failure = false;
1633 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1634 script->when = SCRIPT_Before;
1635 script->set_target("%c");
1636 script->abort_on_error = true;
1638 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1639 script->when = SCRIPT_After;
1640 script->on_failure = true;
1641 script->on_success = false;
1644 if (*runscripts == NULL) {
1645 *runscripts = New(alist(10, not_owned_by_alist));
1648 (*runscripts)->append(script);
1655 static RUNSCRIPT res_runscript;
1658 * new RunScript items
1659 * name handler value code flags default_value
1661 static RES_ITEM runscript_items[] = {
1662 {"command", store_runscript_cmd, ITEM(res_runscript), 0, ITEM_REQUIRED, 0},
1663 {"target", store_runscript_target, ITEM(res_runscript), 0, 0, 0},
1664 {"runsonsuccess", store_bool, ITEM(res_runscript.on_success), 0, 0, 0},
1665 {"runsonfailure", store_bool, ITEM(res_runscript.on_failure), 0, 0, 0},
1666 {"abortjobonerror", store_bool, ITEM(res_runscript.abort_on_error), 0, 0, 0},
1667 {"runswhen", store_runscript_when, ITEM(res_runscript.when), 0, 0, 0},
1668 {"runsonclient", store_runscript_target, ITEM(res_runscript), 0, 0, 0}, /* TODO */
1669 {NULL, NULL, {0}, 0, 0, 0}
1673 * Store RunScript info
1675 * Note, when this routine is called, we are inside a Job
1676 * resource. We treat the RunScript like a sort of
1677 * mini-resource within the Job resource.
1679 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1682 alist **runscripts = (alist **)(item->value) ;
1684 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1686 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1688 token = lex_get_token(lc, T_SKIP_EOL);
1690 if (token != T_BOB) {
1691 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1694 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1695 if (token == T_EOB) {
1698 if (token != T_IDENTIFIER) {
1699 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1701 for (i=0; runscript_items[i].name; i++) {
1702 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1703 token = lex_get_token(lc, T_SKIP_EOL);
1704 if (token != T_EQUALS) {
1705 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1708 /* Call item handler */
1709 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1716 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1721 if (res_runscript.command == NULL) {
1722 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1723 "command", "runscript");
1726 /* run on client by default */
1727 if (res_runscript.target == NULL) {
1728 res_runscript.set_target("%c");
1731 RUNSCRIPT *script = new_runscript();
1732 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1734 if (*runscripts == NULL) {
1735 *runscripts = New(alist(10, not_owned_by_alist));
1738 (*runscripts)->append(script);
1743 set_bit(index, res_all.hdr.item_present);