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 int res_all_size = sizeof(res_all);
79 /* Definition of records permitted within each
80 * resource with the routine to process the record
81 * information. NOTE! quoted names must be in lower case.
86 * name handler value code flags default_value
88 static RES_ITEM dir_items[] = {
89 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
90 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
91 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
92 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
93 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
94 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
95 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
96 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
97 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
98 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
99 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
100 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
101 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
102 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
103 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
104 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
105 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
106 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
107 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
108 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
109 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
110 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
111 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
112 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
113 {NULL, NULL, {0}, 0, 0, 0}
119 * name handler value code flags default_value
121 static RES_ITEM con_items[] = {
122 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
123 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
124 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
125 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
126 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
127 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
128 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
129 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
130 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
131 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
132 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
133 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
134 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
135 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
136 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
137 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
138 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
139 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
140 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
141 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
142 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
143 {NULL, NULL, {0}, 0, 0, 0}
148 * Client or File daemon resource
150 * name handler value code flags default_value
153 static RES_ITEM cli_items[] = {
154 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
155 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
156 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
157 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
158 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
159 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
160 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
161 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
162 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
163 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
164 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
165 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
166 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
167 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
168 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
169 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
170 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
171 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
172 {NULL, NULL, {0}, 0, 0, 0}
175 /* Storage daemon resource
177 * name handler value code flags default_value
179 static RES_ITEM store_items[] = {
180 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
181 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
182 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
183 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
184 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
185 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
186 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
187 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
188 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
189 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
190 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
191 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
192 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
193 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
194 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
195 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
196 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
197 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
198 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
199 {NULL, NULL, {0}, 0, 0, 0}
203 * Catalog Resource Directives
205 * name handler value code flags default_value
207 static RES_ITEM cat_items[] = {
208 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
209 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
210 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
211 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
212 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
213 /* keep this password as store_str for the moment */
214 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
215 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
216 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
217 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
218 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
219 /* Turned off for the moment */
220 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
221 {NULL, NULL, {0}, 0, 0, 0}
225 * Job Resource Directives
227 * name handler value code flags default_value
229 RES_ITEM job_items[] = {
230 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
231 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
232 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
233 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
234 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
235 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
236 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
237 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
238 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
239 {"differentialbackuppool", store_res, ITEM(res_job.diff_pool), R_POOL, 0, 0},
240 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
241 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
242 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
243 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
244 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
245 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
246 {"nextpool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
247 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
248 /* Root of where to restore files */
249 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
250 /* Where to find bootstrap during restore */
251 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
252 /* Where to write bootstrap file during backup */
253 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
254 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
255 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
256 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
257 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
258 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
259 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
260 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
261 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
262 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
263 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
264 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
265 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
266 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
267 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
268 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
269 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
270 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
271 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
272 {"runbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
273 {"runafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
274 {"runafterfailedjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
275 {"clientrunbeforejob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
276 {"clientrunafterjob", store_short_runscript, ITEM(res_job.RunScripts), 0, 0, 0},
277 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
278 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
279 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
280 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
281 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
282 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, false},
283 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
284 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
285 {"runscript", store_runscript, ITEM(res_job.RunScripts), 0, ITEM_NO_EQUALS, 0},
286 {NULL, NULL, {0}, 0, 0, 0}
291 * name handler value code flags default_value
293 static RES_ITEM fs_items[] = {
294 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
295 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
296 {"include", store_inc, {0}, 0, ITEM_NO_EQUALS, 0},
297 {"exclude", store_inc, {0}, 1, ITEM_NO_EQUALS, 0},
298 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
299 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, false},
300 {NULL, NULL, {0}, 0, 0, 0}
303 /* Schedule -- see run_conf.c */
306 * name handler value code flags default_value
308 static RES_ITEM sch_items[] = {
309 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
310 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
311 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
312 {NULL, NULL, {0}, 0, 0, 0}
317 * name handler value code flags default_value
319 static RES_ITEM pool_items[] = {
320 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
321 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
322 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
323 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
324 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
325 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
326 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
327 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
328 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
329 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
330 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
331 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
332 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
333 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
334 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
335 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
336 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
337 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
338 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
339 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
340 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
341 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
342 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
343 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
344 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
345 {NULL, NULL, {0}, 0, 0, 0}
350 * name handler value code flags default_value
352 static RES_ITEM counter_items[] = {
353 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
354 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
355 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
356 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
357 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
358 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
359 {NULL, NULL, {0}, 0, 0, 0}
363 /* Message resource */
364 extern RES_ITEM msgs_items[];
367 * This is the master resource definition.
368 * It must have one item for each of the resources.
370 * NOTE!!! keep it in the same order as the R_codes
371 * or eliminate all resources[rindex].name
373 * name items rcode res_head
375 RES_TABLE resources[] = {
376 {"director", dir_items, R_DIRECTOR},
377 {"client", cli_items, R_CLIENT},
378 {"job", job_items, R_JOB},
379 {"storage", store_items, R_STORAGE},
380 {"catalog", cat_items, R_CATALOG},
381 {"schedule", sch_items, R_SCHEDULE},
382 {"fileset", fs_items, R_FILESET},
383 {"pool", pool_items, R_POOL},
384 {"messages", msgs_items, R_MSGS},
385 {"counter", counter_items, R_COUNTER},
386 {"console", con_items, R_CONSOLE},
387 {"jobdefs", job_items, R_JOBDEFS},
388 {"device", NULL, R_DEVICE}, /* info obtained from SD */
393 /* Keywords (RHS) permitted in Job Level records
395 * level_name level job_type
397 struct s_jl joblevels[] = {
398 {"Full", L_FULL, JT_BACKUP},
399 {"Base", L_BASE, JT_BACKUP},
400 {"Incremental", L_INCREMENTAL, JT_BACKUP},
401 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
402 {"Since", L_SINCE, JT_BACKUP},
403 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
404 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
405 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
406 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
407 {"Data", L_VERIFY_DATA, JT_VERIFY},
408 {" ", L_NONE, JT_ADMIN},
409 {" ", L_NONE, JT_RESTORE},
413 /* Keywords (RHS) permitted in Job type records
417 struct s_jt jobtypes[] = {
418 {"backup", JT_BACKUP},
420 {"verify", JT_VERIFY},
421 {"restore", JT_RESTORE},
422 {"migrate", JT_MIGRATE},
427 /* Keywords (RHS) permitted in Selection type records
431 struct s_jt migtypes[] = {
432 {"smallestvolume", MT_SMALLEST_VOL},
433 {"oldestvolume", MT_OLDEST_VOL},
434 {"pooloccupancy", MT_POOL_OCCUPANCY},
435 {"pooltime", MT_POOL_TIME},
436 {"client", MT_CLIENT},
437 {"volume", MT_VOLUME},
439 {"sqlquery", MT_SQLQUERY},
445 /* Options permitted in Restore replace= */
446 struct s_kw ReplaceOptions[] = {
447 {"always", REPLACE_ALWAYS},
448 {"ifnewer", REPLACE_IFNEWER},
449 {"ifolder", REPLACE_IFOLDER},
450 {"never", REPLACE_NEVER},
454 const char *level_to_str(int level)
457 static char level_no[30];
458 const char *str = level_no;
460 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
461 for (i=0; joblevels[i].level_name; i++) {
462 if (level == joblevels[i].level) {
463 str = joblevels[i].level_name;
470 /* Dump contents of resource */
471 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
473 URES *res = (URES *)reshdr;
475 char ed1[100], ed2[100], ed3[100];
479 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
482 if (type < 0) { /* no recursion */
488 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
489 reshdr->name, res->res_dir.MaxConcurrentJobs,
490 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
491 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
492 if (res->res_dir.query_file) {
493 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
495 if (res->res_dir.messages) {
496 sendit(sock, _(" --> "));
497 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
501 sendit(sock, _("Console: name=%s SSL=%d\n"),
502 res->res_con.hdr.name, res->res_con.tls_enable);
505 if (res->res_counter.WrapCounter) {
506 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
507 res->res_counter.hdr.name, res->res_counter.MinValue,
508 res->res_counter.MaxValue, res->res_counter.CurrentValue,
509 res->res_counter.WrapCounter->hdr.name);
511 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
512 res->res_counter.hdr.name, res->res_counter.MinValue,
513 res->res_counter.MaxValue);
515 if (res->res_counter.Catalog) {
516 sendit(sock, _(" --> "));
517 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
522 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
523 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
524 res->res_client.MaxConcurrentJobs);
525 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
526 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
527 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
528 res->res_client.AutoPrune);
529 if (res->res_client.catalog) {
530 sendit(sock, _(" --> "));
531 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
537 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
538 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
539 " poolid=%s volname=%s MediaType=%s\n"),
540 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
541 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
542 dev->offline, dev->autochanger,
543 edit_uint64(dev->PoolId, ed1),
544 dev->VolumeName, dev->MediaType);
547 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
548 " DeviceName=%s MediaType=%s StorageId=%s\n"),
549 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
550 res->res_store.MaxConcurrentJobs,
551 res->res_store.dev_name(),
552 res->res_store.media_type,
553 edit_int64(res->res_store.StorageId, ed1));
556 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
557 " db_user=%s MutliDBConn=%d\n"),
558 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
559 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
560 res->res_cat.mult_db_connections);
564 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
565 type == R_JOB ? _("Job") : _("JobDefs"),
566 res->res_job.hdr.name, res->res_job.JobType,
567 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
568 res->res_job.enabled);
569 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
570 res->res_job.MaxConcurrentJobs,
571 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
572 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
573 res->res_job.spool_data, res->res_job.write_part_after_job);
574 if (res->res_job.JobType == JT_MIGRATE) {
575 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
577 if (res->res_job.client) {
578 sendit(sock, _(" --> "));
579 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
581 if (res->res_job.fileset) {
582 sendit(sock, _(" --> "));
583 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
585 if (res->res_job.schedule) {
586 sendit(sock, _(" --> "));
587 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
589 if (res->res_job.RestoreWhere) {
590 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
592 if (res->res_job.RestoreBootstrap) {
593 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
595 if (res->res_job.WriteBootstrap) {
596 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
598 if (res->res_job.storage) {
600 foreach_alist(store, res->res_job.storage) {
601 sendit(sock, _(" --> "));
602 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
605 if (res->res_job.RunScripts) {
607 foreach_alist(script, res->res_job.RunScripts) {
608 sendit(sock, _(" --> RunScript\n"));
609 sendit(sock, _(" --> Command=%s\n"), NPRT(script->command));
610 sendit(sock, _(" --> Target=%s\n"), NPRT(script->target));
611 sendit(sock, _(" --> RunOnSuccess=%u\n"), script->on_success);
612 sendit(sock, _(" --> RunOnFailure=%u\n"), script->on_failure);
613 sendit(sock, _(" --> AbortJobOnError=%u\n"), script->abort_on_error);
614 sendit(sock, _(" --> RunWhen=%u\n"), script->when);
617 if (res->res_job.pool) {
618 sendit(sock, _(" --> "));
619 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
621 if (res->res_job.full_pool) {
622 sendit(sock, _(" --> "));
623 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
625 if (res->res_job.inc_pool) {
626 sendit(sock, _(" --> "));
627 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
629 if (res->res_job.diff_pool) {
630 sendit(sock, _(" --> "));
631 dump_resource(-R_POOL, (RES *)res->res_job.diff_pool, sendit, sock);
633 if (res->res_job.verify_job) {
634 sendit(sock, _(" --> "));
635 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
637 if (res->res_job.run_cmds) {
639 foreach_alist(runcmd, res->res_job.run_cmds) {
640 sendit(sock, _(" --> Run=%s\n"), runcmd);
643 if (res->res_job.selection_pattern) {
644 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
646 if (res->res_job.messages) {
647 sendit(sock, _(" --> "));
648 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
654 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
655 for (i=0; i<res->res_fs.num_includes; i++) {
656 INCEXE *incexe = res->res_fs.include_items[i];
657 for (j=0; j<incexe->num_opts; j++) {
658 FOPTS *fo = incexe->opts_list[j];
659 sendit(sock, " O %s\n", fo->opts);
660 for (k=0; k<fo->regex.size(); k++) {
661 sendit(sock, " R %s\n", fo->regex.get(k));
663 for (k=0; k<fo->regexdir.size(); k++) {
664 sendit(sock, " RD %s\n", fo->regexdir.get(k));
666 for (k=0; k<fo->regexfile.size(); k++) {
667 sendit(sock, " RF %s\n", fo->regexfile.get(k));
669 for (k=0; k<fo->wild.size(); k++) {
670 sendit(sock, " W %s\n", fo->wild.get(k));
672 for (k=0; k<fo->wilddir.size(); k++) {
673 sendit(sock, " WD %s\n", fo->wilddir.get(k));
675 for (k=0; k<fo->wildfile.size(); k++) {
676 sendit(sock, " WF %s\n", fo->wildfile.get(k));
678 for (k=0; k<fo->base.size(); k++) {
679 sendit(sock, " B %s\n", fo->base.get(k));
681 for (k=0; k<fo->fstype.size(); k++) {
682 sendit(sock, " X %s\n", fo->fstype.get(k));
685 sendit(sock, " D %s\n", fo->reader);
688 sendit(sock, " T %s\n", fo->writer);
690 sendit(sock, " N\n");
692 for (j=0; j<incexe->name_list.size(); j++) {
693 sendit(sock, " I %s\n", incexe->name_list.get(j));
695 if (incexe->name_list.size()) {
696 sendit(sock, " N\n");
700 for (i=0; i<res->res_fs.num_excludes; i++) {
701 INCEXE *incexe = res->res_fs.exclude_items[i];
702 for (j=0; j<incexe->name_list.size(); j++) {
703 sendit(sock, " E %s\n", incexe->name_list.get(j));
705 if (incexe->name_list.size()) {
706 sendit(sock, " N\n");
712 if (res->res_sch.run) {
714 RUN *run = res->res_sch.run;
715 char buf[1000], num[30];
716 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
721 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
722 bstrncpy(buf, _(" hour="), sizeof(buf));
723 for (i=0; i<24; i++) {
724 if (bit_is_set(i, run->hour)) {
725 bsnprintf(num, sizeof(num), "%d ", i);
726 bstrncat(buf, num, sizeof(buf));
729 bstrncat(buf, "\n", sizeof(buf));
731 bstrncpy(buf, _(" mday="), sizeof(buf));
732 for (i=0; i<31; i++) {
733 if (bit_is_set(i, run->mday)) {
734 bsnprintf(num, sizeof(num), "%d ", i);
735 bstrncat(buf, num, sizeof(buf));
738 bstrncat(buf, "\n", sizeof(buf));
740 bstrncpy(buf, _(" month="), sizeof(buf));
741 for (i=0; i<12; i++) {
742 if (bit_is_set(i, run->month)) {
743 bsnprintf(num, sizeof(num), "%d ", i);
744 bstrncat(buf, num, sizeof(buf));
747 bstrncat(buf, "\n", sizeof(buf));
749 bstrncpy(buf, _(" wday="), sizeof(buf));
750 for (i=0; i<7; i++) {
751 if (bit_is_set(i, run->wday)) {
752 bsnprintf(num, sizeof(num), "%d ", i);
753 bstrncat(buf, num, sizeof(buf));
756 bstrncat(buf, "\n", sizeof(buf));
758 bstrncpy(buf, _(" wom="), sizeof(buf));
759 for (i=0; i<5; i++) {
760 if (bit_is_set(i, run->wom)) {
761 bsnprintf(num, sizeof(num), "%d ", i);
762 bstrncat(buf, num, sizeof(buf));
765 bstrncat(buf, "\n", sizeof(buf));
767 bstrncpy(buf, _(" woy="), sizeof(buf));
768 for (i=0; i<54; i++) {
769 if (bit_is_set(i, run->woy)) {
770 bsnprintf(num, sizeof(num), "%d ", i);
771 bstrncat(buf, num, sizeof(buf));
774 bstrncat(buf, "\n", sizeof(buf));
776 sendit(sock, _(" mins=%d\n"), run->minute);
778 sendit(sock, _(" --> "));
779 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
782 sendit(sock, _(" --> "));
783 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
786 sendit(sock, _(" --> "));
787 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
789 /* If another Run record is chained in, go print it */
795 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
799 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
800 res->res_pool.pool_type);
801 sendit(sock, _(" use_cat=%d use_once=%d cat_files=%d\n"),
802 res->res_pool.use_catalog, res->res_pool.use_volume_once,
803 res->res_pool.catalog_files);
804 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
805 res->res_pool.max_volumes, res->res_pool.AutoPrune,
806 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
807 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
808 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
809 res->res_pool.Recycle,
810 NPRT(res->res_pool.label_format));
811 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
812 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
813 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
814 res->res_pool.recycle_oldest_volume,
815 res->res_pool.purge_oldest_volume,
816 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
817 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
818 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
819 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
820 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
821 if (res->res_pool.NextPool) {
822 sendit(sock, _(" --> "));
823 dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
825 if (res->res_pool.storage) {
827 foreach_alist(store, res->res_pool.storage) {
828 sendit(sock, _(" --> "));
829 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
834 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
835 if (res->res_msgs.mail_cmd)
836 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
837 if (res->res_msgs.operator_cmd)
838 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
841 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
844 if (recurse && res->res_dir.hdr.next) {
845 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
850 * Free all the members of an INCEXE structure
852 static void free_incexe(INCEXE *incexe)
854 incexe->name_list.destroy();
855 for (int i=0; i<incexe->num_opts; i++) {
856 FOPTS *fopt = incexe->opts_list[i];
857 fopt->regex.destroy();
858 fopt->regexdir.destroy();
859 fopt->regexfile.destroy();
860 fopt->wild.destroy();
861 fopt->wilddir.destroy();
862 fopt->wildfile.destroy();
863 fopt->base.destroy();
864 fopt->fstype.destroy();
873 if (incexe->opts_list) {
874 free(incexe->opts_list);
880 * Free memory of resource -- called when daemon terminates.
881 * NB, we don't need to worry about freeing any references
882 * to other resources as they will be freed when that
883 * resource chain is traversed. Mainly we worry about freeing
884 * allocated strings (names).
886 void free_resource(RES *sres, int type)
889 RES *nres; /* next resource if linked */
890 URES *res = (URES *)sres;
895 /* common stuff -- free the resource name and description */
896 nres = (RES *)res->res_dir.hdr.next;
897 if (res->res_dir.hdr.name) {
898 free(res->res_dir.hdr.name);
900 if (res->res_dir.hdr.desc) {
901 free(res->res_dir.hdr.desc);
906 if (res->res_dir.working_directory) {
907 free(res->res_dir.working_directory);
909 if (res->res_dir.scripts_directory) {
910 free((char *)res->res_dir.scripts_directory);
912 if (res->res_dir.pid_directory) {
913 free(res->res_dir.pid_directory);
915 if (res->res_dir.subsys_directory) {
916 free(res->res_dir.subsys_directory);
918 if (res->res_dir.password) {
919 free(res->res_dir.password);
921 if (res->res_dir.query_file) {
922 free(res->res_dir.query_file);
924 if (res->res_dir.DIRaddrs) {
925 free_addresses(res->res_dir.DIRaddrs);
927 if (res->res_dir.tls_ctx) {
928 free_tls_context(res->res_dir.tls_ctx);
930 if (res->res_dir.tls_ca_certfile) {
931 free(res->res_dir.tls_ca_certfile);
933 if (res->res_dir.tls_ca_certdir) {
934 free(res->res_dir.tls_ca_certdir);
936 if (res->res_dir.tls_certfile) {
937 free(res->res_dir.tls_certfile);
939 if (res->res_dir.tls_keyfile) {
940 free(res->res_dir.tls_keyfile);
942 if (res->res_dir.tls_dhfile) {
943 free(res->res_dir.tls_dhfile);
945 if (res->res_dir.tls_allowed_cns) {
946 delete res->res_dir.tls_allowed_cns;
953 if (res->res_con.password) {
954 free(res->res_con.password);
956 if (res->res_con.tls_ctx) {
957 free_tls_context(res->res_con.tls_ctx);
959 if (res->res_con.tls_ca_certfile) {
960 free(res->res_con.tls_ca_certfile);
962 if (res->res_con.tls_ca_certdir) {
963 free(res->res_con.tls_ca_certdir);
965 if (res->res_con.tls_certfile) {
966 free(res->res_con.tls_certfile);
968 if (res->res_con.tls_keyfile) {
969 free(res->res_con.tls_keyfile);
971 if (res->res_con.tls_dhfile) {
972 free(res->res_con.tls_dhfile);
974 if (res->res_con.tls_allowed_cns) {
975 delete res->res_con.tls_allowed_cns;
977 for (int i=0; i<Num_ACL; i++) {
978 if (res->res_con.ACL_lists[i]) {
979 delete res->res_con.ACL_lists[i];
980 res->res_con.ACL_lists[i] = NULL;
985 if (res->res_client.address) {
986 free(res->res_client.address);
988 if (res->res_client.password) {
989 free(res->res_client.password);
991 if (res->res_client.tls_ctx) {
992 free_tls_context(res->res_client.tls_ctx);
994 if (res->res_client.tls_ca_certfile) {
995 free(res->res_client.tls_ca_certfile);
997 if (res->res_client.tls_ca_certdir) {
998 free(res->res_client.tls_ca_certdir);
1000 if (res->res_client.tls_certfile) {
1001 free(res->res_client.tls_certfile);
1003 if (res->res_client.tls_keyfile) {
1004 free(res->res_client.tls_keyfile);
1008 if (res->res_store.address) {
1009 free(res->res_store.address);
1011 if (res->res_store.password) {
1012 free(res->res_store.password);
1014 if (res->res_store.media_type) {
1015 free(res->res_store.media_type);
1017 if (res->res_store.device) {
1018 delete res->res_store.device;
1020 if (res->res_store.tls_ctx) {
1021 free_tls_context(res->res_store.tls_ctx);
1023 if (res->res_store.tls_ca_certfile) {
1024 free(res->res_store.tls_ca_certfile);
1026 if (res->res_store.tls_ca_certdir) {
1027 free(res->res_store.tls_ca_certdir);
1029 if (res->res_store.tls_certfile) {
1030 free(res->res_store.tls_certfile);
1032 if (res->res_store.tls_keyfile) {
1033 free(res->res_store.tls_keyfile);
1037 if (res->res_cat.db_address) {
1038 free(res->res_cat.db_address);
1040 if (res->res_cat.db_socket) {
1041 free(res->res_cat.db_socket);
1043 if (res->res_cat.db_user) {
1044 free(res->res_cat.db_user);
1046 if (res->res_cat.db_name) {
1047 free(res->res_cat.db_name);
1049 if (res->res_cat.db_password) {
1050 free(res->res_cat.db_password);
1054 if ((num=res->res_fs.num_includes)) {
1055 while (--num >= 0) {
1056 free_incexe(res->res_fs.include_items[num]);
1058 free(res->res_fs.include_items);
1060 res->res_fs.num_includes = 0;
1061 if ((num=res->res_fs.num_excludes)) {
1062 while (--num >= 0) {
1063 free_incexe(res->res_fs.exclude_items[num]);
1065 free(res->res_fs.exclude_items);
1067 res->res_fs.num_excludes = 0;
1070 if (res->res_pool.pool_type) {
1071 free(res->res_pool.pool_type);
1073 if (res->res_pool.label_format) {
1074 free(res->res_pool.label_format);
1076 if (res->res_pool.cleaning_prefix) {
1077 free(res->res_pool.cleaning_prefix);
1079 if (res->res_pool.storage) {
1080 delete res->res_pool.storage;
1084 if (res->res_sch.run) {
1086 nrun = res->res_sch.run;
1096 if (res->res_job.RestoreWhere) {
1097 free(res->res_job.RestoreWhere);
1099 if (res->res_job.RestoreBootstrap) {
1100 free(res->res_job.RestoreBootstrap);
1102 if (res->res_job.WriteBootstrap) {
1103 free(res->res_job.WriteBootstrap);
1105 if (res->res_job.selection_pattern) {
1106 free(res->res_job.selection_pattern);
1108 if (res->res_job.run_cmds) {
1109 delete res->res_job.run_cmds;
1111 if (res->res_job.storage) {
1112 delete res->res_job.storage;
1114 if (res->res_job.RunScripts) {
1115 free_runscripts(res->res_job.RunScripts);
1116 delete res->res_job.RunScripts;
1120 if (res->res_msgs.mail_cmd) {
1121 free(res->res_msgs.mail_cmd);
1123 if (res->res_msgs.operator_cmd) {
1124 free(res->res_msgs.operator_cmd);
1126 free_msgs_res((MSGS *)res); /* free message resource */
1130 printf(_("Unknown resource type %d in free_resource.\n"), type);
1132 /* Common stuff again -- free the resource, recurse to next one */
1137 free_resource(nres, type);
1142 * Save the new resource by chaining it into the head list for
1143 * the resource. If this is pass 2, we update any resource
1144 * pointers because they may not have been defined until
1147 void save_resource(int type, RES_ITEM *items, int pass)
1150 int rindex = type - r_first;
1154 /* Check Job requirements after applying JobDefs */
1155 if (type != R_JOB && type != R_JOBDEFS) {
1157 * Ensure that all required items are present
1159 for (i=0; items[i].name; i++) {
1160 if (items[i].flags & ITEM_REQUIRED) {
1161 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1162 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1163 items[i].name, resources[rindex]);
1166 /* If this triggers, take a look at lib/parse_conf.h */
1167 if (i >= MAX_RES_ITEMS) {
1168 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1171 } else if (type == R_JOB) {
1173 * Ensure that the name item is present
1175 if (items[0].flags & ITEM_REQUIRED) {
1176 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1177 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1178 items[0].name, resources[rindex]);
1184 * During pass 2 in each "store" routine, we looked up pointers
1185 * to all the resources referrenced in the current resource, now we
1186 * must copy their addresses from the static record to the allocated
1191 /* Resources not containing a resource */
1199 * Resources containing another resource or alist. First
1200 * look up the resource which contains another resource. It
1201 * was written during pass 1. Then stuff in the pointers to
1202 * the resources it contains, which were inserted this pass.
1203 * Finally, it will all be stored back.
1206 /* Find resource saved in pass 1 */
1207 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1208 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1210 /* Explicitly copy resource pointers from this pass (res_all) */
1211 res->res_pool.NextPool = res_all.res_pool.NextPool;
1212 res->res_pool.storage = res_all.res_pool.storage;
1215 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1216 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1218 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1221 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1222 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1224 res->res_dir.messages = res_all.res_dir.messages;
1225 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1228 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1229 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1230 res_all.res_dir.hdr.name);
1232 /* we must explicitly copy the device alist pointer */
1233 res->res_store.device = res_all.res_store.device;
1237 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1238 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1239 res_all.res_dir.hdr.name);
1241 res->res_job.messages = res_all.res_job.messages;
1242 res->res_job.schedule = res_all.res_job.schedule;
1243 res->res_job.client = res_all.res_job.client;
1244 res->res_job.fileset = res_all.res_job.fileset;
1245 res->res_job.storage = res_all.res_job.storage;
1246 res->res_job.pool = res_all.res_job.pool;
1247 res->res_job.full_pool = res_all.res_job.full_pool;
1248 res->res_job.inc_pool = res_all.res_job.inc_pool;
1249 res->res_job.diff_pool = res_all.res_job.diff_pool;
1250 res->res_job.verify_job = res_all.res_job.verify_job;
1251 res->res_job.jobdefs = res_all.res_job.jobdefs;
1252 res->res_job.run_cmds = res_all.res_job.run_cmds;
1253 res->res_job.RunScripts = res_all.res_job.RunScripts;
1256 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1257 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1259 res->res_counter.Catalog = res_all.res_counter.Catalog;
1260 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1264 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1265 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1267 res->res_client.catalog = res_all.res_client.catalog;
1271 * Schedule is a bit different in that it contains a RUN record
1272 * chain which isn't a "named" resource. This chain was linked
1273 * in by run_conf.c during pass 2, so here we jam the pointer
1274 * into the Schedule resource.
1276 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1277 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1279 res->res_sch.run = res_all.res_sch.run;
1282 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1286 /* Note, the resource name was already saved during pass 1,
1287 * so here, we can just release it.
1289 if (res_all.res_dir.hdr.name) {
1290 free(res_all.res_dir.hdr.name);
1291 res_all.res_dir.hdr.name = NULL;
1293 if (res_all.res_dir.hdr.desc) {
1294 free(res_all.res_dir.hdr.desc);
1295 res_all.res_dir.hdr.desc = NULL;
1301 * The following code is only executed during pass 1
1305 size = sizeof(DIRRES);
1308 size = sizeof(CONRES);
1311 size =sizeof(CLIENT);
1314 size = sizeof(STORE);
1324 size = sizeof(FILESET);
1327 size = sizeof(SCHED);
1330 size = sizeof(POOL);
1333 size = sizeof(MSGS);
1336 size = sizeof(COUNTER);
1342 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1348 res = (URES *)malloc(size);
1349 memcpy(res, &res_all, size);
1350 if (!res_head[rindex]) {
1351 res_head[rindex] = (RES *)res; /* store first entry */
1352 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1353 res->res_dir.hdr.name, rindex);
1356 if (res->res_dir.hdr.name == NULL) {
1357 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1360 /* Add new res to end of chain */
1361 for (next=res_head[rindex]; next->next; next=next->next) {
1362 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1363 Emsg2(M_ERROR_TERM, 0,
1364 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1365 resources[rindex].name, res->res_dir.hdr.name);
1368 next->next = (RES *)res;
1369 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1370 res->res_dir.hdr.name, rindex, pass);
1376 * Store Device. Note, the resource is created upon the
1377 * first reference. The details of the resource are obtained
1378 * later from the SD.
1380 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1384 int rindex = R_DEVICE - r_first;
1385 int size = sizeof(DEVICE);
1389 token = lex_get_token(lc, T_NAME);
1390 if (!res_head[rindex]) {
1391 res = (URES *)malloc(size);
1392 memset(res, 0, size);
1393 res->res_dev.hdr.name = bstrdup(lc->str);
1394 res_head[rindex] = (RES *)res; /* store first entry */
1395 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1396 res->res_dir.hdr.name, rindex);
1399 /* See if it is already defined */
1400 for (next=res_head[rindex]; next->next; next=next->next) {
1401 if (strcmp(next->name, lc->str) == 0) {
1407 res = (URES *)malloc(size);
1408 memset(res, 0, size);
1409 res->res_dev.hdr.name = bstrdup(lc->str);
1410 next->next = (RES *)res;
1411 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1412 res->res_dir.hdr.name, rindex, pass);
1417 set_bit(index, res_all.hdr.item_present);
1419 store_alist_res(lc, item, index, pass);
1424 * Store JobType (backup, verify, restore)
1427 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1431 token = lex_get_token(lc, T_NAME);
1432 /* Store the type both pass 1 and pass 2 */
1433 for (i=0; migtypes[i].type_name; i++) {
1434 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1435 *(int *)(item->value) = migtypes[i].job_type;
1441 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1444 set_bit(index, res_all.hdr.item_present);
1450 * Store JobType (backup, verify, restore)
1453 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1457 token = lex_get_token(lc, T_NAME);
1458 /* Store the type both pass 1 and pass 2 */
1459 for (i=0; jobtypes[i].type_name; i++) {
1460 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1461 *(int *)(item->value) = jobtypes[i].job_type;
1467 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1470 set_bit(index, res_all.hdr.item_present);
1474 * Store Job Level (Full, Incremental, ...)
1477 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1481 token = lex_get_token(lc, T_NAME);
1482 /* Store the level pass 2 so that type is defined */
1483 for (i=0; joblevels[i].level_name; i++) {
1484 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1485 *(int *)(item->value) = joblevels[i].level;
1491 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1494 set_bit(index, res_all.hdr.item_present);
1498 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1501 token = lex_get_token(lc, T_NAME);
1502 /* Scan Replacement options */
1503 for (i=0; ReplaceOptions[i].name; i++) {
1504 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1505 *(int *)(item->value) = ReplaceOptions[i].token;
1511 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1514 set_bit(index, res_all.hdr.item_present);
1518 * Store ACL (access control list)
1521 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1526 token = lex_get_token(lc, T_NAME);
1528 if (((alist **)item->value)[item->code] == NULL) {
1529 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1530 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1532 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1533 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1535 token = lex_get_token(lc, T_ALL);
1536 if (token == T_COMMA) {
1537 continue; /* get another ACL */
1541 set_bit(index, res_all.hdr.item_present);
1545 /* Store a runscript->when in a bit field */
1546 static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass)
1548 lex_get_token(lc, T_NAME);
1550 if (strcasecmp(lc->str, "before") == 0) {
1551 *(int *)(item->value) = SCRIPT_Before ;
1552 } else if (strcasecmp(lc->str, "after") == 0) {
1553 *(int *)(item->value) = SCRIPT_After;
1554 } else if (strcasecmp(lc->str, "always") == 0) {
1555 *(int *)(item->value) = SCRIPT_Any;
1557 scan_err2(lc, _("Expect %s, got: %s"), "Before, After or Always", lc->str);
1562 /* Store a runscript->target
1565 static void store_runscript_target(LEX *lc, RES_ITEM *item, int index, int pass)
1567 lex_get_token(lc, T_STRING);
1570 if (strcmp(lc->str, "%c") == 0) {
1571 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1572 } else if (strcmp(lc->str, "yes") == 0) {
1573 ((RUNSCRIPT*) item->value)->set_target("%c");
1574 } else if (strcmp(lc->str, "no") == 0) {
1575 /* store nothing, run on director */
1577 RES *res = GetResWithName(R_CLIENT, lc->str);
1579 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
1580 lc->str, lc->line_no, lc->line);
1583 ((RUNSCRIPT*) item->value)->set_target(lc->str);
1589 /* Store a runscript->command in a bit field
1592 static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass)
1594 lex_get_token(lc, T_STRING);
1597 ((RUNSCRIPT*) item->value)->set_command(lc->str);
1602 static void store_short_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1604 lex_get_token(lc, T_STRING);
1605 alist **runscripts = (alist **)(item->value) ;
1608 RUNSCRIPT *script = new_runscript();
1610 script->set_command(lc->str);
1612 if (strcmp(item->name, "runbeforejob") == 0) {
1613 script->when = SCRIPT_Before;
1614 script->abort_on_error = true;
1616 } else if (strcmp(item->name, "runafterjob") == 0) {
1617 script->when = SCRIPT_After;
1618 script->on_success = true;
1619 script->on_failure = false;
1621 } else if (strcmp(item->name, "clientrunafterjob") == 0) {
1622 script->when = SCRIPT_After;
1623 script->set_target("%c");
1624 script->on_success = true;
1625 script->on_failure = false;
1627 } else if (strcmp(item->name, "clientrunbeforejob") == 0) {
1628 script->when = SCRIPT_Before;
1629 script->set_target("%c");
1630 script->abort_on_error = true;
1632 } else if (strcmp(item->name, "runafterfailedjob") == 0) {
1633 script->when = SCRIPT_After;
1634 script->on_failure = true;
1635 script->on_success = false;
1638 if (*runscripts == NULL) {
1639 *runscripts = New(alist(10, not_owned_by_alist));
1642 (*runscripts)->append(script);
1649 static RUNSCRIPT res_runscript;
1652 * new RunScript items
1653 * name handler value code flags default_value
1655 static RES_ITEM runscript_items[] = {
1656 {"command", store_runscript_cmd, ITEM(res_runscript), 0, ITEM_REQUIRED, 0},
1657 {"target", store_runscript_target, ITEM(res_runscript), 0, 0, 0},
1658 {"runsonsuccess", store_bool, ITEM(res_runscript.on_success), 0, 0, 0},
1659 {"runsonfailure", store_bool, ITEM(res_runscript.on_failure), 0, 0, 0},
1660 {"abortjobonerror", store_bool, ITEM(res_runscript.abort_on_error), 0, 0, 0},
1661 {"runswhen", store_runscript_when, ITEM(res_runscript.when), 0, 0, 0},
1662 {"runsonclient", store_runscript_target, ITEM(res_runscript), 0, 0, 0}, /* TODO */
1663 {NULL, NULL, {0}, 0, 0, 0}
1667 * Store RunScript info
1669 * Note, when this routine is called, we are inside a Job
1670 * resource. We treat the RunScript like a sort of
1671 * mini-resource within the Job resource.
1673 static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass)
1676 alist **runscripts = (alist **)(item->value) ;
1678 Dmsg1(200, "store_runscript: begin store_runscript pass=%i\n", pass);
1680 res_runscript.reset_default(); /* setting on_success, on_failure, abort_on_error */
1682 token = lex_get_token(lc, T_SKIP_EOL);
1684 if (token != T_BOB) {
1685 scan_err1(lc, _("Expecting open brace. Got %s"), lc->str);
1688 while ((token = lex_get_token(lc, T_SKIP_EOL)) != T_EOF) {
1689 if (token == T_EOB) {
1692 if (token != T_IDENTIFIER) {
1693 scan_err1(lc, _("Expecting keyword, got: %s\n"), lc->str);
1695 for (i=0; runscript_items[i].name; i++) {
1696 if (strcasecmp(runscript_items[i].name, lc->str) == 0) {
1697 token = lex_get_token(lc, T_SKIP_EOL);
1698 if (token != T_EQUALS) {
1699 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
1702 /* Call item handler */
1703 runscript_items[i].handler(lc, &runscript_items[i], i, pass);
1710 scan_err1(lc, _("Keyword %s not permitted in this resource"), lc->str);
1715 if (res_runscript.command == NULL) {
1716 scan_err2(lc, _("%s item is required in %s resource, but not found.\n"),
1717 "command", "runscript");
1720 /* run on client by default */
1721 if (res_runscript.target == NULL) {
1722 res_runscript.set_target("%c");
1725 RUNSCRIPT *script = new_runscript();
1726 memcpy(script, &res_runscript, sizeof(RUNSCRIPT));
1728 if (*runscripts == NULL) {
1729 *runscripts = New(alist(10, not_owned_by_alist));
1732 (*runscripts)->append(script);
1737 set_bit(index, res_all.hdr.item_present);