]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/dird_conf.c
Change store_bit() to store_bool() for the Spooling in
[bacula/bacula] / bacula / src / dird / dird_conf.c
1 /*
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).
5  *
6  *   Note, the configuration file parser consists of three parts
7  *
8  *   1. The generic lexical scanner in lib/lex.c and lib/lex.h
9  *
10  *   2. The generic config  scanner in lib/parse_config.c and
11  *      lib/parse_config.h.
12  *      These files contain the parser code, some utility
13  *      routines, and the common store routines (name, int,
14  *      string).
15  *
16  *   3. The daemon specific file, which contains the Resource
17  *      definitions as well as any specific store routines
18  *      for the resource records.
19  *
20  *     Kern Sibbald, January MM
21  *
22  *     Version $Id$
23  */
24 /*
25    Copyright (C) 2000-2006 Kern Sibbald
26
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.
31
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.
36
37  */
38
39 #include "bacula.h"
40 #include "dird.h"
41
42 /* Define the first and last resource ID record
43  * types. Note, these should be unique for each
44  * daemon though not a requirement.
45  */
46 int r_first = R_FIRST;
47 int r_last  = R_LAST;
48 static RES *sres_head[R_LAST - R_FIRST + 1];
49 RES **res_head = sres_head;
50
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);
55
56
57 /* Forward referenced subroutines */
58
59 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
60 void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
61 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
62 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
63 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
64 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
65
66
67 /* We build the current resource here as we are
68  * scanning the resource configuration definition,
69  * then move it to allocated memory when the resource
70  * scan is complete.
71  */
72 URES res_all;
73 int  res_all_size = sizeof(res_all);
74
75
76 /* Definition of records permitted within each
77  * resource with the routine to process the record
78  * information.  NOTE! quoted names must be in lower case.
79  */
80 /*
81  *    Director Resource
82  *
83  *   name          handler     value                 code flags    default_value
84  */
85 static RES_ITEM dir_items[] = {
86    {"name",        store_name,     ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
87    {"description", store_str,      ITEM(res_dir.hdr.desc), 0, 0, 0},
88    {"messages",    store_res,      ITEM(res_dir.messages), R_MSGS, 0, 0},
89    {"dirport",     store_addresses_port,    ITEM(res_dir.DIRaddrs),  0, ITEM_DEFAULT, 9101},
90    {"diraddress",  store_addresses_address, ITEM(res_dir.DIRaddrs),  0, ITEM_DEFAULT, 9101},
91    {"diraddresses",store_addresses,         ITEM(res_dir.DIRaddrs),  0, ITEM_DEFAULT, 9101},
92    {"queryfile",   store_dir,      ITEM(res_dir.query_file), 0, ITEM_REQUIRED, 0},
93    {"workingdirectory", store_dir, ITEM(res_dir.working_directory), 0, ITEM_REQUIRED, 0},
94    {"scriptsdirectory", store_dir, ITEM(res_dir.scripts_directory), 0, 0, 0},
95    {"piddirectory",store_dir,     ITEM(res_dir.pid_directory), 0, ITEM_REQUIRED, 0},
96    {"subsysdirectory", store_dir,  ITEM(res_dir.subsys_directory), 0, 0, 0},
97    {"maximumconcurrentjobs", store_pint, ITEM(res_dir.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
98    {"password",    store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
99    {"fdconnecttimeout", store_time,ITEM(res_dir.FDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
100    {"sdconnecttimeout", store_time,ITEM(res_dir.SDConnectTimeout), 0, ITEM_DEFAULT, 60 * 30},
101    {"tlsenable",            store_bool,      ITEM(res_dir.tls_enable), 0, 0, 0},
102    {"tlsrequire",           store_bool,      ITEM(res_dir.tls_require), 0, 0, 0},
103    {"tlsverifypeer",        store_bool,      ITEM(res_dir.tls_verify_peer), 0, ITEM_DEFAULT, true},
104    {"tlscacertificatefile", store_dir,       ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
105    {"tlscacertificatedir",  store_dir,       ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
106    {"tlscertificate",       store_dir,       ITEM(res_dir.tls_certfile), 0, 0, 0},
107    {"tlskey",               store_dir,       ITEM(res_dir.tls_keyfile), 0, 0, 0},
108    {"tlsdhfile",            store_dir,       ITEM(res_dir.tls_dhfile), 0, 0, 0},
109    {"tlsallowedcn",         store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
110    {NULL, NULL, NULL, 0, 0, 0}
111 };
112
113 /*
114  *    Console Resource
115  *
116  *   name          handler     value                 code flags    default_value
117  */
118 static RES_ITEM con_items[] = {
119    {"name",        store_name,     ITEM(res_con.hdr.name), 0, ITEM_REQUIRED, 0},
120    {"description", store_str,      ITEM(res_con.hdr.desc), 0, 0, 0},
121    {"password",    store_password, ITEM(res_con.password), 0, ITEM_REQUIRED, 0},
122    {"jobacl",      store_acl,      ITEM(res_con.ACL_lists), Job_ACL, 0, 0},
123    {"clientacl",   store_acl,      ITEM(res_con.ACL_lists), Client_ACL, 0, 0},
124    {"storageacl",  store_acl,      ITEM(res_con.ACL_lists), Storage_ACL, 0, 0},
125    {"scheduleacl", store_acl,      ITEM(res_con.ACL_lists), Schedule_ACL, 0, 0},
126    {"runacl",      store_acl,      ITEM(res_con.ACL_lists), Run_ACL, 0, 0},
127    {"poolacl",     store_acl,      ITEM(res_con.ACL_lists), Pool_ACL, 0, 0},
128    {"commandacl",  store_acl,      ITEM(res_con.ACL_lists), Command_ACL, 0, 0},
129    {"filesetacl",  store_acl,      ITEM(res_con.ACL_lists), FileSet_ACL, 0, 0},
130    {"catalogacl",  store_acl,      ITEM(res_con.ACL_lists), Catalog_ACL, 0, 0},
131    {"tlsenable",            store_bool,      ITEM(res_con.tls_enable), 0, 0, 0},
132    {"tlsrequire",           store_bool,      ITEM(res_con.tls_require), 0, 0, 0},
133    {"tlsverifypeer",        store_bool,      ITEM(res_con.tls_verify_peer), 0, ITEM_DEFAULT, true},
134    {"tlscacertificatefile", store_dir,       ITEM(res_con.tls_ca_certfile), 0, 0, 0},
135    {"tlscacertificatedir",  store_dir,       ITEM(res_con.tls_ca_certdir), 0, 0, 0},
136    {"tlscertificate",       store_dir,       ITEM(res_con.tls_certfile), 0, 0, 0},
137    {"tlskey",               store_dir,       ITEM(res_con.tls_keyfile), 0, 0, 0},
138    {"tlsdhfile",            store_dir,       ITEM(res_con.tls_dhfile), 0, 0, 0},
139    {"tlsallowedcn",         store_alist_str, ITEM(res_con.tls_allowed_cns), 0, 0, 0},
140    {NULL, NULL, NULL, 0, 0, 0}
141 };
142
143
144 /*
145  *    Client or File daemon resource
146  *
147  *   name          handler     value                 code flags    default_value
148  */
149
150 static RES_ITEM cli_items[] = {
151    {"name",     store_name,       ITEM(res_client.hdr.name), 0, ITEM_REQUIRED, 0},
152    {"description", store_str,     ITEM(res_client.hdr.desc), 0, 0, 0},
153    {"address",  store_str,        ITEM(res_client.address),  0, ITEM_REQUIRED, 0},
154    {"fdaddress",  store_str,      ITEM(res_client.address),  0, 0, 0},
155    {"fdport",   store_pint,       ITEM(res_client.FDport),   0, ITEM_DEFAULT, 9102},
156    {"password", store_password,   ITEM(res_client.password), 0, ITEM_REQUIRED, 0},
157    {"fdpassword", store_password,   ITEM(res_client.password), 0, 0, 0},
158    {"catalog",  store_res,        ITEM(res_client.catalog),  R_CATALOG, ITEM_REQUIRED, 0},
159    {"fileretention", store_time,  ITEM(res_client.FileRetention), 0, ITEM_DEFAULT, 60*60*24*60},
160    {"jobretention",  store_time,  ITEM(res_client.JobRetention),  0, ITEM_DEFAULT, 60*60*24*180},
161    {"autoprune", store_bool,      ITEM(res_client.AutoPrune), 0, ITEM_DEFAULT, true},
162    {"maximumconcurrentjobs", store_pint, ITEM(res_client.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
163    {"tlsenable",            store_bool,      ITEM(res_client.tls_enable), 0, 0, 0},
164    {"tlsrequire",           store_bool,      ITEM(res_client.tls_require), 0, 0, 0},
165    {"tlscacertificatefile", store_dir,       ITEM(res_client.tls_ca_certfile), 0, 0, 0},
166    {"tlscacertificatedir",  store_dir,       ITEM(res_client.tls_ca_certdir), 0, 0, 0},
167    {"tlscertificate",       store_dir,       ITEM(res_client.tls_certfile), 0, 0, 0},
168    {"tlskey",               store_dir,       ITEM(res_client.tls_keyfile), 0, 0, 0},
169    {NULL, NULL, NULL, 0, 0, 0}
170 };
171
172 /* Storage daemon resource
173  *
174  *   name          handler     value                 code flags    default_value
175  */
176 static RES_ITEM store_items[] = {
177    {"name",        store_name,     ITEM(res_store.hdr.name),   0, ITEM_REQUIRED, 0},
178    {"description", store_str,      ITEM(res_store.hdr.desc),   0, 0, 0},
179    {"sdport",      store_pint,     ITEM(res_store.SDport),     0, ITEM_DEFAULT, 9103},
180    {"address",     store_str,      ITEM(res_store.address),    0, ITEM_REQUIRED, 0},
181    {"sdaddress",   store_str,      ITEM(res_store.address),    0, 0, 0},
182    {"password",    store_password, ITEM(res_store.password),   0, ITEM_REQUIRED, 0},
183    {"sdpassword",  store_password, ITEM(res_store.password),   0, 0, 0},
184    {"device",      store_device,   ITEM(res_store.device),     R_DEVICE, ITEM_REQUIRED, 0},
185    {"mediatype",   store_strname,  ITEM(res_store.media_type), 0, ITEM_REQUIRED, 0},
186    {"autochanger", store_bool,     ITEM(res_store.autochanger), 0, ITEM_DEFAULT, 0},
187    {"enabled",     store_bool,     ITEM(res_store.enabled),     0, ITEM_DEFAULT, true},
188    {"maximumconcurrentjobs", store_pint, ITEM(res_store.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
189    {"sddport", store_pint, ITEM(res_store.SDDport), 0, 0, 0}, /* deprecated */
190    {"tlsenable",            store_bool,      ITEM(res_store.tls_enable), 0, 0, 0},
191    {"tlsrequire",           store_bool,      ITEM(res_store.tls_require), 0, 0, 0},
192    {"tlscacertificatefile", store_dir,       ITEM(res_store.tls_ca_certfile), 0, 0, 0},
193    {"tlscacertificatedir",  store_dir,       ITEM(res_store.tls_ca_certdir), 0, 0, 0},
194    {"tlscertificate",       store_dir,       ITEM(res_store.tls_certfile), 0, 0, 0},
195    {"tlskey",               store_dir,       ITEM(res_store.tls_keyfile), 0, 0, 0},
196    {NULL, NULL, NULL, 0, 0, 0}
197 };
198
199 /*
200  *    Catalog Resource Directives
201  *
202  *   name          handler     value                 code flags    default_value
203  */
204 static RES_ITEM cat_items[] = {
205    {"name",     store_name,     ITEM(res_cat.hdr.name),    0, ITEM_REQUIRED, 0},
206    {"description", store_str,   ITEM(res_cat.hdr.desc),    0, 0, 0},
207    {"address",  store_str,      ITEM(res_cat.db_address),  0, 0, 0},
208    {"dbaddress", store_str,     ITEM(res_cat.db_address),  0, 0, 0},
209    {"dbport",   store_pint,     ITEM(res_cat.db_port),      0, 0, 0},
210    /* keep this password as store_str for the moment */
211    {"password", store_str,      ITEM(res_cat.db_password), 0, 0, 0},
212    {"dbpassword", store_str,    ITEM(res_cat.db_password), 0, 0, 0},
213    {"user",     store_str,      ITEM(res_cat.db_user),     0, 0, 0},
214    {"dbname",   store_str,      ITEM(res_cat.db_name),     0, ITEM_REQUIRED, 0},
215    {"dbsocket", store_str,      ITEM(res_cat.db_socket),   0, 0, 0},
216    /* Turned off for the moment */
217    {"multipleconnections", store_bit, ITEM(res_cat.mult_db_connections), 0, 0, 0},
218    {NULL, NULL, NULL, 0, 0, 0}
219 };
220
221 /*
222  *    Job Resource Directives
223  *
224  *   name          handler     value                 code flags    default_value
225  */
226 RES_ITEM job_items[] = {
227    {"name",      store_name,    ITEM(res_job.hdr.name), 0, ITEM_REQUIRED, 0},
228    {"description", store_str,   ITEM(res_job.hdr.desc), 0, 0, 0},
229    {"type",      store_jobtype, ITEM(res_job.JobType),  0, ITEM_REQUIRED, 0},
230    {"level",     store_level,   ITEM(res_job.JobLevel),    0, 0, 0},
231    {"messages",  store_res,     ITEM(res_job.messages), R_MSGS, ITEM_REQUIRED, 0},
232    {"storage",   store_alist_res, ITEM(res_job.storage),  R_STORAGE, 0, 0},
233    {"pool",      store_res,     ITEM(res_job.pool),     R_POOL, ITEM_REQUIRED, 0},
234    {"fullbackuppool",  store_res, ITEM(res_job.full_pool),   R_POOL, 0, 0},
235    {"incrementalbackuppool",  store_res, ITEM(res_job.inc_pool), R_POOL, 0, 0},
236    {"differentialbackuppool", store_res, ITEM(res_job.dif_pool), R_POOL, 0, 0},
237    {"client",    store_res,     ITEM(res_job.client),   R_CLIENT, ITEM_REQUIRED, 0},
238    {"fileset",   store_res,     ITEM(res_job.fileset),  R_FILESET, ITEM_REQUIRED, 0},
239    {"schedule",  store_res,     ITEM(res_job.schedule), R_SCHEDULE, 0, 0},
240    {"verifyjob", store_res,     ITEM(res_job.verify_job), R_JOB, 0, 0},
241    {"jobtoverify", store_res,   ITEM(res_job.verify_job), R_JOB, 0, 0},
242    {"jobdefs",   store_res,     ITEM(res_job.jobdefs),    R_JOBDEFS, 0, 0},
243    {"nextpool",  store_res,     ITEM(res_job.next_pool),  R_POOL, 0, 0},
244    {"run",       store_alist_str, ITEM(res_job.run_cmds), 0, 0, 0},
245    /* Root of where to restore files */
246    {"where",    store_dir,      ITEM(res_job.RestoreWhere), 0, 0, 0},
247    /* Where to find bootstrap during restore */
248    {"bootstrap",store_dir,      ITEM(res_job.RestoreBootstrap), 0, 0, 0},
249    /* Where to write bootstrap file during backup */
250    {"writebootstrap",store_dir, ITEM(res_job.WriteBootstrap), 0, 0, 0},
251    {"writeverifylist",store_dir, ITEM(res_job.WriteVerifyList), 0, 0, 0},
252    {"replace",  store_replace,  ITEM(res_job.replace), 0, ITEM_DEFAULT, REPLACE_ALWAYS},
253    {"maxruntime",   store_time, ITEM(res_job.MaxRunTime), 0, 0, 0},
254    {"fullmaxwaittime",  store_time, ITEM(res_job.FullMaxWaitTime), 0, 0, 0},
255    {"incrementalmaxwaittime",  store_time, ITEM(res_job.IncMaxWaitTime), 0, 0, 0},
256    {"differentialmaxwaittime",  store_time, ITEM(res_job.DiffMaxWaitTime), 0, 0, 0},
257    {"maxwaittime",  store_time, ITEM(res_job.MaxWaitTime), 0, 0, 0},
258    {"maxstartdelay",store_time, ITEM(res_job.MaxStartDelay), 0, 0, 0},
259    {"jobretention", store_time, ITEM(res_job.JobRetention),  0, 0, 0},
260    {"prefixlinks", store_bool, ITEM(res_job.PrefixLinks), 0, ITEM_DEFAULT, false},
261    {"prunejobs",   store_bool, ITEM(res_job.PruneJobs), 0, ITEM_DEFAULT, false},
262    {"prunefiles",  store_bool, ITEM(res_job.PruneFiles), 0, ITEM_DEFAULT, false},
263    {"prunevolumes",store_bool, ITEM(res_job.PruneVolumes), 0, ITEM_DEFAULT, false},
264    {"enabled",     store_bool, ITEM(res_job.enabled), 0, ITEM_DEFAULT, true},
265    {"spoolattributes",store_bool, ITEM(res_job.SpoolAttributes), 0, ITEM_DEFAULT, false},
266    {"spooldata",   store_bool, ITEM(res_job.spool_data), 0, ITEM_DEFAULT, false},
267    {"rerunfailedlevels",   store_bool, ITEM(res_job.rerun_failed_levels), 0, ITEM_DEFAULT, false},
268    {"prefermountedvolumes", store_bool, ITEM(res_job.PreferMountedVolumes), 0, ITEM_DEFAULT, true},
269    {"runbeforejob", store_str,  ITEM(res_job.RunBeforeJob), 0, 0, 0},
270    {"runafterjob",  store_str,  ITEM(res_job.RunAfterJob),  0, 0, 0},
271    {"runafterfailedjob",  store_str,  ITEM(res_job.RunAfterFailedJob),  0, 0, 0},
272    {"clientrunbeforejob", store_str,  ITEM(res_job.ClientRunBeforeJob), 0, 0, 0},
273    {"clientrunafterjob",  store_str,  ITEM(res_job.ClientRunAfterJob),  0, 0, 0},
274    {"maximumconcurrentjobs", store_pint, ITEM(res_job.MaxConcurrentJobs), 0, ITEM_DEFAULT, 1},
275    {"rescheduleonerror", store_bool, ITEM(res_job.RescheduleOnError), 0, ITEM_DEFAULT, false},
276    {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30},
277    {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0},
278    {"priority",   store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10},
279    {"writepartafterjob",   store_bool, ITEM(res_job.write_part_after_job), 0, ITEM_DEFAULT, false},
280    {"selectionpattern", store_str, ITEM(res_job.selection_pattern), 0, 0, 0},
281    {"selectiontype", store_migtype, ITEM(res_job.selection_type), 0, 0, 0},
282    {NULL, NULL, NULL, 0, 0, 0}
283 };
284
285 /* FileSet resource
286  *
287  *   name          handler     value                 code flags    default_value
288  */
289 static RES_ITEM fs_items[] = {
290    {"name",        store_name, ITEM(res_fs.hdr.name), 0, ITEM_REQUIRED, 0},
291    {"description", store_str,  ITEM(res_fs.hdr.desc), 0, 0, 0},
292    {"include",     store_inc,  NULL,                  0, ITEM_NO_EQUALS, 0},
293    {"exclude",     store_inc,  NULL,                  1, ITEM_NO_EQUALS, 0},
294    {"ignorefilesetchanges", store_bool, ITEM(res_fs.ignore_fs_changes), 0, ITEM_DEFAULT, false},
295    {"enablevss",   store_bool, ITEM(res_fs.enable_vss), 0, ITEM_DEFAULT, false},
296    {NULL,          NULL,       NULL,                  0, 0, 0}
297 };
298
299 /* Schedule -- see run_conf.c */
300 /* Schedule
301  *
302  *   name          handler     value                 code flags    default_value
303  */
304 static RES_ITEM sch_items[] = {
305    {"name",     store_name,  ITEM(res_sch.hdr.name), 0, ITEM_REQUIRED, 0},
306    {"description", store_str, ITEM(res_sch.hdr.desc), 0, 0, 0},
307    {"run",      store_run,   ITEM(res_sch.run),      0, 0, 0},
308    {NULL, NULL, NULL, 0, 0, 0}
309 };
310
311 /* Pool resource
312  *
313  *   name             handler     value                        code flags default_value
314  */
315 static RES_ITEM pool_items[] = {
316    {"name",            store_name,    ITEM(res_pool.hdr.name),      0, ITEM_REQUIRED, 0},
317    {"description",     store_str,     ITEM(res_pool.hdr.desc),      0, 0,     0},
318    {"pooltype",        store_strname, ITEM(res_pool.pool_type),     0, ITEM_REQUIRED, 0},
319    {"labelformat",     store_strname, ITEM(res_pool.label_format),  0, 0,     0},
320    {"labeltype",       store_label,   ITEM(res_pool.LabelType),     0, 0,     0},     
321    {"cleaningprefix",  store_strname, ITEM(res_pool.cleaning_prefix), 0, 0,   0},
322    {"usecatalog",      store_bool,    ITEM(res_pool.use_catalog),    0, ITEM_DEFAULT, true},
323    {"usevolumeonce",   store_bool,    ITEM(res_pool.use_volume_once), 0, 0,   0},
324    {"purgeoldestvolume", store_bool,  ITEM(res_pool.purge_oldest_volume), 0, 0, 0},
325    {"recycleoldestvolume", store_bool,  ITEM(res_pool.recycle_oldest_volume), 0, 0, 0},
326    {"recyclecurrentvolume", store_bool, ITEM(res_pool.recycle_current_volume), 0, 0, 0},
327    {"maximumvolumes",  store_pint,    ITEM(res_pool.max_volumes),   0, 0,        0},
328    {"maximumvolumejobs", store_pint,  ITEM(res_pool.MaxVolJobs),    0, 0,       0},
329    {"maximumvolumefiles", store_pint, ITEM(res_pool.MaxVolFiles),   0, 0,       0},
330    {"maximumvolumebytes", store_size, ITEM(res_pool.MaxVolBytes),   0, 0,       0},
331    {"acceptanyvolume", store_bool,    ITEM(res_pool.accept_any_volume), 0, ITEM_DEFAULT, true},
332    {"catalogfiles",    store_bool,    ITEM(res_pool.catalog_files),  0, ITEM_DEFAULT, true},
333    {"volumeretention", store_time,    ITEM(res_pool.VolRetention),   0, ITEM_DEFAULT, 60*60*24*365},
334    {"volumeuseduration", store_time,  ITEM(res_pool.VolUseDuration), 0, 0, 0},
335    {"migrationtime",  store_time,     ITEM(res_pool.MigrationTime), 0, 0, 0},
336    {"migrationhighbytes", store_size, ITEM(res_pool.MigrationHighBytes), 0, 0, 0},
337    {"migrationlowbytes", store_size,  ITEM(res_pool.MigrationLowBytes), 0, 0, 0},
338    {"nextpool",      store_res,       ITEM(res_pool.NextPool), R_POOL, 0, 0},
339    {"storage",       store_alist_res, ITEM(res_pool.storage),  R_STORAGE, 0, 0},
340    {"autoprune",       store_bool,    ITEM(res_pool.AutoPrune), 0, ITEM_DEFAULT, true},
341    {"recycle",         store_bool,    ITEM(res_pool.Recycle),   0, ITEM_DEFAULT, true},
342    {NULL, NULL, NULL, 0, 0, 0}
343 };
344
345 /*
346  * Counter Resource
347  *   name             handler     value                        code flags default_value
348  */
349 static RES_ITEM counter_items[] = {
350    {"name",            store_name,    ITEM(res_counter.hdr.name),        0, ITEM_REQUIRED, 0},
351    {"description",     store_str,     ITEM(res_counter.hdr.desc),        0, 0,     0},
352    {"minimum",         store_int,     ITEM(res_counter.MinValue),        0, ITEM_DEFAULT, 0},
353    {"maximum",         store_pint,    ITEM(res_counter.MaxValue),        0, ITEM_DEFAULT, INT32_MAX},
354    {"wrapcounter",     store_res,     ITEM(res_counter.WrapCounter),     R_COUNTER, 0, 0},
355    {"catalog",         store_res,     ITEM(res_counter.Catalog),         R_CATALOG, 0, 0},
356    {NULL, NULL, NULL, 0, 0, 0}
357 };
358
359
360 /* Message resource */
361 extern RES_ITEM msgs_items[];
362
363 /*
364  * This is the master resource definition.
365  * It must have one item for each of the resources.
366  *
367  *  NOTE!!! keep it in the same order as the R_codes
368  *    or eliminate all resources[rindex].name
369  *
370  *  name             items        rcode        res_head
371  */
372 RES_TABLE resources[] = {
373    {"director",      dir_items,   R_DIRECTOR},
374    {"client",        cli_items,   R_CLIENT},
375    {"job",           job_items,   R_JOB},
376    {"storage",       store_items, R_STORAGE},
377    {"catalog",       cat_items,   R_CATALOG},
378    {"schedule",      sch_items,   R_SCHEDULE},
379    {"fileset",       fs_items,    R_FILESET},
380    {"pool",          pool_items,  R_POOL},
381    {"messages",      msgs_items,  R_MSGS},
382    {"counter",       counter_items, R_COUNTER},
383    {"console",       con_items,   R_CONSOLE},
384    {"jobdefs",       job_items,   R_JOBDEFS},
385    {"device",        NULL,        R_DEVICE},  /* info obtained from SD */
386    {NULL,            NULL,        0}
387 };
388
389
390 /* Keywords (RHS) permitted in Job Level records
391  *
392  *   level_name      level              job_type
393  */
394 struct s_jl joblevels[] = {
395    {"Full",          L_FULL,            JT_BACKUP},
396    {"Base",          L_BASE,            JT_BACKUP},
397    {"Incremental",   L_INCREMENTAL,     JT_BACKUP},
398    {"Differential",  L_DIFFERENTIAL,    JT_BACKUP},
399    {"Since",         L_SINCE,           JT_BACKUP},
400    {"Catalog",       L_VERIFY_CATALOG,  JT_VERIFY},
401    {"InitCatalog",   L_VERIFY_INIT,     JT_VERIFY},
402    {"VolumeToCatalog", L_VERIFY_VOLUME_TO_CATALOG,   JT_VERIFY},
403    {"DiskToCatalog", L_VERIFY_DISK_TO_CATALOG,   JT_VERIFY},
404    {"Data",          L_VERIFY_DATA,     JT_VERIFY},
405    {" ",             L_NONE,            JT_ADMIN},
406    {" ",             L_NONE,            JT_RESTORE},
407    {NULL,            0,                          0}
408 };
409
410 /* Keywords (RHS) permitted in Job type records
411  *
412  *   type_name       job_type
413  */
414 struct s_jt jobtypes[] = {
415    {"backup",        JT_BACKUP},
416    {"admin",         JT_ADMIN},
417    {"verify",        JT_VERIFY},
418    {"restore",       JT_RESTORE},
419    {"migrate",       JT_MIGRATE},
420    {NULL,            0}
421 };
422
423
424 /* Keywords (RHS) permitted in Selection type records
425  *
426  *   type_name       job_type
427  */
428 struct s_jt migtypes[] = {
429    {"smallestvolume",   MT_SMALLEST_VOL},
430    {"oldestvolume",     MT_OLDEST_VOL},
431    {"pooloccupancy",    MT_POOL_OCCUPANCY},
432    {"pooltime",         MT_POOL_TIME},
433    {"client",           MT_CLIENT},
434    {"volume",           MT_VOLUME},
435    {"job",              MT_JOB},
436    {"sqlquery",         MT_SQLQUERY},
437    {NULL,            0}
438 };
439
440
441
442 /* Options permitted in Restore replace= */
443 struct s_kw ReplaceOptions[] = {
444    {"always",         REPLACE_ALWAYS},
445    {"ifnewer",        REPLACE_IFNEWER},
446    {"ifolder",        REPLACE_IFOLDER},
447    {"never",          REPLACE_NEVER},
448    {NULL,               0}
449 };
450
451 const char *level_to_str(int level)
452 {
453    int i;
454    static char level_no[30];
455    const char *str = level_no;
456
457    bsnprintf(level_no, sizeof(level_no), "%c (%d)", level, level);    /* default if not found */
458    for (i=0; joblevels[i].level_name; i++) {
459       if (level == joblevels[i].level) {
460          str = joblevels[i].level_name;
461          break;
462       }
463    }
464    return str;
465 }
466
467 /* Dump contents of resource */
468 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
469 {
470    URES *res = (URES *)reshdr;
471    bool recurse = true;
472    char ed1[100], ed2[100], ed3[100];
473    DEVICE *dev;
474
475    if (res == NULL) {
476       sendit(sock, _("No %s resource defined\n"), res_to_str(type));
477       return;
478    }
479    if (type < 0) {                    /* no recursion */
480       type = - type;
481       recurse = false;
482    }
483    switch (type) {
484    case R_DIRECTOR:
485       sendit(sock, _("Director: name=%s MaxJobs=%d FDtimeout=%s SDtimeout=%s\n"),
486          reshdr->name, res->res_dir.MaxConcurrentJobs,
487          edit_uint64(res->res_dir.FDConnectTimeout, ed1),
488          edit_uint64(res->res_dir.SDConnectTimeout, ed2));
489       if (res->res_dir.query_file) {
490          sendit(sock, _("   query_file=%s\n"), res->res_dir.query_file);
491       }
492       if (res->res_dir.messages) {
493          sendit(sock, _("  --> "));
494          dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock);
495       }
496       break;
497    case R_CONSOLE:
498       sendit(sock, _("Console: name=%s SSL=%d\n"),
499          res->res_con.hdr.name, res->res_con.tls_enable);
500       break;
501    case R_COUNTER:
502       if (res->res_counter.WrapCounter) {
503          sendit(sock, _("Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n"),
504             res->res_counter.hdr.name, res->res_counter.MinValue,
505             res->res_counter.MaxValue, res->res_counter.CurrentValue,
506             res->res_counter.WrapCounter->hdr.name);
507       } else {
508          sendit(sock, _("Counter: name=%s min=%d max=%d\n"),
509             res->res_counter.hdr.name, res->res_counter.MinValue,
510             res->res_counter.MaxValue);
511       }
512       if (res->res_counter.Catalog) {
513          sendit(sock, _("  --> "));
514          dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock);
515       }
516       break;
517
518    case R_CLIENT:
519       sendit(sock, _("Client: name=%s address=%s FDport=%d MaxJobs=%u\n"),
520          res->res_client.hdr.name, res->res_client.address, res->res_client.FDport,
521          res->res_client.MaxConcurrentJobs);
522       sendit(sock, _("      JobRetention=%s FileRetention=%s AutoPrune=%d\n"),
523          edit_utime(res->res_client.JobRetention, ed1, sizeof(ed1)),
524          edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)),
525          res->res_client.AutoPrune);
526       if (res->res_client.catalog) {
527          sendit(sock, _("  --> "));
528          dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock);
529       }
530       break;
531    case R_DEVICE:
532       dev = &res->res_dev;
533       char ed1[50];
534       sendit(sock, _("Device: name=%s ok=%d num_writers=%d max_writers=%d\n"
535 "      reserved=%d open=%d append=%d read=%d labeled=%d offline=%d autochgr=%d\n"
536 "      poolid=%s volname=%s MediaType=%s\n"),
537          dev->hdr.name, dev->found, dev->num_writers, dev->max_writers,
538          dev->reserved, dev->open, dev->append, dev->read, dev->labeled,
539          dev->offline, dev->autochanger,
540          edit_uint64(dev->PoolId, ed1),
541          dev->VolumeName, dev->MediaType);
542       break;
543    case R_STORAGE:
544       sendit(sock, _("Storage: name=%s address=%s SDport=%d MaxJobs=%u\n"
545 "      DeviceName=%s MediaType=%s StorageId=%s\n"),
546          res->res_store.hdr.name, res->res_store.address, res->res_store.SDport,
547          res->res_store.MaxConcurrentJobs,
548          res->res_store.dev_name(),
549          res->res_store.media_type,
550          edit_int64(res->res_store.StorageId, ed1));
551       break;
552    case R_CATALOG:
553       sendit(sock, _("Catalog: name=%s address=%s DBport=%d db_name=%s\n"
554 "      db_user=%s MutliDBConn=%d\n"),
555          res->res_cat.hdr.name, NPRT(res->res_cat.db_address),
556          res->res_cat.db_port, res->res_cat.db_name, NPRT(res->res_cat.db_user),
557          res->res_cat.mult_db_connections);
558       break;
559    case R_JOB:
560    case R_JOBDEFS:
561       sendit(sock, _("%s: name=%s JobType=%d level=%s Priority=%d Enabled=%d\n"),
562          type == R_JOB ? _("Job") : _("JobDefs"),
563          res->res_job.hdr.name, res->res_job.JobType,
564          level_to_str(res->res_job.JobLevel), res->res_job.Priority,
565          res->res_job.enabled);
566       sendit(sock, _("     MaxJobs=%u Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n"),
567          res->res_job.MaxConcurrentJobs, 
568          res->res_job.RescheduleOnError, res->res_job.RescheduleTimes,
569          edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1),
570          res->res_job.spool_data, res->res_job.write_part_after_job);
571       if (res->res_job.JobType == JT_MIGRATE) {
572          sendit(sock, _("     SelectionType=%d\n"), res->res_job.selection_type);
573       }
574       if (res->res_job.client) {
575          sendit(sock, _("  --> "));
576          dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock);
577       }
578       if (res->res_job.fileset) {
579          sendit(sock, _("  --> "));
580          dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock);
581       }
582       if (res->res_job.schedule) {
583          sendit(sock, _("  --> "));
584          dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock);
585       }
586       if (res->res_job.RestoreWhere) {
587          sendit(sock, _("  --> Where=%s\n"), NPRT(res->res_job.RestoreWhere));
588       }
589       if (res->res_job.RestoreBootstrap) {
590          sendit(sock, _("  --> Bootstrap=%s\n"), NPRT(res->res_job.RestoreBootstrap));
591       }
592       if (res->res_job.RunBeforeJob) {
593          sendit(sock, _("  --> RunBefore=%s\n"), NPRT(res->res_job.RunBeforeJob));
594       }
595       if (res->res_job.RunAfterJob) {
596          sendit(sock, _("  --> RunAfter=%s\n"), NPRT(res->res_job.RunAfterJob));
597       }
598       if (res->res_job.RunAfterFailedJob) {
599          sendit(sock, _("  --> RunAfterFailed=%s\n"), NPRT(res->res_job.RunAfterFailedJob));
600       }
601       if (res->res_job.WriteBootstrap) {
602          sendit(sock, _("  --> WriteBootstrap=%s\n"), NPRT(res->res_job.WriteBootstrap));
603       }
604       if (res->res_job.storage) {
605          STORE *store;
606          foreach_alist(store, res->res_job.storage) {
607             sendit(sock, _("  --> "));
608             dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
609          }
610       }
611       if (res->res_job.pool) {
612          sendit(sock, _("  --> "));
613          dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock);
614       }
615       if (res->res_job.full_pool) {
616          sendit(sock, _("  --> "));
617          dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock);
618       }
619       if (res->res_job.inc_pool) {
620          sendit(sock, _("  --> "));
621          dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock);
622       }
623       if (res->res_job.dif_pool) {
624          sendit(sock, _("  --> "));
625          dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock);
626       }
627       if (res->res_job.verify_job) {
628          sendit(sock, _("  --> "));
629          dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock);
630       }
631       if (res->res_job.run_cmds) {
632          char *runcmd;
633          foreach_alist(runcmd, res->res_job.run_cmds) {
634             sendit(sock, _("  --> Run=%s\n"), runcmd);
635          }
636       }
637       if (res->res_job.selection_pattern) {
638          sendit(sock, _("  --> SelectionPattern=%s\n"), NPRT(res->res_job.selection_pattern));
639       }
640       if (res->res_job.messages) {
641          sendit(sock, _("  --> "));
642          dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock);
643       }
644       break;
645    case R_FILESET:
646    {
647       int i, j, k;
648       sendit(sock, _("FileSet: name=%s\n"), res->res_fs.hdr.name);
649       for (i=0; i<res->res_fs.num_includes; i++) {
650          INCEXE *incexe = res->res_fs.include_items[i];
651          for (j=0; j<incexe->num_opts; j++) {
652             FOPTS *fo = incexe->opts_list[j];
653             sendit(sock, "      O %s\n", fo->opts);
654             for (k=0; k<fo->regex.size(); k++) {
655                sendit(sock, "      R %s\n", fo->regex.get(k));
656             }
657             for (k=0; k<fo->regexdir.size(); k++) {
658                sendit(sock, "      RD %s\n", fo->regexdir.get(k));
659             }
660             for (k=0; k<fo->regexfile.size(); k++) {
661                sendit(sock, "      RF %s\n", fo->regexfile.get(k));
662             }
663             for (k=0; k<fo->wild.size(); k++) {
664                sendit(sock, "      W %s\n", fo->wild.get(k));
665             }
666             for (k=0; k<fo->wilddir.size(); k++) {
667                sendit(sock, "      WD %s\n", fo->wilddir.get(k));
668             }
669             for (k=0; k<fo->wildfile.size(); k++) {
670                sendit(sock, "      WF %s\n", fo->wildfile.get(k));
671             }
672             for (k=0; k<fo->base.size(); k++) {
673                sendit(sock, "      B %s\n", fo->base.get(k));
674             }
675             for (k=0; k<fo->fstype.size(); k++) {
676                sendit(sock, "      X %s\n", fo->fstype.get(k));
677             }
678             if (fo->reader) {
679                sendit(sock, "      D %s\n", fo->reader);
680             }
681             if (fo->writer) {
682                sendit(sock, "      T %s\n", fo->writer);
683             }
684             sendit(sock, "      N\n");
685          }
686          for (j=0; j<incexe->name_list.size(); j++) {
687             sendit(sock, "      I %s\n", incexe->name_list.get(j));
688          }
689          if (incexe->name_list.size()) {
690             sendit(sock, "      N\n");
691          }
692       }
693
694       for (i=0; i<res->res_fs.num_excludes; i++) {
695          INCEXE *incexe = res->res_fs.exclude_items[i];
696          for (j=0; j<incexe->name_list.size(); j++) {
697             sendit(sock, "      E %s\n", incexe->name_list.get(j));
698          }
699          if (incexe->name_list.size()) {
700             sendit(sock, "      N\n");
701          }
702       }
703       break;
704    }
705    case R_SCHEDULE:
706       if (res->res_sch.run) {
707          int i;
708          RUN *run = res->res_sch.run;
709          char buf[1000], num[30];
710          sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
711          if (!run) {
712             break;
713          }
714 next_run:
715          sendit(sock, _("  --> Run Level=%s\n"), level_to_str(run->level));
716          bstrncpy(buf, _("      hour="), sizeof(buf));
717          for (i=0; i<24; i++) {
718             if (bit_is_set(i, run->hour)) {
719                bsnprintf(num, sizeof(num), "%d ", i);
720                bstrncat(buf, num, sizeof(buf));
721             }
722          }
723          bstrncat(buf, "\n", sizeof(buf));
724          sendit(sock, buf);
725          bstrncpy(buf, _("      mday="), sizeof(buf));
726          for (i=0; i<31; i++) {
727             if (bit_is_set(i, run->mday)) {
728                bsnprintf(num, sizeof(num), "%d ", i);
729                bstrncat(buf, num, sizeof(buf));
730             }
731          }
732          bstrncat(buf, "\n", sizeof(buf));
733          sendit(sock, buf);
734          bstrncpy(buf, _("      month="), sizeof(buf));
735          for (i=0; i<12; i++) {
736             if (bit_is_set(i, run->month)) {
737                bsnprintf(num, sizeof(num), "%d ", i);
738                bstrncat(buf, num, sizeof(buf));
739             }
740          }
741          bstrncat(buf, "\n", sizeof(buf));
742          sendit(sock, buf);
743          bstrncpy(buf, _("      wday="), sizeof(buf));
744          for (i=0; i<7; i++) {
745             if (bit_is_set(i, run->wday)) {
746                bsnprintf(num, sizeof(num), "%d ", i);
747                bstrncat(buf, num, sizeof(buf));
748             }
749          }
750          bstrncat(buf, "\n", sizeof(buf));
751          sendit(sock, buf);
752          bstrncpy(buf, _("      wom="), sizeof(buf));
753          for (i=0; i<5; i++) {
754             if (bit_is_set(i, run->wom)) {
755                bsnprintf(num, sizeof(num), "%d ", i);
756                bstrncat(buf, num, sizeof(buf));
757             }
758          }
759          bstrncat(buf, "\n", sizeof(buf));
760          sendit(sock, buf);
761          bstrncpy(buf, _("      woy="), sizeof(buf));
762          for (i=0; i<54; i++) {
763             if (bit_is_set(i, run->woy)) {
764                bsnprintf(num, sizeof(num), "%d ", i);
765                bstrncat(buf, num, sizeof(buf));
766             }
767          }
768          bstrncat(buf, "\n", sizeof(buf));
769          sendit(sock, buf);
770          sendit(sock, _("      mins=%d\n"), run->minute);
771          if (run->pool) {
772             sendit(sock, _("     --> "));
773             dump_resource(-R_POOL, (RES *)run->pool, sendit, sock);
774          }
775          if (run->storage) {
776             sendit(sock, _("     --> "));
777             dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock);
778          }
779          if (run->msgs) {
780             sendit(sock, _("     --> "));
781             dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock);
782          }
783          /* If another Run record is chained in, go print it */
784          if (run->next) {
785             run = run->next;
786             goto next_run;
787          }
788       } else {
789          sendit(sock, _("Schedule: name=%s\n"), res->res_sch.hdr.name);
790       }
791       break;
792    case R_POOL:
793       sendit(sock, _("Pool: name=%s PoolType=%s\n"), res->res_pool.hdr.name,
794               res->res_pool.pool_type);
795       sendit(sock, _("      use_cat=%d use_once=%d acpt_any=%d cat_files=%d\n"),
796               res->res_pool.use_catalog, res->res_pool.use_volume_once,
797               res->res_pool.accept_any_volume, res->res_pool.catalog_files);
798       sendit(sock, _("      max_vols=%d auto_prune=%d VolRetention=%s\n"),
799               res->res_pool.max_volumes, res->res_pool.AutoPrune,
800               edit_utime(res->res_pool.VolRetention, ed1, sizeof(ed1)));
801       sendit(sock, _("      VolUse=%s recycle=%d LabelFormat=%s\n"),
802               edit_utime(res->res_pool.VolUseDuration, ed1, sizeof(ed1)),
803               res->res_pool.Recycle,
804               NPRT(res->res_pool.label_format));
805       sendit(sock, _("      CleaningPrefix=%s LabelType=%d\n"),
806               NPRT(res->res_pool.cleaning_prefix), res->res_pool.LabelType);
807       sendit(sock, _("      RecyleOldest=%d PurgeOldest=%d MaxVolJobs=%d MaxVolFiles=%d\n"),
808               res->res_pool.recycle_oldest_volume,
809               res->res_pool.purge_oldest_volume,
810               res->res_pool.MaxVolJobs, res->res_pool.MaxVolFiles);
811       sendit(sock, _("      MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
812               edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
813               edit_uint64(res->res_pool.MigrationHighBytes, ed2),
814               edit_uint64(res->res_pool.MigrationLowBytes, ed3));
815       if (res->res_pool.NextPool) {
816          sendit(sock, _("  --> "));
817          dump_resource(-R_POOL, (RES *)res->res_pool.NextPool, sendit, sock);
818       }
819       if (res->res_pool.storage) {
820          STORE *store;
821          foreach_alist(store, res->res_pool.storage) {
822             sendit(sock, _("  --> "));
823             dump_resource(-R_STORAGE, (RES *)store, sendit, sock);
824          }
825       }
826       break;
827    case R_MSGS:
828       sendit(sock, _("Messages: name=%s\n"), res->res_msgs.hdr.name);
829       if (res->res_msgs.mail_cmd)
830          sendit(sock, _("      mailcmd=%s\n"), res->res_msgs.mail_cmd);
831       if (res->res_msgs.operator_cmd)
832          sendit(sock, _("      opcmd=%s\n"), res->res_msgs.operator_cmd);
833       break;
834    default:
835       sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type);
836       break;
837    }
838    if (recurse && res->res_dir.hdr.next) {
839       dump_resource(type, res->res_dir.hdr.next, sendit, sock);
840    }
841 }
842
843 /*
844  * Free all the members of an INCEXE structure
845  */
846 static void free_incexe(INCEXE *incexe)
847 {
848    incexe->name_list.destroy();
849    for (int i=0; i<incexe->num_opts; i++) {
850       FOPTS *fopt = incexe->opts_list[i];
851       fopt->regex.destroy();
852       fopt->regexdir.destroy();
853       fopt->regexfile.destroy();
854       fopt->wild.destroy();
855       fopt->wilddir.destroy();
856       fopt->wildfile.destroy();
857       fopt->base.destroy();
858       fopt->fstype.destroy();
859       if (fopt->reader) {
860          free(fopt->reader);
861       }
862       if (fopt->writer) {
863          free(fopt->writer);
864       }
865       free(fopt);
866    }
867    if (incexe->opts_list) {
868       free(incexe->opts_list);
869    }
870    free(incexe);
871 }
872
873 /*
874  * Free memory of resource -- called when daemon terminates.
875  * NB, we don't need to worry about freeing any references
876  * to other resources as they will be freed when that
877  * resource chain is traversed.  Mainly we worry about freeing
878  * allocated strings (names).
879  */
880 void free_resource(RES *sres, int type)
881 {
882    int num;
883    RES *nres;                         /* next resource if linked */
884    URES *res = (URES *)sres;
885
886    if (res == NULL)
887       return;
888
889    /* common stuff -- free the resource name and description */
890    nres = (RES *)res->res_dir.hdr.next;
891    if (res->res_dir.hdr.name) {
892       free(res->res_dir.hdr.name);
893    }
894    if (res->res_dir.hdr.desc) {
895       free(res->res_dir.hdr.desc);
896    }
897
898    switch (type) {
899    case R_DIRECTOR:
900       if (res->res_dir.working_directory) {
901          free(res->res_dir.working_directory);
902       }
903       if (res->res_dir.scripts_directory) {
904          free((char *)res->res_dir.scripts_directory);
905       }
906       if (res->res_dir.pid_directory) {
907          free(res->res_dir.pid_directory);
908       }
909       if (res->res_dir.subsys_directory) {
910          free(res->res_dir.subsys_directory);
911       }
912       if (res->res_dir.password) {
913          free(res->res_dir.password);
914       }
915       if (res->res_dir.query_file) {
916          free(res->res_dir.query_file);
917       }
918       if (res->res_dir.DIRaddrs) {
919          free_addresses(res->res_dir.DIRaddrs);
920       }
921       if (res->res_dir.tls_ctx) { 
922          free_tls_context(res->res_dir.tls_ctx);
923       }
924       if (res->res_dir.tls_ca_certfile) {
925          free(res->res_dir.tls_ca_certfile);
926       }
927       if (res->res_dir.tls_ca_certdir) {
928          free(res->res_dir.tls_ca_certdir);
929       }
930       if (res->res_dir.tls_certfile) {
931          free(res->res_dir.tls_certfile);
932       }
933       if (res->res_dir.tls_keyfile) {
934          free(res->res_dir.tls_keyfile);
935       }
936       if (res->res_dir.tls_dhfile) {
937          free(res->res_dir.tls_dhfile);
938       }
939       if (res->res_dir.tls_allowed_cns) {
940          delete res->res_dir.tls_allowed_cns;
941       }
942       break;
943    case R_DEVICE:
944    case R_COUNTER:
945        break;
946    case R_CONSOLE:
947       if (res->res_con.password) {
948          free(res->res_con.password);
949       }
950       if (res->res_con.tls_ctx) { 
951          free_tls_context(res->res_con.tls_ctx);
952       }
953       if (res->res_con.tls_ca_certfile) {
954          free(res->res_con.tls_ca_certfile);
955       }
956       if (res->res_con.tls_ca_certdir) {
957          free(res->res_con.tls_ca_certdir);
958       }
959       if (res->res_con.tls_certfile) {
960          free(res->res_con.tls_certfile);
961       }
962       if (res->res_con.tls_keyfile) {
963          free(res->res_con.tls_keyfile);
964       }
965       if (res->res_con.tls_dhfile) {
966          free(res->res_con.tls_dhfile);
967       }
968       if (res->res_con.tls_allowed_cns) {
969          delete res->res_con.tls_allowed_cns;
970       }
971       for (int i=0; i<Num_ACL; i++) {
972          if (res->res_con.ACL_lists[i]) {
973             delete res->res_con.ACL_lists[i];
974             res->res_con.ACL_lists[i] = NULL;
975          }
976       }
977       break;
978    case R_CLIENT:
979       if (res->res_client.address) {
980          free(res->res_client.address);
981       }
982       if (res->res_client.password) {
983          free(res->res_client.password);
984       }
985       if (res->res_client.tls_ctx) { 
986          free_tls_context(res->res_client.tls_ctx);
987       }
988       if (res->res_client.tls_ca_certfile) {
989          free(res->res_client.tls_ca_certfile);
990       }
991       if (res->res_client.tls_ca_certdir) {
992          free(res->res_client.tls_ca_certdir);
993       }
994       if (res->res_client.tls_certfile) {
995          free(res->res_client.tls_certfile);
996       }
997       if (res->res_client.tls_keyfile) {
998          free(res->res_client.tls_keyfile);
999       }
1000       break;
1001    case R_STORAGE:
1002       if (res->res_store.address) {
1003          free(res->res_store.address);
1004       }
1005       if (res->res_store.password) {
1006          free(res->res_store.password);
1007       }
1008       if (res->res_store.media_type) {
1009          free(res->res_store.media_type);
1010       }
1011       if (res->res_store.device) {
1012          delete res->res_store.device;
1013       }
1014       if (res->res_store.tls_ctx) { 
1015          free_tls_context(res->res_store.tls_ctx);
1016       }
1017       if (res->res_store.tls_ca_certfile) {
1018          free(res->res_store.tls_ca_certfile);
1019       }
1020       if (res->res_store.tls_ca_certdir) {
1021          free(res->res_store.tls_ca_certdir);
1022       }
1023       if (res->res_store.tls_certfile) {
1024          free(res->res_store.tls_certfile);
1025       }
1026       if (res->res_store.tls_keyfile) {
1027          free(res->res_store.tls_keyfile);
1028       }
1029       break;
1030    case R_CATALOG:
1031       if (res->res_cat.db_address) {
1032          free(res->res_cat.db_address);
1033       }
1034       if (res->res_cat.db_socket) {
1035          free(res->res_cat.db_socket);
1036       }
1037       if (res->res_cat.db_user) {
1038          free(res->res_cat.db_user);
1039       }
1040       if (res->res_cat.db_name) {
1041          free(res->res_cat.db_name);
1042       }
1043       if (res->res_cat.db_password) {
1044          free(res->res_cat.db_password);
1045       }
1046       break;
1047    case R_FILESET:
1048       if ((num=res->res_fs.num_includes)) {
1049          while (--num >= 0) {
1050             free_incexe(res->res_fs.include_items[num]);
1051          }
1052          free(res->res_fs.include_items);
1053       }
1054       res->res_fs.num_includes = 0;
1055       if ((num=res->res_fs.num_excludes)) {
1056          while (--num >= 0) {
1057             free_incexe(res->res_fs.exclude_items[num]);
1058          }
1059          free(res->res_fs.exclude_items);
1060       }
1061       res->res_fs.num_excludes = 0;
1062       break;
1063    case R_POOL:
1064       if (res->res_pool.pool_type) {
1065          free(res->res_pool.pool_type);
1066       }
1067       if (res->res_pool.label_format) {
1068          free(res->res_pool.label_format);
1069       }
1070       if (res->res_pool.cleaning_prefix) {
1071          free(res->res_pool.cleaning_prefix);
1072       }
1073       if (res->res_pool.storage) {
1074          delete res->res_pool.storage;
1075       }
1076       break;
1077    case R_SCHEDULE:
1078       if (res->res_sch.run) {
1079          RUN *nrun, *next;
1080          nrun = res->res_sch.run;
1081          while (nrun) {
1082             next = nrun->next;
1083             free(nrun);
1084             nrun = next;
1085          }
1086       }
1087       break;
1088    case R_JOB:
1089    case R_JOBDEFS:
1090       if (res->res_job.RestoreWhere) {
1091          free(res->res_job.RestoreWhere);
1092       }
1093       if (res->res_job.RestoreBootstrap) {
1094          free(res->res_job.RestoreBootstrap);
1095       }
1096       if (res->res_job.WriteBootstrap) {
1097          free(res->res_job.WriteBootstrap);
1098       }
1099       if (res->res_job.RunBeforeJob) {
1100          free(res->res_job.RunBeforeJob);
1101       }
1102       if (res->res_job.RunAfterJob) {
1103          free(res->res_job.RunAfterJob);
1104       }
1105       if (res->res_job.RunAfterFailedJob) {
1106          free(res->res_job.RunAfterFailedJob);
1107       }
1108       if (res->res_job.ClientRunBeforeJob) {
1109          free(res->res_job.ClientRunBeforeJob);
1110       }
1111       if (res->res_job.ClientRunAfterJob) {
1112          free(res->res_job.ClientRunAfterJob);
1113       }
1114       if (res->res_job.selection_pattern) {
1115          free(res->res_job.selection_pattern);
1116       }
1117       if (res->res_job.run_cmds) {
1118          delete res->res_job.run_cmds;
1119       }
1120       if (res->res_job.storage) {
1121          delete res->res_job.storage;
1122       }
1123       break;
1124    case R_MSGS:
1125       if (res->res_msgs.mail_cmd) {
1126          free(res->res_msgs.mail_cmd);
1127       }
1128       if (res->res_msgs.operator_cmd) {
1129          free(res->res_msgs.operator_cmd);
1130       }
1131       free_msgs_res((MSGS *)res);  /* free message resource */
1132       res = NULL;
1133       break;
1134    default:
1135       printf(_("Unknown resource type %d in free_resource.\n"), type);
1136    }
1137    /* Common stuff again -- free the resource, recurse to next one */
1138    if (res) {
1139       free(res);
1140    }
1141    if (nres) {
1142       free_resource(nres, type);
1143    }
1144 }
1145
1146 /*
1147  * Save the new resource by chaining it into the head list for
1148  * the resource. If this is pass 2, we update any resource
1149  * pointers because they may not have been defined until
1150  * later in pass 1.
1151  */
1152 void save_resource(int type, RES_ITEM *items, int pass)
1153 {
1154    URES *res;
1155    int rindex = type - r_first;
1156    int i, size = 0;
1157    bool error = false;
1158
1159    /* Check Job requirements after applying JobDefs */
1160    if (type != R_JOB && type != R_JOBDEFS) {
1161       /*
1162        * Ensure that all required items are present
1163        */
1164       for (i=0; items[i].name; i++) {
1165          if (items[i].flags & ITEM_REQUIRED) {
1166             if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
1167                 Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1168                     items[i].name, resources[rindex]);
1169             }
1170          }
1171          /* If this triggers, take a look at lib/parse_conf.h */
1172          if (i >= MAX_RES_ITEMS) {
1173             Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
1174          }
1175       }
1176    } else if (type == R_JOB) {
1177       /*
1178        * Ensure that the name item is present
1179        */
1180       if (items[0].flags & ITEM_REQUIRED) {
1181          if (!bit_is_set(0, res_all.res_dir.hdr.item_present)) {
1182              Emsg2(M_ERROR_TERM, 0, _("%s item is required in %s resource, but not found.\n"),
1183                    items[0].name, resources[rindex]);
1184          }
1185       }
1186    }
1187
1188    /*
1189     * During pass 2 in each "store" routine, we looked up pointers
1190     * to all the resources referrenced in the current resource, now we
1191     * must copy their addresses from the static record to the allocated
1192     * record.
1193     */
1194    if (pass == 2) {
1195       switch (type) {
1196       /* Resources not containing a resource */
1197       case R_CATALOG:
1198       case R_MSGS:
1199       case R_FILESET:
1200       case R_DEVICE:
1201          break;
1202
1203       /*
1204        * Resources containing another resource or alist. First
1205        *  look up the resource which contains another resource. It
1206        *  was written during pass 1.  Then stuff in the pointers to
1207        *  the resources it contains, which were inserted this pass.
1208        *  Finally, it will all be stored back.
1209        */
1210       case R_POOL:
1211          /* Find resource saved in pass 1 */
1212          if ((res = (URES *)GetResWithName(R_POOL, res_all.res_con.hdr.name)) == NULL) {
1213             Emsg1(M_ERROR_TERM, 0, _("Cannot find Pool resource %s\n"), res_all.res_con.hdr.name);
1214          }
1215          /* Explicitly copy resource pointers from this pass (res_all) */
1216          res->res_pool.NextPool = res_all.res_pool.NextPool;
1217          res->res_pool.storage    = res_all.res_pool.storage;
1218          break;
1219       case R_CONSOLE:
1220          if ((res = (URES *)GetResWithName(R_CONSOLE, res_all.res_con.hdr.name)) == NULL) {
1221             Emsg1(M_ERROR_TERM, 0, _("Cannot find Console resource %s\n"), res_all.res_con.hdr.name);
1222          }
1223          res->res_con.tls_allowed_cns = res_all.res_con.tls_allowed_cns;
1224          break;
1225       case R_DIRECTOR:
1226          if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
1227             Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
1228          }
1229          res->res_dir.messages = res_all.res_dir.messages;
1230          res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
1231          break;
1232       case R_STORAGE:
1233          if ((res = (URES *)GetResWithName(type, res_all.res_store.hdr.name)) == NULL) {
1234             Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"),
1235                   res_all.res_dir.hdr.name);
1236          }
1237          /* we must explicitly copy the device alist pointer */
1238          res->res_store.device   = res_all.res_store.device;
1239          break;
1240       case R_JOB:
1241       case R_JOBDEFS:
1242          if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) {
1243             Emsg1(M_ERROR_TERM, 0, _("Cannot find Job resource %s\n"),
1244                   res_all.res_dir.hdr.name);
1245          }
1246          res->res_job.messages   = res_all.res_job.messages;
1247          res->res_job.schedule   = res_all.res_job.schedule;
1248          res->res_job.client     = res_all.res_job.client;
1249          res->res_job.fileset    = res_all.res_job.fileset;
1250          res->res_job.storage    = res_all.res_job.storage;
1251          res->res_job.pool       = res_all.res_job.pool;
1252          res->res_job.full_pool  = res_all.res_job.full_pool;
1253          res->res_job.inc_pool   = res_all.res_job.inc_pool;
1254          res->res_job.dif_pool   = res_all.res_job.dif_pool;
1255          res->res_job.verify_job = res_all.res_job.verify_job;
1256          res->res_job.jobdefs    = res_all.res_job.jobdefs;
1257          res->res_job.run_cmds   = res_all.res_job.run_cmds;
1258          break;
1259       case R_COUNTER:
1260          if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) {
1261             Emsg1(M_ERROR_TERM, 0, _("Cannot find Counter resource %s\n"), res_all.res_counter.hdr.name);
1262          }
1263          res->res_counter.Catalog = res_all.res_counter.Catalog;
1264          res->res_counter.WrapCounter = res_all.res_counter.WrapCounter;
1265          break;
1266
1267       case R_CLIENT:
1268          if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) {
1269             Emsg1(M_ERROR_TERM, 0, _("Cannot find Client resource %s\n"), res_all.res_client.hdr.name);
1270          }
1271          res->res_client.catalog = res_all.res_client.catalog;
1272          break;
1273       case R_SCHEDULE:
1274          /*
1275           * Schedule is a bit different in that it contains a RUN record
1276           * chain which isn't a "named" resource. This chain was linked
1277           * in by run_conf.c during pass 2, so here we jam the pointer
1278           * into the Schedule resource.
1279           */
1280          if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) {
1281             Emsg1(M_ERROR_TERM, 0, _("Cannot find Schedule resource %s\n"), res_all.res_client.hdr.name);
1282          }
1283          res->res_sch.run = res_all.res_sch.run;
1284          break;
1285       default:
1286          Emsg1(M_ERROR, 0, _("Unknown resource type %d in save_resource.\n"), type);
1287          error = true;
1288          break;
1289       }
1290       /* Note, the resource name was already saved during pass 1,
1291        * so here, we can just release it.
1292        */
1293       if (res_all.res_dir.hdr.name) {
1294          free(res_all.res_dir.hdr.name);
1295          res_all.res_dir.hdr.name = NULL;
1296       }
1297       if (res_all.res_dir.hdr.desc) {
1298          free(res_all.res_dir.hdr.desc);
1299          res_all.res_dir.hdr.desc = NULL;
1300       }
1301       return;
1302    }
1303
1304    /*
1305     * The following code is only executed during pass 1
1306     */
1307    switch (type) {
1308    case R_DIRECTOR:
1309       size = sizeof(DIRRES);
1310       break;
1311    case R_CONSOLE:
1312       size = sizeof(CONRES);
1313       break;
1314    case R_CLIENT:
1315       size =sizeof(CLIENT);
1316       break;
1317    case R_STORAGE:
1318       size = sizeof(STORE);
1319       break;
1320    case R_CATALOG:
1321       size = sizeof(CAT);
1322       break;
1323    case R_JOB:
1324    case R_JOBDEFS:
1325       size = sizeof(JOB);
1326       break;
1327    case R_FILESET:
1328       size = sizeof(FILESET);
1329       break;
1330    case R_SCHEDULE:
1331       size = sizeof(SCHED);
1332       break;
1333    case R_POOL:
1334       size = sizeof(POOL);
1335       break;
1336    case R_MSGS:
1337       size = sizeof(MSGS);
1338       break;
1339    case R_COUNTER:
1340       size = sizeof(COUNTER);
1341       break;
1342    case R_DEVICE:
1343       error = true;
1344       break;
1345    default:
1346       printf(_("Unknown resource type %d in save_resrouce.\n"), type);
1347       error = true; 
1348       break;
1349    }
1350    /* Common */
1351    if (!error) {
1352       res = (URES *)malloc(size);
1353       memcpy(res, &res_all, size);
1354       if (!res_head[rindex]) {
1355          res_head[rindex] = (RES *)res; /* store first entry */
1356          Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type),
1357                res->res_dir.hdr.name, rindex);
1358       } else {
1359          RES *next;
1360          if (res->res_dir.hdr.name == NULL) {
1361             Emsg1(M_ERROR_TERM, 0, _("Name item is required in %s resource, but not found.\n"),
1362                   resources[rindex]);
1363          }   
1364          /* Add new res to end of chain */
1365          for (next=res_head[rindex]; next->next; next=next->next) {
1366             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
1367                Emsg2(M_ERROR_TERM, 0,
1368                   _("Attempt to define second %s resource named \"%s\" is not permitted.\n"),
1369                   resources[rindex].name, res->res_dir.hdr.name);
1370             }
1371          }
1372          next->next = (RES *)res;
1373          Dmsg4(900, _("Inserting %s res: %s index=%d pass=%d\n"), res_to_str(type),
1374                res->res_dir.hdr.name, rindex, pass);
1375       }
1376    }
1377 }
1378
1379 /*
1380  * Store Device. Note, the resource is created upon the
1381  *  first reference. The details of the resource are obtained
1382  *  later from the SD.
1383  */
1384 static void store_device(LEX *lc, RES_ITEM *item, int index, int pass)
1385 {
1386    int token;
1387    URES *res;
1388    int rindex = R_DEVICE - r_first;
1389    int size = sizeof(DEVICE);
1390    bool found = false;
1391
1392    if (pass == 1) {
1393       token = lex_get_token(lc, T_NAME);
1394       if (!res_head[rindex]) {
1395          res = (URES *)malloc(size);
1396          memset(res, 0, size);
1397          res->res_dev.hdr.name = bstrdup(lc->str);
1398          res_head[rindex] = (RES *)res; /* store first entry */
1399          Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(R_DEVICE),
1400                res->res_dir.hdr.name, rindex);
1401       } else {
1402          RES *next;
1403          /* See if it is already defined */
1404          for (next=res_head[rindex]; next->next; next=next->next) {
1405             if (strcmp(next->name, lc->str) == 0) {
1406                found = true;
1407                break;
1408             }
1409          }
1410          if (!found) {
1411             res = (URES *)malloc(size);
1412             memset(res, 0, size);
1413             res->res_dev.hdr.name = bstrdup(lc->str);
1414             next->next = (RES *)res;
1415             Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(R_DEVICE),
1416                res->res_dir.hdr.name, rindex, pass);
1417          }
1418       }
1419
1420       scan_to_eol(lc);
1421       set_bit(index, res_all.hdr.item_present);
1422    } else {
1423       store_alist_res(lc, item, index, pass);
1424    }
1425 }
1426
1427 /*
1428  * Store JobType (backup, verify, restore)
1429  *
1430  */
1431 static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
1432 {
1433    int token, i;
1434
1435    token = lex_get_token(lc, T_NAME);
1436    /* Store the type both pass 1 and pass 2 */
1437    for (i=0; migtypes[i].type_name; i++) {
1438       if (strcasecmp(lc->str, migtypes[i].type_name) == 0) {
1439          *(int *)(item->value) = migtypes[i].job_type;
1440          i = 0;
1441          break;
1442       }
1443    }
1444    if (i != 0) {
1445       scan_err1(lc, _("Expected a Migration Job Type keyword, got: %s"), lc->str);
1446    }
1447    scan_to_eol(lc);
1448    set_bit(index, res_all.hdr.item_present);
1449 }
1450
1451
1452
1453 /*
1454  * Store JobType (backup, verify, restore)
1455  *
1456  */
1457 void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass)
1458 {
1459    int token, i;
1460
1461    token = lex_get_token(lc, T_NAME);
1462    /* Store the type both pass 1 and pass 2 */
1463    for (i=0; jobtypes[i].type_name; i++) {
1464       if (strcasecmp(lc->str, jobtypes[i].type_name) == 0) {
1465          *(int *)(item->value) = jobtypes[i].job_type;
1466          i = 0;
1467          break;
1468       }
1469    }
1470    if (i != 0) {
1471       scan_err1(lc, _("Expected a Job Type keyword, got: %s"), lc->str);
1472    }
1473    scan_to_eol(lc);
1474    set_bit(index, res_all.hdr.item_present);
1475 }
1476
1477 /*
1478  * Store Job Level (Full, Incremental, ...)
1479  *
1480  */
1481 void store_level(LEX *lc, RES_ITEM *item, int index, int pass)
1482 {
1483    int token, i;
1484
1485    token = lex_get_token(lc, T_NAME);
1486    /* Store the level pass 2 so that type is defined */
1487    for (i=0; joblevels[i].level_name; i++) {
1488       if (strcasecmp(lc->str, joblevels[i].level_name) == 0) {
1489          *(int *)(item->value) = joblevels[i].level;
1490          i = 0;
1491          break;
1492       }
1493    }
1494    if (i != 0) {
1495       scan_err1(lc, _("Expected a Job Level keyword, got: %s"), lc->str);
1496    }
1497    scan_to_eol(lc);
1498    set_bit(index, res_all.hdr.item_present);
1499 }
1500
1501
1502 void store_replace(LEX *lc, RES_ITEM *item, int index, int pass)
1503 {
1504    int token, i;
1505    token = lex_get_token(lc, T_NAME);
1506    /* Scan Replacement options */
1507    for (i=0; ReplaceOptions[i].name; i++) {
1508       if (strcasecmp(lc->str, ReplaceOptions[i].name) == 0) {
1509          *(int *)(item->value) = ReplaceOptions[i].token;
1510          i = 0;
1511          break;
1512       }
1513    }
1514    if (i != 0) {
1515       scan_err1(lc, _("Expected a Restore replacement option, got: %s"), lc->str);
1516    }
1517    scan_to_eol(lc);
1518    set_bit(index, res_all.hdr.item_present);
1519 }
1520
1521 /*
1522  * Store ACL (access control list)
1523  *
1524  */
1525 void store_acl(LEX *lc, RES_ITEM *item, int index, int pass)
1526 {
1527    int token;
1528
1529    for (;;) {
1530       token = lex_get_token(lc, T_NAME);
1531       if (pass == 1) {
1532          if (((alist **)item->value)[item->code] == NULL) {
1533             ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist));
1534             Dmsg1(900, "Defined new ACL alist at %d\n", item->code);
1535          }
1536          ((alist **)item->value)[item->code]->append(bstrdup(lc->str));
1537          Dmsg2(900, "Appended to %d %s\n", item->code, lc->str);
1538       }
1539       token = lex_get_token(lc, T_ALL);
1540       if (token == T_COMMA) {
1541          continue;                    /* get another ACL */
1542       }
1543       break;
1544    }
1545    set_bit(index, res_all.hdr.item_present);
1546 }