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);
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 {"enabled", store_yesno, ITEM(res_store.enabled), 1, ITEM_DEFAULT, 1},
187 {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
188 {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
189 {"tlsenable", store_yesno, ITEM(res_store.tls_enable), 1, 0, 0},
190 {"tlsrequire", store_yesno, ITEM(res_store.tls_require), 1, 0, 0},
191 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
192 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
193 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
194 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
195 {NULL, NULL, NULL, 0, 0, 0}
199 * Catalog Resource Directives
201 * name handler value code flags default_value
203 static RES_ITEM cat_items[] = {
204 {"name", store_name, ITEM(res_cat.hdr.name), 0, ITEM_REQUIRED, 0},
205 {"description", store_str, ITEM(res_cat.hdr.desc), 0, 0, 0},
206 {"address", store_str, ITEM(res_cat.db_address), 0, 0, 0},
207 {"dbaddress", store_str, ITEM(res_cat.db_address), 0, 0, 0},
208 {"dbport", store_pint, ITEM(res_cat.db_port), 0, 0, 0},
209 /* keep this password as store_str for the moment */
210 {"password", store_str, ITEM(res_cat.db_password), 0, 0, 0},
211 {"dbpassword", store_str, ITEM(res_cat.db_password), 0, 0, 0},
212 {"user", store_str, ITEM(res_cat.db_user), 0, 0, 0},
213 {"dbname", store_str, ITEM(res_cat.db_name), 0, ITEM_REQUIRED, 0},
214 {"dbsocket", store_str, ITEM(res_cat.db_socket), 0, 0, 0},
215 /* Turned off for the moment */
216 {"multipleconnections", store_yesno, ITEM(res_cat.mult_db_connections), 0, 0, 0},
217 {NULL, NULL, NULL, 0, 0, 0}
221 * Job Resource Directives
223 * name handler value code flags default_value
225 RES_ITEM job_items[] = {
226 {"name", store_name, ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
227 {"description", store_str, ITEM(res_job.hdr.desc), 0, 0, 0},
228 {"type", store_jobtype, ITEM(res_job.JobType), 0, ITEM_REQUIRED, 0},
229 {"level", store_level, ITEM(res_job.JobLevel), 0, 0, 0},
230 {"messages", store_res, ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
231 {"storage", store_alist_res, ITEM(res_job.storage), R_STORAGE, ITEM_REQUIRED, 0},
232 {"pool", store_res, ITEM(res_job.pool), R_POOL, ITEM_REQUIRED, 0},
233 {"fullbackuppool", store_res, ITEM(res_job.full_pool), R_POOL, 0, 0},
234 {"incrementalbackuppool", store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
235 {"differentialbackuppool", store_res, ITEM(res_job.dif_pool), R_POOL, 0, 0},
236 {"client", store_res, ITEM(res_job.client), R_CLIENT, ITEM_REQUIRED, 0},
237 {"fileset", store_res, ITEM(res_job.fileset), R_FILESET, ITEM_REQUIRED, 0},
238 {"schedule", store_res, ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
239 {"verifyjob", store_res, ITEM(res_job.verify_job), R_JOB, 0, 0},
240 {"migrationjob", store_res, ITEM(res_job.migration_job), R_JOB, 0, 0},
241 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
242 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
243 /* Root of where to restore files */
244 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
245 /* Where to find bootstrap during restore */
246 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
247 /* Where to write bootstrap file during backup */
248 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
249 {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
250 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
251 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
252 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
253 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
254 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
255 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
256 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
257 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
258 {"prefixlinks", store_yesno, ITEM(res_job.PrefixLinks), 1, ITEM_DEFAULT, 0},
259 {"prunejobs", store_yesno, ITEM(res_job.PruneJobs), 1, ITEM_DEFAULT, 0},
260 {"prunefiles", store_yesno, ITEM(res_job.PruneFiles), 1, ITEM_DEFAULT, 0},
261 {"prunevolumes",store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0},
262 {"enabled", store_yesno, ITEM(res_job.enabled), 1, ITEM_DEFAULT, 1},
263 {"spoolattributes",store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0},
264 {"spooldata", store_yesno, ITEM(res_job.spool_data), 1, ITEM_DEFAULT, 0},
265 {"rerunfailedlevels", store_yesno, ITEM(res_job.rerun_failed_levels), 1, ITEM_DEFAULT, 0},
266 {"prefermountedvolumes", store_yesno, ITEM(res_job.PreferMountedVolumes), 1, ITEM_DEFAULT, 1},
267 {"runbeforejob", store_str, ITEM(res_job.RunBeforeJob), 0, 0, 0},
268 {"runafterjob", store_str, ITEM(res_job.RunAfterJob), 0, 0, 0},
269 {"runafterfailedjob", store_str, ITEM(res_job.RunAfterFailedJob), 0, 0, 0},
270 {"clientrunbeforejob", store_str, ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
271 {"clientrunafterjob", store_str, ITEM(res_job.ClientRunAfterJob), 0, 0, 0},
272 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
273 {"rescheduleonerror", store_yesno, ITEM(res_job.RescheduleOnError), 1, ITEM_DEFAULT, 0},
274 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
275 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
276 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
277 {"writepartafterjob", store_yesno, ITEM(res_job.write_part_after_job), 1, ITEM_DEFAULT, 0},
278 {NULL, NULL, NULL, 0, 0, 0}
283 * name handler value code flags default_value
285 static RES_ITEM fs_items[] = {
286 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
287 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
288 {"include", store_inc, NULL, 0, ITEM_NO_EQUALS, 0},
289 {"exclude", store_inc, NULL, 1, ITEM_NO_EQUALS, 0},
290 {"ignorefilesetchanges", store_yesno, ITEM(res_fs.ignore_fs_changes), 1, ITEM_DEFAULT, 0},
291 {"enablevss", store_yesno, ITEM(res_fs.enable_vss), 1, ITEM_DEFAULT, 0},
292 {NULL, NULL, NULL, 0, 0, 0}
295 /* Schedule -- see run_conf.c */
298 * name handler value code flags default_value
300 static RES_ITEM sch_items[] = {
301 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
302 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
303 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
304 {NULL, NULL, NULL, 0, 0, 0}
309 * name handler value code flags default_value
311 static RES_ITEM pool_items[] = {
312 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
313 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
314 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
315 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
316 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
317 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
318 {"usecatalog", store_yesno, ITEM(res_pool.use_catalog), 1, ITEM_DEFAULT, 1},
319 {"usevolumeonce", store_yesno, ITEM(res_pool.use_volume_once),1, 0, 0},
320 {"purgeoldestvolume", store_yesno, ITEM(res_pool.purge_oldest_volume), 1, 0, 0},
321 {"recycleoldestvolume", store_yesno, ITEM(res_pool.recycle_oldest_volume), 1, 0, 0},
322 {"recyclecurrentvolume", store_yesno, ITEM(res_pool.recycle_current_volume), 1, 0, 0},
323 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
324 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
325 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
326 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
327 {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, ITEM_DEFAULT, 1},
328 {"catalogfiles", store_yesno, ITEM(res_pool.catalog_files), 1, ITEM_DEFAULT, 1},
329 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
330 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
331 {"migrationtime", store_time, ITEM(res_pool.MigrationTime), 0, 0, 0},
332 {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
333 {"migrationlowbytes", store_size, ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
334 {"nextpool", store_res, ITEM(res_pool.NextPool), R_POOL, 0, 0},
335 {"storage", store_alist_res, ITEM(res_pool.storage), R_STORAGE, 0, 0},
336 {"autoprune", store_yesno, ITEM(res_pool.AutoPrune), 1, ITEM_DEFAULT, 1},
337 {"recycle", store_yesno, ITEM(res_pool.Recycle), 1, ITEM_DEFAULT, 1},
338 {NULL, NULL, NULL, 0, 0, 0}
343 * name handler value code flags default_value
345 static RES_ITEM counter_items[] = {
346 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
347 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
348 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
349 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
350 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
351 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
352 {NULL, NULL, NULL, 0, 0, 0}
356 /* Message resource */
357 extern RES_ITEM msgs_items[];
360 * This is the master resource definition.
361 * It must have one item for each of the resources.
363 * NOTE!!! keep it in the same order as the R_codes
364 * or eliminate all resources[rindex].name
366 * name items rcode res_head
368 RES_TABLE resources[] = {
369 {"director", dir_items, R_DIRECTOR},
370 {"client", cli_items, R_CLIENT},
371 {"job", job_items, R_JOB},
372 {"storage", store_items, R_STORAGE},
373 {"catalog", cat_items, R_CATALOG},
374 {"schedule", sch_items, R_SCHEDULE},
375 {"fileset", fs_items, R_FILESET},
376 {"pool", pool_items, R_POOL},
377 {"messages", msgs_items, R_MSGS},
378 {"counter", counter_items, R_COUNTER},
379 {"console", con_items, R_CONSOLE},
380 {"jobdefs", job_items, R_JOBDEFS},
381 {"device", NULL, R_DEVICE}, /* info obtained from SD */
386 /* Keywords (RHS) permitted in Job Level records
388 * level_name level job_type
390 struct s_jl joblevels[] = {
391 {"Full", L_FULL, JT_BACKUP},
392 {"Base", L_BASE, JT_BACKUP},
393 {"Incremental", L_INCREMENTAL, JT_BACKUP},
394 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
395 {"Since", L_SINCE, JT_BACKUP},
396 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
397 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
398 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
399 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
400 {"Data", L_VERIFY_DATA, JT_VERIFY},
401 {" ", L_NONE, JT_ADMIN},
402 {" ", L_NONE, JT_RESTORE},
406 /* Keywords (RHS) permitted in Job type records
410 struct s_jt jobtypes[] = {
411 {"backup", JT_BACKUP},
413 {"verify", JT_VERIFY},
414 {"restore", JT_RESTORE},
416 {"migrate", JT_MIGRATE},
421 /* Options permitted in Restore replace= */
422 struct s_kw ReplaceOptions[] = {
423 {"always", REPLACE_ALWAYS},
424 {"ifnewer", REPLACE_IFNEWER},
425 {"ifolder", REPLACE_IFOLDER},
426 {"never", REPLACE_NEVER},
430 const char *level_to_str(int level)
433 static char level_no[30];
434 const char *str = level_no;
436 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
437 for (i=0; joblevels[i].level_name; i++) {
438 if (level == joblevels[i].level) {
439 str = joblevels[i].level_name;
446 /* Dump contents of resource */
447 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
449 URES *res = (URES *)reshdr;
451 char ed1[100], ed2[100], ed3[100];
455 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
458 if (type < 0) { /* no recursion */
464 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
465 reshdr->name, res->res_dir.MaxConcurrentJobs,
466 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
467 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
468 if (res->res_dir.query_file) {
469 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
471 if (res->res_dir.messages) {
472 sendit(sock, _(" --> "));
473 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
477 sendit(sock, _("Console: name=%s SSL=%d\n"),
478 res->res_con.hdr.name, res->res_con.tls_enable);
481 if (res->res_counter.WrapCounter) {
482 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
483 res->res_counter.hdr.name, res->res_counter.MinValue,
484 res->res_counter.MaxValue, res->res_counter.CurrentValue,
485 res->res_counter.WrapCounter->hdr.name);
487 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
488 res->res_counter.hdr.name, res->res_counter.MinValue,
489 res->res_counter.MaxValue);
491 if (res->res_counter.Catalog) {
492 sendit(sock, _(" --> "));
493 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
498 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
499 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
500 res->res_client.MaxConcurrentJobs);
501 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
502 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
503 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
504 res->res_client.AutoPrune);
505 if (res->res_client.catalog) {
506 sendit(sock, _(" --> "));
507 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
513 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
514 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
515 " poolid=%s volname=%s MediaType=%s\n"),
516 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
517 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
518 dev->offline, dev->autochanger,
519 edit_uint64(dev->PoolId, ed1),
520 dev->VolumeName, dev->MediaType);
523 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
524 " DeviceName=%s MediaType=%s StorageId=%s\n"),
525 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
526 res->res_store.MaxConcurrentJobs,
527 res->res_store.dev_name(),
528 res->res_store.media_type,
529 edit_int64(res->res_store.StorageId, ed1));
532 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
533 " db_user=%s MutliDBConn=%d\n"),
534 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
535 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
536 res->res_cat.mult_db_connections);
540 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
541 type == R_JOB ? _("Job") : _("JobDefs"),
542 res->res_job.hdr.name, res->res_job.JobType,
543 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
544 res->res_job.enabled);
545 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
546 res->res_job.MaxConcurrentJobs,
547 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
548 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
549 res->res_job.spool_data, res->res_job.write_part_after_job);
550 if (res->res_job.client) {
551 sendit(sock, _(" --> "));
552 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
554 if (res->res_job.fileset) {
555 sendit(sock, _(" --> "));
556 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
558 if (res->res_job.schedule) {
559 sendit(sock, _(" --> "));
560 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
562 if (res->res_job.RestoreWhere) {
563 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
565 if (res->res_job.RestoreBootstrap) {
566 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
568 if (res->res_job.RunBeforeJob) {
569 sendit(sock, _(" --> RunBefore=%s\n"), NPRT(res->res_job.RunBeforeJob));
571 if (res->res_job.RunAfterJob) {
572 sendit(sock, _(" --> RunAfter=%s\n"), NPRT(res->res_job.RunAfterJob));
574 if (res->res_job.RunAfterFailedJob) {
575 sendit(sock, _(" --> RunAfterFailed=%s\n"), NPRT(res->res_job.RunAfterFailedJob));
577 if (res->res_job.WriteBootstrap) {
578 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
580 if (res->res_job.storage) {
582 foreach_alist(store, res->res_job.storage) {
583 sendit(sock, _(" --> "));
584 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
587 if (res->res_job.pool) {
588 sendit(sock, _(" --> "));
589 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
591 if (res->res_job.full_pool) {
592 sendit(sock, _(" --> "));
593 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
595 if (res->res_job.inc_pool) {
596 sendit(sock, _(" --> "));
597 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
599 if (res->res_job.dif_pool) {
600 sendit(sock, _(" --> "));
601 dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock);
603 if (res->res_job.verify_job) {
604 sendit(sock, _(" --> "));
605 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
607 if (res->res_job.run_cmds) {
609 foreach_alist(runcmd, res->res_job.run_cmds) {
610 sendit(sock, _(" --> Run=%s\n"), runcmd);
613 if (res->res_job.messages) {
614 sendit(sock, _(" --> "));
615 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
621 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
622 for (i=0; i<res->res_fs.num_includes; i++) {
623 INCEXE *incexe = res->res_fs.include_items[i];
624 for (j=0; j<incexe->num_opts; j++) {
625 FOPTS *fo = incexe->opts_list[j];
626 sendit(sock, " O %s\n", fo->opts);
627 for (k=0; k<fo->regex.size(); k++) {
628 sendit(sock, " R %s\n", fo->regex.get(k));
630 for (k=0; k<fo->regexdir.size(); k++) {
631 sendit(sock, " RD %s\n", fo->regexdir.get(k));
633 for (k=0; k<fo->regexfile.size(); k++) {
634 sendit(sock, " RF %s\n", fo->regexfile.get(k));
636 for (k=0; k<fo->wild.size(); k++) {
637 sendit(sock, " W %s\n", fo->wild.get(k));
639 for (k=0; k<fo->wilddir.size(); k++) {
640 sendit(sock, " WD %s\n", fo->wilddir.get(k));
642 for (k=0; k<fo->wildfile.size(); k++) {
643 sendit(sock, " WF %s\n", fo->wildfile.get(k));
645 for (k=0; k<fo->base.size(); k++) {
646 sendit(sock, " B %s\n", fo->base.get(k));
648 for (k=0; k<fo->fstype.size(); k++) {
649 sendit(sock, " X %s\n", fo->fstype.get(k));
652 sendit(sock, " D %s\n", fo->reader);
655 sendit(sock, " T %s\n", fo->writer);
657 sendit(sock, " N\n");
659 for (j=0; j<incexe->name_list.size(); j++) {
660 sendit(sock, " I %s\n", incexe->name_list.get(j));
662 if (incexe->name_list.size()) {
663 sendit(sock, " N\n");
667 for (i=0; i<res->res_fs.num_excludes; i++) {
668 INCEXE *incexe = res->res_fs.exclude_items[i];
669 for (j=0; j<incexe->name_list.size(); j++) {
670 sendit(sock, " E %s\n", incexe->name_list.get(j));
672 if (incexe->name_list.size()) {
673 sendit(sock, " N\n");
679 if (res->res_sch.run) {
681 RUN *run = res->res_sch.run;
682 char buf[1000], num[30];
683 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
688 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
689 bstrncpy(buf, _(" hour="), sizeof(buf));
690 for (i=0; i<24; i++) {
691 if (bit_is_set(i, run->hour)) {
692 bsnprintf(num, sizeof(num), "%d ", i);
693 bstrncat(buf, num, sizeof(buf));
696 bstrncat(buf, "\n", sizeof(buf));
698 bstrncpy(buf, _(" mday="), sizeof(buf));
699 for (i=0; i<31; i++) {
700 if (bit_is_set(i, run->mday)) {
701 bsnprintf(num, sizeof(num), "%d ", i);
702 bstrncat(buf, num, sizeof(buf));
705 bstrncat(buf, "\n", sizeof(buf));
707 bstrncpy(buf, _(" month="), sizeof(buf));
708 for (i=0; i<12; i++) {
709 if (bit_is_set(i, run->month)) {
710 bsnprintf(num, sizeof(num), "%d ", i);
711 bstrncat(buf, num, sizeof(buf));
714 bstrncat(buf, "\n", sizeof(buf));
716 bstrncpy(buf, _(" wday="), sizeof(buf));
717 for (i=0; i<7; i++) {
718 if (bit_is_set(i, run->wday)) {
719 bsnprintf(num, sizeof(num), "%d ", i);
720 bstrncat(buf, num, sizeof(buf));
723 bstrncat(buf, "\n", sizeof(buf));
725 bstrncpy(buf, _(" wom="), sizeof(buf));
726 for (i=0; i<5; i++) {
727 if (bit_is_set(i, run->wom)) {
728 bsnprintf(num, sizeof(num), "%d ", i);
729 bstrncat(buf, num, sizeof(buf));
732 bstrncat(buf, "\n", sizeof(buf));
734 bstrncpy(buf, _(" woy="), sizeof(buf));
735 for (i=0; i<54; i++) {
736 if (bit_is_set(i, run->woy)) {
737 bsnprintf(num, sizeof(num), "%d ", i);
738 bstrncat(buf, num, sizeof(buf));
741 bstrncat(buf, "\n", sizeof(buf));
743 sendit(sock, _(" mins=%d\n"), run->minute);
745 sendit(sock, _(" --> "));
746 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
749 sendit(sock, _(" --> "));
750 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
753 sendit(sock, _(" --> "));
754 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
756 /* If another Run record is chained in, go print it */
762 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
766 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
767 res->res_pool.pool_type);
768 sendit(sock, _(" use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n"),
769 res->res_pool.use_catalog, res->res_pool.use_volume_once,
770 res->res_pool.accept_any_volume, res->res_pool.catalog_files);
771 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
772 res->res_pool.max_volumes, res->res_pool.AutoPrune,
773 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
774 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
775 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
776 res->res_pool.Recycle,
777 NPRT(res->res_pool.label_format));
778 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
779 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
780 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
781 res->res_pool.recycle_oldest_volume,
782 res->res_pool.purge_oldest_volume,
783 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
784 sendit(sock, _(" MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
785 edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
786 edit_uint64(res->res_pool.MigrationHighBytes, ed2),
787 edit_uint64(res->res_pool.MigrationLowBytes, ed3));
788 if (res->res_pool.NextPool) {
789 sendit(sock, _(" --> "));
790 dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
792 if (res->res_pool.storage) {
794 foreach_alist(store, res->res_pool.storage) {
795 sendit(sock, _(" --> "));
796 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
801 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
802 if (res->res_msgs.mail_cmd)
803 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
804 if (res->res_msgs.operator_cmd)
805 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
808 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
811 if (recurse && res->res_dir.hdr.next) {
812 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
817 * Free all the members of an INCEXE structure
819 static void free_incexe(INCEXE *incexe)
821 incexe->name_list.destroy();
822 for (int i=0; i<incexe->num_opts; i++) {
823 FOPTS *fopt = incexe->opts_list[i];
824 fopt->regex.destroy();
825 fopt->regexdir.destroy();
826 fopt->regexfile.destroy();
827 fopt->wild.destroy();
828 fopt->wilddir.destroy();
829 fopt->wildfile.destroy();
830 fopt->base.destroy();
831 fopt->fstype.destroy();
840 if (incexe->opts_list) {
841 free(incexe->opts_list);
847 * Free memory of resource -- called when daemon terminates.
848 * NB, we don't need to worry about freeing any references
849 * to other resources as they will be freed when that
850 * resource chain is traversed. Mainly we worry about freeing
851 * allocated strings (names).
853 void free_resource(RES *sres, int type)
856 RES *nres; /* next resource if linked */
857 URES *res = (URES *)sres;
862 /* common stuff -- free the resource name and description */
863 nres = (RES *)res->res_dir.hdr.next;
864 if (res->res_dir.hdr.name) {
865 free(res->res_dir.hdr.name);
867 if (res->res_dir.hdr.desc) {
868 free(res->res_dir.hdr.desc);
873 if (res->res_dir.working_directory) {
874 free(res->res_dir.working_directory);
876 if (res->res_dir.scripts_directory) {
877 free((char *)res->res_dir.scripts_directory);
879 if (res->res_dir.pid_directory) {
880 free(res->res_dir.pid_directory);
882 if (res->res_dir.subsys_directory) {
883 free(res->res_dir.subsys_directory);
885 if (res->res_dir.password) {
886 free(res->res_dir.password);
888 if (res->res_dir.query_file) {
889 free(res->res_dir.query_file);
891 if (res->res_dir.DIRaddrs) {
892 free_addresses(res->res_dir.DIRaddrs);
894 if (res->res_dir.tls_ctx) {
895 free_tls_context(res->res_dir.tls_ctx);
897 if (res->res_dir.tls_ca_certfile) {
898 free(res->res_dir.tls_ca_certfile);
900 if (res->res_dir.tls_ca_certdir) {
901 free(res->res_dir.tls_ca_certdir);
903 if (res->res_dir.tls_certfile) {
904 free(res->res_dir.tls_certfile);
906 if (res->res_dir.tls_keyfile) {
907 free(res->res_dir.tls_keyfile);
909 if (res->res_dir.tls_dhfile) {
910 free(res->res_dir.tls_dhfile);
912 if (res->res_dir.tls_allowed_cns) {
913 delete res->res_dir.tls_allowed_cns;
920 if (res->res_con.password) {
921 free(res->res_con.password);
923 if (res->res_con.tls_ctx) {
924 free_tls_context(res->res_con.tls_ctx);
926 if (res->res_con.tls_ca_certfile) {
927 free(res->res_con.tls_ca_certfile);
929 if (res->res_con.tls_ca_certdir) {
930 free(res->res_con.tls_ca_certdir);
932 if (res->res_con.tls_certfile) {
933 free(res->res_con.tls_certfile);
935 if (res->res_con.tls_keyfile) {
936 free(res->res_con.tls_keyfile);
938 if (res->res_con.tls_dhfile) {
939 free(res->res_con.tls_dhfile);
941 if (res->res_con.tls_allowed_cns) {
942 delete res->res_con.tls_allowed_cns;
944 for (int i=0; i<Num_ACL; i++) {
945 if (res->res_con.ACL_lists[i]) {
946 delete res->res_con.ACL_lists[i];
947 res->res_con.ACL_lists[i] = NULL;
952 if (res->res_client.address) {
953 free(res->res_client.address);
955 if (res->res_client.password) {
956 free(res->res_client.password);
958 if (res->res_client.tls_ctx) {
959 free_tls_context(res->res_client.tls_ctx);
961 if (res->res_client.tls_ca_certfile) {
962 free(res->res_client.tls_ca_certfile);
964 if (res->res_client.tls_ca_certdir) {
965 free(res->res_client.tls_ca_certdir);
967 if (res->res_client.tls_certfile) {
968 free(res->res_client.tls_certfile);
970 if (res->res_client.tls_keyfile) {
971 free(res->res_client.tls_keyfile);
975 if (res->res_store.address) {
976 free(res->res_store.address);
978 if (res->res_store.password) {
979 free(res->res_store.password);
981 if (res->res_store.media_type) {
982 free(res->res_store.media_type);
984 if (res->res_store.device) {
985 delete res->res_store.device;
987 if (res->res_store.tls_ctx) {
988 free_tls_context(res->res_store.tls_ctx);
990 if (res->res_store.tls_ca_certfile) {
991 free(res->res_store.tls_ca_certfile);
993 if (res->res_store.tls_ca_certdir) {
994 free(res->res_store.tls_ca_certdir);
996 if (res->res_store.tls_certfile) {
997 free(res->res_store.tls_certfile);
999 if (res->res_store.tls_keyfile) {
1000 free(res->res_store.tls_keyfile);
1004 if (res->res_cat.db_address) {
1005 free(res->res_cat.db_address);
1007 if (res->res_cat.db_socket) {
1008 free(res->res_cat.db_socket);
1010 if (res->res_cat.db_user) {
1011 free(res->res_cat.db_user);
1013 if (res->res_cat.db_name) {
1014 free(res->res_cat.db_name);
1016 if (res->res_cat.db_password) {
1017 free(res->res_cat.db_password);
1021 if ((num=res->res_fs.num_includes)) {
1022 while (--num >= 0) {
1023 free_incexe(res->res_fs.include_items[num]);
1025 free(res->res_fs.include_items);
1027 res->res_fs.num_includes = 0;
1028 if ((num=res->res_fs.num_excludes)) {
1029 while (--num >= 0) {
1030 free_incexe(res->res_fs.exclude_items[num]);
1032 free(res->res_fs.exclude_items);
1034 res->res_fs.num_excludes = 0;
1037 if (res->res_pool.pool_type) {
1038 free(res->res_pool.pool_type);
1040 if (res->res_pool.label_format) {
1041 free(res->res_pool.label_format);
1043 if (res->res_pool.cleaning_prefix) {
1044 free(res->res_pool.cleaning_prefix);
1046 if (res->res_pool.storage) {
1047 delete res->res_pool.storage;
1051 if (res->res_sch.run) {
1053 nrun = res->res_sch.run;
1063 if (res->res_job.RestoreWhere) {
1064 free(res->res_job.RestoreWhere);
1066 if (res->res_job.RestoreBootstrap) {
1067 free(res->res_job.RestoreBootstrap);
1069 if (res->res_job.WriteBootstrap) {
1070 free(res->res_job.WriteBootstrap);
1072 if (res->res_job.RunBeforeJob) {
1073 free(res->res_job.RunBeforeJob);
1075 if (res->res_job.RunAfterJob) {
1076 free(res->res_job.RunAfterJob);
1078 if (res->res_job.RunAfterFailedJob) {
1079 free(res->res_job.RunAfterFailedJob);
1081 if (res->res_job.ClientRunBeforeJob) {
1082 free(res->res_job.ClientRunBeforeJob);
1084 if (res->res_job.ClientRunAfterJob) {
1085 free(res->res_job.ClientRunAfterJob);
1087 if (res->res_job.run_cmds) {
1088 delete res->res_job.run_cmds;
1090 if (res->res_job.storage) {
1091 delete res->res_job.storage;
1095 if (res->res_msgs.mail_cmd) {
1096 free(res->res_msgs.mail_cmd);
1098 if (res->res_msgs.operator_cmd) {
1099 free(res->res_msgs.operator_cmd);
1101 free_msgs_res((MSGS *)res); /* free message resource */
1105 printf(_("Unknown resource type %d in free_resource.\n"), type);
1107 /* Common stuff again -- free the resource, recurse to next one */
1112 free_resource(nres, type);
1117 * Save the new resource by chaining it into the head list for
1118 * the resource. If this is pass 2, we update any resource
1119 * pointers because they may not have been defined until
1122 void save_resource(int type, RES_ITEM *items, int pass)
1125 int rindex = type - r_first;
1129 /* Check Job requirements after applying JobDefs */
1130 if (type != R_JOB && type != R_JOBDEFS) {
1132 * Ensure that all required items are present
1134 for (i=0; items[i].name; i++) {
1135 if (items[i].flags & ITEM_REQUIRED) {
1136 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1137 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1138 items[i].name, resources[rindex]);
1141 /* If this triggers, take a look at lib/parse_conf.h */
1142 if (i >= MAX_RES_ITEMS) {
1143 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1146 } else if (type == R_JOB) {
1148 * Ensure that the name item is present
1150 if (items[0].flags & ITEM_REQUIRED) {
1151 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1152 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1153 items[0].name, resources[rindex]);
1159 * During pass 2 in each "store" routine, we looked up pointers
1160 * to all the resources referrenced in the current resource, now we
1161 * must copy their addresses from the static record to the allocated
1166 /* Resources not containing a resource */
1174 * Resources containing another resource or alist. First
1175 * look up the resource which contains another resource. It
1176 * was written during pass 1. Then stuff in the pointers to
1177 * the resources it contains, which were inserted this pass.
1178 * Finally, it will all be stored back.
1181 /* Find resource saved in pass 1 */
1182 if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1183 Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1185 /* Explicitly copy resource pointers from this pass (res_all) */
1186 res->res_pool.NextPool = res_all.res_pool.NextPool;
1187 res->res_pool.storage = res_all.res_pool.storage;
1190 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1191 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1193 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1196 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1197 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1199 res->res_dir.messages = res_all.res_dir.messages;
1200 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1203 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1204 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1205 res_all.res_dir.hdr.name);
1207 /* we must explicitly copy the device alist pointer */
1208 res->res_store.device = res_all.res_store.device;
1212 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1213 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1214 res_all.res_dir.hdr.name);
1216 res->res_job.messages = res_all.res_job.messages;
1217 res->res_job.schedule = res_all.res_job.schedule;
1218 res->res_job.client = res_all.res_job.client;
1219 res->res_job.fileset = res_all.res_job.fileset;
1220 res->res_job.storage = res_all.res_job.storage;
1221 res->res_job.pool = res_all.res_job.pool;
1222 res->res_job.full_pool = res_all.res_job.full_pool;
1223 res->res_job.inc_pool = res_all.res_job.inc_pool;
1224 res->res_job.dif_pool = res_all.res_job.dif_pool;
1225 res->res_job.verify_job = res_all.res_job.verify_job;
1226 res->res_job.jobdefs = res_all.res_job.jobdefs;
1227 res->res_job.run_cmds = res_all.res_job.run_cmds;
1230 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1231 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1233 res->res_counter.Catalog = res_all.res_counter.Catalog;
1234 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1238 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1239 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1241 res->res_client.catalog = res_all.res_client.catalog;
1245 * Schedule is a bit different in that it contains a RUN record
1246 * chain which isn't a "named" resource. This chain was linked
1247 * in by run_conf.c during pass 2, so here we jam the pointer
1248 * into the Schedule resource.
1250 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1251 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1253 res->res_sch.run = res_all.res_sch.run;
1256 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1260 /* Note, the resource name was already saved during pass 1,
1261 * so here, we can just release it.
1263 if (res_all.res_dir.hdr.name) {
1264 free(res_all.res_dir.hdr.name);
1265 res_all.res_dir.hdr.name = NULL;
1267 if (res_all.res_dir.hdr.desc) {
1268 free(res_all.res_dir.hdr.desc);
1269 res_all.res_dir.hdr.desc = NULL;
1275 * The following code is only executed during pass 1
1279 size = sizeof(DIRRES);
1282 size = sizeof(CONRES);
1285 size =sizeof(CLIENT);
1288 size = sizeof(STORE);
1298 size = sizeof(FILESET);
1301 size = sizeof(SCHED);
1304 size = sizeof(POOL);
1307 size = sizeof(MSGS);
1310 size = sizeof(COUNTER);
1316 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1322 res = (URES *)malloc(size);
1323 memcpy(res, &res_all, size);
1324 if (!res_head[rindex]) {
1325 res_head[rindex] = (RES *)res; /* store first entry */
1326 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1327 res->res_dir.hdr.name, rindex);
1330 if (res->res_dir.hdr.name == NULL) {
1331 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1334 /* Add new res to end of chain */
1335 for (next=res_head[rindex]; next->next; next=next->next) {
1336 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1337 Emsg2(M_ERROR_TERM, 0,
1338 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1339 resources[rindex].name, res->res_dir.hdr.name);
1342 next->next = (RES *)res;
1343 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1344 res->res_dir.hdr.name, rindex, pass);
1350 * Store Device. Note, the resource is created upon the
1351 * first reference. The details of the resource are obtained
1352 * later from the SD.
1354 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1358 int rindex = R_DEVICE - r_first;
1359 int size = sizeof(DEVICE);
1363 token = lex_get_token(lc, T_NAME);
1364 if (!res_head[rindex]) {
1365 res = (URES *)malloc(size);
1366 memset(res, 0, size);
1367 res->res_dev.hdr.name = bstrdup(lc->str);
1368 res_head[rindex] = (RES *)res; /* store first entry */
1369 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1370 res->res_dir.hdr.name, rindex);
1373 /* See if it is already defined */
1374 for (next=res_head[rindex]; next->next; next=next->next) {
1375 if (strcmp(next->name, lc->str) == 0) {
1381 res = (URES *)malloc(size);
1382 memset(res, 0, size);
1383 res->res_dev.hdr.name = bstrdup(lc->str);
1384 next->next = (RES *)res;
1385 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1386 res->res_dir.hdr.name, rindex, pass);
1391 set_bit(index, res_all.hdr.item_present);
1393 store_alist_res(lc, item, index, pass);
1399 * Store JobType (backup, verify, restore)
1402 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1406 token = lex_get_token(lc, T_NAME);
1407 /* Store the type both pass 1 and pass 2 */
1408 for (i=0; jobtypes[i].type_name; i++) {
1409 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1410 *(int *)(item->value) = jobtypes[i].job_type;
1416 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1419 set_bit(index, res_all.hdr.item_present);
1423 * Store Job Level (Full, Incremental, ...)
1426 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1430 token = lex_get_token(lc, T_NAME);
1431 /* Store the level pass 2 so that type is defined */
1432 for (i=0; joblevels[i].level_name; i++) {
1433 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1434 *(int *)(item->value) = joblevels[i].level;
1440 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1443 set_bit(index, res_all.hdr.item_present);
1447 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1450 token = lex_get_token(lc, T_NAME);
1451 /* Scan Replacement options */
1452 for (i=0; ReplaceOptions[i].name; i++) {
1453 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1454 *(int *)(item->value) = ReplaceOptions[i].token;
1460 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1463 set_bit(index, res_all.hdr.item_present);
1467 * Store ACL (access control list)
1470 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1475 token = lex_get_token(lc, T_NAME);
1477 if (((alist **)item->value)[item->code] == NULL) {
1478 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1479 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1481 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1482 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1484 token = lex_get_token(lc, T_ALL);
1485 if (token == T_COMMA) {
1486 continue; /* get another ACL */
1490 set_bit(index, res_all.hdr.item_present);