]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored_conf.c
Merge branch 'master' into basejobv3
[bacula/bacula] / bacula / src / stored / stored_conf.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  * Configuration file parser for Bacula Storage daemon
30  *
31  *     Kern Sibbald, March MM
32  *
33  *   Version $Id$
34  */
35
36 #include "bacula.h"
37 #include "stored.h"
38
39 /* First and last resource ids */
40 int32_t r_first = R_FIRST;
41 int32_t r_last  = R_LAST;
42 static RES *sres_head[R_LAST - R_FIRST + 1];
43 RES **res_head = sres_head;
44
45
46 /* Forward referenced subroutines */
47 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass);
48 static void store_maxblocksize(LEX *lc, RES_ITEM *item, int index, int pass);
49
50
51 /* We build the current resource here statically,
52  * then move it to dynamic memory */
53 #if defined(_MSC_VER)
54 extern "C" { // work around visual compiler mangling variables
55     URES res_all;
56 }
57 #else
58 URES res_all;
59 #endif
60 int32_t res_all_size = sizeof(res_all);
61
62 /* Definition of records permitted within each
63  * resource with the routine to process the record
64  * information.
65  */
66
67 /* Globals for the Storage daemon. */
68 static RES_ITEM store_items[] = {
69    {"name",                  store_name, ITEM(res_store.hdr.name),   0, ITEM_REQUIRED, 0},
70    {"description",           store_str,  ITEM(res_dir.hdr.desc),     0, 0, 0},
71    {"sdaddress",             store_addresses_address,  ITEM(res_store.sdaddrs),     0, ITEM_DEFAULT, 9103},
72    {"sdaddresses",           store_addresses,  ITEM(res_store.sdaddrs), 0, ITEM_DEFAULT, 9103},
73    {"messages",              store_res,  ITEM(res_store.messages),   R_MSGS, 0, 0},
74    {"sdport",                store_addresses_port,  ITEM(res_store.sdaddrs),     0, ITEM_DEFAULT, 9103},
75    {"workingdirectory",      store_dir,  ITEM(res_store.working_directory), 0, ITEM_REQUIRED, 0},
76    {"piddirectory",          store_dir,  ITEM(res_store.pid_directory), 0, ITEM_REQUIRED, 0},
77    {"subsysdirectory",       store_dir,  ITEM(res_store.subsys_directory), 0, 0, 0},
78    {"plugindirectory",       store_dir,  ITEM(res_store.plugin_directory), 0, 0, 0},
79    {"scriptsdirectory",      store_dir,  ITEM(res_store.scripts_directory), 0, 0, 0},
80    {"maximumconcurrentjobs", store_pint32, ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 20},
81    {"heartbeatinterval",     store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
82    {"tlsauthenticate",       store_bool,    ITEM(res_store.tls_authenticate), 0, 0, 0},
83    {"tlsenable",             store_bool,    ITEM(res_store.tls_enable), 0, 0, 0},
84    {"tlsrequire",            store_bool,    ITEM(res_store.tls_require), 0, 0, 0},
85    {"tlsverifypeer",         store_bool,    ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1},
86    {"tlscacertificatefile",  store_dir,       ITEM(res_store.tls_ca_certfile), 0, 0, 0},
87    {"tlscacertificatedir",   store_dir,       ITEM(res_store.tls_ca_certdir), 0, 0, 0},
88    {"tlscertificate",        store_dir,       ITEM(res_store.tls_certfile), 0, 0, 0},
89    {"tlskey",                store_dir,       ITEM(res_store.tls_keyfile), 0, 0, 0},
90    {"tlsdhfile",             store_dir,       ITEM(res_store.tls_dhfile), 0, 0, 0},
91    {"tlsallowedcn",          store_alist_str, ITEM(res_store.tls_allowed_cns), 0, 0, 0},
92    {"clientconnectwait",     store_time,  ITEM(res_store.client_wait), 0, ITEM_DEFAULT, 30 * 60},
93    {"verid",                 store_str,       ITEM(res_store.verid), 0, 0, 0},
94    {NULL, NULL, {0}, 0, 0, 0}
95 };
96
97
98 /* Directors that can speak to the Storage daemon */
99 static RES_ITEM dir_items[] = {
100    {"name",        store_name,     ITEM(res_dir.hdr.name),   0, ITEM_REQUIRED, 0},
101    {"description", store_str,      ITEM(res_dir.hdr.desc),   0, 0, 0},
102    {"password",    store_password, ITEM(res_dir.password),   0, ITEM_REQUIRED, 0},
103    {"monitor",     store_bool,     ITEM(res_dir.monitor),    0, 0, 0},
104    {"tlsauthenticate",      store_bool,    ITEM(res_dir.tls_authenticate), 0, 0, 0},
105    {"tlsenable",            store_bool,    ITEM(res_dir.tls_enable), 0, 0, 0},
106    {"tlsrequire",           store_bool,    ITEM(res_dir.tls_require), 0, 0, 0},
107    {"tlsverifypeer",        store_bool,    ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1},
108    {"tlscacertificatefile", store_dir,       ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
109    {"tlscacertificatedir",  store_dir,       ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
110    {"tlscertificate",       store_dir,       ITEM(res_dir.tls_certfile), 0, 0, 0},
111    {"tlskey",               store_dir,       ITEM(res_dir.tls_keyfile), 0, 0, 0},
112    {"tlsdhfile",            store_dir,       ITEM(res_dir.tls_dhfile), 0, 0, 0},
113    {"tlsallowedcn",         store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
114    {NULL, NULL, {0}, 0, 0, 0}
115 };
116
117 /* Device definition */
118 static RES_ITEM dev_items[] = {
119    {"name",                  store_name,   ITEM(res_dev.hdr.name),    0, ITEM_REQUIRED, 0},
120    {"description",           store_str,    ITEM(res_dir.hdr.desc),    0, 0, 0},
121    {"mediatype",             store_strname,ITEM(res_dev.media_type),  0, ITEM_REQUIRED, 0},
122    {"devicetype",            store_devtype,ITEM(res_dev.dev_type),    0, 0, 0},
123    {"archivedevice",         store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
124    {"hardwareendoffile",     store_bit,  ITEM(res_dev.cap_bits), CAP_EOF,  ITEM_DEFAULT, 1},
125    {"hardwareendofmedium",   store_bit,  ITEM(res_dev.cap_bits), CAP_EOM,  ITEM_DEFAULT, 1},
126    {"backwardspacerecord",   store_bit,  ITEM(res_dev.cap_bits), CAP_BSR,  ITEM_DEFAULT, 1},
127    {"backwardspacefile",     store_bit,  ITEM(res_dev.cap_bits), CAP_BSF,  ITEM_DEFAULT, 1},
128    {"bsfateom",              store_bit,  ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
129    {"twoeof",                store_bit,  ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
130    {"forwardspacerecord",    store_bit,  ITEM(res_dev.cap_bits), CAP_FSR,  ITEM_DEFAULT, 1},
131    {"forwardspacefile",      store_bit,  ITEM(res_dev.cap_bits), CAP_FSF,  ITEM_DEFAULT, 1},
132    {"fastforwardspacefile",  store_bit,  ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
133    {"removablemedia",        store_bit,  ITEM(res_dev.cap_bits), CAP_REM,  ITEM_DEFAULT, 1},
134    {"randomaccess",          store_bit,  ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
135    {"automaticmount",        store_bit,  ITEM(res_dev.cap_bits), CAP_AUTOMOUNT,  ITEM_DEFAULT, 0},
136    {"labelmedia",            store_bit,  ITEM(res_dev.cap_bits), CAP_LABEL,      ITEM_DEFAULT, 0},
137    {"alwaysopen",            store_bit,  ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
138    {"autochanger",           store_bit,  ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
139    {"closeonpoll",           store_bit,  ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
140    {"blockpositioning",      store_bit,  ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
141    {"usemtiocget",           store_bit,  ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
142    {"checklabels",           store_bit,  ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
143    {"requiresmount",         store_bit,  ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
144    {"offlineonunmount",      store_bit,  ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
145    {"autoselect",            store_bool, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
146    {"changerdevice",         store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
147    {"changercommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
148    {"alertcommand",          store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
149    {"maximumchangerwait",    store_time,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
150    {"maximumopenwait",       store_time,   ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
151    {"maximumopenvolumes",    store_pint32,   ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
152    {"maximumnetworkbuffersize", store_pint32, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
153    {"volumepollinterval",    store_time,   ITEM(res_dev.vol_poll_interval), 0, 0, 0},
154    {"maximumrewindwait",     store_time,   ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
155    {"minimumblocksize",      store_pint32,   ITEM(res_dev.min_block_size), 0, 0, 0},
156    {"maximumblocksize",      store_maxblocksize, ITEM(res_dev.max_block_size), 0, 0, 0},
157    {"maximumvolumesize",     store_size,   ITEM(res_dev.max_volume_size), 0, 0, 0},
158    {"maximumfilesize",       store_size,   ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
159    {"volumecapacity",        store_size,   ITEM(res_dev.volume_capacity), 0, 0, 0},
160    {"maximumconcurrentjobs", store_pint32, ITEM(res_dev.max_concurrent_jobs), 0, 0, 0},
161    {"spooldirectory",        store_dir,    ITEM(res_dev.spool_directory), 0, 0, 0},
162    {"maximumspoolsize",      store_size,   ITEM(res_dev.max_spool_size), 0, 0, 0},
163    {"maximumjobspoolsize",   store_size,   ITEM(res_dev.max_job_spool_size), 0, 0, 0},
164    {"driveindex",            store_pint32,   ITEM(res_dev.drive_index), 0, 0, 0},
165    {"maximumpartsize",       store_size,   ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
166    {"mountpoint",            store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
167    {"mountcommand",          store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
168    {"unmountcommand",        store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
169    {"writepartcommand",      store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
170    {"freespacecommand",      store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
171    {"labeltype",             store_label,  ITEM(res_dev.label_type), 0, 0, 0},
172    {NULL, NULL, {0}, 0, 0, 0}
173 };
174
175 /* Autochanger definition */
176 static RES_ITEM changer_items[] = {
177    {"name",              store_name,      ITEM(res_changer.hdr.name),        0, ITEM_REQUIRED, 0},
178    {"description",       store_str,       ITEM(res_changer.hdr.desc),        0, 0, 0},
179    {"device",            store_alist_res, ITEM(res_changer.device),   R_DEVICE, ITEM_REQUIRED, 0},
180    {"changerdevice",     store_strname,   ITEM(res_changer.changer_name),    0, ITEM_REQUIRED, 0},
181    {"changercommand",    store_strname,   ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
182    {NULL, NULL, {0}, 0, 0, 0}
183 };
184
185
186 // {"mountanonymousvolumes", store_bit,  ITEM(res_dev.cap_bits), CAP_ANONVOLS,   ITEM_DEFAULT, 0},
187
188
189 /* Message resource */
190 extern RES_ITEM msgs_items[];
191
192
193 /* This is the master resource definition */
194 RES_TABLE resources[] = {
195    {"director",      dir_items,     R_DIRECTOR},
196    {"storage",       store_items,   R_STORAGE},
197    {"device",        dev_items,     R_DEVICE},
198    {"messages",      msgs_items,    R_MSGS},
199    {"autochanger",   changer_items, R_AUTOCHANGER},
200    {NULL,            NULL,          0}
201 };
202
203 /*
204  * Device types
205  *
206  *   device type     device code = token
207  */
208 struct s_kw {
209    const char *name;
210    int32_t token;
211 };
212
213 static s_kw dev_types[] = {
214    {"file",          B_FILE_DEV},
215    {"tape",          B_TAPE_DEV},
216    {"dvd",           B_DVD_DEV},
217    {"fifo",          B_FIFO_DEV},
218    {"vtl",           B_VTL_DEV},
219    {"vtape",         B_VTAPE_DEV},
220    {NULL,            0}
221 };
222
223
224 /*
225  * Store Device Type (File, FIFO, Tape, DVD)
226  *
227  */
228 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
229 {
230    int token, i;
231
232    token = lex_get_token(lc, T_NAME);
233    /* Store the label pass 2 so that type is defined */
234    for (i=0; dev_types[i].name; i++) {
235       if (strcasecmp(lc->str, dev_types[i].name) == 0) {
236          *(uint32_t *)(item->value) = dev_types[i].token;
237          i = 0;
238          break;
239       }
240    }
241    if (i != 0) {
242       scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
243    }
244    scan_to_eol(lc);
245    set_bit(index, res_all.hdr.item_present);
246 }
247
248 /*
249  * Store Maximum Block Size, and check it is not greater than MAX_BLOCK_LENGTH
250  *
251  */
252 static void store_maxblocksize(LEX *lc, RES_ITEM *item, int index, int pass)
253 {
254    lex_get_token(lc, T_PINT32);
255    if (lc->pint32_val <= MAX_BLOCK_LENGTH) {
256       *(uint32_t *)(item->value) = lc->pint32_val;
257       scan_to_eol(lc);
258       set_bit(index, res_all.hdr.item_present);
259    } else {
260       scan_err2(lc, _("Maximum Block Size configured value %u is greater than allowed maximum: %u"), lc->pint32_val, MAX_BLOCK_LENGTH );
261    }
262 }
263
264
265 /* Dump contents of resource */
266 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
267 {
268    URES *res = (URES *)reshdr;
269    char buf[1000];
270    int recurse = 1;
271    IPADDR *p;
272    if (res == NULL) {
273       sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
274       return;
275    }
276    sendit(sock, _("dump_resource type=%d\n"), type);
277    if (type < 0) {                    /* no recursion */
278       type = - type;
279       recurse = 0;
280    }
281    switch (type) {
282    case R_DIRECTOR:
283       sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
284       break;
285    case R_STORAGE:
286       sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
287              res->res_store.hdr.name,
288              NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
289              get_first_port_host_order(res->res_store.sdaddrs),
290              get_first_port_host_order(res->res_store.sddaddrs),
291              edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
292       if (res->res_store.sdaddrs) {
293          foreach_dlist(p, res->res_store.sdaddrs) {
294             sendit(sock, "        SDaddr=%s SDport=%d\n",
295                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
296          }
297       }
298       if (res->res_store.sddaddrs) {
299          foreach_dlist(p, res->res_store.sddaddrs) {
300             sendit(sock, "        SDDaddr=%s SDDport=%d\n",
301                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
302          }
303       }
304       break;
305    case R_DEVICE:
306       sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
307          res->res_dev.hdr.name,
308          res->res_dev.media_type, res->res_dev.device_name,
309          res->res_dev.label_type);
310       sendit(sock, "        rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
311          res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
312          res->res_dev.max_block_size, res->res_dev.max_changer_wait);
313       sendit(sock, "        max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
314          res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
315          res->res_dev.max_volume_size);
316       sendit(sock, "        max_file_size=%" lld " capacity=%" lld "\n",
317          res->res_dev.max_file_size, res->res_dev.volume_capacity);
318       sendit(sock, "        spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
319       sendit(sock, "        max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
320          res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
321       if (res->res_dev.changer_res) {
322          sendit(sock, "         changer=%p\n", res->res_dev.changer_res);
323       }
324       bstrncpy(buf, "        ", sizeof(buf));
325       if (res->res_dev.cap_bits & CAP_EOF) {
326          bstrncat(buf, "CAP_EOF ", sizeof(buf));
327       }
328       if (res->res_dev.cap_bits & CAP_BSR) {
329          bstrncat(buf, "CAP_BSR ", sizeof(buf));
330       }
331       if (res->res_dev.cap_bits & CAP_BSF) {
332          bstrncat(buf, "CAP_BSF ", sizeof(buf));
333       }
334       if (res->res_dev.cap_bits & CAP_FSR) {
335          bstrncat(buf, "CAP_FSR ", sizeof(buf));
336       }
337       if (res->res_dev.cap_bits & CAP_FSF) {
338          bstrncat(buf, "CAP_FSF ", sizeof(buf));
339       }
340       if (res->res_dev.cap_bits & CAP_EOM) {
341          bstrncat(buf, "CAP_EOM ", sizeof(buf));
342       }
343       if (res->res_dev.cap_bits & CAP_REM) {
344          bstrncat(buf, "CAP_REM ", sizeof(buf));
345       }
346       if (res->res_dev.cap_bits & CAP_RACCESS) {
347          bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
348       }
349       if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
350          bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
351       }
352       if (res->res_dev.cap_bits & CAP_LABEL) {
353          bstrncat(buf, "CAP_LABEL ", sizeof(buf));
354       }
355       if (res->res_dev.cap_bits & CAP_ANONVOLS) {
356          bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
357       }
358       if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
359          bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
360       }
361       if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
362          bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
363       }
364       if (res->res_dev.cap_bits & CAP_REQMOUNT) {
365          bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
366       }
367       if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
368          bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
369       }
370       bstrncat(buf, "\n", sizeof(buf));
371       sendit(sock, buf);
372       break;
373    case R_AUTOCHANGER:
374       DEVRES *dev;
375       sendit(sock, "Changer: name=%s Changer_devname=%s\n      Changer_cmd=%s\n",
376          res->res_changer.hdr.name,
377          res->res_changer.changer_name, res->res_changer.changer_command);
378       foreach_alist(dev, res->res_changer.device) {
379          sendit(sock, "   --->Device: name=%s\n", dev->hdr.name);
380       }
381       bstrncat(buf, "\n", sizeof(buf));
382       sendit(sock, buf);
383       break;
384    case R_MSGS:
385       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
386       if (res->res_msgs.mail_cmd)
387          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
388       if (res->res_msgs.operator_cmd)
389          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
390       break;
391    default:
392       sendit(sock, _("Warning: unknown resource type %d\n"), type);
393       break;
394    }
395    if (recurse && res->res_dir.hdr.next)
396       dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
397 }
398
399 /*
400  * Free memory of resource.
401  * NB, we don't need to worry about freeing any references
402  * to other resources as they will be freed when that
403  * resource chain is traversed.  Mainly we worry about freeing
404  * allocated strings (names).
405  */
406 void free_resource(RES *sres, int type)
407 {
408    RES *nres;
409    URES *res = (URES *)sres;
410
411    if (res == NULL)
412       return;
413
414    /* common stuff -- free the resource name */
415    nres = (RES *)res->res_dir.hdr.next;
416    if (res->res_dir.hdr.name) {
417       free(res->res_dir.hdr.name);
418    }
419    if (res->res_dir.hdr.desc) {
420       free(res->res_dir.hdr.desc);
421    }
422
423
424    switch (type) {
425    case R_DIRECTOR:
426       if (res->res_dir.password) {
427          free(res->res_dir.password);
428       }
429       if (res->res_dir.address) {
430          free(res->res_dir.address);
431       }
432       if (res->res_dir.tls_ctx) { 
433          free_tls_context(res->res_dir.tls_ctx);
434       }
435       if (res->res_dir.tls_ca_certfile) {
436          free(res->res_dir.tls_ca_certfile);
437       }
438       if (res->res_dir.tls_ca_certdir) {
439          free(res->res_dir.tls_ca_certdir);
440       }
441       if (res->res_dir.tls_certfile) {
442          free(res->res_dir.tls_certfile);
443       }
444       if (res->res_dir.tls_keyfile) {
445          free(res->res_dir.tls_keyfile);
446       }
447       if (res->res_dir.tls_dhfile) {
448          free(res->res_dir.tls_dhfile);
449       }
450       if (res->res_dir.tls_allowed_cns) {
451          delete res->res_dir.tls_allowed_cns;
452       }
453       break;
454    case R_AUTOCHANGER:
455       if (res->res_changer.changer_name) {
456          free(res->res_changer.changer_name);
457       }
458       if (res->res_changer.changer_command) {
459          free(res->res_changer.changer_command);
460       }
461       if (res->res_changer.device) {
462          delete res->res_changer.device;
463       }
464       break; 
465    case R_STORAGE:
466       if (res->res_store.sdaddrs) {
467          free_addresses(res->res_store.sdaddrs);
468       }
469       if (res->res_store.sddaddrs) {
470          free_addresses(res->res_store.sddaddrs);
471       }
472       if (res->res_store.working_directory) {
473          free(res->res_store.working_directory);
474       }
475       if (res->res_store.pid_directory) {
476          free(res->res_store.pid_directory);
477       }
478       if (res->res_store.subsys_directory) {
479          free(res->res_store.subsys_directory);
480       }
481       if (res->res_store.scripts_directory) {
482          free(res->res_store.scripts_directory);
483       }
484       if (res->res_store.tls_ctx) { 
485          free_tls_context(res->res_store.tls_ctx);
486       }
487       if (res->res_store.tls_ca_certfile) {
488          free(res->res_store.tls_ca_certfile);
489       }
490       if (res->res_store.tls_ca_certdir) {
491          free(res->res_store.tls_ca_certdir);
492       }
493       if (res->res_store.tls_certfile) {
494          free(res->res_store.tls_certfile);
495       }
496       if (res->res_store.tls_keyfile) {
497          free(res->res_store.tls_keyfile);
498       }
499       if (res->res_store.tls_dhfile) {
500          free(res->res_store.tls_dhfile);
501       }
502       if (res->res_store.tls_allowed_cns) {
503          delete res->res_store.tls_allowed_cns;
504       }
505       if (res->res_store.verid) {
506          free(res->res_store.verid);
507       }
508       break;
509    case R_DEVICE:
510       if (res->res_dev.media_type) {
511          free(res->res_dev.media_type);
512       }
513       if (res->res_dev.device_name) {
514          free(res->res_dev.device_name);
515       }
516       if (res->res_dev.changer_name) {
517          free(res->res_dev.changer_name);
518       }
519       if (res->res_dev.changer_command) {
520          free(res->res_dev.changer_command);
521       }
522       if (res->res_dev.alert_command) {
523          free(res->res_dev.alert_command);
524       }
525       if (res->res_dev.spool_directory) {
526          free(res->res_dev.spool_directory);
527       }
528       if (res->res_dev.mount_point) {
529          free(res->res_dev.mount_point);
530       }
531       if (res->res_dev.mount_command) {
532          free(res->res_dev.mount_command);
533       }
534       if (res->res_dev.unmount_command) {
535          free(res->res_dev.unmount_command);
536       }
537       if (res->res_dev.write_part_command) {
538          free(res->res_dev.write_part_command);
539       }
540       if (res->res_dev.free_space_command) {
541          free(res->res_dev.free_space_command);
542       }
543       break;
544    case R_MSGS:
545       if (res->res_msgs.mail_cmd) {
546          free(res->res_msgs.mail_cmd);
547       }
548       if (res->res_msgs.operator_cmd) {
549          free(res->res_msgs.operator_cmd);
550       }
551       free_msgs_res((MSGS *)res);  /* free message resource */
552       res = NULL;
553       break;
554    default:
555       Dmsg1(0, _("Unknown resource type %d\n"), type);
556       break;
557    }
558    /* Common stuff again -- free the resource, recurse to next one */
559    if (res) {
560       free(res);
561    }
562    if (nres) {
563       free_resource(nres, type);
564    }
565 }
566
567 /* Save the new resource by chaining it into the head list for
568  * the resource. If this is pass 2, we update any resource
569  * or alist pointers.  
570  */
571 void save_resource(int type, RES_ITEM *items, int pass)
572 {
573    URES *res;
574    int rindex = type - r_first;
575    int i, size;
576    int error = 0;
577
578    /*
579     * Ensure that all required items are present
580     */
581    for (i=0; items[i].name; i++) {
582       if (items[i].flags & ITEM_REQUIRED) {
583          if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
584             Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
585               items[i].name, resources[rindex]);
586           }
587       }
588       /* If this triggers, take a look at lib/parse_conf.h */
589       if (i >= MAX_RES_ITEMS) {
590          Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
591       }
592    }
593
594    /* During pass 2, we looked up pointers to all the resources
595     * referrenced in the current resource, , now we
596     * must copy their address from the static record to the allocated
597     * record.
598     */
599    if (pass == 2) {
600       DEVRES *dev;
601       int errstat;
602       switch (type) {
603       /* Resources not containing a resource */
604       case R_DEVICE:
605       case R_MSGS:
606          break;
607
608       /* Resources containing a resource or an alist */
609       case R_DIRECTOR:
610          if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
611             Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
612          }
613          res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
614          break;
615       case R_STORAGE:
616          if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
617             Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
618          }
619          res->res_store.messages = res_all.res_store.messages;
620          res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
621          break;
622       case R_AUTOCHANGER:
623          if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
624             Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
625                   res_all.res_changer.hdr.name);
626          }
627          /* we must explicitly copy the device alist pointer */
628          res->res_changer.device   = res_all.res_changer.device;
629          /*
630           * Now update each device in this resource to point back 
631           *  to the changer resource.
632           */
633          foreach_alist(dev, res->res_changer.device) {
634             dev->changer_res = (AUTOCHANGER *)&res->res_changer;
635          }
636          if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
637             berrno be;
638             Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"), 
639                   be.bstrerror(errstat));
640          }
641          break;
642       default:
643          printf(_("Unknown resource type %d\n"), type);
644          error = 1;
645          break;
646       }
647
648
649       if (res_all.res_dir.hdr.name) {
650          free(res_all.res_dir.hdr.name);
651          res_all.res_dir.hdr.name = NULL;
652       }
653       if (res_all.res_dir.hdr.desc) {
654          free(res_all.res_dir.hdr.desc);
655          res_all.res_dir.hdr.desc = NULL;
656       }
657       return;
658    }
659
660    /* The following code is only executed on pass 1 */
661    switch (type) {
662       case R_DIRECTOR:
663          size = sizeof(DIRRES);
664          break;
665       case R_STORAGE:
666          size = sizeof(STORES);
667          break;
668       case R_DEVICE:
669          size = sizeof(DEVRES);
670          break;
671       case R_MSGS:
672          size = sizeof(MSGS);
673          break;
674       case R_AUTOCHANGER:
675          size = sizeof(AUTOCHANGER);
676          break;
677       default:
678          printf(_("Unknown resource type %d\n"), type);
679          error = 1;
680          size = 1;
681          break;
682    }
683    /* Common */
684    if (!error) {
685       res = (URES *)malloc(size);
686       memcpy(res, &res_all, size);
687       if (!res_head[rindex]) {
688          res_head[rindex] = (RES *)res; /* store first entry */
689       } else {
690          RES *next, *last;
691          /* Add new res to end of chain */
692          for (last=next=res_head[rindex]; next; next=next->next) {
693             last = next;
694             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
695                Emsg2(M_ERROR_TERM, 0,
696                   _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
697                   resources[rindex].name, res->res_dir.hdr.name);
698             }
699          }
700          last->next = (RES *)res;
701          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
702                res->res_dir.hdr.name);
703       }
704    }
705 }
706
707 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
708 {
709    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
710       r_first, r_last, resources, res_head);
711    return config->parse_config();
712 }