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 {"jobdefs", store_res, ITEM(res_job.jobdefs), R_JOBDEFS, 0, 0},
241 {"run", store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
242 {"where", store_dir, ITEM(res_job.RestoreWhere), 0, 0, 0},
243 {"bootstrap",store_dir, ITEM(res_job.RestoreBootstrap), 0, 0, 0},
244 {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
245 {"replace", store_replace, ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
246 {"maxruntime", store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
247 {"fullmaxwaittime", store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
248 {"incrementalmaxwaittime", store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
249 {"differentialmaxwaittime", store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
250 {"maxwaittime", store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
251 {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
252 {"jobretention", store_time, ITEM(res_job.JobRetention), 0, 0, 0},
253 {"prefixlinks", store_yesno, ITEM(res_job.PrefixLinks), 1, ITEM_DEFAULT, 0},
254 {"prunejobs", store_yesno, ITEM(res_job.PruneJobs), 1, ITEM_DEFAULT, 0},
255 {"prunefiles", store_yesno, ITEM(res_job.PruneFiles), 1, ITEM_DEFAULT, 0},
256 {"prunevolumes",store_yesno, ITEM(res_job.PruneVolumes), 1, ITEM_DEFAULT, 0},
257 {"enabled", store_yesno, ITEM(res_job.enabled), 1, ITEM_DEFAULT, 1},
258 {"spoolattributes",store_yesno, ITEM(res_job.SpoolAttributes), 1, ITEM_DEFAULT, 0},
259 {"spooldata", store_yesno, ITEM(res_job.spool_data), 1, ITEM_DEFAULT, 0},
260 {"rerunfailedlevels", store_yesno, ITEM(res_job.rerun_failed_levels), 1, ITEM_DEFAULT, 0},
261 {"prefermountedvolumes", store_yesno, ITEM(res_job.PreferMountedVolumes), 1, ITEM_DEFAULT, 1},
262 {"runbeforejob", store_str, ITEM(res_job.RunBeforeJob), 0, 0, 0},
263 {"runafterjob", store_str, ITEM(res_job.RunAfterJob), 0, 0, 0},
264 {"runafterfailedjob", store_str, ITEM(res_job.RunAfterFailedJob), 0, 0, 0},
265 {"clientrunbeforejob", store_str, ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
266 {"clientrunafterjob", store_str, ITEM(res_job.ClientRunAfterJob), 0, 0, 0},
267 {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
268 {"rescheduleonerror", store_yesno, ITEM(res_job.RescheduleOnError), 1, ITEM_DEFAULT, 0},
269 {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
270 {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
271 {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
272 {"writepartafterjob", store_yesno, ITEM(res_job.write_part_after_job), 1, ITEM_DEFAULT, 0},
273 {NULL, NULL, NULL, 0, 0, 0}
278 * name handler value code flags default_value
280 static RES_ITEM fs_items[] = {
281 {"name", store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
282 {"description", store_str, ITEM(res_fs.hdr.desc), 0, 0, 0},
283 {"include", store_inc, NULL, 0, ITEM_NO_EQUALS, 0},
284 {"exclude", store_inc, NULL, 1, ITEM_NO_EQUALS, 0},
285 {"ignorefilesetchanges", store_yesno, ITEM(res_fs.ignore_fs_changes), 1, ITEM_DEFAULT, 0},
286 {"enablevss", store_yesno, ITEM(res_fs.enable_vss), 1, ITEM_DEFAULT, 0},
287 {NULL, NULL, NULL, 0, 0, 0}
290 /* Schedule -- see run_conf.c */
293 * name handler value code flags default_value
295 static RES_ITEM sch_items[] = {
296 {"name", store_name, ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
297 {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
298 {"run", store_run, ITEM(res_sch.run), 0, 0, 0},
299 {NULL, NULL, NULL, 0, 0, 0}
304 * name handler value code flags default_value
306 static RES_ITEM pool_items[] = {
307 {"name", store_name, ITEM(res_pool.hdr.name), 0, ITEM_REQUIRED, 0},
308 {"description", store_str, ITEM(res_pool.hdr.desc), 0, 0, 0},
309 {"pooltype", store_strname, ITEM(res_pool.pool_type), 0, ITEM_REQUIRED, 0},
310 {"labelformat", store_strname, ITEM(res_pool.label_format), 0, 0, 0},
311 {"labeltype", store_label, ITEM(res_pool.LabelType), 0, 0, 0},
312 {"cleaningprefix", store_strname, ITEM(res_pool.cleaning_prefix), 0, 0, 0},
313 {"usecatalog", store_yesno, ITEM(res_pool.use_catalog), 1, ITEM_DEFAULT, 1},
314 {"usevolumeonce", store_yesno, ITEM(res_pool.use_volume_once),1, 0, 0},
315 {"purgeoldestvolume", store_yesno, ITEM(res_pool.purge_oldest_volume), 1, 0, 0},
316 {"recycleoldestvolume", store_yesno, ITEM(res_pool.recycle_oldest_volume), 1, 0, 0},
317 {"recyclecurrentvolume", store_yesno, ITEM(res_pool.recycle_current_volume), 1, 0, 0},
318 {"maximumvolumes", store_pint, ITEM(res_pool.max_volumes), 0, 0, 0},
319 {"maximumvolumejobs", store_pint, ITEM(res_pool.MaxVolJobs), 0, 0, 0},
320 {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles), 0, 0, 0},
321 {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes), 0, 0, 0},
322 {"acceptanyvolume", store_yesno, ITEM(res_pool.accept_any_volume), 1, ITEM_DEFAULT, 1},
323 {"catalogfiles", store_yesno, ITEM(res_pool.catalog_files), 1, ITEM_DEFAULT, 1},
324 {"volumeretention", store_time, ITEM(res_pool.VolRetention), 0, ITEM_DEFAULT, 60*60*24*365},
325 {"volumeuseduration", store_time, ITEM(res_pool.VolUseDuration), 0, 0, 0},
326 {"autoprune", store_yesno, ITEM(res_pool.AutoPrune), 1, ITEM_DEFAULT, 1},
327 {"recycle", store_yesno, ITEM(res_pool.Recycle), 1, ITEM_DEFAULT, 1},
328 {NULL, NULL, NULL, 0, 0, 0}
333 * name handler value code flags default_value
335 static RES_ITEM counter_items[] = {
336 {"name", store_name, ITEM(res_counter.hdr.name), 0, ITEM_REQUIRED, 0},
337 {"description", store_str, ITEM(res_counter.hdr.desc), 0, 0, 0},
338 {"minimum", store_int, ITEM(res_counter.MinValue), 0, ITEM_DEFAULT, 0},
339 {"maximum", store_pint, ITEM(res_counter.MaxValue), 0, ITEM_DEFAULT, INT32_MAX},
340 {"wrapcounter", store_res, ITEM(res_counter.WrapCounter), R_COUNTER, 0, 0},
341 {"catalog", store_res, ITEM(res_counter.Catalog), R_CATALOG, 0, 0},
342 {NULL, NULL, NULL, 0, 0, 0}
346 /* Message resource */
347 extern RES_ITEM msgs_items[];
350 * This is the master resource definition.
351 * It must have one item for each of the resources.
353 * NOTE!!! keep it in the same order as the R_codes
354 * or eliminate all resources[rindex].name
356 * name items rcode res_head
358 RES_TABLE resources[] = {
359 {"director", dir_items, R_DIRECTOR},
360 {"client", cli_items, R_CLIENT},
361 {"job", job_items, R_JOB},
362 {"storage", store_items, R_STORAGE},
363 {"catalog", cat_items, R_CATALOG},
364 {"schedule", sch_items, R_SCHEDULE},
365 {"fileset", fs_items, R_FILESET},
366 {"pool", pool_items, R_POOL},
367 {"messages", msgs_items, R_MSGS},
368 {"counter", counter_items, R_COUNTER},
369 {"console", con_items, R_CONSOLE},
370 {"jobdefs", job_items, R_JOBDEFS},
371 {"device", NULL, R_DEVICE}, /* info obtained from SD */
376 /* Keywords (RHS) permitted in Job Level records
378 * level_name level job_type
380 struct s_jl joblevels[] = {
381 {"Full", L_FULL, JT_BACKUP},
382 {"Base", L_BASE, JT_BACKUP},
383 {"Incremental", L_INCREMENTAL, JT_BACKUP},
384 {"Differential", L_DIFFERENTIAL, JT_BACKUP},
385 {"Since", L_SINCE, JT_BACKUP},
386 {"Catalog", L_VERIFY_CATALOG, JT_VERIFY},
387 {"InitCatalog", L_VERIFY_INIT, JT_VERIFY},
388 {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG, JT_VERIFY},
389 {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG, JT_VERIFY},
390 {"Data", L_VERIFY_DATA, JT_VERIFY},
391 {" ", L_NONE, JT_ADMIN},
392 {" ", L_NONE, JT_RESTORE},
396 /* Keywords (RHS) permitted in Job type records
400 struct s_jt jobtypes[] = {
401 {"backup", JT_BACKUP},
403 {"verify", JT_VERIFY},
404 {"restore", JT_RESTORE},
409 /* Options permitted in Restore replace= */
410 struct s_kw ReplaceOptions[] = {
411 {"always", REPLACE_ALWAYS},
412 {"ifnewer", REPLACE_IFNEWER},
413 {"ifolder", REPLACE_IFOLDER},
414 {"never", REPLACE_NEVER},
418 const char *level_to_str(int level)
421 static char level_no[30];
422 const char *str = level_no;
424 bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level); /* default if not found */
425 for (i=0; joblevels[i].level_name; i++) {
426 if (level == joblevels[i].level) {
427 str = joblevels[i].level_name;
434 /* Dump contents of resource */
435 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
437 URES *res = (URES *)reshdr;
439 char ed1[100], ed2[100];
443 sendit(sock, _("No %s resource defined\n"), res_to_str(type));
446 if (type < 0) { /* no recursion */
452 sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
453 reshdr->name, res->res_dir.MaxConcurrentJobs,
454 edit_uint64(res->res_dir.FDConnectTimeout, ed1),
455 edit_uint64(res->res_dir.SDConnectTimeout, ed2));
456 if (res->res_dir.query_file) {
457 sendit(sock, _(" query_file=%s\n"), res->res_dir.query_file);
459 if (res->res_dir.messages) {
460 sendit(sock, _(" --> "));
461 dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
466 sendit(sock, _("Console: name=%s SSL=%d\n"),
467 res->res_con.hdr.name, res->res_con.tls_enable);
469 sendit(sock, _("Console: name=%s SSL=%d\n"),
470 res->res_con.hdr.name, BNET_TLS_NONE);
474 if (res->res_counter.WrapCounter) {
475 sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
476 res->res_counter.hdr.name, res->res_counter.MinValue,
477 res->res_counter.MaxValue, res->res_counter.CurrentValue,
478 res->res_counter.WrapCounter->hdr.name);
480 sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
481 res->res_counter.hdr.name, res->res_counter.MinValue,
482 res->res_counter.MaxValue);
484 if (res->res_counter.Catalog) {
485 sendit(sock, _(" --> "));
486 dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
491 sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
492 res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
493 res->res_client.MaxConcurrentJobs);
494 sendit(sock, _(" JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
495 edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
496 edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
497 res->res_client.AutoPrune);
498 if (res->res_client.catalog) {
499 sendit(sock, _(" --> "));
500 dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
506 sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
507 " reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
508 " poolid=%s volname=%s MediaType=%s\n"),
509 dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
510 dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
511 dev->offline, dev->autochanger,
512 edit_uint64(dev->PoolId, ed1),
513 dev->VolumeName, dev->MediaType);
516 sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
517 " DeviceName=%s MediaType=%s StorageId=%s\n"),
518 res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
519 res->res_store.MaxConcurrentJobs,
520 res->res_store.dev_name(),
521 res->res_store.media_type,
522 edit_int64(res->res_store.StorageId, ed1));
525 sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
526 " db_user=%s MutliDBConn=%d\n"),
527 res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
528 res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
529 res->res_cat.mult_db_connections);
533 sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
534 type == R_JOB ? _("Job") : _("JobDefs"),
535 res->res_job.hdr.name, res->res_job.JobType,
536 level_to_str(res->res_job.JobLevel), res->res_job.Priority,
537 res->res_job.enabled);
538 sendit(sock, _(" MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
539 res->res_job.MaxConcurrentJobs,
540 res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
541 edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
542 res->res_job.spool_data, res->res_job.write_part_after_job);
543 if (res->res_job.client) {
544 sendit(sock, _(" --> "));
545 dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
547 if (res->res_job.fileset) {
548 sendit(sock, _(" --> "));
549 dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
551 if (res->res_job.schedule) {
552 sendit(sock, _(" --> "));
553 dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
555 if (res->res_job.RestoreWhere) {
556 sendit(sock, _(" --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
558 if (res->res_job.RestoreBootstrap) {
559 sendit(sock, _(" --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
561 if (res->res_job.RunBeforeJob) {
562 sendit(sock, _(" --> RunBefore=%s\n"), NPRT(res->res_job.RunBeforeJob));
564 if (res->res_job.RunAfterJob) {
565 sendit(sock, _(" --> RunAfter=%s\n"), NPRT(res->res_job.RunAfterJob));
567 if (res->res_job.RunAfterFailedJob) {
568 sendit(sock, _(" --> RunAfterFailed=%s\n"), NPRT(res->res_job.RunAfterFailedJob));
570 if (res->res_job.WriteBootstrap) {
571 sendit(sock, _(" --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
573 if (res->res_job.storage) {
575 foreach_alist(store, res->res_job.storage) {
576 sendit(sock, _(" --> "));
577 dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
580 if (res->res_job.pool) {
581 sendit(sock, _(" --> "));
582 dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
584 if (res->res_job.full_pool) {
585 sendit(sock, _(" --> "));
586 dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
588 if (res->res_job.inc_pool) {
589 sendit(sock, _(" --> "));
590 dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
592 if (res->res_job.dif_pool) {
593 sendit(sock, _(" --> "));
594 dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock);
596 if (res->res_job.verify_job) {
597 sendit(sock, _(" --> "));
598 dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
600 if (res->res_job.run_cmds) {
602 foreach_alist(runcmd, res->res_job.run_cmds) {
603 sendit(sock, _(" --> Run=%s\n"), runcmd);
606 if (res->res_job.messages) {
607 sendit(sock, _(" --> "));
608 dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
614 sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
615 for (i=0; i<res->res_fs.num_includes; i++) {
616 INCEXE *incexe = res->res_fs.include_items[i];
617 for (j=0; j<incexe->num_opts; j++) {
618 FOPTS *fo = incexe->opts_list[j];
619 sendit(sock, " O %s\n", fo->opts);
620 for (k=0; k<fo->regex.size(); k++) {
621 sendit(sock, " R %s\n", fo->regex.get(k));
623 for (k=0; k<fo->regexdir.size(); k++) {
624 sendit(sock, " RD %s\n", fo->regexdir.get(k));
626 for (k=0; k<fo->regexfile.size(); k++) {
627 sendit(sock, " RF %s\n", fo->regexfile.get(k));
629 for (k=0; k<fo->wild.size(); k++) {
630 sendit(sock, " W %s\n", fo->wild.get(k));
632 for (k=0; k<fo->wilddir.size(); k++) {
633 sendit(sock, " WD %s\n", fo->wilddir.get(k));
635 for (k=0; k<fo->wildfile.size(); k++) {
636 sendit(sock, " WF %s\n", fo->wildfile.get(k));
638 for (k=0; k<fo->base.size(); k++) {
639 sendit(sock, " B %s\n", fo->base.get(k));
641 for (k=0; k<fo->fstype.size(); k++) {
642 sendit(sock, " X %s\n", fo->fstype.get(k));
645 sendit(sock, " D %s\n", fo->reader);
648 sendit(sock, " T %s\n", fo->writer);
650 sendit(sock, " N\n");
652 for (j=0; j<incexe->name_list.size(); j++) {
653 sendit(sock, " I %s\n", incexe->name_list.get(j));
655 if (incexe->name_list.size()) {
656 sendit(sock, " N\n");
660 for (i=0; i<res->res_fs.num_excludes; i++) {
661 INCEXE *incexe = res->res_fs.exclude_items[i];
662 for (j=0; j<incexe->name_list.size(); j++) {
663 sendit(sock, " E %s\n", incexe->name_list.get(j));
665 if (incexe->name_list.size()) {
666 sendit(sock, " N\n");
672 if (res->res_sch.run) {
674 RUN *run = res->res_sch.run;
675 char buf[1000], num[30];
676 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
681 sendit(sock, _(" --> Run Level=%s\n"), level_to_str(run->level));
682 bstrncpy(buf, _(" hour="), sizeof(buf));
683 for (i=0; i<24; i++) {
684 if (bit_is_set(i, run->hour)) {
685 bsnprintf(num, sizeof(num), "%d ", i);
686 bstrncat(buf, num, sizeof(buf));
689 bstrncat(buf, "\n", sizeof(buf));
691 bstrncpy(buf, _(" mday="), sizeof(buf));
692 for (i=0; i<31; i++) {
693 if (bit_is_set(i, run->mday)) {
694 bsnprintf(num, sizeof(num), "%d ", i);
695 bstrncat(buf, num, sizeof(buf));
698 bstrncat(buf, "\n", sizeof(buf));
700 bstrncpy(buf, _(" month="), sizeof(buf));
701 for (i=0; i<12; i++) {
702 if (bit_is_set(i, run->month)) {
703 bsnprintf(num, sizeof(num), "%d ", i);
704 bstrncat(buf, num, sizeof(buf));
707 bstrncat(buf, "\n", sizeof(buf));
709 bstrncpy(buf, _(" wday="), sizeof(buf));
710 for (i=0; i<7; i++) {
711 if (bit_is_set(i, run->wday)) {
712 bsnprintf(num, sizeof(num), "%d ", i);
713 bstrncat(buf, num, sizeof(buf));
716 bstrncat(buf, "\n", sizeof(buf));
718 bstrncpy(buf, _(" wom="), sizeof(buf));
719 for (i=0; i<5; i++) {
720 if (bit_is_set(i, run->wom)) {
721 bsnprintf(num, sizeof(num), "%d ", i);
722 bstrncat(buf, num, sizeof(buf));
725 bstrncat(buf, "\n", sizeof(buf));
727 bstrncpy(buf, _(" woy="), sizeof(buf));
728 for (i=0; i<54; i++) {
729 if (bit_is_set(i, run->woy)) {
730 bsnprintf(num, sizeof(num), "%d ", i);
731 bstrncat(buf, num, sizeof(buf));
734 bstrncat(buf, "\n", sizeof(buf));
736 sendit(sock, _(" mins=%d\n"), run->minute);
738 sendit(sock, _(" --> "));
739 dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
742 sendit(sock, _(" --> "));
743 dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
746 sendit(sock, _(" --> "));
747 dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
749 /* If another Run record is chained in, go print it */
755 sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
759 sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
760 res->res_pool.pool_type);
761 sendit(sock, _(" use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n"),
762 res->res_pool.use_catalog, res->res_pool.use_volume_once,
763 res->res_pool.accept_any_volume, res->res_pool.catalog_files);
764 sendit(sock, _(" max_vols=%d auto_prune=%d VolRetention=%s\n"),
765 res->res_pool.max_volumes, res->res_pool.AutoPrune,
766 edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
767 sendit(sock, _(" VolUse=%s recycle=%d LabelFormat=%s\n"),
768 edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
769 res->res_pool.Recycle,
770 NPRT(res->res_pool.label_format));
771 sendit(sock, _(" CleaningPrefix=%s LabelType=%d\n"),
772 NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
773 sendit(sock, _(" RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
774 res->res_pool.recycle_oldest_volume,
775 res->res_pool.purge_oldest_volume,
776 res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
779 sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
780 if (res->res_msgs.mail_cmd)
781 sendit(sock, _(" mailcmd=%s\n"), res->res_msgs.mail_cmd);
782 if (res->res_msgs.operator_cmd)
783 sendit(sock, _(" opcmd=%s\n"), res->res_msgs.operator_cmd);
786 sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
789 if (recurse && res->res_dir.hdr.next) {
790 dump_resource(type, res->res_dir.hdr.next, sendit, sock);
795 * Free all the members of an INCEXE structure
797 static void free_incexe(INCEXE *incexe)
799 incexe->name_list.destroy();
800 for (int i=0; i<incexe->num_opts; i++) {
801 FOPTS *fopt = incexe->opts_list[i];
802 fopt->regex.destroy();
803 fopt->regexdir.destroy();
804 fopt->regexfile.destroy();
805 fopt->wild.destroy();
806 fopt->wilddir.destroy();
807 fopt->wildfile.destroy();
808 fopt->base.destroy();
809 fopt->fstype.destroy();
818 if (incexe->opts_list) {
819 free(incexe->opts_list);
825 * Free memory of resource -- called when daemon terminates.
826 * NB, we don't need to worry about freeing any references
827 * to other resources as they will be freed when that
828 * resource chain is traversed. Mainly we worry about freeing
829 * allocated strings (names).
831 void free_resource(RES *sres, int type)
834 RES *nres; /* next resource if linked */
835 URES *res = (URES *)sres;
840 /* common stuff -- free the resource name and description */
841 nres = (RES *)res->res_dir.hdr.next;
842 if (res->res_dir.hdr.name) {
843 free(res->res_dir.hdr.name);
845 if (res->res_dir.hdr.desc) {
846 free(res->res_dir.hdr.desc);
851 if (res->res_dir.working_directory) {
852 free(res->res_dir.working_directory);
854 if (res->res_dir.scripts_directory) {
855 free((char *)res->res_dir.scripts_directory);
857 if (res->res_dir.pid_directory) {
858 free(res->res_dir.pid_directory);
860 if (res->res_dir.subsys_directory) {
861 free(res->res_dir.subsys_directory);
863 if (res->res_dir.password) {
864 free(res->res_dir.password);
866 if (res->res_dir.query_file) {
867 free(res->res_dir.query_file);
869 if (res->res_dir.DIRaddrs) {
870 free_addresses(res->res_dir.DIRaddrs);
872 if (res->res_dir.tls_ctx) {
873 free_tls_context(res->res_dir.tls_ctx);
875 if (res->res_dir.tls_ca_certfile) {
876 free(res->res_dir.tls_ca_certfile);
878 if (res->res_dir.tls_ca_certdir) {
879 free(res->res_dir.tls_ca_certdir);
881 if (res->res_dir.tls_certfile) {
882 free(res->res_dir.tls_certfile);
884 if (res->res_dir.tls_keyfile) {
885 free(res->res_dir.tls_keyfile);
887 if (res->res_dir.tls_dhfile) {
888 free(res->res_dir.tls_dhfile);
890 if (res->res_dir.tls_allowed_cns) {
891 delete res->res_dir.tls_allowed_cns;
898 if (res->res_con.password) {
899 free(res->res_con.password);
901 if (res->res_con.tls_ctx) {
902 free_tls_context(res->res_con.tls_ctx);
904 if (res->res_con.tls_ca_certfile) {
905 free(res->res_con.tls_ca_certfile);
907 if (res->res_con.tls_ca_certdir) {
908 free(res->res_con.tls_ca_certdir);
910 if (res->res_con.tls_certfile) {
911 free(res->res_con.tls_certfile);
913 if (res->res_con.tls_keyfile) {
914 free(res->res_con.tls_keyfile);
916 if (res->res_con.tls_dhfile) {
917 free(res->res_con.tls_dhfile);
919 if (res->res_con.tls_allowed_cns) {
920 delete res->res_con.tls_allowed_cns;
922 for (int i=0; i<Num_ACL; i++) {
923 if (res->res_con.ACL_lists[i]) {
924 delete res->res_con.ACL_lists[i];
925 res->res_con.ACL_lists[i] = NULL;
930 if (res->res_client.address) {
931 free(res->res_client.address);
933 if (res->res_client.password) {
934 free(res->res_client.password);
936 if (res->res_client.tls_ctx) {
937 free_tls_context(res->res_client.tls_ctx);
939 if (res->res_client.tls_ca_certfile) {
940 free(res->res_client.tls_ca_certfile);
942 if (res->res_client.tls_ca_certdir) {
943 free(res->res_client.tls_ca_certdir);
945 if (res->res_client.tls_certfile) {
946 free(res->res_client.tls_certfile);
948 if (res->res_client.tls_keyfile) {
949 free(res->res_client.tls_keyfile);
953 if (res->res_store.address) {
954 free(res->res_store.address);
956 if (res->res_store.password) {
957 free(res->res_store.password);
959 if (res->res_store.media_type) {
960 free(res->res_store.media_type);
962 if (res->res_store.device) {
963 delete res->res_store.device;
965 if (res->res_store.tls_ctx) {
966 free_tls_context(res->res_store.tls_ctx);
968 if (res->res_store.tls_ca_certfile) {
969 free(res->res_store.tls_ca_certfile);
971 if (res->res_store.tls_ca_certdir) {
972 free(res->res_store.tls_ca_certdir);
974 if (res->res_store.tls_certfile) {
975 free(res->res_store.tls_certfile);
977 if (res->res_store.tls_keyfile) {
978 free(res->res_store.tls_keyfile);
982 if (res->res_cat.db_address) {
983 free(res->res_cat.db_address);
985 if (res->res_cat.db_socket) {
986 free(res->res_cat.db_socket);
988 if (res->res_cat.db_user) {
989 free(res->res_cat.db_user);
991 if (res->res_cat.db_name) {
992 free(res->res_cat.db_name);
994 if (res->res_cat.db_password) {
995 free(res->res_cat.db_password);
999 if ((num=res->res_fs.num_includes)) {
1000 while (--num >= 0) {
1001 free_incexe(res->res_fs.include_items[num]);
1003 free(res->res_fs.include_items);
1005 res->res_fs.num_includes = 0;
1006 if ((num=res->res_fs.num_excludes)) {
1007 while (--num >= 0) {
1008 free_incexe(res->res_fs.exclude_items[num]);
1010 free(res->res_fs.exclude_items);
1012 res->res_fs.num_excludes = 0;
1015 if (res->res_pool.pool_type) {
1016 free(res->res_pool.pool_type);
1018 if (res->res_pool.label_format) {
1019 free(res->res_pool.label_format);
1021 if (res->res_pool.cleaning_prefix) {
1022 free(res->res_pool.cleaning_prefix);
1026 if (res->res_sch.run) {
1028 nrun = res->res_sch.run;
1038 if (res->res_job.RestoreWhere) {
1039 free(res->res_job.RestoreWhere);
1041 if (res->res_job.RestoreBootstrap) {
1042 free(res->res_job.RestoreBootstrap);
1044 if (res->res_job.WriteBootstrap) {
1045 free(res->res_job.WriteBootstrap);
1047 if (res->res_job.RunBeforeJob) {
1048 free(res->res_job.RunBeforeJob);
1050 if (res->res_job.RunAfterJob) {
1051 free(res->res_job.RunAfterJob);
1053 if (res->res_job.RunAfterFailedJob) {
1054 free(res->res_job.RunAfterFailedJob);
1056 if (res->res_job.ClientRunBeforeJob) {
1057 free(res->res_job.ClientRunBeforeJob);
1059 if (res->res_job.ClientRunAfterJob) {
1060 free(res->res_job.ClientRunAfterJob);
1062 if (res->res_job.run_cmds) {
1063 delete res->res_job.run_cmds;
1065 if (res->res_job.storage) {
1066 delete res->res_job.storage;
1070 if (res->res_msgs.mail_cmd) {
1071 free(res->res_msgs.mail_cmd);
1073 if (res->res_msgs.operator_cmd) {
1074 free(res->res_msgs.operator_cmd);
1076 free_msgs_res((MSGS *)res); /* free message resource */
1080 printf(_("Unknown resource type %d in free_resource.\n"), type);
1082 /* Common stuff again -- free the resource, recurse to next one */
1087 free_resource(nres, type);
1092 * Save the new resource by chaining it into the head list for
1093 * the resource. If this is pass 2, we update any resource
1094 * pointers because they may not have been defined until
1097 void save_resource(int type, RES_ITEM *items, int pass)
1100 int rindex = type - r_first;
1104 /* Check Job requirements after applying JobDefs */
1105 if (type != R_JOB && type != R_JOBDEFS) {
1107 * Ensure that all required items are present
1109 for (i=0; items[i].name; i++) {
1110 if (items[i].flags & ITEM_REQUIRED) {
1111 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1112 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1113 items[i].name, resources[rindex]);
1116 /* If this triggers, take a look at lib/parse_conf.h */
1117 if (i >= MAX_RES_ITEMS) {
1118 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1121 } else if (type == R_JOB) {
1123 * Ensure that the name item is present
1125 if (items[0].flags & ITEM_REQUIRED) {
1126 if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1127 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1128 items[0].name, resources[rindex]);
1134 * During pass 2 in each "store" routine, we looked up pointers
1135 * to all the resources referrenced in the current resource, now we
1136 * must copy their addresses from the static record to the allocated
1141 /* Resources not containing a resource */
1149 /* Resources containing another resource or alist */
1151 if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1152 Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1154 res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1157 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1158 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1160 res->res_dir.messages = res_all.res_dir.messages;
1161 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1164 if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1165 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1166 res_all.res_dir.hdr.name);
1168 /* we must explicitly copy the device alist pointer */
1169 res->res_store.device = res_all.res_store.device;
1173 if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1174 Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1175 res_all.res_dir.hdr.name);
1177 res->res_job.messages = res_all.res_job.messages;
1178 res->res_job.schedule = res_all.res_job.schedule;
1179 res->res_job.client = res_all.res_job.client;
1180 res->res_job.fileset = res_all.res_job.fileset;
1181 res->res_job.storage = res_all.res_job.storage;
1182 res->res_job.pool = res_all.res_job.pool;
1183 res->res_job.full_pool = res_all.res_job.full_pool;
1184 res->res_job.inc_pool = res_all.res_job.inc_pool;
1185 res->res_job.dif_pool = res_all.res_job.dif_pool;
1186 res->res_job.verify_job = res_all.res_job.verify_job;
1187 res->res_job.jobdefs = res_all.res_job.jobdefs;
1188 res->res_job.run_cmds = res_all.res_job.run_cmds;
1191 if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1192 Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1194 res->res_counter.Catalog = res_all.res_counter.Catalog;
1195 res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1199 if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1200 Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1202 res->res_client.catalog = res_all.res_client.catalog;
1206 * Schedule is a bit different in that it contains a RUN record
1207 * chain which isn't a "named" resource. This chain was linked
1208 * in by run_conf.c during pass 2, so here we jam the pointer
1209 * into the Schedule resource.
1211 if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1212 Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1214 res->res_sch.run = res_all.res_sch.run;
1217 Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1221 /* Note, the resource name was already saved during pass 1,
1222 * so here, we can just release it.
1224 if (res_all.res_dir.hdr.name) {
1225 free(res_all.res_dir.hdr.name);
1226 res_all.res_dir.hdr.name = NULL;
1228 if (res_all.res_dir.hdr.desc) {
1229 free(res_all.res_dir.hdr.desc);
1230 res_all.res_dir.hdr.desc = NULL;
1236 * The following code is only executed during pass 1
1240 size = sizeof(DIRRES);
1243 size = sizeof(CONRES);
1246 size =sizeof(CLIENT);
1249 size = sizeof(STORE);
1259 size = sizeof(FILESET);
1262 size = sizeof(SCHED);
1265 size = sizeof(POOL);
1268 size = sizeof(MSGS);
1271 size = sizeof(COUNTER);
1277 printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1283 res = (URES *)malloc(size);
1284 memcpy(res, &res_all, size);
1285 if (!res_head[rindex]) {
1286 res_head[rindex] = (RES *)res; /* store first entry */
1287 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1288 res->res_dir.hdr.name, rindex);
1291 if (res->res_dir.hdr.name == NULL) {
1292 Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1295 /* Add new res to end of chain */
1296 for (next=res_head[rindex]; next->next; next=next->next) {
1297 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1298 Emsg2(M_ERROR_TERM, 0,
1299 _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1300 resources[rindex].name, res->res_dir.hdr.name);
1303 next->next = (RES *)res;
1304 Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1305 res->res_dir.hdr.name, rindex, pass);
1311 * Store Device. Note, the resource is created upon the
1312 * first reference. The details of the resource are obtained
1313 * later from the SD.
1315 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1319 int rindex = R_DEVICE - r_first;
1320 int size = sizeof(DEVICE);
1324 token = lex_get_token(lc, T_NAME);
1325 if (!res_head[rindex]) {
1326 res = (URES *)malloc(size);
1327 memset(res, 0, size);
1328 res->res_dev.hdr.name = bstrdup(lc->str);
1329 res_head[rindex] = (RES *)res; /* store first entry */
1330 Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1331 res->res_dir.hdr.name, rindex);
1334 /* See if it is already defined */
1335 for (next=res_head[rindex]; next->next; next=next->next) {
1336 if (strcmp(next->name, lc->str) == 0) {
1342 res = (URES *)malloc(size);
1343 memset(res, 0, size);
1344 res->res_dev.hdr.name = bstrdup(lc->str);
1345 next->next = (RES *)res;
1346 Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1347 res->res_dir.hdr.name, rindex, pass);
1352 set_bit(index, res_all.hdr.item_present);
1354 store_alist_res(lc, item, index, pass);
1360 * Store JobType (backup, verify, restore)
1363 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1367 token = lex_get_token(lc, T_NAME);
1368 /* Store the type both pass 1 and pass 2 */
1369 for (i=0; jobtypes[i].type_name; i++) {
1370 if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1371 *(int *)(item->value) = jobtypes[i].job_type;
1377 scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1380 set_bit(index, res_all.hdr.item_present);
1384 * Store Job Level (Full, Incremental, ...)
1387 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1391 token = lex_get_token(lc, T_NAME);
1392 /* Store the level pass 2 so that type is defined */
1393 for (i=0; joblevels[i].level_name; i++) {
1394 if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1395 *(int *)(item->value) = joblevels[i].level;
1401 scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1404 set_bit(index, res_all.hdr.item_present);
1408 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1411 token = lex_get_token(lc, T_NAME);
1412 /* Scan Replacement options */
1413 for (i=0; ReplaceOptions[i].name; i++) {
1414 if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1415 *(int *)(item->value) = ReplaceOptions[i].token;
1421 scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1424 set_bit(index, res_all.hdr.item_present);
1428 * Store ACL (access control list)
1431 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1436 token = lex_get_token(lc, T_NAME);
1438 if (((alist **)item->value)[item->code] == NULL) {
1439 ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1440 Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1442 ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1443 Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1445 token = lex_get_token(lc, T_ALL);
1446 if (token == T_COMMA) {
1447 continue; /* get another ACL */
1451 set_bit(index, res_all.hdr.item_present);