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