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