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);
67 /* We build the current resource here as we are
68 * scanning the resource configuration definition,
69 * then move it to allocated memory when the resource
73 int res_all_size = sizeof(res_all);
76 /* Definition of records permitted within each
77 * resource with the routine to process the record
78 * information. NOTE! quoted names must be in lower case.
83 * name handler value code flags default_value
85 static RES_ITEM dir_items[] = {
86 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
87 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
88 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
89 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
90 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
91 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
92 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
93 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
94 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
95 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
96 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
97 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
98 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
99 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
100 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
101 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
102 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
103 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
104 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
105 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
106 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
107 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
108 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
109 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
110 {NULL, NULL, NULL, 0, 0, 0}
116 * name handler value code flags default_value
118 static RES_ITEM con_items[] = {
119 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
120 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
121 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
122 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
123 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
124 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
125 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
126 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
127 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
128 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
129 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
130 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
131 {"tlsenable", store_bool, ITEM(res_con.tls_enable), 0, 0, 0},
132 {"tlsrequire", store_bool, ITEM(res_con.tls_require), 0, 0, 0},
133 {"tlsverifypeer", store_bool, ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
134 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
135 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
136 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
137 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
138 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
139 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
140 {NULL, NULL, NULL, 0, 0, 0}
145 * Client or File daemon resource
147 * name handler value code flags default_value
150 static RES_ITEM cli_items[] = {
151 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
152 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
153 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
154 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
155 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
156 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
157 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
158 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
159 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
160 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
161 {"autoprune", store_bool, ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
162 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
163 {"tlsenable", store_bool, ITEM(res_client.tls_enable), 0, 0, 0},
164 {"tlsrequire", store_bool, ITEM(res_client.tls_require), 0, 0, 0},
165 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
166 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
167 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
168 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
169 {NULL, NULL, NULL, 0, 0, 0}
172 /* Storage daemon resource
174 * name handler value code flags default_value
176 static RES_ITEM store_items[] = {
177 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
178 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
179 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
180 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
181 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
182 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
183 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
184 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
185 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
186 {"autochanger", store_bool, ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
187 {"enabled", store_bool, ITEM(res_store.enabled), 0, ITEM_DEFAULT, true},
188 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
189 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
190 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
191 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
192 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
193 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
194 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
195 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
196 {NULL, NULL, NULL, 0, 0, 0}
200 * Catalog Resource Directives
202 * name handler value code flags default_value
204 static RES_ITEM cat_items[] = {
205 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
206 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
207 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
208 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
209 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
210 /* keep this password as store_str for the moment */
211 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
212 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
213 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
214 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
215 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
216 /* Turned off for the moment */
217 {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
218 {NULL, NULL, NULL, 0, 0, 0}
222 * Job Resource Directives
224 * name handler value code flags default_value
226 RES_ITEM job_items[] = {
227 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
228 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
229 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
230 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
231 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
232 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, 0, 0},
233 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
234 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
235 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
236 {"differentialbackuppool", store_res, ITEM(res_job.dif_pool), R_POOL, 0, 0},
237 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
238 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
239 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
240 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
241 {"jobtoverify", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
242 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
243 {"nextpool", store_res, ITEM(res_job.next_pool), R_POOL, 0, 0},
244 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
245 /* Root of where to restore files */
246 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
247 /* Where to find bootstrap during restore */
248 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
249 /* Where to write bootstrap file during backup */
250 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
251 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
252 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
253 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
254 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
255 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
256 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
257 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
258 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
259 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
260 {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
261 {"prunejobs", store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
262 {"prunefiles", store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
263 {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
264 {"enabled", store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
265 {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
266 {"spooldata", store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
267 {"rerunfailedlevels", store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
268 {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
269 {"runbeforejob", store_str, ITEM(res_job.RunBeforeJob), 0, 0, 0},
270 {"runafterjob", store_str, ITEM(res_job.RunAfterJob), 0, 0, 0},
271 {"runafterfailedjob", store_str, ITEM(res_job.RunAfterFailedJob), 0, 0, 0},
272 {"clientrunbeforejob", store_str, ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
273 {"clientrunafterjob", store_str, ITEM(res_job.ClientRunAfterJob), 0, 0, 0},
274 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
275 {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
276 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
277 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
278 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
279 {"writepartafterjob", store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, false},
280 {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
281 {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
282 {NULL, NULL, NULL, 0, 0, 0}
287 * name handler value code flags default_value
289 static RES_ITEM fs_items[] = {
290 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
291 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
292 {"include", store_inc, NULL, 0, ITEM_NO_EQUALS, 0},
293 {"exclude", store_inc, NULL, 1, ITEM_NO_EQUALS, 0},
294 {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
295 {"enablevss", store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, false},
296 {NULL, NULL, NULL, 0, 0, 0}
299 /* Schedule -- see run_conf.c */
302 * name handler value code flags default_value
304 static RES_ITEM sch_items[] = {
305 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
306 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
307 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
308 {NULL, NULL, NULL, 0, 0, 0}
313 * name handler value code flags default_value
315 static RES_ITEM pool_items[] = {
316 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
317 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
318 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
319 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
320 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
321 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
322 {"usecatalog", store_bool, ITEM(res_pool.use_catalog), 0, ITEM_DEFAULT, true},
323 {"usevolumeonce", store_bool, ITEM(res_pool.use_volume_once), 0, 0, 0},
324 {"purgeoldestvolume", store_bool, ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
325 {"recycleoldestvolume", store_bool, ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
326 {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
327 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
328 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
329 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
330 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
331 {"acceptanyvolume", store_bool, ITEM(res_pool.accept_any_volume), 0, ITEM_DEFAULT, true},
332 {"catalogfiles", store_bool, ITEM(res_pool.catalog_files), 0, ITEM_DEFAULT, true},
333 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
334 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
335 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
336 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
337 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
338 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
339 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
340 {"autoprune", store_bool, ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
341 {"recycle", store_bool, ITEM(res_pool.Recycle), 0, ITEM_DEFAULT, true},
342 {NULL, NULL, NULL, 0, 0, 0}
347 * name handler value code flags default_value
349 static RES_ITEM counter_items[] = {
350 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
351 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
352 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
353 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
354 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
355 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
356 {NULL, NULL, NULL, 0, 0, 0}
360 /* Message resource */
361 extern RES_ITEM msgs_items[];
364 * This is the master resource definition.
365 * It must have one item for each of the resources.
367 * NOTE!!! keep it in the same order as the R_codes
368 * or eliminate all resources[rindex].name
370 * name items rcode res_head
372 RES_TABLE resources[] = {
373 {"director", dir_items, R_DIRECTOR},
374 {"client", cli_items, R_CLIENT},
375 {"job", job_items, R_JOB},
376 {"storage", store_items, R_STORAGE},
377 {"catalog", cat_items, R_CATALOG},
378 {"schedule", sch_items, R_SCHEDULE},
379 {"fileset", fs_items, R_FILESET},
380 {"pool", pool_items, R_POOL},
381 {"messages", msgs_items, R_MSGS},
382 {"counter", counter_items, R_COUNTER},
383 {"console", con_items, R_CONSOLE},
384 {"jobdefs", job_items, R_JOBDEFS},
385 {"device", NULL, R_DEVICE}, /* info obtained from SD */
390 /* Keywords (RHS) permitted in Job Level records
392 * level_name level job_type
394 struct s_jl joblevels[] = {
395 {"Full", L_FULL, JT_BACKUP},
396 {"Base", L_BASE, JT_BACKUP},
397 {"Incremental", L_INCREMENTAL, JT_BACKUP},
398 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
399 {"Since", L_SINCE, JT_BACKUP},
400 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
401 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
402 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
403 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
404 {"Data", L_VERIFY_DATA, JT_VERIFY},
405 {" ", L_NONE, JT_ADMIN},
406 {" ", L_NONE, JT_RESTORE},
410 /* Keywords (RHS) permitted in Job type records
414 struct s_jt jobtypes[] = {
415 {"backup", JT_BACKUP},
417 {"verify", JT_VERIFY},
418 {"restore", JT_RESTORE},
419 {"migrate", JT_MIGRATE},
424 /* Keywords (RHS) permitted in Selection type records
428 struct s_jt migtypes[] = {
429 {"smallestvolume", MT_SMALLEST_VOL},
430 {"oldestvolume", MT_OLDEST_VOL},
431 {"pooloccupancy", MT_POOL_OCCUPANCY},
432 {"pooltime", MT_POOL_TIME},
433 {"client", MT_CLIENT},
434 {"volume", MT_VOLUME},
436 {"sqlquery", MT_SQLQUERY},
442 /* Options permitted in Restore replace= */
443 struct s_kw ReplaceOptions[] = {
444 {"always", REPLACE_ALWAYS},
445 {"ifnewer", REPLACE_IFNEWER},
446 {"ifolder", REPLACE_IFOLDER},
447 {"never", REPLACE_NEVER},
451 const char *level_to_str(int level)
454 static char level_no[30];
455 const char *str = level_no;
457 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
458 for (i=0; joblevels[i].level_name; i++) {
459 if (level == joblevels[i].level) {
460 str = joblevels[i].level_name;
467 /* Dump contents of resource */
468 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
470 URES *res = (URES *)reshdr;
472 char ed1[100], ed2[100], ed3[100];
476 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
479 if (type < 0) { /* no recursion */
485 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
486 reshdr->name, res->res_dir.MaxConcurrentJobs,
487 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
488 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
489 if (res->res_dir.query_file) {
490 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
492 if (res->res_dir.messages) {
493 sendit(sock, _(" --> "));
494 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
498 sendit(sock, _("Console: name=%s SSL=%d\n"),
499 res->res_con.hdr.name, res->res_con.tls_enable);
502 if (res->res_counter.WrapCounter) {
503 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
504 res->res_counter.hdr.name, res->res_counter.MinValue,
505 res->res_counter.MaxValue, res->res_counter.CurrentValue,
506 res->res_counter.WrapCounter->hdr.name);
508 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
509 res->res_counter.hdr.name, res->res_counter.MinValue,
510 res->res_counter.MaxValue);
512 if (res->res_counter.Catalog) {
513 sendit(sock, _(" --> "));
514 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
519 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
520 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
521 res->res_client.MaxConcurrentJobs);
522 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
523 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
524 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
525 res->res_client.AutoPrune);
526 if (res->res_client.catalog) {
527 sendit(sock, _(" --> "));
528 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
534 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
535 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
536 " poolid=%s volname=%s MediaType=%s\n"),
537 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
538 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
539 dev->offline, dev->autochanger,
540 edit_uint64(dev->PoolId, ed1),
541 dev->VolumeName, dev->MediaType);
544 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
545 " DeviceName=%s MediaType=%s StorageId=%s\n"),
546 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
547 res->res_store.MaxConcurrentJobs,
548 res->res_store.dev_name(),
549 res->res_store.media_type,
550 edit_int64(res->res_store.StorageId, ed1));
553 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
554 " db_user=%s MutliDBConn=%d\n"),
555 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
556 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
557 res->res_cat.mult_db_connections);
561 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
562 type == R_JOB ? _("Job") : _("JobDefs"),
563 res->res_job.hdr.name, res->res_job.JobType,
564 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
565 res->res_job.enabled);
566 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
567 res->res_job.MaxConcurrentJobs,
568 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
569 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
570 res->res_job.spool_data, res->res_job.write_part_after_job);
571 if (res->res_job.JobType == JT_MIGRATE) {
572 sendit(sock, _(" SelectionType=%d\n"), res->res_job.selection_type);
574 if (res->res_job.client) {
575 sendit(sock, _(" --> "));
576 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
578 if (res->res_job.fileset) {
579 sendit(sock, _(" --> "));
580 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
582 if (res->res_job.schedule) {
583 sendit(sock, _(" --> "));
584 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
586 if (res->res_job.RestoreWhere) {
587 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
589 if (res->res_job.RestoreBootstrap) {
590 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
592 if (res->res_job.RunBeforeJob) {
593 sendit(sock, _(" --> RunBefore=%s\n"), NPRT(res->res_job.RunBeforeJob));
595 if (res->res_job.RunAfterJob) {
596 sendit(sock, _(" --> RunAfter=%s\n"), NPRT(res->res_job.RunAfterJob));
598 if (res->res_job.RunAfterFailedJob) {
599 sendit(sock, _(" --> RunAfterFailed=%s\n"), NPRT(res->res_job.RunAfterFailedJob));
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.pool) {
612 sendit(sock, _(" --> "));
613 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
615 if (res->res_job.full_pool) {
616 sendit(sock, _(" --> "));
617 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
619 if (res->res_job.inc_pool) {
620 sendit(sock, _(" --> "));
621 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
623 if (res->res_job.dif_pool) {
624 sendit(sock, _(" --> "));
625 dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock);
627 if (res->res_job.verify_job) {
628 sendit(sock, _(" --> "));
629 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
631 if (res->res_job.run_cmds) {
633 foreach_alist(runcmd, res->res_job.run_cmds) {
634 sendit(sock, _(" --> Run=%s\n"), runcmd);
637 if (res->res_job.selection_pattern) {
638 sendit(sock, _(" --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
640 if (res->res_job.messages) {
641 sendit(sock, _(" --> "));
642 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
648 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
649 for (i=0; i<res->res_fs.num_includes; i++) {
650 INCEXE *incexe = res->res_fs.include_items[i];
651 for (j=0; j<incexe->num_opts; j++) {
652 FOPTS *fo = incexe->opts_list[j];
653 sendit(sock, " O %s\n", fo->opts);
654 for (k=0; k<fo->regex.size(); k++) {
655 sendit(sock, " R %s\n", fo->regex.get(k));
657 for (k=0; k<fo->regexdir.size(); k++) {
658 sendit(sock, " RD %s\n", fo->regexdir.get(k));
660 for (k=0; k<fo->regexfile.size(); k++) {
661 sendit(sock, " RF %s\n", fo->regexfile.get(k));
663 for (k=0; k<fo->wild.size(); k++) {
664 sendit(sock, " W %s\n", fo->wild.get(k));
666 for (k=0; k<fo->wilddir.size(); k++) {
667 sendit(sock, " WD %s\n", fo->wilddir.get(k));
669 for (k=0; k<fo->wildfile.size(); k++) {
670 sendit(sock, " WF %s\n", fo->wildfile.get(k));
672 for (k=0; k<fo->base.size(); k++) {
673 sendit(sock, " B %s\n", fo->base.get(k));
675 for (k=0; k<fo->fstype.size(); k++) {
676 sendit(sock, " X %s\n", fo->fstype.get(k));
679 sendit(sock, " D %s\n", fo->reader);
682 sendit(sock, " T %s\n", fo->writer);
684 sendit(sock, " N\n");
686 for (j=0; j<incexe->name_list.size(); j++) {
687 sendit(sock, " I %s\n", incexe->name_list.get(j));
689 if (incexe->name_list.size()) {
690 sendit(sock, " N\n");
694 for (i=0; i<res->res_fs.num_excludes; i++) {
695 INCEXE *incexe = res->res_fs.exclude_items[i];
696 for (j=0; j<incexe->name_list.size(); j++) {
697 sendit(sock, " E %s\n", incexe->name_list.get(j));
699 if (incexe->name_list.size()) {
700 sendit(sock, " N\n");
706 if (res->res_sch.run) {
708 RUN *run = res->res_sch.run;
709 char buf[1000], num[30];
710 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
715 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
716 bstrncpy(buf, _(" hour="), sizeof(buf));
717 for (i=0; i<24; i++) {
718 if (bit_is_set(i, run->hour)) {
719 bsnprintf(num, sizeof(num), "%d ", i);
720 bstrncat(buf, num, sizeof(buf));
723 bstrncat(buf, "\n", sizeof(buf));
725 bstrncpy(buf, _(" mday="), sizeof(buf));
726 for (i=0; i<31; i++) {
727 if (bit_is_set(i, run->mday)) {
728 bsnprintf(num, sizeof(num), "%d ", i);
729 bstrncat(buf, num, sizeof(buf));
732 bstrncat(buf, "\n", sizeof(buf));
734 bstrncpy(buf, _(" month="), sizeof(buf));
735 for (i=0; i<12; i++) {
736 if (bit_is_set(i, run->month)) {
737 bsnprintf(num, sizeof(num), "%d ", i);
738 bstrncat(buf, num, sizeof(buf));
741 bstrncat(buf, "\n", sizeof(buf));
743 bstrncpy(buf, _(" wday="), sizeof(buf));
744 for (i=0; i<7; i++) {
745 if (bit_is_set(i, run->wday)) {
746 bsnprintf(num, sizeof(num), "%d ", i);
747 bstrncat(buf, num, sizeof(buf));
750 bstrncat(buf, "\n", sizeof(buf));
752 bstrncpy(buf, _(" wom="), sizeof(buf));
753 for (i=0; i<5; i++) {
754 if (bit_is_set(i, run->wom)) {
755 bsnprintf(num, sizeof(num), "%d ", i);
756 bstrncat(buf, num, sizeof(buf));
759 bstrncat(buf, "\n", sizeof(buf));
761 bstrncpy(buf, _(" woy="), sizeof(buf));
762 for (i=0; i<54; i++) {
763 if (bit_is_set(i, run->woy)) {
764 bsnprintf(num, sizeof(num), "%d ", i);
765 bstrncat(buf, num, sizeof(buf));
768 bstrncat(buf, "\n", sizeof(buf));
770 sendit(sock, _(" mins=%d\n"), run->minute);
772 sendit(sock, _(" --> "));
773 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
776 sendit(sock, _(" --> "));
777 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
780 sendit(sock, _(" --> "));
781 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
783 /* If another Run record is chained in, go print it */
789 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
793 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
794 res->res_pool.pool_type);
795 sendit(sock, _(" use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n"),
796 res->res_pool.use_catalog, res->res_pool.use_volume_once,
797 res->res_pool.accept_any_volume, res->res_pool.catalog_files);
798 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
799 res->res_pool.max_volumes, res->res_pool.AutoPrune,
800 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
801 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
802 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
803 res->res_pool.Recycle,
804 NPRT(res->res_pool.label_format));
805 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
806 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
807 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
808 res->res_pool.recycle_oldest_volume,
809 res->res_pool.purge_oldest_volume,
810 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
811 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
812 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
813 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
814 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
815 if (res->res_pool.NextPool) {
816 sendit(sock, _(" --> "));
817 dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
819 if (res->res_pool.storage) {
821 foreach_alist(store, res->res_pool.storage) {
822 sendit(sock, _(" --> "));
823 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
828 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
829 if (res->res_msgs.mail_cmd)
830 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
831 if (res->res_msgs.operator_cmd)
832 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
835 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
838 if (recurse && res->res_dir.hdr.next) {
839 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
844 * Free all the members of an INCEXE structure
846 static void free_incexe(INCEXE *incexe)
848 incexe->name_list.destroy();
849 for (int i=0; i<incexe->num_opts; i++) {
850 FOPTS *fopt = incexe->opts_list[i];
851 fopt->regex.destroy();
852 fopt->regexdir.destroy();
853 fopt->regexfile.destroy();
854 fopt->wild.destroy();
855 fopt->wilddir.destroy();
856 fopt->wildfile.destroy();
857 fopt->base.destroy();
858 fopt->fstype.destroy();
867 if (incexe->opts_list) {
868 free(incexe->opts_list);
874 * Free memory of resource -- called when daemon terminates.
875 * NB, we don't need to worry about freeing any references
876 * to other resources as they will be freed when that
877 * resource chain is traversed. Mainly we worry about freeing
878 * allocated strings (names).
880 void free_resource(RES *sres, int type)
883 RES *nres; /* next resource if linked */
884 URES *res = (URES *)sres;
889 /* common stuff -- free the resource name and description */
890 nres = (RES *)res->res_dir.hdr.next;
891 if (res->res_dir.hdr.name) {
892 free(res->res_dir.hdr.name);
894 if (res->res_dir.hdr.desc) {
895 free(res->res_dir.hdr.desc);
900 if (res->res_dir.working_directory) {
901 free(res->res_dir.working_directory);
903 if (res->res_dir.scripts_directory) {
904 free((char *)res->res_dir.scripts_directory);
906 if (res->res_dir.pid_directory) {
907 free(res->res_dir.pid_directory);
909 if (res->res_dir.subsys_directory) {
910 free(res->res_dir.subsys_directory);
912 if (res->res_dir.password) {
913 free(res->res_dir.password);
915 if (res->res_dir.query_file) {
916 free(res->res_dir.query_file);
918 if (res->res_dir.DIRaddrs) {
919 free_addresses(res->res_dir.DIRaddrs);
921 if (res->res_dir.tls_ctx) {
922 free_tls_context(res->res_dir.tls_ctx);
924 if (res->res_dir.tls_ca_certfile) {
925 free(res->res_dir.tls_ca_certfile);
927 if (res->res_dir.tls_ca_certdir) {
928 free(res->res_dir.tls_ca_certdir);
930 if (res->res_dir.tls_certfile) {
931 free(res->res_dir.tls_certfile);
933 if (res->res_dir.tls_keyfile) {
934 free(res->res_dir.tls_keyfile);
936 if (res->res_dir.tls_dhfile) {
937 free(res->res_dir.tls_dhfile);
939 if (res->res_dir.tls_allowed_cns) {
940 delete res->res_dir.tls_allowed_cns;
947 if (res->res_con.password) {
948 free(res->res_con.password);
950 if (res->res_con.tls_ctx) {
951 free_tls_context(res->res_con.tls_ctx);
953 if (res->res_con.tls_ca_certfile) {
954 free(res->res_con.tls_ca_certfile);
956 if (res->res_con.tls_ca_certdir) {
957 free(res->res_con.tls_ca_certdir);
959 if (res->res_con.tls_certfile) {
960 free(res->res_con.tls_certfile);
962 if (res->res_con.tls_keyfile) {
963 free(res->res_con.tls_keyfile);
965 if (res->res_con.tls_dhfile) {
966 free(res->res_con.tls_dhfile);
968 if (res->res_con.tls_allowed_cns) {
969 delete res->res_con.tls_allowed_cns;
971 for (int i=0; i<Num_ACL; i++) {
972 if (res->res_con.ACL_lists[i]) {
973 delete res->res_con.ACL_lists[i];
974 res->res_con.ACL_lists[i] = NULL;
979 if (res->res_client.address) {
980 free(res->res_client.address);
982 if (res->res_client.password) {
983 free(res->res_client.password);
985 if (res->res_client.tls_ctx) {
986 free_tls_context(res->res_client.tls_ctx);
988 if (res->res_client.tls_ca_certfile) {
989 free(res->res_client.tls_ca_certfile);
991 if (res->res_client.tls_ca_certdir) {
992 free(res->res_client.tls_ca_certdir);
994 if (res->res_client.tls_certfile) {
995 free(res->res_client.tls_certfile);
997 if (res->res_client.tls_keyfile) {
998 free(res->res_client.tls_keyfile);
1002 if (res->res_store.address) {
1003 free(res->res_store.address);
1005 if (res->res_store.password) {
1006 free(res->res_store.password);
1008 if (res->res_store.media_type) {
1009 free(res->res_store.media_type);
1011 if (res->res_store.device) {
1012 delete res->res_store.device;
1014 if (res->res_store.tls_ctx) {
1015 free_tls_context(res->res_store.tls_ctx);
1017 if (res->res_store.tls_ca_certfile) {
1018 free(res->res_store.tls_ca_certfile);
1020 if (res->res_store.tls_ca_certdir) {
1021 free(res->res_store.tls_ca_certdir);
1023 if (res->res_store.tls_certfile) {
1024 free(res->res_store.tls_certfile);
1026 if (res->res_store.tls_keyfile) {
1027 free(res->res_store.tls_keyfile);
1031 if (res->res_cat.db_address) {
1032 free(res->res_cat.db_address);
1034 if (res->res_cat.db_socket) {
1035 free(res->res_cat.db_socket);
1037 if (res->res_cat.db_user) {
1038 free(res->res_cat.db_user);
1040 if (res->res_cat.db_name) {
1041 free(res->res_cat.db_name);
1043 if (res->res_cat.db_password) {
1044 free(res->res_cat.db_password);
1048 if ((num=res->res_fs.num_includes)) {
1049 while (--num >= 0) {
1050 free_incexe(res->res_fs.include_items[num]);
1052 free(res->res_fs.include_items);
1054 res->res_fs.num_includes = 0;
1055 if ((num=res->res_fs.num_excludes)) {
1056 while (--num >= 0) {
1057 free_incexe(res->res_fs.exclude_items[num]);
1059 free(res->res_fs.exclude_items);
1061 res->res_fs.num_excludes = 0;
1064 if (res->res_pool.pool_type) {
1065 free(res->res_pool.pool_type);
1067 if (res->res_pool.label_format) {
1068 free(res->res_pool.label_format);
1070 if (res->res_pool.cleaning_prefix) {
1071 free(res->res_pool.cleaning_prefix);
1073 if (res->res_pool.storage) {
1074 delete res->res_pool.storage;
1078 if (res->res_sch.run) {
1080 nrun = res->res_sch.run;
1090 if (res->res_job.RestoreWhere) {
1091 free(res->res_job.RestoreWhere);
1093 if (res->res_job.RestoreBootstrap) {
1094 free(res->res_job.RestoreBootstrap);
1096 if (res->res_job.WriteBootstrap) {
1097 free(res->res_job.WriteBootstrap);
1099 if (res->res_job.RunBeforeJob) {
1100 free(res->res_job.RunBeforeJob);
1102 if (res->res_job.RunAfterJob) {
1103 free(res->res_job.RunAfterJob);
1105 if (res->res_job.RunAfterFailedJob) {
1106 free(res->res_job.RunAfterFailedJob);
1108 if (res->res_job.ClientRunBeforeJob) {
1109 free(res->res_job.ClientRunBeforeJob);
1111 if (res->res_job.ClientRunAfterJob) {
1112 free(res->res_job.ClientRunAfterJob);
1114 if (res->res_job.selection_pattern) {
1115 free(res->res_job.selection_pattern);
1117 if (res->res_job.run_cmds) {
1118 delete res->res_job.run_cmds;
1120 if (res->res_job.storage) {
1121 delete res->res_job.storage;
1125 if (res->res_msgs.mail_cmd) {
1126 free(res->res_msgs.mail_cmd);
1128 if (res->res_msgs.operator_cmd) {
1129 free(res->res_msgs.operator_cmd);
1131 free_msgs_res((MSGS *)res); /* free message resource */
1135 printf(_("Unknown resource type %d in free_resource.\n"), type);
1137 /* Common stuff again -- free the resource, recurse to next one */
1142 free_resource(nres, type);
1147 * Save the new resource by chaining it into the head list for
1148 * the resource. If this is pass 2, we update any resource
1149 * pointers because they may not have been defined until
1152 void save_resource(int type, RES_ITEM *items, int pass)
1155 int rindex = type - r_first;
1159 /* Check Job requirements after applying JobDefs */
1160 if (type != R_JOB && type != R_JOBDEFS) {
1162 * Ensure that all required items are present
1164 for (i=0; items[i].name; i++) {
1165 if (items[i].flags & ITEM_REQUIRED) {
1166 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1167 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1168 items[i].name, resources[rindex]);
1171 /* If this triggers, take a look at lib/parse_conf.h */
1172 if (i >= MAX_RES_ITEMS) {
1173 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1176 } else if (type == R_JOB) {
1178 * Ensure that the name item is present
1180 if (items[0].flags & ITEM_REQUIRED) {
1181 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1182 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1183 items[0].name, resources[rindex]);
1189 * During pass 2 in each "store" routine, we looked up pointers
1190 * to all the resources referrenced in the current resource, now we
1191 * must copy their addresses from the static record to the allocated
1196 /* Resources not containing a resource */
1204 * Resources containing another resource or alist. First
1205 * look up the resource which contains another resource. It
1206 * was written during pass 1. Then stuff in the pointers to
1207 * the resources it contains, which were inserted this pass.
1208 * Finally, it will all be stored back.
1211 /* Find resource saved in pass 1 */
1212 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1213 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1215 /* Explicitly copy resource pointers from this pass (res_all) */
1216 res->res_pool.NextPool = res_all.res_pool.NextPool;
1217 res->res_pool.storage = res_all.res_pool.storage;
1220 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1221 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1223 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1226 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1227 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1229 res->res_dir.messages = res_all.res_dir.messages;
1230 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1233 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1234 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1235 res_all.res_dir.hdr.name);
1237 /* we must explicitly copy the device alist pointer */
1238 res->res_store.device = res_all.res_store.device;
1242 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1243 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1244 res_all.res_dir.hdr.name);
1246 res->res_job.messages = res_all.res_job.messages;
1247 res->res_job.schedule = res_all.res_job.schedule;
1248 res->res_job.client = res_all.res_job.client;
1249 res->res_job.fileset = res_all.res_job.fileset;
1250 res->res_job.storage = res_all.res_job.storage;
1251 res->res_job.pool = res_all.res_job.pool;
1252 res->res_job.full_pool = res_all.res_job.full_pool;
1253 res->res_job.inc_pool = res_all.res_job.inc_pool;
1254 res->res_job.dif_pool = res_all.res_job.dif_pool;
1255 res->res_job.verify_job = res_all.res_job.verify_job;
1256 res->res_job.jobdefs = res_all.res_job.jobdefs;
1257 res->res_job.run_cmds = res_all.res_job.run_cmds;
1260 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1261 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1263 res->res_counter.Catalog = res_all.res_counter.Catalog;
1264 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1268 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1269 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1271 res->res_client.catalog = res_all.res_client.catalog;
1275 * Schedule is a bit different in that it contains a RUN record
1276 * chain which isn't a "named" resource. This chain was linked
1277 * in by run_conf.c during pass 2, so here we jam the pointer
1278 * into the Schedule resource.
1280 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1281 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1283 res->res_sch.run = res_all.res_sch.run;
1286 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1290 /* Note, the resource name was already saved during pass 1,
1291 * so here, we can just release it.
1293 if (res_all.res_dir.hdr.name) {
1294 free(res_all.res_dir.hdr.name);
1295 res_all.res_dir.hdr.name = NULL;
1297 if (res_all.res_dir.hdr.desc) {
1298 free(res_all.res_dir.hdr.desc);
1299 res_all.res_dir.hdr.desc = NULL;
1305 * The following code is only executed during pass 1
1309 size = sizeof(DIRRES);
1312 size = sizeof(CONRES);
1315 size =sizeof(CLIENT);
1318 size = sizeof(STORE);
1328 size = sizeof(FILESET);
1331 size = sizeof(SCHED);
1334 size = sizeof(POOL);
1337 size = sizeof(MSGS);
1340 size = sizeof(COUNTER);
1346 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1352 res = (URES *)malloc(size);
1353 memcpy(res, &res_all, size);
1354 if (!res_head[rindex]) {
1355 res_head[rindex] = (RES *)res; /* store first entry */
1356 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1357 res->res_dir.hdr.name, rindex);
1360 if (res->res_dir.hdr.name == NULL) {
1361 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1364 /* Add new res to end of chain */
1365 for (next=res_head[rindex]; next->next; next=next->next) {
1366 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1367 Emsg2(M_ERROR_TERM, 0,
1368 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1369 resources[rindex].name, res->res_dir.hdr.name);
1372 next->next = (RES *)res;
1373 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1374 res->res_dir.hdr.name, rindex, pass);
1380 * Store Device. Note, the resource is created upon the
1381 * first reference. The details of the resource are obtained
1382 * later from the SD.
1384 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1388 int rindex = R_DEVICE - r_first;
1389 int size = sizeof(DEVICE);
1393 token = lex_get_token(lc, T_NAME);
1394 if (!res_head[rindex]) {
1395 res = (URES *)malloc(size);
1396 memset(res, 0, size);
1397 res->res_dev.hdr.name = bstrdup(lc->str);
1398 res_head[rindex] = (RES *)res; /* store first entry */
1399 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1400 res->res_dir.hdr.name, rindex);
1403 /* See if it is already defined */
1404 for (next=res_head[rindex]; next->next; next=next->next) {
1405 if (strcmp(next->name, lc->str) == 0) {
1411 res = (URES *)malloc(size);
1412 memset(res, 0, size);
1413 res->res_dev.hdr.name = bstrdup(lc->str);
1414 next->next = (RES *)res;
1415 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1416 res->res_dir.hdr.name, rindex, pass);
1421 set_bit(index, res_all.hdr.item_present);
1423 store_alist_res(lc, item, index, pass);
1428 * Store JobType (backup, verify, restore)
1431 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1435 token = lex_get_token(lc, T_NAME);
1436 /* Store the type both pass 1 and pass 2 */
1437 for (i=0; migtypes[i].type_name; i++) {
1438 if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1439 *(int *)(item->value) = migtypes[i].job_type;
1445 scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1448 set_bit(index, res_all.hdr.item_present);
1454 * Store JobType (backup, verify, restore)
1457 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1461 token = lex_get_token(lc, T_NAME);
1462 /* Store the type both pass 1 and pass 2 */
1463 for (i=0; jobtypes[i].type_name; i++) {
1464 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1465 *(int *)(item->value) = jobtypes[i].job_type;
1471 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1474 set_bit(index, res_all.hdr.item_present);
1478 * Store Job Level (Full, Incremental, ...)
1481 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1485 token = lex_get_token(lc, T_NAME);
1486 /* Store the level pass 2 so that type is defined */
1487 for (i=0; joblevels[i].level_name; i++) {
1488 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1489 *(int *)(item->value) = joblevels[i].level;
1495 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1498 set_bit(index, res_all.hdr.item_present);
1502 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1505 token = lex_get_token(lc, T_NAME);
1506 /* Scan Replacement options */
1507 for (i=0; ReplaceOptions[i].name; i++) {
1508 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1509 *(int *)(item->value) = ReplaceOptions[i].token;
1515 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1518 set_bit(index, res_all.hdr.item_present);
1522 * Store ACL (access control list)
1525 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1530 token = lex_get_token(lc, T_NAME);
1532 if (((alist **)item->value)[item->code] == NULL) {
1533 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1534 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1536 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1537 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1539 token = lex_get_token(lc, T_ALL);
1540 if (token == T_COMMA) {
1541 continue; /* get another ACL */
1545 set_bit(index, res_all.hdr.item_present);