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