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