]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored_conf.c
Mark translatable strings in all source files.
[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 amended with additional clauses defined in the
14    file LICENSE in the main source directory.
15
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
19    the file LICENSE for additional details.
20
21  */
22
23 #include "bacula.h"
24 #include "stored.h"
25
26 extern int debug_level;
27
28
29 /* First and last resource ids */
30 int r_first = R_FIRST;
31 int r_last  = R_LAST;
32 static RES *sres_head[R_LAST - R_FIRST + 1];
33 RES **res_head = sres_head;
34
35
36 /* Forward referenced subroutines */
37
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),   R_MSGS, 0, 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    {"requiresmount",         store_yesno,  ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
119    {"offlineonunmount",      store_yesno,  ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
120    {"autoselect",            store_yesno,  ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
121    {"changerdevice",         store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
122    {"changercommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
123    {"alertcommand",          store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
124    {"maximumchangerwait",    store_pint,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
125    {"maximumopenwait",       store_pint,   ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
126    {"maximumopenvolumes",    store_pint,   ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
127    {"maximumnetworkbuffersize", store_pint, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
128    {"volumepollinterval",    store_time,   ITEM(res_dev.vol_poll_interval), 0, 0, 0},
129    {"maximumrewindwait",     store_pint,   ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
130    {"minimumblocksize",      store_pint,   ITEM(res_dev.min_block_size), 0, 0, 0},
131    {"maximumblocksize",      store_pint,   ITEM(res_dev.max_block_size), 0, 0, 0},
132    {"maximumvolumesize",     store_size,   ITEM(res_dev.max_volume_size), 0, 0, 0},
133    {"maximumfilesize",       store_size,   ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
134    {"volumecapacity",        store_size,   ITEM(res_dev.volume_capacity), 0, 0, 0},
135    {"spooldirectory",        store_dir,    ITEM(res_dev.spool_directory), 0, 0, 0},
136    {"maximumspoolsize",      store_size,   ITEM(res_dev.max_spool_size), 0, 0, 0},
137    {"maximumjobspoolsize",   store_size,   ITEM(res_dev.max_job_spool_size), 0, 0, 0},
138    {"driveindex",            store_pint,   ITEM(res_dev.drive_index), 0, 0, 0},
139    {"maximumpartsize",       store_size,   ITEM(res_dev.max_part_size), 0, 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[1000];
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       if (res->res_dev.cap_bits & CAP_REQMOUNT) {
280          bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
281       }
282       if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
283          bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
284       }
285       bstrncat(buf, "\n", sizeof(buf));
286       sendit(sock, buf);
287       break;
288    case R_AUTOCHANGER:
289       DEVRES *dev;
290       sendit(sock, "Changer: name=%s Changer_devname=%s\n      Changer_cmd=%s\n",
291          res->res_changer.hdr.name,
292          res->res_changer.changer_name, res->res_changer.changer_command);
293       foreach_alist(dev, res->res_changer.device) {
294          sendit(sock, "   --->Device: name=%s\n", dev->hdr.name);
295       }
296       bstrncat(buf, "\n", sizeof(buf));
297       sendit(sock, buf);
298       break;
299    case R_MSGS:
300       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
301       if (res->res_msgs.mail_cmd)
302          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
303       if (res->res_msgs.operator_cmd)
304          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
305       break;
306    default:
307       sendit(sock, _("Warning: unknown resource type %d\n"), type);
308       break;
309    }
310    if (recurse && res->res_dir.hdr.next)
311       dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
312 }
313
314 /*
315  * Free memory of resource.
316  * NB, we don't need to worry about freeing any references
317  * to other resources as they will be freed when that
318  * resource chain is traversed.  Mainly we worry about freeing
319  * allocated strings (names).
320  */
321 void free_resource(RES *sres, int type)
322 {
323    RES *nres;
324    URES *res = (URES *)sres;
325
326    if (res == NULL)
327       return;
328
329    /* common stuff -- free the resource name */
330    nres = (RES *)res->res_dir.hdr.next;
331    if (res->res_dir.hdr.name) {
332       free(res->res_dir.hdr.name);
333    }
334    if (res->res_dir.hdr.desc) {
335       free(res->res_dir.hdr.desc);
336    }
337
338
339    switch (type) {
340    case R_DIRECTOR:
341       if (res->res_dir.password) {
342          free(res->res_dir.password);
343       }
344       if (res->res_dir.address) {
345          free(res->res_dir.address);
346       }
347       if (res->res_dir.tls_ctx) { 
348          free_tls_context(res->res_dir.tls_ctx);
349       }
350       if (res->res_dir.tls_ca_certfile) {
351          free(res->res_dir.tls_ca_certfile);
352       }
353       if (res->res_dir.tls_ca_certdir) {
354          free(res->res_dir.tls_ca_certdir);
355       }
356       if (res->res_dir.tls_certfile) {
357          free(res->res_dir.tls_certfile);
358       }
359       if (res->res_dir.tls_keyfile) {
360          free(res->res_dir.tls_keyfile);
361       }
362       if (res->res_dir.tls_dhfile) {
363          free(res->res_dir.tls_dhfile);
364       }
365       if (res->res_dir.tls_allowed_cns) {
366          delete res->res_dir.tls_allowed_cns;
367       }
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       if (res->res_store.tls_ctx) { 
400          free_tls_context(res->res_store.tls_ctx);
401       }
402       if (res->res_store.tls_ca_certfile) {
403          free(res->res_store.tls_ca_certfile);
404       }
405       if (res->res_store.tls_ca_certdir) {
406          free(res->res_store.tls_ca_certdir);
407       }
408       if (res->res_store.tls_certfile) {
409          free(res->res_store.tls_certfile);
410       }
411       if (res->res_store.tls_keyfile) {
412          free(res->res_store.tls_keyfile);
413       }
414       if (res->res_store.tls_dhfile) {
415          free(res->res_store.tls_dhfile);
416       }
417       if (res->res_store.tls_allowed_cns) {
418          delete res->res_store.tls_allowed_cns;
419       }
420       break;
421    case R_DEVICE:
422       if (res->res_dev.media_type) {
423          free(res->res_dev.media_type);
424       }
425       if (res->res_dev.device_name) {
426          free(res->res_dev.device_name);
427       }
428       if (res->res_dev.changer_name) {
429          free(res->res_dev.changer_name);
430       }
431       if (res->res_dev.changer_command) {
432          free(res->res_dev.changer_command);
433       }
434       if (res->res_dev.alert_command) {
435          free(res->res_dev.alert_command);
436       }
437       if (res->res_dev.spool_directory) {
438          free(res->res_dev.spool_directory);
439       }
440       if (res->res_dev.mount_point) {
441          free(res->res_dev.mount_point);
442       }
443       if (res->res_dev.mount_command) {
444          free(res->res_dev.mount_command);
445       }
446       if (res->res_dev.unmount_command) {
447          free(res->res_dev.unmount_command);
448       }
449       if (res->res_dev.write_part_command) {
450          free(res->res_dev.write_part_command);
451       }
452       if (res->res_dev.free_space_command) {
453          free(res->res_dev.free_space_command);
454       }
455       break;
456    case R_MSGS:
457       if (res->res_msgs.mail_cmd) {
458          free(res->res_msgs.mail_cmd);
459       }
460       if (res->res_msgs.operator_cmd) {
461          free(res->res_msgs.operator_cmd);
462       }
463       free_msgs_res((MSGS *)res);  /* free message resource */
464       res = NULL;
465       break;
466    default:
467       Dmsg1(0, _("Unknown resource type %d\n"), type);
468       break;
469    }
470    /* Common stuff again -- free the resource, recurse to next one */
471    if (res) {
472       free(res);
473    }
474    if (nres) {
475       free_resource(nres, type);
476    }
477 }
478
479 /* Save the new resource by chaining it into the head list for
480  * the resource. If this is pass 2, we update any resource
481  * or alist pointers.  
482  */
483 void save_resource(int type, RES_ITEM *items, int pass)
484 {
485    URES *res;
486    int rindex = type - r_first;
487    int i, size;
488    int error = 0;
489
490    /*
491     * Ensure that all required items are present
492     */
493    for (i=0; items[i].name; i++) {
494       if (items[i].flags & ITEM_REQUIRED) {
495          if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
496             Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
497               items[i].name, resources[rindex]);
498           }
499       }
500       /* If this triggers, take a look at lib/parse_conf.h */
501       if (i >= MAX_RES_ITEMS) {
502          Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
503       }
504    }
505
506    /* During pass 2, we looked up pointers to all the resources
507     * referrenced in the current resource, , now we
508     * must copy their address from the static record to the allocated
509     * record.
510     */
511    if (pass == 2) {
512       DEVRES *dev;
513       int errstat;
514       switch (type) {
515       /* Resources not containing a resource */
516       case R_DEVICE:
517       case R_MSGS:
518          break;
519
520       /* Resources containing a resource or an alist */
521       case R_DIRECTOR:
522          if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
523             Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
524          }
525          res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
526          break;
527       case R_STORAGE:
528          if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
529             Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
530          }
531          res->res_store.messages = res_all.res_store.messages;
532          res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
533          break;
534       case R_AUTOCHANGER:
535          if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
536             Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
537                   res_all.res_changer.hdr.name);
538          }
539          /* we must explicitly copy the device alist pointer */
540          res->res_changer.device   = res_all.res_changer.device;
541          /*
542           * Now update each device in this resource to point back 
543           *  to the changer resource.
544           */
545          foreach_alist(dev, res->res_changer.device) {
546             dev->changer_res = (AUTOCHANGER *)&res->res_changer;
547          }
548          if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
549             berrno be;
550             Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"), 
551                   be.strerror(errstat));
552          }
553          break;
554       default:
555          printf(_("Unknown resource type %d\n"), type);
556          error = 1;
557          break;
558       }
559
560
561       if (res_all.res_dir.hdr.name) {
562          free(res_all.res_dir.hdr.name);
563          res_all.res_dir.hdr.name = NULL;
564       }
565       if (res_all.res_dir.hdr.desc) {
566          free(res_all.res_dir.hdr.desc);
567          res_all.res_dir.hdr.desc = NULL;
568       }
569       return;
570    }
571
572    /* The following code is only executed on pass 1 */
573    switch (type) {
574       case R_DIRECTOR:
575          size = sizeof(DIRRES);
576          break;
577       case R_STORAGE:
578          size = sizeof(STORES);
579          break;
580       case R_DEVICE:
581          size = sizeof(DEVRES);
582          break;
583       case R_MSGS:
584          size = sizeof(MSGS);
585          break;
586       case R_AUTOCHANGER:
587          size = sizeof(AUTOCHANGER);
588          break;
589       default:
590          printf(_("Unknown resource type %d\n"), type);
591          error = 1;
592          size = 1;
593          break;
594    }
595    /* Common */
596    if (!error) {
597       res = (URES *)malloc(size);
598       memcpy(res, &res_all, size);
599       if (!res_head[rindex]) {
600          res_head[rindex] = (RES *)res; /* store first entry */
601       } else {
602          RES *next;
603          /* Add new res to end of chain */
604          for (next=res_head[rindex]; next->next; next=next->next) {
605             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
606                Emsg2(M_ERROR_TERM, 0,
607                   _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
608                   resources[rindex].name, res->res_dir.hdr.name);
609             }
610          }
611          next->next = (RES *)res;
612          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
613                res->res_dir.hdr.name);
614       }
615    }
616 }