]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored_conf.c
First stab at a simple script to dump the content of the complete Ingres bacula datab...
[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_size64,   ITEM(res_dev.max_volume_size), 0, 0, 0},
157    {"maximumfilesize",       store_size64,   ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
158    {"volumecapacity",        store_size64,   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_size64,   ITEM(res_dev.max_spool_size), 0, 0, 0},
162    {"maximumjobspoolsize",   store_size64,   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_size64,   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    store_size32(lc, item, index, pass);
254    if (*(uint32_t *)(item->value) > MAX_BLOCK_LENGTH) {
255       scan_err2(lc, _("Maximum Block Size configured value %u is greater than allowed maximum: %u"), 
256          *(uint32_t *)(item->value), MAX_BLOCK_LENGTH );
257    }
258 }
259
260
261 /* Dump contents of resource */
262 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
263 {
264    URES *res = (URES *)reshdr;
265    char buf[1000];
266    int recurse = 1;
267    IPADDR *p;
268    if (res == NULL) {
269       sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
270       return;
271    }
272    sendit(sock, _("dump_resource type=%d\n"), type);
273    if (type < 0) {                    /* no recursion */
274       type = - type;
275       recurse = 0;
276    }
277    switch (type) {
278    case R_DIRECTOR:
279       sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
280       break;
281    case R_STORAGE:
282       sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
283              res->res_store.hdr.name,
284              NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
285              get_first_port_host_order(res->res_store.sdaddrs),
286              get_first_port_host_order(res->res_store.sddaddrs),
287              edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
288       if (res->res_store.sdaddrs) {
289          foreach_dlist(p, res->res_store.sdaddrs) {
290             sendit(sock, "        SDaddr=%s SDport=%d\n",
291                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
292          }
293       }
294       if (res->res_store.sddaddrs) {
295          foreach_dlist(p, res->res_store.sddaddrs) {
296             sendit(sock, "        SDDaddr=%s SDDport=%d\n",
297                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
298          }
299       }
300       break;
301    case R_DEVICE:
302       sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
303          res->res_dev.hdr.name,
304          res->res_dev.media_type, res->res_dev.device_name,
305          res->res_dev.label_type);
306       sendit(sock, "        rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
307          res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
308          res->res_dev.max_block_size, res->res_dev.max_changer_wait);
309       sendit(sock, "        max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
310          res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
311          res->res_dev.max_volume_size);
312       sendit(sock, "        max_file_size=%" lld " capacity=%" lld "\n",
313          res->res_dev.max_file_size, res->res_dev.volume_capacity);
314       sendit(sock, "        spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
315       sendit(sock, "        max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
316          res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
317       if (res->res_dev.changer_res) {
318          sendit(sock, "         changer=%p\n", res->res_dev.changer_res);
319       }
320       bstrncpy(buf, "        ", sizeof(buf));
321       if (res->res_dev.cap_bits & CAP_EOF) {
322          bstrncat(buf, "CAP_EOF ", sizeof(buf));
323       }
324       if (res->res_dev.cap_bits & CAP_BSR) {
325          bstrncat(buf, "CAP_BSR ", sizeof(buf));
326       }
327       if (res->res_dev.cap_bits & CAP_BSF) {
328          bstrncat(buf, "CAP_BSF ", sizeof(buf));
329       }
330       if (res->res_dev.cap_bits & CAP_FSR) {
331          bstrncat(buf, "CAP_FSR ", sizeof(buf));
332       }
333       if (res->res_dev.cap_bits & CAP_FSF) {
334          bstrncat(buf, "CAP_FSF ", sizeof(buf));
335       }
336       if (res->res_dev.cap_bits & CAP_EOM) {
337          bstrncat(buf, "CAP_EOM ", sizeof(buf));
338       }
339       if (res->res_dev.cap_bits & CAP_REM) {
340          bstrncat(buf, "CAP_REM ", sizeof(buf));
341       }
342       if (res->res_dev.cap_bits & CAP_RACCESS) {
343          bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
344       }
345       if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
346          bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
347       }
348       if (res->res_dev.cap_bits & CAP_LABEL) {
349          bstrncat(buf, "CAP_LABEL ", sizeof(buf));
350       }
351       if (res->res_dev.cap_bits & CAP_ANONVOLS) {
352          bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
353       }
354       if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
355          bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
356       }
357       if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
358          bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
359       }
360       if (res->res_dev.cap_bits & CAP_REQMOUNT) {
361          bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
362       }
363       if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
364          bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
365       }
366       bstrncat(buf, "\n", sizeof(buf));
367       sendit(sock, buf);
368       break;
369    case R_AUTOCHANGER:
370       DEVRES *dev;
371       sendit(sock, "Changer: name=%s Changer_devname=%s\n      Changer_cmd=%s\n",
372          res->res_changer.hdr.name,
373          res->res_changer.changer_name, res->res_changer.changer_command);
374       foreach_alist(dev, res->res_changer.device) {
375          sendit(sock, "   --->Device: name=%s\n", dev->hdr.name);
376       }
377       bstrncat(buf, "\n", sizeof(buf));
378       sendit(sock, buf);
379       break;
380    case R_MSGS:
381       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
382       if (res->res_msgs.mail_cmd)
383          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
384       if (res->res_msgs.operator_cmd)
385          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
386       break;
387    default:
388       sendit(sock, _("Warning: unknown resource type %d\n"), type);
389       break;
390    }
391    if (recurse && res->res_dir.hdr.next)
392       dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
393 }
394
395 /*
396  * Free memory of resource.
397  * NB, we don't need to worry about freeing any references
398  * to other resources as they will be freed when that
399  * resource chain is traversed.  Mainly we worry about freeing
400  * allocated strings (names).
401  */
402 void free_resource(RES *sres, int type)
403 {
404    RES *nres;
405    URES *res = (URES *)sres;
406
407    if (res == NULL)
408       return;
409
410    /* common stuff -- free the resource name */
411    nres = (RES *)res->res_dir.hdr.next;
412    if (res->res_dir.hdr.name) {
413       free(res->res_dir.hdr.name);
414    }
415    if (res->res_dir.hdr.desc) {
416       free(res->res_dir.hdr.desc);
417    }
418
419
420    switch (type) {
421    case R_DIRECTOR:
422       if (res->res_dir.password) {
423          free(res->res_dir.password);
424       }
425       if (res->res_dir.address) {
426          free(res->res_dir.address);
427       }
428       if (res->res_dir.tls_ctx) { 
429          free_tls_context(res->res_dir.tls_ctx);
430       }
431       if (res->res_dir.tls_ca_certfile) {
432          free(res->res_dir.tls_ca_certfile);
433       }
434       if (res->res_dir.tls_ca_certdir) {
435          free(res->res_dir.tls_ca_certdir);
436       }
437       if (res->res_dir.tls_certfile) {
438          free(res->res_dir.tls_certfile);
439       }
440       if (res->res_dir.tls_keyfile) {
441          free(res->res_dir.tls_keyfile);
442       }
443       if (res->res_dir.tls_dhfile) {
444          free(res->res_dir.tls_dhfile);
445       }
446       if (res->res_dir.tls_allowed_cns) {
447          delete res->res_dir.tls_allowed_cns;
448       }
449       break;
450    case R_AUTOCHANGER:
451       if (res->res_changer.changer_name) {
452          free(res->res_changer.changer_name);
453       }
454       if (res->res_changer.changer_command) {
455          free(res->res_changer.changer_command);
456       }
457       if (res->res_changer.device) {
458          delete res->res_changer.device;
459       }
460       break; 
461    case R_STORAGE:
462       if (res->res_store.sdaddrs) {
463          free_addresses(res->res_store.sdaddrs);
464       }
465       if (res->res_store.sddaddrs) {
466          free_addresses(res->res_store.sddaddrs);
467       }
468       if (res->res_store.working_directory) {
469          free(res->res_store.working_directory);
470       }
471       if (res->res_store.pid_directory) {
472          free(res->res_store.pid_directory);
473       }
474       if (res->res_store.subsys_directory) {
475          free(res->res_store.subsys_directory);
476       }
477       if (res->res_store.scripts_directory) {
478          free(res->res_store.scripts_directory);
479       }
480       if (res->res_store.tls_ctx) { 
481          free_tls_context(res->res_store.tls_ctx);
482       }
483       if (res->res_store.tls_ca_certfile) {
484          free(res->res_store.tls_ca_certfile);
485       }
486       if (res->res_store.tls_ca_certdir) {
487          free(res->res_store.tls_ca_certdir);
488       }
489       if (res->res_store.tls_certfile) {
490          free(res->res_store.tls_certfile);
491       }
492       if (res->res_store.tls_keyfile) {
493          free(res->res_store.tls_keyfile);
494       }
495       if (res->res_store.tls_dhfile) {
496          free(res->res_store.tls_dhfile);
497       }
498       if (res->res_store.tls_allowed_cns) {
499          delete res->res_store.tls_allowed_cns;
500       }
501       if (res->res_store.verid) {
502          free(res->res_store.verid);
503       }
504       break;
505    case R_DEVICE:
506       if (res->res_dev.media_type) {
507          free(res->res_dev.media_type);
508       }
509       if (res->res_dev.device_name) {
510          free(res->res_dev.device_name);
511       }
512       if (res->res_dev.changer_name) {
513          free(res->res_dev.changer_name);
514       }
515       if (res->res_dev.changer_command) {
516          free(res->res_dev.changer_command);
517       }
518       if (res->res_dev.alert_command) {
519          free(res->res_dev.alert_command);
520       }
521       if (res->res_dev.spool_directory) {
522          free(res->res_dev.spool_directory);
523       }
524       if (res->res_dev.mount_point) {
525          free(res->res_dev.mount_point);
526       }
527       if (res->res_dev.mount_command) {
528          free(res->res_dev.mount_command);
529       }
530       if (res->res_dev.unmount_command) {
531          free(res->res_dev.unmount_command);
532       }
533       if (res->res_dev.write_part_command) {
534          free(res->res_dev.write_part_command);
535       }
536       if (res->res_dev.free_space_command) {
537          free(res->res_dev.free_space_command);
538       }
539       break;
540    case R_MSGS:
541       if (res->res_msgs.mail_cmd) {
542          free(res->res_msgs.mail_cmd);
543       }
544       if (res->res_msgs.operator_cmd) {
545          free(res->res_msgs.operator_cmd);
546       }
547       free_msgs_res((MSGS *)res);  /* free message resource */
548       res = NULL;
549       break;
550    default:
551       Dmsg1(0, _("Unknown resource type %d\n"), type);
552       break;
553    }
554    /* Common stuff again -- free the resource, recurse to next one */
555    if (res) {
556       free(res);
557    }
558    if (nres) {
559       free_resource(nres, type);
560    }
561 }
562
563 /* Save the new resource by chaining it into the head list for
564  * the resource. If this is pass 2, we update any resource
565  * or alist pointers.  
566  */
567 void save_resource(int type, RES_ITEM *items, int pass)
568 {
569    URES *res;
570    int rindex = type - r_first;
571    int i, size;
572    int error = 0;
573
574    /*
575     * Ensure that all required items are present
576     */
577    for (i=0; items[i].name; i++) {
578       if (items[i].flags & ITEM_REQUIRED) {
579          if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
580             Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
581               items[i].name, resources[rindex]);
582           }
583       }
584       /* If this triggers, take a look at lib/parse_conf.h */
585       if (i >= MAX_RES_ITEMS) {
586          Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
587       }
588    }
589
590    /* During pass 2, we looked up pointers to all the resources
591     * referrenced in the current resource, , now we
592     * must copy their address from the static record to the allocated
593     * record.
594     */
595    if (pass == 2) {
596       DEVRES *dev;
597       int errstat;
598       switch (type) {
599       /* Resources not containing a resource */
600       case R_DEVICE:
601       case R_MSGS:
602          break;
603
604       /* Resources containing a resource or an alist */
605       case R_DIRECTOR:
606          if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
607             Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
608          }
609          res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
610          break;
611       case R_STORAGE:
612          if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
613             Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
614          }
615          res->res_store.messages = res_all.res_store.messages;
616          res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
617          break;
618       case R_AUTOCHANGER:
619          if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
620             Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
621                   res_all.res_changer.hdr.name);
622          }
623          /* we must explicitly copy the device alist pointer */
624          res->res_changer.device   = res_all.res_changer.device;
625          /*
626           * Now update each device in this resource to point back 
627           *  to the changer resource.
628           */
629          foreach_alist(dev, res->res_changer.device) {
630             dev->changer_res = (AUTOCHANGER *)&res->res_changer;
631          }
632          if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
633             berrno be;
634             Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"), 
635                   be.bstrerror(errstat));
636          }
637          break;
638       default:
639          printf(_("Unknown resource type %d\n"), type);
640          error = 1;
641          break;
642       }
643
644
645       if (res_all.res_dir.hdr.name) {
646          free(res_all.res_dir.hdr.name);
647          res_all.res_dir.hdr.name = NULL;
648       }
649       if (res_all.res_dir.hdr.desc) {
650          free(res_all.res_dir.hdr.desc);
651          res_all.res_dir.hdr.desc = NULL;
652       }
653       return;
654    }
655
656    /* The following code is only executed on pass 1 */
657    switch (type) {
658       case R_DIRECTOR:
659          size = sizeof(DIRRES);
660          break;
661       case R_STORAGE:
662          size = sizeof(STORES);
663          break;
664       case R_DEVICE:
665          size = sizeof(DEVRES);
666          break;
667       case R_MSGS:
668          size = sizeof(MSGS);
669          break;
670       case R_AUTOCHANGER:
671          size = sizeof(AUTOCHANGER);
672          break;
673       default:
674          printf(_("Unknown resource type %d\n"), type);
675          error = 1;
676          size = 1;
677          break;
678    }
679    /* Common */
680    if (!error) {
681       res = (URES *)malloc(size);
682       memcpy(res, &res_all, size);
683       if (!res_head[rindex]) {
684          res_head[rindex] = (RES *)res; /* store first entry */
685       } else {
686          RES *next, *last;
687          /* Add new res to end of chain */
688          for (last=next=res_head[rindex]; next; next=next->next) {
689             last = next;
690             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
691                Emsg2(M_ERROR_TERM, 0,
692                   _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
693                   resources[rindex].name, res->res_dir.hdr.name);
694             }
695          }
696          last->next = (RES *)res;
697          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
698                res->res_dir.hdr.name);
699       }
700    }
701 }
702
703 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
704 {
705    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
706       r_first, r_last, resources, res_head);
707    return config->parse_config();
708 }