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