]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored_conf.c
Tweak version date
[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 three of the GNU Affero 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 Affero 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 i;
230
231    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       rwl_destroy(&res->res_changer.changer_lock);
461       break; 
462    case R_STORAGE:
463       if (res->res_store.sdaddrs) {
464          free_addresses(res->res_store.sdaddrs);
465       }
466       if (res->res_store.sddaddrs) {
467          free_addresses(res->res_store.sddaddrs);
468       }
469       if (res->res_store.working_directory) {
470          free(res->res_store.working_directory);
471       }
472       if (res->res_store.pid_directory) {
473          free(res->res_store.pid_directory);
474       }
475       if (res->res_store.subsys_directory) {
476          free(res->res_store.subsys_directory);
477       }
478       if (res->res_store.plugin_directory) {
479          free(res->res_store.plugin_directory);
480       }
481       if (res->res_store.scripts_directory) {
482          free(res->res_store.scripts_directory);
483       }
484       if (res->res_store.tls_ctx) { 
485          free_tls_context(res->res_store.tls_ctx);
486       }
487       if (res->res_store.tls_ca_certfile) {
488          free(res->res_store.tls_ca_certfile);
489       }
490       if (res->res_store.tls_ca_certdir) {
491          free(res->res_store.tls_ca_certdir);
492       }
493       if (res->res_store.tls_certfile) {
494          free(res->res_store.tls_certfile);
495       }
496       if (res->res_store.tls_keyfile) {
497          free(res->res_store.tls_keyfile);
498       }
499       if (res->res_store.tls_dhfile) {
500          free(res->res_store.tls_dhfile);
501       }
502       if (res->res_store.tls_allowed_cns) {
503          delete res->res_store.tls_allowed_cns;
504       }
505       if (res->res_store.verid) {
506          free(res->res_store.verid);
507       }
508       break;
509    case R_DEVICE:
510       if (res->res_dev.media_type) {
511          free(res->res_dev.media_type);
512       }
513       if (res->res_dev.device_name) {
514          free(res->res_dev.device_name);
515       }
516       if (res->res_dev.changer_name) {
517          free(res->res_dev.changer_name);
518       }
519       if (res->res_dev.changer_command) {
520          free(res->res_dev.changer_command);
521       }
522       if (res->res_dev.alert_command) {
523          free(res->res_dev.alert_command);
524       }
525       if (res->res_dev.spool_directory) {
526          free(res->res_dev.spool_directory);
527       }
528       if (res->res_dev.mount_point) {
529          free(res->res_dev.mount_point);
530       }
531       if (res->res_dev.mount_command) {
532          free(res->res_dev.mount_command);
533       }
534       if (res->res_dev.unmount_command) {
535          free(res->res_dev.unmount_command);
536       }
537       if (res->res_dev.write_part_command) {
538          free(res->res_dev.write_part_command);
539       }
540       if (res->res_dev.free_space_command) {
541          free(res->res_dev.free_space_command);
542       }
543       break;
544    case R_MSGS:
545       if (res->res_msgs.mail_cmd) {
546          free(res->res_msgs.mail_cmd);
547       }
548       if (res->res_msgs.operator_cmd) {
549          free(res->res_msgs.operator_cmd);
550       }
551       free_msgs_res((MSGS *)res);  /* free message resource */
552       res = NULL;
553       break;
554    default:
555       Dmsg1(0, _("Unknown resource type %d\n"), type);
556       break;
557    }
558    /* Common stuff again -- free the resource, recurse to next one */
559    if (res) {
560       free(res);
561    }
562    if (nres) {
563       free_resource(nres, type);
564    }
565 }
566
567 /* Save the new resource by chaining it into the head list for
568  * the resource. If this is pass 2, we update any resource
569  * or alist pointers.  
570  */
571 void save_resource(int type, RES_ITEM *items, int pass)
572 {
573    URES *res;
574    int rindex = type - r_first;
575    int i, size;
576    int error = 0;
577
578    /*
579     * Ensure that all required items are present
580     */
581    for (i=0; items[i].name; i++) {
582       if (items[i].flags & ITEM_REQUIRED) {
583          if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
584             Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
585               items[i].name, resources[rindex]);
586           }
587       }
588       /* If this triggers, take a look at lib/parse_conf.h */
589       if (i >= MAX_RES_ITEMS) {
590          Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
591       }
592    }
593
594    /* During pass 2, we looked up pointers to all the resources
595     * referrenced in the current resource, , now we
596     * must copy their address from the static record to the allocated
597     * record.
598     */
599    if (pass == 2) {
600       DEVRES *dev;
601       int errstat;
602       switch (type) {
603       /* Resources not containing a resource */
604       case R_DEVICE:
605       case R_MSGS:
606          break;
607
608       /* Resources containing a resource or an alist */
609       case R_DIRECTOR:
610          if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
611             Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
612          }
613          res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
614          break;
615       case R_STORAGE:
616          if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
617             Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
618          }
619          res->res_store.messages = res_all.res_store.messages;
620          res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
621          break;
622       case R_AUTOCHANGER:
623          if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
624             Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
625                   res_all.res_changer.hdr.name);
626          }
627          /* we must explicitly copy the device alist pointer */
628          res->res_changer.device   = res_all.res_changer.device;
629          /*
630           * Now update each device in this resource to point back 
631           *  to the changer resource.
632           */
633          foreach_alist(dev, res->res_changer.device) {
634             dev->changer_res = (AUTOCHANGER *)&res->res_changer;
635          }
636          if ((errstat = rwl_init(&res->res_changer.changer_lock, 
637                                  PRIO_SD_ACH_ACCESS)) != 0)
638          {
639             berrno be;
640             Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init lock: ERR=%s\n"), 
641                   be.bstrerror(errstat));
642          }
643          break;
644       default:
645          printf(_("Unknown resource type %d\n"), type);
646          error = 1;
647          break;
648       }
649
650
651       if (res_all.res_dir.hdr.name) {
652          free(res_all.res_dir.hdr.name);
653          res_all.res_dir.hdr.name = NULL;
654       }
655       if (res_all.res_dir.hdr.desc) {
656          free(res_all.res_dir.hdr.desc);
657          res_all.res_dir.hdr.desc = NULL;
658       }
659       return;
660    }
661
662    /* The following code is only executed on pass 1 */
663    switch (type) {
664       case R_DIRECTOR:
665          size = sizeof(DIRRES);
666          break;
667       case R_STORAGE:
668          size = sizeof(STORES);
669          break;
670       case R_DEVICE:
671          size = sizeof(DEVRES);
672          break;
673       case R_MSGS:
674          size = sizeof(MSGS);
675          break;
676       case R_AUTOCHANGER:
677          size = sizeof(AUTOCHANGER);
678          break;
679       default:
680          printf(_("Unknown resource type %d\n"), type);
681          error = 1;
682          size = 1;
683          break;
684    }
685    /* Common */
686    if (!error) {
687       res = (URES *)malloc(size);
688       memcpy(res, &res_all, size);
689       if (!res_head[rindex]) {
690          res_head[rindex] = (RES *)res; /* store first entry */
691       } else {
692          RES *next, *last;
693          /* Add new res to end of chain */
694          for (last=next=res_head[rindex]; next; next=next->next) {
695             last = next;
696             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
697                Emsg2(M_ERROR_TERM, 0,
698                   _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
699                   resources[rindex].name, res->res_dir.hdr.name);
700             }
701          }
702          last->next = (RES *)res;
703          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
704                res->res_dir.hdr.name);
705       }
706    }
707 }
708
709 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
710 {
711    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
712       r_first, r_last, resources, res_head);
713    return config->parse_config();
714 }