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