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-2005 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);
66 /* We build the current resource here as we are
67 * scanning the resource configuration definition,
68 * then move it to allocated memory when the resource
72 int res_all_size = sizeof(res_all);
75 /* Definition of records permitted within each
76 * resource with the routine to process the record
77 * information. NOTE! quoted names must be in lower case.
82 * name handler value code flags default_value
84 static RES_ITEM dir_items[] = {
85 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
86 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
87 {"messages", store_res, ITEM(res_dir.messages), R_MSGS, 0, 0},
88 {"dirport", store_addresses_port, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
89 {"diraddress", store_addresses_address, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
90 {"diraddresses",store_addresses, ITEM(res_dir.DIRaddrs), 0, ITEM_DEFAULT, 9101},
91 {"queryfile", store_dir, ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
92 {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
93 {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
94 {"piddirectory",store_dir, ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
95 {"subsysdirectory", store_dir, ITEM(res_dir.subsys_directory), 0, 0, 0},
96 {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
97 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
98 {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
99 {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
100 {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, 0, 0},
101 {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, 0, 0},
102 {"tlsverifypeer", store_yesno, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1},
103 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
104 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
105 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
106 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
107 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
108 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
109 {NULL, NULL, NULL, 0, 0, 0}
115 * name handler value code flags default_value
117 static RES_ITEM con_items[] = {
118 {"name", store_name, ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
119 {"description", store_str, ITEM(res_con.hdr.desc), 0, 0, 0},
120 {"password", store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
121 {"jobacl", store_acl, ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
122 {"clientacl", store_acl, ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
123 {"storageacl", store_acl, ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
124 {"scheduleacl", store_acl, ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
125 {"runacl", store_acl, ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
126 {"poolacl", store_acl, ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
127 {"commandacl", store_acl, ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
128 {"filesetacl", store_acl, ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
129 {"catalogacl", store_acl, ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
130 {"tlsenable", store_yesno, ITEM(res_con.tls_enable), 1, 0, 0},
131 {"tlsrequire", store_yesno, ITEM(res_con.tls_require), 1, 0, 0},
132 {"tlsverifypeer", store_yesno, ITEM(res_con.tls_verify_peer), 1, ITEM_DEFAULT, 1},
133 {"tlscacertificatefile", store_dir, ITEM(res_con.tls_ca_certfile), 0, 0, 0},
134 {"tlscacertificatedir", store_dir, ITEM(res_con.tls_ca_certdir), 0, 0, 0},
135 {"tlscertificate", store_dir, ITEM(res_con.tls_certfile), 0, 0, 0},
136 {"tlskey", store_dir, ITEM(res_con.tls_keyfile), 0, 0, 0},
137 {"tlsdhfile", store_dir, ITEM(res_con.tls_dhfile), 0, 0, 0},
138 {"tlsallowedcn", store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
139 {NULL, NULL, NULL, 0, 0, 0}
144 * Client or File daemon resource
146 * name handler value code flags default_value
149 static RES_ITEM cli_items[] = {
150 {"name", store_name, ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
151 {"description", store_str, ITEM(res_client.hdr.desc), 0, 0, 0},
152 {"address", store_str, ITEM(res_client.address), 0, ITEM_REQUIRED, 0},
153 {"fdaddress", store_str, ITEM(res_client.address), 0, 0, 0},
154 {"fdport", store_pint, ITEM(res_client.FDport), 0, ITEM_DEFAULT, 9102},
155 {"password", store_password, ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
156 {"fdpassword", store_password, ITEM(res_client.password), 0, 0, 0},
157 {"catalog", store_res, ITEM(res_client.catalog), R_CATALOG, ITEM_REQUIRED, 0},
158 {"fileretention", store_time, ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
159 {"jobretention", store_time, ITEM(res_client.JobRetention), 0, ITEM_DEFAULT, 60*60*24*180},
160 {"autoprune", store_yesno, ITEM(res_client.AutoPrune), 1, ITEM_DEFAULT, 1},
161 {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
162 {"tlsenable", store_yesno, ITEM(res_client.tls_enable), 1, 0, 0},
163 {"tlsrequire", store_yesno, ITEM(res_client.tls_require), 1, 0, 0},
164 {"tlscacertificatefile", store_dir, ITEM(res_client.tls_ca_certfile), 0, 0, 0},
165 {"tlscacertificatedir", store_dir, ITEM(res_client.tls_ca_certdir), 0, 0, 0},
166 {"tlscertificate", store_dir, ITEM(res_client.tls_certfile), 0, 0, 0},
167 {"tlskey", store_dir, ITEM(res_client.tls_keyfile), 0, 0, 0},
168 {NULL, NULL, NULL, 0, 0, 0}
171 /* Storage daemon resource
173 * name handler value code flags default_value
175 static RES_ITEM store_items[] = {
176 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
177 {"description", store_str, ITEM(res_store.hdr.desc), 0, 0, 0},
178 {"sdport", store_pint, ITEM(res_store.SDport), 0, ITEM_DEFAULT, 9103},
179 {"address", store_str, ITEM(res_store.address), 0, ITEM_REQUIRED, 0},
180 {"sdaddress", store_str, ITEM(res_store.address), 0, 0, 0},
181 {"password", store_password, ITEM(res_store.password), 0, ITEM_REQUIRED, 0},
182 {"sdpassword", store_password, ITEM(res_store.password), 0, 0, 0},
183 {"device", store_device, ITEM(res_store.device), R_DEVICE, ITEM_REQUIRED, 0},
184 {"mediatype", store_strname, ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
185 {"autochanger", store_yesno, ITEM(res_store.autochanger), 1, ITEM_DEFAULT, 0},
186 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
187 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
188 {"tlsenable", store_yesno, ITEM(res_store.tls_enable), 1, 0, 0},
189 {"tlsrequire", store_yesno, ITEM(res_store.tls_require), 1, 0, 0},
190 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
191 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
192 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
193 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
194 {NULL, NULL, NULL, 0, 0, 0}
198 * Catalog Resource Directives
200 * name handler value code flags default_value
202 static RES_ITEM cat_items[] = {
203 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
204 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
205 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
206 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
207 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
208 /* keep this password as store_str for the moment */
209 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
210 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
211 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
212 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
213 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
214 /* Turned off for the moment */
215 {"multipleconnections", store_yesno, ITEM(res_cat.mult_db_connections), 0, 0, 0},
216 {NULL, NULL, NULL, 0, 0, 0}
220 * Job Resource Directives
222 * name handler value code flags default_value
224 RES_ITEM job_items[] = {
225 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
226 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
227 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
228 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
229 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
230 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, ITEM_REQUIRED, 0},
231 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
232 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
233 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
234 {"differentialbackuppool", store_res, ITEM(res_job.dif_pool), R_POOL, 0, 0},
235 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
236 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
237 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
238 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
239 {"migrationjob", store_res, ITEM(res_job.migration_job), R_JOB, 0, 0},
240 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
241 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
242 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
243 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
244 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
245 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
246 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
247 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
248 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
249 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
250 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
251 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
252 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
253 {"prefixlinks", store_yesno, ITEM(res_job.PrefixLinks), 1, ITEM_DEFAULT, 0},
254 {"prunejobs", store_yesno, ITEM(res_job.PruneJobs), 1, ITEM_DEFAULT, 0},
255 {"prunefiles", store_yesno, ITEM(res_job.PruneFiles), 1, ITEM_DEFAULT, 0},
256 {"prunevolumes",store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0},
257 {"spoolattributes",store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0},
258 {"spooldata", store_yesno, ITEM(res_job.spool_data), 1, ITEM_DEFAULT, 0},
259 {"rerunfailedlevels", store_yesno, ITEM(res_job.rerun_failed_levels), 1, ITEM_DEFAULT, 0},
260 {"prefermountedvolumes", store_yesno, ITEM(res_job.PreferMountedVolumes), 1, ITEM_DEFAULT, 1},
261 {"runbeforejob", store_str, ITEM(res_job.RunBeforeJob), 0, 0, 0},
262 {"runafterjob", store_str, ITEM(res_job.RunAfterJob), 0, 0, 0},
263 {"runafterfailedjob", store_str, ITEM(res_job.RunAfterFailedJob), 0, 0, 0},
264 {"clientrunbeforejob", store_str, ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
265 {"clientrunafterjob", store_str, ITEM(res_job.ClientRunAfterJob), 0, 0, 0},
266 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
267 {"rescheduleonerror", store_yesno, ITEM(res_job.RescheduleOnError), 1, ITEM_DEFAULT, 0},
268 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
269 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
270 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
271 {"writepartafterjob", store_yesno, ITEM(res_job.write_part_after_job), 1, ITEM_DEFAULT, 0},
272 {NULL, NULL, NULL, 0, 0, 0}
277 * name handler value code flags default_value
279 static RES_ITEM fs_items[] = {
280 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
281 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
282 {"include", store_inc, NULL, 0, ITEM_NO_EQUALS, 0},
283 {"exclude", store_inc, NULL, 1, ITEM_NO_EQUALS, 0},
284 {"ignorefilesetchanges", store_yesno, ITEM(res_fs.ignore_fs_changes), 1, ITEM_DEFAULT, 0},
285 {"enablevss", store_yesno, ITEM(res_fs.enable_vss), 1, ITEM_DEFAULT, 0},
286 {NULL, NULL, NULL, 0, 0, 0}
289 /* Schedule -- see run_conf.c */
292 * name handler value code flags default_value
294 static RES_ITEM sch_items[] = {
295 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
296 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
297 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
298 {NULL, NULL, NULL, 0, 0, 0}
303 * name handler value code flags default_value
305 static RES_ITEM pool_items[] = {
306 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
307 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
308 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
309 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
310 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
311 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
312 {"usecatalog", store_yesno, ITEM(res_pool.use_catalog), 1, ITEM_DEFAULT, 1},
313 {"usevolumeonce", store_yesno, ITEM(res_pool.use_volume_once),1, 0, 0},
314 {"purgeoldestvolume", store_yesno, ITEM(res_pool.purge_oldest_volume), 1, 0, 0},
315 {"recycleoldestvolume", store_yesno, ITEM(res_pool.recycle_oldest_volume), 1, 0, 0},
316 {"recyclecurrentvolume", store_yesno, ITEM(res_pool.recycle_current_volume), 1, 0, 0},
317 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
318 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
319 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
320 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
321 {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, ITEM_DEFAULT, 1},
322 {"catalogfiles", store_yesno, ITEM(res_pool.catalog_files), 1, ITEM_DEFAULT, 1},
323 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
324 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
325 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
326 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
327 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
328 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
329 {"autoprune", store_yesno, ITEM(res_pool.AutoPrune), 1, ITEM_DEFAULT, 1},
330 {"recycle", store_yesno, ITEM(res_pool.Recycle), 1, ITEM_DEFAULT, 1},
331 {NULL, NULL, NULL, 0, 0, 0}
336 * name handler value code flags default_value
338 static RES_ITEM counter_items[] = {
339 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
340 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
341 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
342 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
343 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
344 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
345 {NULL, NULL, NULL, 0, 0, 0}
349 /* Message resource */
350 extern RES_ITEM msgs_items[];
353 * This is the master resource definition.
354 * It must have one item for each of the resources.
356 * NOTE!!! keep it in the same order as the R_codes
357 * or eliminate all resources[rindex].name
359 * name items rcode res_head
361 RES_TABLE resources[] = {
362 {"director", dir_items, R_DIRECTOR},
363 {"client", cli_items, R_CLIENT},
364 {"job", job_items, R_JOB},
365 {"storage", store_items, R_STORAGE},
366 {"catalog", cat_items, R_CATALOG},
367 {"schedule", sch_items, R_SCHEDULE},
368 {"fileset", fs_items, R_FILESET},
369 {"pool", pool_items, R_POOL},
370 {"messages", msgs_items, R_MSGS},
371 {"counter", counter_items, R_COUNTER},
372 {"console", con_items, R_CONSOLE},
373 {"jobdefs", job_items, R_JOBDEFS},
374 {"device", NULL, R_DEVICE}, /* info obtained from SD */
379 /* Keywords (RHS) permitted in Job Level records
381 * level_name level job_type
383 struct s_jl joblevels[] = {
384 {"Full", L_FULL, JT_BACKUP},
385 {"Base", L_BASE, JT_BACKUP},
386 {"Incremental", L_INCREMENTAL, JT_BACKUP},
387 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
388 {"Since", L_SINCE, JT_BACKUP},
389 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
390 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
391 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
392 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
393 {"Data", L_VERIFY_DATA, JT_VERIFY},
394 {" ", L_NONE, JT_ADMIN},
395 {" ", L_NONE, JT_RESTORE},
399 /* Keywords (RHS) permitted in Job type records
403 struct s_jt jobtypes[] = {
404 {"backup", JT_BACKUP},
406 {"verify", JT_VERIFY},
407 {"restore", JT_RESTORE},
409 {"migrate", JT_MIGRATE},
414 /* Options permitted in Restore replace= */
415 struct s_kw ReplaceOptions[] = {
416 {"always", REPLACE_ALWAYS},
417 {"ifnewer", REPLACE_IFNEWER},
418 {"ifolder", REPLACE_IFOLDER},
419 {"never", REPLACE_NEVER},
423 const char *level_to_str(int level)
426 static char level_no[30];
427 const char *str = level_no;
429 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
430 for (i=0; joblevels[i].level_name; i++) {
431 if (level == joblevels[i].level) {
432 str = joblevels[i].level_name;
439 /* Dump contents of resource */
440 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
442 URES *res = (URES *)reshdr;
444 char ed1[100], ed2[100], ed3[100];
448 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
451 if (type < 0) { /* no recursion */
457 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
458 reshdr->name, res->res_dir.MaxConcurrentJobs,
459 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
460 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
461 if (res->res_dir.query_file) {
462 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
464 if (res->res_dir.messages) {
465 sendit(sock, _(" --> "));
466 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
470 sendit(sock, _("Console: name=%s SSL=%d\n"),
471 res->res_con.hdr.name, res->res_con.tls_enable);
474 if (res->res_counter.WrapCounter) {
475 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
476 res->res_counter.hdr.name, res->res_counter.MinValue,
477 res->res_counter.MaxValue, res->res_counter.CurrentValue,
478 res->res_counter.WrapCounter->hdr.name);
480 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
481 res->res_counter.hdr.name, res->res_counter.MinValue,
482 res->res_counter.MaxValue);
484 if (res->res_counter.Catalog) {
485 sendit(sock, _(" --> "));
486 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
491 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
492 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
493 res->res_client.MaxConcurrentJobs);
494 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
495 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
496 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
497 res->res_client.AutoPrune);
498 if (res->res_client.catalog) {
499 sendit(sock, _(" --> "));
500 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
506 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
507 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
508 " poolid=%s volname=%s MediaType=%s\n"),
509 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
510 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
511 dev->offline, dev->autochanger,
512 edit_uint64(dev->PoolId, ed1),
513 dev->VolumeName, dev->MediaType);
516 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
517 " DeviceName=%s MediaType=%s StorageId=%s\n"),
518 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
519 res->res_store.MaxConcurrentJobs,
520 res->res_store.dev_name(),
521 res->res_store.media_type,
522 edit_int64(res->res_store.StorageId, ed1));
525 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
526 " db_user=%s MutliDBConn=%d\n"),
527 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
528 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
529 res->res_cat.mult_db_connections);
533 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d MaxJobs=%u\n"),
534 type == R_JOB ? _("Job") : _("JobDefs"),
535 res->res_job.hdr.name, res->res_job.JobType,
536 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
537 res->res_job.MaxConcurrentJobs);
538 sendit(sock, _(" Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
539 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
540 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
541 res->res_job.spool_data, res->res_job.write_part_after_job);
542 if (res->res_job.client) {
543 sendit(sock, _(" --> "));
544 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
546 if (res->res_job.fileset) {
547 sendit(sock, _(" --> "));
548 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
550 if (res->res_job.schedule) {
551 sendit(sock, _(" --> "));
552 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
554 if (res->res_job.RestoreWhere) {
555 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
557 if (res->res_job.RestoreBootstrap) {
558 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
560 if (res->res_job.RunBeforeJob) {
561 sendit(sock, _(" --> RunBefore=%s\n"), NPRT(res->res_job.RunBeforeJob));
563 if (res->res_job.RunAfterJob) {
564 sendit(sock, _(" --> RunAfter=%s\n"), NPRT(res->res_job.RunAfterJob));
566 if (res->res_job.RunAfterFailedJob) {
567 sendit(sock, _(" --> RunAfterFailed=%s\n"), NPRT(res->res_job.RunAfterFailedJob));
569 if (res->res_job.WriteBootstrap) {
570 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
572 if (res->res_job.storage) {
574 foreach_alist(store, res->res_job.storage) {
575 sendit(sock, _(" --> "));
576 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
579 if (res->res_job.pool) {
580 sendit(sock, _(" --> "));
581 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
583 if (res->res_job.full_pool) {
584 sendit(sock, _(" --> "));
585 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
587 if (res->res_job.inc_pool) {
588 sendit(sock, _(" --> "));
589 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
591 if (res->res_job.dif_pool) {
592 sendit(sock, _(" --> "));
593 dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock);
595 if (res->res_job.verify_job) {
596 sendit(sock, _(" --> "));
597 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
599 if (res->res_job.run_cmds) {
601 foreach_alist(runcmd, res->res_job.run_cmds) {
602 sendit(sock, _(" --> Run=%s\n"), runcmd);
605 if (res->res_job.messages) {
606 sendit(sock, _(" --> "));
607 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
613 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
614 for (i=0; i<res->res_fs.num_includes; i++) {
615 INCEXE *incexe = res->res_fs.include_items[i];
616 for (j=0; j<incexe->num_opts; j++) {
617 FOPTS *fo = incexe->opts_list[j];
618 sendit(sock, " O %s\n", fo->opts);
619 for (k=0; k<fo->regex.size(); k++) {
620 sendit(sock, " R %s\n", fo->regex.get(k));
622 for (k=0; k<fo->regexdir.size(); k++) {
623 sendit(sock, " RD %s\n", fo->regexdir.get(k));
625 for (k=0; k<fo->regexfile.size(); k++) {
626 sendit(sock, " RF %s\n", fo->regexfile.get(k));
628 for (k=0; k<fo->wild.size(); k++) {
629 sendit(sock, " W %s\n", fo->wild.get(k));
631 for (k=0; k<fo->wilddir.size(); k++) {
632 sendit(sock, " WD %s\n", fo->wilddir.get(k));
634 for (k=0; k<fo->wildfile.size(); k++) {
635 sendit(sock, " WF %s\n", fo->wildfile.get(k));
637 for (k=0; k<fo->base.size(); k++) {
638 sendit(sock, " B %s\n", fo->base.get(k));
640 for (k=0; k<fo->fstype.size(); k++) {
641 sendit(sock, " X %s\n", fo->fstype.get(k));
644 sendit(sock, " D %s\n", fo->reader);
647 sendit(sock, " T %s\n", fo->writer);
649 sendit(sock, " N\n");
651 for (j=0; j<incexe->name_list.size(); j++) {
652 sendit(sock, " I %s\n", incexe->name_list.get(j));
654 if (incexe->name_list.size()) {
655 sendit(sock, " N\n");
659 for (i=0; i<res->res_fs.num_excludes; i++) {
660 INCEXE *incexe = res->res_fs.exclude_items[i];
661 for (j=0; j<incexe->name_list.size(); j++) {
662 sendit(sock, " E %s\n", incexe->name_list.get(j));
664 if (incexe->name_list.size()) {
665 sendit(sock, " N\n");
671 if (res->res_sch.run) {
673 RUN *run = res->res_sch.run;
674 char buf[1000], num[30];
675 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
680 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
681 bstrncpy(buf, _(" hour="), sizeof(buf));
682 for (i=0; i<24; i++) {
683 if (bit_is_set(i, run->hour)) {
684 bsnprintf(num, sizeof(num), "%d ", i);
685 bstrncat(buf, num, sizeof(buf));
688 bstrncat(buf, "\n", sizeof(buf));
690 bstrncpy(buf, _(" mday="), sizeof(buf));
691 for (i=0; i<31; i++) {
692 if (bit_is_set(i, run->mday)) {
693 bsnprintf(num, sizeof(num), "%d ", i);
694 bstrncat(buf, num, sizeof(buf));
697 bstrncat(buf, "\n", sizeof(buf));
699 bstrncpy(buf, _(" month="), sizeof(buf));
700 for (i=0; i<12; i++) {
701 if (bit_is_set(i, run->month)) {
702 bsnprintf(num, sizeof(num), "%d ", i);
703 bstrncat(buf, num, sizeof(buf));
706 bstrncat(buf, "\n", sizeof(buf));
708 bstrncpy(buf, _(" wday="), sizeof(buf));
709 for (i=0; i<7; i++) {
710 if (bit_is_set(i, run->wday)) {
711 bsnprintf(num, sizeof(num), "%d ", i);
712 bstrncat(buf, num, sizeof(buf));
715 bstrncat(buf, "\n", sizeof(buf));
717 bstrncpy(buf, _(" wom="), sizeof(buf));
718 for (i=0; i<5; i++) {
719 if (bit_is_set(i, run->wom)) {
720 bsnprintf(num, sizeof(num), "%d ", i);
721 bstrncat(buf, num, sizeof(buf));
724 bstrncat(buf, "\n", sizeof(buf));
726 bstrncpy(buf, _(" woy="), sizeof(buf));
727 for (i=0; i<54; i++) {
728 if (bit_is_set(i, run->woy)) {
729 bsnprintf(num, sizeof(num), "%d ", i);
730 bstrncat(buf, num, sizeof(buf));
733 bstrncat(buf, "\n", sizeof(buf));
735 sendit(sock, _(" mins=%d\n"), run->minute);
737 sendit(sock, _(" --> "));
738 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
741 sendit(sock, _(" --> "));
742 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
745 sendit(sock, _(" --> "));
746 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
748 /* If another Run record is chained in, go print it */
754 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
758 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
759 res->res_pool.pool_type);
760 sendit(sock, _(" use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n"),
761 res->res_pool.use_catalog, res->res_pool.use_volume_once,
762 res->res_pool.accept_any_volume, res->res_pool.catalog_files);
763 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
764 res->res_pool.max_volumes, res->res_pool.AutoPrune,
765 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
766 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
767 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
768 res->res_pool.Recycle,
769 NPRT(res->res_pool.label_format));
770 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
771 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
772 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
773 res->res_pool.recycle_oldest_volume,
774 res->res_pool.purge_oldest_volume,
775 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
776 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
777 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
778 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
779 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
780 if (res->res_pool.NextPool) {
781 sendit(sock, _(" --> "));
782 dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
786 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
787 if (res->res_msgs.mail_cmd)
788 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
789 if (res->res_msgs.operator_cmd)
790 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
793 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
796 if (recurse && res->res_dir.hdr.next) {
797 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
802 * Free all the members of an INCEXE structure
804 static void free_incexe(INCEXE *incexe)
806 incexe->name_list.destroy();
807 for (int i=0; i<incexe->num_opts; i++) {
808 FOPTS *fopt = incexe->opts_list[i];
809 fopt->regex.destroy();
810 fopt->regexdir.destroy();
811 fopt->regexfile.destroy();
812 fopt->wild.destroy();
813 fopt->wilddir.destroy();
814 fopt->wildfile.destroy();
815 fopt->base.destroy();
816 fopt->fstype.destroy();
825 if (incexe->opts_list) {
826 free(incexe->opts_list);
832 * Free memory of resource -- called when daemon terminates.
833 * NB, we don't need to worry about freeing any references
834 * to other resources as they will be freed when that
835 * resource chain is traversed. Mainly we worry about freeing
836 * allocated strings (names).
838 void free_resource(RES *sres, int type)
841 RES *nres; /* next resource if linked */
842 URES *res = (URES *)sres;
847 /* common stuff -- free the resource name and description */
848 nres = (RES *)res->res_dir.hdr.next;
849 if (res->res_dir.hdr.name) {
850 free(res->res_dir.hdr.name);
852 if (res->res_dir.hdr.desc) {
853 free(res->res_dir.hdr.desc);
858 if (res->res_dir.working_directory) {
859 free(res->res_dir.working_directory);
861 if (res->res_dir.scripts_directory) {
862 free((char *)res->res_dir.scripts_directory);
864 if (res->res_dir.pid_directory) {
865 free(res->res_dir.pid_directory);
867 if (res->res_dir.subsys_directory) {
868 free(res->res_dir.subsys_directory);
870 if (res->res_dir.password) {
871 free(res->res_dir.password);
873 if (res->res_dir.query_file) {
874 free(res->res_dir.query_file);
876 if (res->res_dir.DIRaddrs) {
877 free_addresses(res->res_dir.DIRaddrs);
879 if (res->res_dir.tls_ctx) {
880 free_tls_context(res->res_dir.tls_ctx);
882 if (res->res_dir.tls_ca_certfile) {
883 free(res->res_dir.tls_ca_certfile);
885 if (res->res_dir.tls_ca_certdir) {
886 free(res->res_dir.tls_ca_certdir);
888 if (res->res_dir.tls_certfile) {
889 free(res->res_dir.tls_certfile);
891 if (res->res_dir.tls_keyfile) {
892 free(res->res_dir.tls_keyfile);
894 if (res->res_dir.tls_dhfile) {
895 free(res->res_dir.tls_dhfile);
897 if (res->res_dir.tls_allowed_cns) {
898 delete res->res_dir.tls_allowed_cns;
905 if (res->res_con.password) {
906 free(res->res_con.password);
908 if (res->res_con.tls_ctx) {
909 free_tls_context(res->res_con.tls_ctx);
911 if (res->res_con.tls_ca_certfile) {
912 free(res->res_con.tls_ca_certfile);
914 if (res->res_con.tls_ca_certdir) {
915 free(res->res_con.tls_ca_certdir);
917 if (res->res_con.tls_certfile) {
918 free(res->res_con.tls_certfile);
920 if (res->res_con.tls_keyfile) {
921 free(res->res_con.tls_keyfile);
923 if (res->res_con.tls_dhfile) {
924 free(res->res_con.tls_dhfile);
926 if (res->res_con.tls_allowed_cns) {
927 delete res->res_con.tls_allowed_cns;
929 for (int i=0; i<Num_ACL; i++) {
930 if (res->res_con.ACL_lists[i]) {
931 delete res->res_con.ACL_lists[i];
932 res->res_con.ACL_lists[i] = NULL;
937 if (res->res_client.address) {
938 free(res->res_client.address);
940 if (res->res_client.password) {
941 free(res->res_client.password);
943 if (res->res_client.tls_ctx) {
944 free_tls_context(res->res_client.tls_ctx);
946 if (res->res_client.tls_ca_certfile) {
947 free(res->res_client.tls_ca_certfile);
949 if (res->res_client.tls_ca_certdir) {
950 free(res->res_client.tls_ca_certdir);
952 if (res->res_client.tls_certfile) {
953 free(res->res_client.tls_certfile);
955 if (res->res_client.tls_keyfile) {
956 free(res->res_client.tls_keyfile);
960 if (res->res_store.address) {
961 free(res->res_store.address);
963 if (res->res_store.password) {
964 free(res->res_store.password);
966 if (res->res_store.media_type) {
967 free(res->res_store.media_type);
969 if (res->res_store.device) {
970 delete res->res_store.device;
972 if (res->res_store.tls_ctx) {
973 free_tls_context(res->res_store.tls_ctx);
975 if (res->res_store.tls_ca_certfile) {
976 free(res->res_store.tls_ca_certfile);
978 if (res->res_store.tls_ca_certdir) {
979 free(res->res_store.tls_ca_certdir);
981 if (res->res_store.tls_certfile) {
982 free(res->res_store.tls_certfile);
984 if (res->res_store.tls_keyfile) {
985 free(res->res_store.tls_keyfile);
989 if (res->res_cat.db_address) {
990 free(res->res_cat.db_address);
992 if (res->res_cat.db_socket) {
993 free(res->res_cat.db_socket);
995 if (res->res_cat.db_user) {
996 free(res->res_cat.db_user);
998 if (res->res_cat.db_name) {
999 free(res->res_cat.db_name);
1001 if (res->res_cat.db_password) {
1002 free(res->res_cat.db_password);
1006 if ((num=res->res_fs.num_includes)) {
1007 while (--num >= 0) {
1008 free_incexe(res->res_fs.include_items[num]);
1010 free(res->res_fs.include_items);
1012 res->res_fs.num_includes = 0;
1013 if ((num=res->res_fs.num_excludes)) {
1014 while (--num >= 0) {
1015 free_incexe(res->res_fs.exclude_items[num]);
1017 free(res->res_fs.exclude_items);
1019 res->res_fs.num_excludes = 0;
1022 if (res->res_pool.pool_type) {
1023 free(res->res_pool.pool_type);
1025 if (res->res_pool.label_format) {
1026 free(res->res_pool.label_format);
1028 if (res->res_pool.cleaning_prefix) {
1029 free(res->res_pool.cleaning_prefix);
1033 if (res->res_sch.run) {
1035 nrun = res->res_sch.run;
1045 if (res->res_job.RestoreWhere) {
1046 free(res->res_job.RestoreWhere);
1048 if (res->res_job.RestoreBootstrap) {
1049 free(res->res_job.RestoreBootstrap);
1051 if (res->res_job.WriteBootstrap) {
1052 free(res->res_job.WriteBootstrap);
1054 if (res->res_job.RunBeforeJob) {
1055 free(res->res_job.RunBeforeJob);
1057 if (res->res_job.RunAfterJob) {
1058 free(res->res_job.RunAfterJob);
1060 if (res->res_job.RunAfterFailedJob) {
1061 free(res->res_job.RunAfterFailedJob);
1063 if (res->res_job.ClientRunBeforeJob) {
1064 free(res->res_job.ClientRunBeforeJob);
1066 if (res->res_job.ClientRunAfterJob) {
1067 free(res->res_job.ClientRunAfterJob);
1069 if (res->res_job.run_cmds) {
1070 delete res->res_job.run_cmds;
1072 if (res->res_job.storage) {
1073 delete res->res_job.storage;
1077 if (res->res_msgs.mail_cmd) {
1078 free(res->res_msgs.mail_cmd);
1080 if (res->res_msgs.operator_cmd) {
1081 free(res->res_msgs.operator_cmd);
1083 free_msgs_res((MSGS *)res); /* free message resource */
1087 printf(_("Unknown resource type %d in free_resource.\n"), type);
1089 /* Common stuff again -- free the resource, recurse to next one */
1094 free_resource(nres, type);
1099 * Save the new resource by chaining it into the head list for
1100 * the resource. If this is pass 2, we update any resource
1101 * pointers because they may not have been defined until
1104 void save_resource(int type, RES_ITEM *items, int pass)
1107 int rindex = type - r_first;
1111 /* Check Job requirements after applying JobDefs */
1112 if (type != R_JOB && type != R_JOBDEFS) {
1114 * Ensure that all required items are present
1116 for (i=0; items[i].name; i++) {
1117 if (items[i].flags & ITEM_REQUIRED) {
1118 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1119 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1120 items[i].name, resources[rindex]);
1123 /* If this triggers, take a look at lib/parse_conf.h */
1124 if (i >= MAX_RES_ITEMS) {
1125 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1128 } else if (type == R_JOB) {
1130 * Ensure that the name item is present
1132 if (items[0].flags & ITEM_REQUIRED) {
1133 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1134 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1135 items[0].name, resources[rindex]);
1141 * During pass 2 in each "store" routine, we looked up pointers
1142 * to all the resources referrenced in the current resource, now we
1143 * must copy their addresses from the static record to the allocated
1148 /* Resources not containing a resource */
1156 * Resources containing another resource or alist. First
1157 * look up the resource which contains another resource. It
1158 * was written during pass 1. Then stuff in the pointers to
1159 * the resources it contains, which were inserted this pass.
1160 * Finally, it will all be stored back.
1163 /* Find resource saved in pass 1 */
1164 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1165 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1167 /* Update it with pointer to NextPool from this pass (res_all) */
1168 res->res_pool.NextPool = res_all.res_pool.NextPool;
1171 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1172 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1174 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1177 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1178 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1180 res->res_dir.messages = res_all.res_dir.messages;
1181 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1184 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1185 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1186 res_all.res_dir.hdr.name);
1188 /* we must explicitly copy the device alist pointer */
1189 res->res_store.device = res_all.res_store.device;
1193 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1194 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1195 res_all.res_dir.hdr.name);
1197 res->res_job.messages = res_all.res_job.messages;
1198 res->res_job.schedule = res_all.res_job.schedule;
1199 res->res_job.client = res_all.res_job.client;
1200 res->res_job.fileset = res_all.res_job.fileset;
1201 res->res_job.storage = res_all.res_job.storage;
1202 res->res_job.pool = res_all.res_job.pool;
1203 res->res_job.full_pool = res_all.res_job.full_pool;
1204 res->res_job.inc_pool = res_all.res_job.inc_pool;
1205 res->res_job.dif_pool = res_all.res_job.dif_pool;
1206 res->res_job.verify_job = res_all.res_job.verify_job;
1207 res->res_job.jobdefs = res_all.res_job.jobdefs;
1208 res->res_job.run_cmds = res_all.res_job.run_cmds;
1211 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1212 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1214 res->res_counter.Catalog = res_all.res_counter.Catalog;
1215 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1219 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1220 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1222 res->res_client.catalog = res_all.res_client.catalog;
1226 * Schedule is a bit different in that it contains a RUN record
1227 * chain which isn't a "named" resource. This chain was linked
1228 * in by run_conf.c during pass 2, so here we jam the pointer
1229 * into the Schedule resource.
1231 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1232 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1234 res->res_sch.run = res_all.res_sch.run;
1237 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1241 /* Note, the resource name was already saved during pass 1,
1242 * so here, we can just release it.
1244 if (res_all.res_dir.hdr.name) {
1245 free(res_all.res_dir.hdr.name);
1246 res_all.res_dir.hdr.name = NULL;
1248 if (res_all.res_dir.hdr.desc) {
1249 free(res_all.res_dir.hdr.desc);
1250 res_all.res_dir.hdr.desc = NULL;
1256 * The following code is only executed during pass 1
1260 size = sizeof(DIRRES);
1263 size = sizeof(CONRES);
1266 size =sizeof(CLIENT);
1269 size = sizeof(STORE);
1279 size = sizeof(FILESET);
1282 size = sizeof(SCHED);
1285 size = sizeof(POOL);
1288 size = sizeof(MSGS);
1291 size = sizeof(COUNTER);
1297 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1303 res = (URES *)malloc(size);
1304 memcpy(res, &res_all, size);
1305 if (!res_head[rindex]) {
1306 res_head[rindex] = (RES *)res; /* store first entry */
1307 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1308 res->res_dir.hdr.name, rindex);
1311 if (res->res_dir.hdr.name == NULL) {
1312 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1315 /* Add new res to end of chain */
1316 for (next=res_head[rindex]; next->next; next=next->next) {
1317 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1318 Emsg2(M_ERROR_TERM, 0,
1319 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1320 resources[rindex].name, res->res_dir.hdr.name);
1323 next->next = (RES *)res;
1324 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1325 res->res_dir.hdr.name, rindex, pass);
1331 * Store Device. Note, the resource is created upon the
1332 * first reference. The details of the resource are obtained
1333 * later from the SD.
1335 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1339 int rindex = R_DEVICE - r_first;
1340 int size = sizeof(DEVICE);
1344 token = lex_get_token(lc, T_NAME);
1345 if (!res_head[rindex]) {
1346 res = (URES *)malloc(size);
1347 memset(res, 0, size);
1348 res->res_dev.hdr.name = bstrdup(lc->str);
1349 res_head[rindex] = (RES *)res; /* store first entry */
1350 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1351 res->res_dir.hdr.name, rindex);
1354 /* See if it is already defined */
1355 for (next=res_head[rindex]; next->next; next=next->next) {
1356 if (strcmp(next->name, lc->str) == 0) {
1362 res = (URES *)malloc(size);
1363 memset(res, 0, size);
1364 res->res_dev.hdr.name = bstrdup(lc->str);
1365 next->next = (RES *)res;
1366 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1367 res->res_dir.hdr.name, rindex, pass);
1372 set_bit(index, res_all.hdr.item_present);
1374 store_alist_res(lc, item, index, pass);
1380 * Store JobType (backup, verify, restore)
1383 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1387 token = lex_get_token(lc, T_NAME);
1388 /* Store the type both pass 1 and pass 2 */
1389 for (i=0; jobtypes[i].type_name; i++) {
1390 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1391 *(int *)(item->value) = jobtypes[i].job_type;
1397 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1400 set_bit(index, res_all.hdr.item_present);
1404 * Store Job Level (Full, Incremental, ...)
1407 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1411 token = lex_get_token(lc, T_NAME);
1412 /* Store the level pass 2 so that type is defined */
1413 for (i=0; joblevels[i].level_name; i++) {
1414 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1415 *(int *)(item->value) = joblevels[i].level;
1421 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1424 set_bit(index, res_all.hdr.item_present);
1428 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1431 token = lex_get_token(lc, T_NAME);
1432 /* Scan Replacement options */
1433 for (i=0; ReplaceOptions[i].name; i++) {
1434 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1435 *(int *)(item->value) = ReplaceOptions[i].token;
1441 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1444 set_bit(index, res_all.hdr.item_present);
1448 * Store ACL (access control list)
1451 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1456 token = lex_get_token(lc, T_NAME);
1458 if (((alist **)item->value)[item->code] == NULL) {
1459 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1460 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1462 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1463 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1465 token = lex_get_token(lc, T_ALL);
1466 if (token == T_COMMA) {
1467 continue; /* get another ACL */
1471 set_bit(index, res_all.hdr.item_present);