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