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 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
240 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
241 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
242 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
243 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
244 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
245 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
246 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
247 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
248 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
249 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
250 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
251 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
252 {"prefixlinks", store_yesno, ITEM(res_job.PrefixLinks), 1, ITEM_DEFAULT, 0},
253 {"prunejobs", store_yesno, ITEM(res_job.PruneJobs), 1, ITEM_DEFAULT, 0},
254 {"prunefiles", store_yesno, ITEM(res_job.PruneFiles), 1, ITEM_DEFAULT, 0},
255 {"prunevolumes",store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0},
256 {"spoolattributes",store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0},
257 {"spooldata", store_yesno, ITEM(res_job.spool_data), 1, ITEM_DEFAULT, 0},
258 {"rerunfailedlevels", store_yesno, ITEM(res_job.rerun_failed_levels), 1, ITEM_DEFAULT, 0},
259 {"prefermountedvolumes", store_yesno, ITEM(res_job.PreferMountedVolumes), 1, ITEM_DEFAULT, 1},
260 {"runbeforejob", store_str, ITEM(res_job.RunBeforeJob), 0, 0, 0},
261 {"runafterjob", store_str, ITEM(res_job.RunAfterJob), 0, 0, 0},
262 {"runafterfailedjob", store_str, ITEM(res_job.RunAfterFailedJob), 0, 0, 0},
263 {"clientrunbeforejob", store_str, ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
264 {"clientrunafterjob", store_str, ITEM(res_job.ClientRunAfterJob), 0, 0, 0},
265 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
266 {"rescheduleonerror", store_yesno, ITEM(res_job.RescheduleOnError), 1, ITEM_DEFAULT, 0},
267 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
268 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
269 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
270 {"writepartafterjob", store_yesno, ITEM(res_job.write_part_after_job), 1, ITEM_DEFAULT, 0},
271 {NULL, NULL, NULL, 0, 0, 0}
276 * name handler value code flags default_value
278 static RES_ITEM fs_items[] = {
279 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
280 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
281 {"include", store_inc, NULL, 0, ITEM_NO_EQUALS, 0},
282 {"exclude", store_inc, NULL, 1, ITEM_NO_EQUALS, 0},
283 {"ignorefilesetchanges", store_yesno, ITEM(res_fs.ignore_fs_changes), 1, ITEM_DEFAULT, 0},
284 {"enablevss", store_yesno, ITEM(res_fs.enable_vss), 1, ITEM_DEFAULT, 0},
285 {NULL, NULL, NULL, 0, 0, 0}
288 /* Schedule -- see run_conf.c */
291 * name handler value code flags default_value
293 static RES_ITEM sch_items[] = {
294 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
295 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
296 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
297 {NULL, NULL, NULL, 0, 0, 0}
302 * name handler value code flags default_value
304 static RES_ITEM pool_items[] = {
305 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
306 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
307 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
308 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
309 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
310 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
311 {"usecatalog", store_yesno, ITEM(res_pool.use_catalog), 1, ITEM_DEFAULT, 1},
312 {"usevolumeonce", store_yesno, ITEM(res_pool.use_volume_once),1, 0, 0},
313 {"purgeoldestvolume", store_yesno, ITEM(res_pool.purge_oldest_volume), 1, 0, 0},
314 {"recycleoldestvolume", store_yesno, ITEM(res_pool.recycle_oldest_volume), 1, 0, 0},
315 {"recyclecurrentvolume", store_yesno, ITEM(res_pool.recycle_current_volume), 1, 0, 0},
316 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
317 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
318 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
319 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
320 {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, ITEM_DEFAULT, 1},
321 {"catalogfiles", store_yesno, ITEM(res_pool.catalog_files), 1, ITEM_DEFAULT, 1},
322 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
323 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
324 {"autoprune", store_yesno, ITEM(res_pool.AutoPrune), 1, ITEM_DEFAULT, 1},
325 {"recycle", store_yesno, ITEM(res_pool.Recycle), 1, ITEM_DEFAULT, 1},
326 {NULL, NULL, NULL, 0, 0, 0}
331 * name handler value code flags default_value
333 static RES_ITEM counter_items[] = {
334 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
335 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
336 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
337 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
338 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
339 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
340 {NULL, NULL, NULL, 0, 0, 0}
344 /* Message resource */
345 extern RES_ITEM msgs_items[];
348 * This is the master resource definition.
349 * It must have one item for each of the resources.
351 * NOTE!!! keep it in the same order as the R_codes
352 * or eliminate all resources[rindex].name
354 * name items rcode res_head
356 RES_TABLE resources[] = {
357 {"director", dir_items, R_DIRECTOR},
358 {"client", cli_items, R_CLIENT},
359 {"job", job_items, R_JOB},
360 {"storage", store_items, R_STORAGE},
361 {"catalog", cat_items, R_CATALOG},
362 {"schedule", sch_items, R_SCHEDULE},
363 {"fileset", fs_items, R_FILESET},
364 {"pool", pool_items, R_POOL},
365 {"messages", msgs_items, R_MSGS},
366 {"counter", counter_items, R_COUNTER},
367 {"console", con_items, R_CONSOLE},
368 {"jobdefs", job_items, R_JOBDEFS},
369 {"device", NULL, R_DEVICE}, /* info obtained from SD */
374 /* Keywords (RHS) permitted in Job Level records
376 * level_name level job_type
378 struct s_jl joblevels[] = {
379 {"Full", L_FULL, JT_BACKUP},
380 {"Base", L_BASE, JT_BACKUP},
381 {"Incremental", L_INCREMENTAL, JT_BACKUP},
382 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
383 {"Since", L_SINCE, JT_BACKUP},
384 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
385 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
386 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
387 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
388 {"Data", L_VERIFY_DATA, JT_VERIFY},
389 {" ", L_NONE, JT_ADMIN},
390 {" ", L_NONE, JT_RESTORE},
394 /* Keywords (RHS) permitted in Job type records
398 struct s_jt jobtypes[] = {
399 {"backup", JT_BACKUP},
401 {"verify", JT_VERIFY},
402 {"restore", JT_RESTORE},
407 /* Options permitted in Restore replace= */
408 struct s_kw ReplaceOptions[] = {
409 {"always", REPLACE_ALWAYS},
410 {"ifnewer", REPLACE_IFNEWER},
411 {"ifolder", REPLACE_IFOLDER},
412 {"never", REPLACE_NEVER},
416 const char *level_to_str(int level)
419 static char level_no[30];
420 const char *str = level_no;
422 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
423 for (i=0; joblevels[i].level_name; i++) {
424 if (level == joblevels[i].level) {
425 str = joblevels[i].level_name;
432 /* Dump contents of resource */
433 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
435 URES *res = (URES *)reshdr;
437 char ed1[100], ed2[100];
441 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
444 if (type < 0) { /* no recursion */
450 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
451 reshdr->name, res->res_dir.MaxConcurrentJobs,
452 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
453 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
454 if (res->res_dir.query_file) {
455 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
457 if (res->res_dir.messages) {
458 sendit(sock, _(" --> "));
459 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
464 sendit(sock, _("Console: name=%s SSL=%d\n"),
465 res->res_con.hdr.name, res->res_con.tls_enable);
467 sendit(sock, _("Console: name=%s SSL=%d\n"),
468 res->res_con.hdr.name, BNET_TLS_NONE);
472 if (res->res_counter.WrapCounter) {
473 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
474 res->res_counter.hdr.name, res->res_counter.MinValue,
475 res->res_counter.MaxValue, res->res_counter.CurrentValue,
476 res->res_counter.WrapCounter->hdr.name);
478 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
479 res->res_counter.hdr.name, res->res_counter.MinValue,
480 res->res_counter.MaxValue);
482 if (res->res_counter.Catalog) {
483 sendit(sock, _(" --> "));
484 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
489 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
490 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
491 res->res_client.MaxConcurrentJobs);
492 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
493 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
494 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
495 res->res_client.AutoPrune);
496 if (res->res_client.catalog) {
497 sendit(sock, _(" --> "));
498 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
504 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
505 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
506 " poolid=%s volname=%s MediaType=%s\n"),
507 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
508 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
509 dev->offline, dev->autochanger,
510 edit_uint64(dev->PoolId, ed1),
511 dev->VolumeName, dev->MediaType);
514 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
515 " DeviceName=%s MediaType=%s StorageId=%s\n"),
516 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
517 res->res_store.MaxConcurrentJobs,
518 res->res_store.dev_name(),
519 res->res_store.media_type,
520 edit_int64(res->res_store.StorageId, ed1));
523 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
524 " db_user=%s MutliDBConn=%d\n"),
525 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
526 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
527 res->res_cat.mult_db_connections);
531 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d MaxJobs=%u\n"),
532 type == R_JOB ? _("Job") : _("JobDefs"),
533 res->res_job.hdr.name, res->res_job.JobType,
534 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
535 res->res_job.MaxConcurrentJobs);
536 sendit(sock, _(" Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
537 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
538 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
539 res->res_job.spool_data, res->res_job.write_part_after_job);
540 if (res->res_job.client) {
541 sendit(sock, _(" --> "));
542 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
544 if (res->res_job.fileset) {
545 sendit(sock, _(" --> "));
546 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
548 if (res->res_job.schedule) {
549 sendit(sock, _(" --> "));
550 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
552 if (res->res_job.RestoreWhere) {
553 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
555 if (res->res_job.RestoreBootstrap) {
556 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
558 if (res->res_job.RunBeforeJob) {
559 sendit(sock, _(" --> RunBefore=%s\n"), NPRT(res->res_job.RunBeforeJob));
561 if (res->res_job.RunAfterJob) {
562 sendit(sock, _(" --> RunAfter=%s\n"), NPRT(res->res_job.RunAfterJob));
564 if (res->res_job.RunAfterFailedJob) {
565 sendit(sock, _(" --> RunAfterFailed=%s\n"), NPRT(res->res_job.RunAfterFailedJob));
567 if (res->res_job.WriteBootstrap) {
568 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
570 if (res->res_job.storage) {
572 foreach_alist(store, res->res_job.storage) {
573 sendit(sock, _(" --> "));
574 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
577 if (res->res_job.pool) {
578 sendit(sock, _(" --> "));
579 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
581 if (res->res_job.full_pool) {
582 sendit(sock, _(" --> "));
583 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
585 if (res->res_job.inc_pool) {
586 sendit(sock, _(" --> "));
587 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
589 if (res->res_job.dif_pool) {
590 sendit(sock, _(" --> "));
591 dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock);
593 if (res->res_job.verify_job) {
594 sendit(sock, _(" --> "));
595 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
597 if (res->res_job.run_cmds) {
599 foreach_alist(runcmd, res->res_job.run_cmds) {
600 sendit(sock, _(" --> Run=%s\n"), runcmd);
603 if (res->res_job.messages) {
604 sendit(sock, _(" --> "));
605 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
611 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
612 for (i=0; i<res->res_fs.num_includes; i++) {
613 INCEXE *incexe = res->res_fs.include_items[i];
614 for (j=0; j<incexe->num_opts; j++) {
615 FOPTS *fo = incexe->opts_list[j];
616 sendit(sock, " O %s\n", fo->opts);
617 for (k=0; k<fo->regex.size(); k++) {
618 sendit(sock, " R %s\n", fo->regex.get(k));
620 for (k=0; k<fo->regexdir.size(); k++) {
621 sendit(sock, " RD %s\n", fo->regexdir.get(k));
623 for (k=0; k<fo->regexfile.size(); k++) {
624 sendit(sock, " RF %s\n", fo->regexfile.get(k));
626 for (k=0; k<fo->wild.size(); k++) {
627 sendit(sock, " W %s\n", fo->wild.get(k));
629 for (k=0; k<fo->wilddir.size(); k++) {
630 sendit(sock, " WD %s\n", fo->wilddir.get(k));
632 for (k=0; k<fo->wildfile.size(); k++) {
633 sendit(sock, " WF %s\n", fo->wildfile.get(k));
635 for (k=0; k<fo->base.size(); k++) {
636 sendit(sock, " B %s\n", fo->base.get(k));
638 for (k=0; k<fo->fstype.size(); k++) {
639 sendit(sock, " X %s\n", fo->fstype.get(k));
642 sendit(sock, " D %s\n", fo->reader);
645 sendit(sock, " T %s\n", fo->writer);
647 sendit(sock, " N\n");
649 for (j=0; j<incexe->name_list.size(); j++) {
650 sendit(sock, " I %s\n", incexe->name_list.get(j));
652 if (incexe->name_list.size()) {
653 sendit(sock, " N\n");
657 for (i=0; i<res->res_fs.num_excludes; i++) {
658 INCEXE *incexe = res->res_fs.exclude_items[i];
659 for (j=0; j<incexe->name_list.size(); j++) {
660 sendit(sock, " E %s\n", incexe->name_list.get(j));
662 if (incexe->name_list.size()) {
663 sendit(sock, " N\n");
669 if (res->res_sch.run) {
671 RUN *run = res->res_sch.run;
672 char buf[1000], num[30];
673 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
678 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
679 bstrncpy(buf, _(" hour="), sizeof(buf));
680 for (i=0; i<24; i++) {
681 if (bit_is_set(i, run->hour)) {
682 bsnprintf(num, sizeof(num), "%d ", i);
683 bstrncat(buf, num, sizeof(buf));
686 bstrncat(buf, "\n", sizeof(buf));
688 bstrncpy(buf, _(" mday="), sizeof(buf));
689 for (i=0; i<31; i++) {
690 if (bit_is_set(i, run->mday)) {
691 bsnprintf(num, sizeof(num), "%d ", i);
692 bstrncat(buf, num, sizeof(buf));
695 bstrncat(buf, "\n", sizeof(buf));
697 bstrncpy(buf, _(" month="), sizeof(buf));
698 for (i=0; i<12; i++) {
699 if (bit_is_set(i, run->month)) {
700 bsnprintf(num, sizeof(num), "%d ", i);
701 bstrncat(buf, num, sizeof(buf));
704 bstrncat(buf, "\n", sizeof(buf));
706 bstrncpy(buf, _(" wday="), sizeof(buf));
707 for (i=0; i<7; i++) {
708 if (bit_is_set(i, run->wday)) {
709 bsnprintf(num, sizeof(num), "%d ", i);
710 bstrncat(buf, num, sizeof(buf));
713 bstrncat(buf, "\n", sizeof(buf));
715 bstrncpy(buf, _(" wom="), sizeof(buf));
716 for (i=0; i<5; i++) {
717 if (bit_is_set(i, run->wom)) {
718 bsnprintf(num, sizeof(num), "%d ", i);
719 bstrncat(buf, num, sizeof(buf));
722 bstrncat(buf, "\n", sizeof(buf));
724 bstrncpy(buf, _(" woy="), sizeof(buf));
725 for (i=0; i<54; i++) {
726 if (bit_is_set(i, run->woy)) {
727 bsnprintf(num, sizeof(num), "%d ", i);
728 bstrncat(buf, num, sizeof(buf));
731 bstrncat(buf, "\n", sizeof(buf));
733 sendit(sock, _(" mins=%d\n"), run->minute);
735 sendit(sock, _(" --> "));
736 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
739 sendit(sock, _(" --> "));
740 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
743 sendit(sock, _(" --> "));
744 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
746 /* If another Run record is chained in, go print it */
752 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
756 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
757 res->res_pool.pool_type);
758 sendit(sock, _(" use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n"),
759 res->res_pool.use_catalog, res->res_pool.use_volume_once,
760 res->res_pool.accept_any_volume, res->res_pool.catalog_files);
761 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
762 res->res_pool.max_volumes, res->res_pool.AutoPrune,
763 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
764 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
765 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
766 res->res_pool.Recycle,
767 NPRT(res->res_pool.label_format));
768 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
769 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
770 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
771 res->res_pool.recycle_oldest_volume,
772 res->res_pool.purge_oldest_volume,
773 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
776 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
777 if (res->res_msgs.mail_cmd)
778 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
779 if (res->res_msgs.operator_cmd)
780 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
783 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
786 if (recurse && res->res_dir.hdr.next) {
787 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
792 * Free all the members of an INCEXE structure
794 static void free_incexe(INCEXE *incexe)
796 incexe->name_list.destroy();
797 for (int i=0; i<incexe->num_opts; i++) {
798 FOPTS *fopt = incexe->opts_list[i];
799 fopt->regex.destroy();
800 fopt->regexdir.destroy();
801 fopt->regexfile.destroy();
802 fopt->wild.destroy();
803 fopt->wilddir.destroy();
804 fopt->wildfile.destroy();
805 fopt->base.destroy();
806 fopt->fstype.destroy();
815 if (incexe->opts_list) {
816 free(incexe->opts_list);
822 * Free memory of resource -- called when daemon terminates.
823 * NB, we don't need to worry about freeing any references
824 * to other resources as they will be freed when that
825 * resource chain is traversed. Mainly we worry about freeing
826 * allocated strings (names).
828 void free_resource(RES *sres, int type)
831 RES *nres; /* next resource if linked */
832 URES *res = (URES *)sres;
837 /* common stuff -- free the resource name and description */
838 nres = (RES *)res->res_dir.hdr.next;
839 if (res->res_dir.hdr.name) {
840 free(res->res_dir.hdr.name);
842 if (res->res_dir.hdr.desc) {
843 free(res->res_dir.hdr.desc);
848 if (res->res_dir.working_directory) {
849 free(res->res_dir.working_directory);
851 if (res->res_dir.scripts_directory) {
852 free((char *)res->res_dir.scripts_directory);
854 if (res->res_dir.pid_directory) {
855 free(res->res_dir.pid_directory);
857 if (res->res_dir.subsys_directory) {
858 free(res->res_dir.subsys_directory);
860 if (res->res_dir.password) {
861 free(res->res_dir.password);
863 if (res->res_dir.query_file) {
864 free(res->res_dir.query_file);
866 if (res->res_dir.DIRaddrs) {
867 free_addresses(res->res_dir.DIRaddrs);
869 if (res->res_dir.tls_ctx) {
870 free_tls_context(res->res_dir.tls_ctx);
872 if (res->res_dir.tls_ca_certfile) {
873 free(res->res_dir.tls_ca_certfile);
875 if (res->res_dir.tls_ca_certdir) {
876 free(res->res_dir.tls_ca_certdir);
878 if (res->res_dir.tls_certfile) {
879 free(res->res_dir.tls_certfile);
881 if (res->res_dir.tls_keyfile) {
882 free(res->res_dir.tls_keyfile);
884 if (res->res_dir.tls_dhfile) {
885 free(res->res_dir.tls_dhfile);
887 if (res->res_dir.tls_allowed_cns) {
888 delete res->res_dir.tls_allowed_cns;
895 if (res->res_con.password) {
896 free(res->res_con.password);
898 if (res->res_con.tls_ctx) {
899 free_tls_context(res->res_con.tls_ctx);
901 if (res->res_con.tls_ca_certfile) {
902 free(res->res_con.tls_ca_certfile);
904 if (res->res_con.tls_ca_certdir) {
905 free(res->res_con.tls_ca_certdir);
907 if (res->res_con.tls_certfile) {
908 free(res->res_con.tls_certfile);
910 if (res->res_con.tls_keyfile) {
911 free(res->res_con.tls_keyfile);
913 if (res->res_con.tls_dhfile) {
914 free(res->res_con.tls_dhfile);
916 if (res->res_con.tls_allowed_cns) {
917 delete res->res_con.tls_allowed_cns;
919 for (int i=0; i<Num_ACL; i++) {
920 if (res->res_con.ACL_lists[i]) {
921 delete res->res_con.ACL_lists[i];
922 res->res_con.ACL_lists[i] = NULL;
927 if (res->res_client.address) {
928 free(res->res_client.address);
930 if (res->res_client.password) {
931 free(res->res_client.password);
933 if (res->res_client.tls_ctx) {
934 free_tls_context(res->res_client.tls_ctx);
936 if (res->res_client.tls_ca_certfile) {
937 free(res->res_client.tls_ca_certfile);
939 if (res->res_client.tls_ca_certdir) {
940 free(res->res_client.tls_ca_certdir);
942 if (res->res_client.tls_certfile) {
943 free(res->res_client.tls_certfile);
945 if (res->res_client.tls_keyfile) {
946 free(res->res_client.tls_keyfile);
950 if (res->res_store.address) {
951 free(res->res_store.address);
953 if (res->res_store.password) {
954 free(res->res_store.password);
956 if (res->res_store.media_type) {
957 free(res->res_store.media_type);
959 if (res->res_store.device) {
960 delete res->res_store.device;
962 if (res->res_store.tls_ctx) {
963 free_tls_context(res->res_store.tls_ctx);
965 if (res->res_store.tls_ca_certfile) {
966 free(res->res_store.tls_ca_certfile);
968 if (res->res_store.tls_ca_certdir) {
969 free(res->res_store.tls_ca_certdir);
971 if (res->res_store.tls_certfile) {
972 free(res->res_store.tls_certfile);
974 if (res->res_store.tls_keyfile) {
975 free(res->res_store.tls_keyfile);
979 if (res->res_cat.db_address) {
980 free(res->res_cat.db_address);
982 if (res->res_cat.db_socket) {
983 free(res->res_cat.db_socket);
985 if (res->res_cat.db_user) {
986 free(res->res_cat.db_user);
988 if (res->res_cat.db_name) {
989 free(res->res_cat.db_name);
991 if (res->res_cat.db_password) {
992 free(res->res_cat.db_password);
996 if ((num=res->res_fs.num_includes)) {
998 free_incexe(res->res_fs.include_items[num]);
1000 free(res->res_fs.include_items);
1002 res->res_fs.num_includes = 0;
1003 if ((num=res->res_fs.num_excludes)) {
1004 while (--num >= 0) {
1005 free_incexe(res->res_fs.exclude_items[num]);
1007 free(res->res_fs.exclude_items);
1009 res->res_fs.num_excludes = 0;
1012 if (res->res_pool.pool_type) {
1013 free(res->res_pool.pool_type);
1015 if (res->res_pool.label_format) {
1016 free(res->res_pool.label_format);
1018 if (res->res_pool.cleaning_prefix) {
1019 free(res->res_pool.cleaning_prefix);
1023 if (res->res_sch.run) {
1025 nrun = res->res_sch.run;
1035 if (res->res_job.RestoreWhere) {
1036 free(res->res_job.RestoreWhere);
1038 if (res->res_job.RestoreBootstrap) {
1039 free(res->res_job.RestoreBootstrap);
1041 if (res->res_job.WriteBootstrap) {
1042 free(res->res_job.WriteBootstrap);
1044 if (res->res_job.RunBeforeJob) {
1045 free(res->res_job.RunBeforeJob);
1047 if (res->res_job.RunAfterJob) {
1048 free(res->res_job.RunAfterJob);
1050 if (res->res_job.RunAfterFailedJob) {
1051 free(res->res_job.RunAfterFailedJob);
1053 if (res->res_job.ClientRunBeforeJob) {
1054 free(res->res_job.ClientRunBeforeJob);
1056 if (res->res_job.ClientRunAfterJob) {
1057 free(res->res_job.ClientRunAfterJob);
1059 if (res->res_job.run_cmds) {
1060 delete res->res_job.run_cmds;
1062 if (res->res_job.storage) {
1063 delete res->res_job.storage;
1067 if (res->res_msgs.mail_cmd) {
1068 free(res->res_msgs.mail_cmd);
1070 if (res->res_msgs.operator_cmd) {
1071 free(res->res_msgs.operator_cmd);
1073 free_msgs_res((MSGS *)res); /* free message resource */
1077 printf(_("Unknown resource type %d in free_resource.\n"), type);
1079 /* Common stuff again -- free the resource, recurse to next one */
1084 free_resource(nres, type);
1089 * Save the new resource by chaining it into the head list for
1090 * the resource. If this is pass 2, we update any resource
1091 * pointers because they may not have been defined until
1094 void save_resource(int type, RES_ITEM *items, int pass)
1097 int rindex = type - r_first;
1101 /* Check Job requirements after applying JobDefs */
1102 if (type != R_JOB && type != R_JOBDEFS) {
1104 * Ensure that all required items are present
1106 for (i=0; items[i].name; i++) {
1107 if (items[i].flags & ITEM_REQUIRED) {
1108 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1109 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1110 items[i].name, resources[rindex]);
1113 /* If this triggers, take a look at lib/parse_conf.h */
1114 if (i >= MAX_RES_ITEMS) {
1115 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1118 } else if (type == R_JOB) {
1120 * Ensure that the name item is present
1122 if (items[0].flags & ITEM_REQUIRED) {
1123 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1124 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1125 items[0].name, resources[rindex]);
1131 * During pass 2 in each "store" routine, we looked up pointers
1132 * to all the resources referrenced in the current resource, now we
1133 * must copy their addresses from the static record to the allocated
1138 /* Resources not containing a resource */
1146 /* Resources containing another resource or alist */
1148 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1149 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1151 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1154 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1155 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1157 res->res_dir.messages = res_all.res_dir.messages;
1158 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1161 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1162 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1163 res_all.res_dir.hdr.name);
1165 /* we must explicitly copy the device alist pointer */
1166 res->res_store.device = res_all.res_store.device;
1170 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1171 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1172 res_all.res_dir.hdr.name);
1174 res->res_job.messages = res_all.res_job.messages;
1175 res->res_job.schedule = res_all.res_job.schedule;
1176 res->res_job.client = res_all.res_job.client;
1177 res->res_job.fileset = res_all.res_job.fileset;
1178 res->res_job.storage = res_all.res_job.storage;
1179 res->res_job.pool = res_all.res_job.pool;
1180 res->res_job.full_pool = res_all.res_job.full_pool;
1181 res->res_job.inc_pool = res_all.res_job.inc_pool;
1182 res->res_job.dif_pool = res_all.res_job.dif_pool;
1183 res->res_job.verify_job = res_all.res_job.verify_job;
1184 res->res_job.jobdefs = res_all.res_job.jobdefs;
1185 res->res_job.run_cmds = res_all.res_job.run_cmds;
1188 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1189 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1191 res->res_counter.Catalog = res_all.res_counter.Catalog;
1192 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1196 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1197 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1199 res->res_client.catalog = res_all.res_client.catalog;
1203 * Schedule is a bit different in that it contains a RUN record
1204 * chain which isn't a "named" resource. This chain was linked
1205 * in by run_conf.c during pass 2, so here we jam the pointer
1206 * into the Schedule resource.
1208 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1209 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1211 res->res_sch.run = res_all.res_sch.run;
1214 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1218 /* Note, the resource name was already saved during pass 1,
1219 * so here, we can just release it.
1221 if (res_all.res_dir.hdr.name) {
1222 free(res_all.res_dir.hdr.name);
1223 res_all.res_dir.hdr.name = NULL;
1225 if (res_all.res_dir.hdr.desc) {
1226 free(res_all.res_dir.hdr.desc);
1227 res_all.res_dir.hdr.desc = NULL;
1233 * The following code is only executed during pass 1
1237 size = sizeof(DIRRES);
1240 size = sizeof(CONRES);
1243 size =sizeof(CLIENT);
1246 size = sizeof(STORE);
1256 size = sizeof(FILESET);
1259 size = sizeof(SCHED);
1262 size = sizeof(POOL);
1265 size = sizeof(MSGS);
1268 size = sizeof(COUNTER);
1274 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1280 res = (URES *)malloc(size);
1281 memcpy(res, &res_all, size);
1282 if (!res_head[rindex]) {
1283 res_head[rindex] = (RES *)res; /* store first entry */
1284 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1285 res->res_dir.hdr.name, rindex);
1288 if (res->res_dir.hdr.name == NULL) {
1289 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1292 /* Add new res to end of chain */
1293 for (next=res_head[rindex]; next->next; next=next->next) {
1294 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1295 Emsg2(M_ERROR_TERM, 0,
1296 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1297 resources[rindex].name, res->res_dir.hdr.name);
1300 next->next = (RES *)res;
1301 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1302 res->res_dir.hdr.name, rindex, pass);
1308 * Store Device. Note, the resource is created upon the
1309 * first reference. The details of the resource are obtained
1310 * later from the SD.
1312 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1316 int rindex = R_DEVICE - r_first;
1317 int size = sizeof(DEVICE);
1321 token = lex_get_token(lc, T_NAME);
1322 if (!res_head[rindex]) {
1323 res = (URES *)malloc(size);
1324 memset(res, 0, size);
1325 res->res_dev.hdr.name = bstrdup(lc->str);
1326 res_head[rindex] = (RES *)res; /* store first entry */
1327 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1328 res->res_dir.hdr.name, rindex);
1331 /* See if it is already defined */
1332 for (next=res_head[rindex]; next->next; next=next->next) {
1333 if (strcmp(next->name, lc->str) == 0) {
1339 res = (URES *)malloc(size);
1340 memset(res, 0, size);
1341 res->res_dev.hdr.name = bstrdup(lc->str);
1342 next->next = (RES *)res;
1343 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1344 res->res_dir.hdr.name, rindex, pass);
1349 set_bit(index, res_all.hdr.item_present);
1351 store_alist_res(lc, item, index, pass);
1357 * Store JobType (backup, verify, restore)
1360 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1364 token = lex_get_token(lc, T_NAME);
1365 /* Store the type both pass 1 and pass 2 */
1366 for (i=0; jobtypes[i].type_name; i++) {
1367 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1368 *(int *)(item->value) = jobtypes[i].job_type;
1374 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1377 set_bit(index, res_all.hdr.item_present);
1381 * Store Job Level (Full, Incremental, ...)
1384 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1388 token = lex_get_token(lc, T_NAME);
1389 /* Store the level pass 2 so that type is defined */
1390 for (i=0; joblevels[i].level_name; i++) {
1391 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1392 *(int *)(item->value) = joblevels[i].level;
1398 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1401 set_bit(index, res_all.hdr.item_present);
1405 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1408 token = lex_get_token(lc, T_NAME);
1409 /* Scan Replacement options */
1410 for (i=0; ReplaceOptions[i].name; i++) {
1411 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1412 *(int *)(item->value) = ReplaceOptions[i].token;
1418 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1421 set_bit(index, res_all.hdr.item_present);
1425 * Store ACL (access control list)
1428 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1433 token = lex_get_token(lc, T_NAME);
1435 if (((alist **)item->value)[item->code] == NULL) {
1436 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1437 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1439 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1440 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1442 token = lex_get_token(lc, T_ALL);
1443 if (token == T_COMMA) {
1444 continue; /* get another ACL */
1448 set_bit(index, res_all.hdr.item_present);