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