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