]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored_conf.c
Implement truncate on purge setting
[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    {"truncateonpurge",       store_bool, ITEM(res_dev.truncate_on_purge), 1, ITEM_DEFAULT, 0},
146    {"changerdevice",         store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
147    {"changercommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
148    {"alertcommand",          store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
149    {"maximumchangerwait",    store_time,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
150    {"maximumopenwait",       store_time,   ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
151    {"maximumopenvolumes",    store_pint32,   ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
152    {"maximumnetworkbuffersize", store_pint32, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
153    {"volumepollinterval",    store_time,   ITEM(res_dev.vol_poll_interval), 0, ITEM_DEFAULT, 5 * 60},
154    {"maximumrewindwait",     store_time,   ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
155    {"minimumblocksize",      store_pint32,   ITEM(res_dev.min_block_size), 0, 0, 0},
156    {"maximumblocksize",      store_maxblocksize, ITEM(res_dev.max_block_size), 0, 0, 0},
157    {"maximumvolumesize",     store_size64,   ITEM(res_dev.max_volume_size), 0, 0, 0},
158    {"maximumfilesize",       store_size64,   ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
159    {"volumecapacity",        store_size64,   ITEM(res_dev.volume_capacity), 0, 0, 0},
160    {"maximumconcurrentjobs", store_pint32, ITEM(res_dev.max_concurrent_jobs), 0, 0, 0},
161    {"spooldirectory",        store_dir,    ITEM(res_dev.spool_directory), 0, 0, 0},
162    {"maximumspoolsize",      store_size64,   ITEM(res_dev.max_spool_size), 0, 0, 0},
163    {"maximumjobspoolsize",   store_size64,   ITEM(res_dev.max_job_spool_size), 0, 0, 0},
164    {"driveindex",            store_pint32,   ITEM(res_dev.drive_index), 0, 0, 0},
165    {"maximumpartsize",       store_size64,   ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
166    {"mountpoint",            store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
167    {"mountcommand",          store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
168    {"unmountcommand",        store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
169    {"writepartcommand",      store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
170    {"freespacecommand",      store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
171    {"labeltype",             store_label,  ITEM(res_dev.label_type), 0, 0, 0},
172    {NULL, NULL, {0}, 0, 0, 0}
173 };
174
175 /* Autochanger definition */
176 static RES_ITEM changer_items[] = {
177    {"name",              store_name,      ITEM(res_changer.hdr.name),        0, ITEM_REQUIRED, 0},
178    {"description",       store_str,       ITEM(res_changer.hdr.desc),        0, 0, 0},
179    {"device",            store_alist_res, ITEM(res_changer.device),   R_DEVICE, ITEM_REQUIRED, 0},
180    {"changerdevice",     store_strname,   ITEM(res_changer.changer_name),    0, ITEM_REQUIRED, 0},
181    {"changercommand",    store_strname,   ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
182    {NULL, NULL, {0}, 0, 0, 0}
183 };
184
185
186 // {"mountanonymousvolumes", store_bit,  ITEM(res_dev.cap_bits), CAP_ANONVOLS,   ITEM_DEFAULT, 0},
187
188
189 /* Message resource */
190 extern RES_ITEM msgs_items[];
191
192
193 /* This is the master resource definition */
194 RES_TABLE resources[] = {
195    {"director",      dir_items,     R_DIRECTOR},
196    {"storage",       store_items,   R_STORAGE},
197    {"device",        dev_items,     R_DEVICE},
198    {"messages",      msgs_items,    R_MSGS},
199    {"autochanger",   changer_items, R_AUTOCHANGER},
200    {NULL,            NULL,          0}
201 };
202
203 /*
204  * Device types
205  *
206  *   device type     device code = token
207  */
208 struct s_kw {
209    const char *name;
210    int32_t token;
211 };
212
213 static s_kw dev_types[] = {
214    {"file",          B_FILE_DEV},
215    {"tape",          B_TAPE_DEV},
216    {"dvd",           B_DVD_DEV},
217    {"fifo",          B_FIFO_DEV},
218    {"vtl",           B_VTL_DEV},
219    {"vtape",         B_VTAPE_DEV},
220    {NULL,            0}
221 };
222
223
224 /*
225  * Store Device Type (File, FIFO, Tape, DVD)
226  *
227  */
228 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
229 {
230    int token, i;
231
232    token = lex_get_token(lc, T_NAME);
233    /* Store the label pass 2 so that type is defined */
234    for (i=0; dev_types[i].name; i++) {
235       if (strcasecmp(lc->str, dev_types[i].name) == 0) {
236          *(uint32_t *)(item->value) = dev_types[i].token;
237          i = 0;
238          break;
239       }
240    }
241    if (i != 0) {
242       scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
243    }
244    scan_to_eol(lc);
245    set_bit(index, res_all.hdr.item_present);
246 }
247
248 /*
249  * Store Maximum Block Size, and check it is not greater than MAX_BLOCK_LENGTH
250  *
251  */
252 static void store_maxblocksize(LEX *lc, RES_ITEM *item, int index, int pass)
253 {
254    store_size32(lc, item, index, pass);
255    if (*(uint32_t *)(item->value) > MAX_BLOCK_LENGTH) {
256       scan_err2(lc, _("Maximum Block Size configured value %u is greater than allowed maximum: %u"), 
257          *(uint32_t *)(item->value), MAX_BLOCK_LENGTH );
258    }
259 }
260
261
262 /* Dump contents of resource */
263 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
264 {
265    URES *res = (URES *)reshdr;
266    char buf[1000];
267    int recurse = 1;
268    IPADDR *p;
269    if (res == NULL) {
270       sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
271       return;
272    }
273    sendit(sock, _("dump_resource type=%d\n"), type);
274    if (type < 0) {                    /* no recursion */
275       type = - type;
276       recurse = 0;
277    }
278    switch (type) {
279    case R_DIRECTOR:
280       sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
281       break;
282    case R_STORAGE:
283       sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
284              res->res_store.hdr.name,
285              NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
286              get_first_port_host_order(res->res_store.sdaddrs),
287              get_first_port_host_order(res->res_store.sddaddrs),
288              edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
289       if (res->res_store.sdaddrs) {
290          foreach_dlist(p, res->res_store.sdaddrs) {
291             sendit(sock, "        SDaddr=%s SDport=%d\n",
292                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
293          }
294       }
295       if (res->res_store.sddaddrs) {
296          foreach_dlist(p, res->res_store.sddaddrs) {
297             sendit(sock, "        SDDaddr=%s SDDport=%d\n",
298                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
299          }
300       }
301       break;
302    case R_DEVICE:
303       sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
304          res->res_dev.hdr.name,
305          res->res_dev.media_type, res->res_dev.device_name,
306          res->res_dev.label_type);
307       sendit(sock, "        rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
308          res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
309          res->res_dev.max_block_size, res->res_dev.max_changer_wait);
310       sendit(sock, "        max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
311          res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
312          res->res_dev.max_volume_size);
313       sendit(sock, "        max_file_size=%" lld " capacity=%" lld "\n",
314          res->res_dev.max_file_size, res->res_dev.volume_capacity);
315       sendit(sock, "        spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
316       sendit(sock, "        max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
317          res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
318       if (res->res_dev.changer_res) {
319          sendit(sock, "         changer=%p\n", res->res_dev.changer_res);
320       }
321       bstrncpy(buf, "        ", sizeof(buf));
322       if (res->res_dev.cap_bits & CAP_EOF) {
323          bstrncat(buf, "CAP_EOF ", sizeof(buf));
324       }
325       if (res->res_dev.cap_bits & CAP_BSR) {
326          bstrncat(buf, "CAP_BSR ", sizeof(buf));
327       }
328       if (res->res_dev.cap_bits & CAP_BSF) {
329          bstrncat(buf, "CAP_BSF ", sizeof(buf));
330       }
331       if (res->res_dev.cap_bits & CAP_FSR) {
332          bstrncat(buf, "CAP_FSR ", sizeof(buf));
333       }
334       if (res->res_dev.cap_bits & CAP_FSF) {
335          bstrncat(buf, "CAP_FSF ", sizeof(buf));
336       }
337       if (res->res_dev.cap_bits & CAP_EOM) {
338          bstrncat(buf, "CAP_EOM ", sizeof(buf));
339       }
340       if (res->res_dev.cap_bits & CAP_REM) {
341          bstrncat(buf, "CAP_REM ", sizeof(buf));
342       }
343       if (res->res_dev.cap_bits & CAP_RACCESS) {
344          bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
345       }
346       if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
347          bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
348       }
349       if (res->res_dev.cap_bits & CAP_LABEL) {
350          bstrncat(buf, "CAP_LABEL ", sizeof(buf));
351       }
352       if (res->res_dev.cap_bits & CAP_ANONVOLS) {
353          bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
354       }
355       if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
356          bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
357       }
358       if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
359          bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
360       }
361       if (res->res_dev.cap_bits & CAP_REQMOUNT) {
362          bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
363       }
364       if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
365          bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
366       }
367       bstrncat(buf, "\n", sizeof(buf));
368       sendit(sock, buf);
369       break;
370    case R_AUTOCHANGER:
371       DEVRES *dev;
372       sendit(sock, "Changer: name=%s Changer_devname=%s\n      Changer_cmd=%s\n",
373          res->res_changer.hdr.name,
374          res->res_changer.changer_name, res->res_changer.changer_command);
375       foreach_alist(dev, res->res_changer.device) {
376          sendit(sock, "   --->Device: name=%s\n", dev->hdr.name);
377       }
378       bstrncat(buf, "\n", sizeof(buf));
379       sendit(sock, buf);
380       break;
381    case R_MSGS:
382       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
383       if (res->res_msgs.mail_cmd)
384          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
385       if (res->res_msgs.operator_cmd)
386          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
387       break;
388    default:
389       sendit(sock, _("Warning: unknown resource type %d\n"), type);
390       break;
391    }
392    if (recurse && res->res_dir.hdr.next)
393       dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
394 }
395
396 /*
397  * Free memory of resource.
398  * NB, we don't need to worry about freeing any references
399  * to other resources as they will be freed when that
400  * resource chain is traversed.  Mainly we worry about freeing
401  * allocated strings (names).
402  */
403 void free_resource(RES *sres, int type)
404 {
405    RES *nres;
406    URES *res = (URES *)sres;
407
408    if (res == NULL)
409       return;
410
411    /* common stuff -- free the resource name */
412    nres = (RES *)res->res_dir.hdr.next;
413    if (res->res_dir.hdr.name) {
414       free(res->res_dir.hdr.name);
415    }
416    if (res->res_dir.hdr.desc) {
417       free(res->res_dir.hdr.desc);
418    }
419
420
421    switch (type) {
422    case R_DIRECTOR:
423       if (res->res_dir.password) {
424          free(res->res_dir.password);
425       }
426       if (res->res_dir.address) {
427          free(res->res_dir.address);
428       }
429       if (res->res_dir.tls_ctx) { 
430          free_tls_context(res->res_dir.tls_ctx);
431       }
432       if (res->res_dir.tls_ca_certfile) {
433          free(res->res_dir.tls_ca_certfile);
434       }
435       if (res->res_dir.tls_ca_certdir) {
436          free(res->res_dir.tls_ca_certdir);
437       }
438       if (res->res_dir.tls_certfile) {
439          free(res->res_dir.tls_certfile);
440       }
441       if (res->res_dir.tls_keyfile) {
442          free(res->res_dir.tls_keyfile);
443       }
444       if (res->res_dir.tls_dhfile) {
445          free(res->res_dir.tls_dhfile);
446       }
447       if (res->res_dir.tls_allowed_cns) {
448          delete res->res_dir.tls_allowed_cns;
449       }
450       break;
451    case R_AUTOCHANGER:
452       if (res->res_changer.changer_name) {
453          free(res->res_changer.changer_name);
454       }
455       if (res->res_changer.changer_command) {
456          free(res->res_changer.changer_command);
457       }
458       if (res->res_changer.device) {
459          delete res->res_changer.device;
460       }
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.scripts_directory) {
479          free(res->res_store.scripts_directory);
480       }
481       if (res->res_store.tls_ctx) { 
482          free_tls_context(res->res_store.tls_ctx);
483       }
484       if (res->res_store.tls_ca_certfile) {
485          free(res->res_store.tls_ca_certfile);
486       }
487       if (res->res_store.tls_ca_certdir) {
488          free(res->res_store.tls_ca_certdir);
489       }
490       if (res->res_store.tls_certfile) {
491          free(res->res_store.tls_certfile);
492       }
493       if (res->res_store.tls_keyfile) {
494          free(res->res_store.tls_keyfile);
495       }
496       if (res->res_store.tls_dhfile) {
497          free(res->res_store.tls_dhfile);
498       }
499       if (res->res_store.tls_allowed_cns) {
500          delete res->res_store.tls_allowed_cns;
501       }
502       if (res->res_store.verid) {
503          free(res->res_store.verid);
504       }
505       break;
506    case R_DEVICE:
507       if (res->res_dev.media_type) {
508          free(res->res_dev.media_type);
509       }
510       if (res->res_dev.device_name) {
511          free(res->res_dev.device_name);
512       }
513       if (res->res_dev.changer_name) {
514          free(res->res_dev.changer_name);
515       }
516       if (res->res_dev.changer_command) {
517          free(res->res_dev.changer_command);
518       }
519       if (res->res_dev.alert_command) {
520          free(res->res_dev.alert_command);
521       }
522       if (res->res_dev.spool_directory) {
523          free(res->res_dev.spool_directory);
524       }
525       if (res->res_dev.mount_point) {
526          free(res->res_dev.mount_point);
527       }
528       if (res->res_dev.mount_command) {
529          free(res->res_dev.mount_command);
530       }
531       if (res->res_dev.unmount_command) {
532          free(res->res_dev.unmount_command);
533       }
534       if (res->res_dev.write_part_command) {
535          free(res->res_dev.write_part_command);
536       }
537       if (res->res_dev.free_space_command) {
538          free(res->res_dev.free_space_command);
539       }
540       break;
541    case R_MSGS:
542       if (res->res_msgs.mail_cmd) {
543          free(res->res_msgs.mail_cmd);
544       }
545       if (res->res_msgs.operator_cmd) {
546          free(res->res_msgs.operator_cmd);
547       }
548       free_msgs_res((MSGS *)res);  /* free message resource */
549       res = NULL;
550       break;
551    default:
552       Dmsg1(0, _("Unknown resource type %d\n"), type);
553       break;
554    }
555    /* Common stuff again -- free the resource, recurse to next one */
556    if (res) {
557       free(res);
558    }
559    if (nres) {
560       free_resource(nres, type);
561    }
562 }
563
564 /* Save the new resource by chaining it into the head list for
565  * the resource. If this is pass 2, we update any resource
566  * or alist pointers.  
567  */
568 void save_resource(int type, RES_ITEM *items, int pass)
569 {
570    URES *res;
571    int rindex = type - r_first;
572    int i, size;
573    int error = 0;
574
575    /*
576     * Ensure that all required items are present
577     */
578    for (i=0; items[i].name; i++) {
579       if (items[i].flags & ITEM_REQUIRED) {
580          if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
581             Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
582               items[i].name, resources[rindex]);
583           }
584       }
585       /* If this triggers, take a look at lib/parse_conf.h */
586       if (i >= MAX_RES_ITEMS) {
587          Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
588       }
589    }
590
591    /* During pass 2, we looked up pointers to all the resources
592     * referrenced in the current resource, , now we
593     * must copy their address from the static record to the allocated
594     * record.
595     */
596    if (pass == 2) {
597       DEVRES *dev;
598       int errstat;
599       switch (type) {
600       /* Resources not containing a resource */
601       case R_DEVICE:
602       case R_MSGS:
603          break;
604
605       /* Resources containing a resource or an alist */
606       case R_DIRECTOR:
607          if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
608             Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
609          }
610          res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
611          break;
612       case R_STORAGE:
613          if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
614             Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
615          }
616          res->res_store.messages = res_all.res_store.messages;
617          res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
618          break;
619       case R_AUTOCHANGER:
620          if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
621             Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
622                   res_all.res_changer.hdr.name);
623          }
624          /* we must explicitly copy the device alist pointer */
625          res->res_changer.device   = res_all.res_changer.device;
626          /*
627           * Now update each device in this resource to point back 
628           *  to the changer resource.
629           */
630          foreach_alist(dev, res->res_changer.device) {
631             dev->changer_res = (AUTOCHANGER *)&res->res_changer;
632          }
633          if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
634             berrno be;
635             Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"), 
636                   be.bstrerror(errstat));
637          }
638          break;
639       default:
640          printf(_("Unknown resource type %d\n"), type);
641          error = 1;
642          break;
643       }
644
645
646       if (res_all.res_dir.hdr.name) {
647          free(res_all.res_dir.hdr.name);
648          res_all.res_dir.hdr.name = NULL;
649       }
650       if (res_all.res_dir.hdr.desc) {
651          free(res_all.res_dir.hdr.desc);
652          res_all.res_dir.hdr.desc = NULL;
653       }
654       return;
655    }
656
657    /* The following code is only executed on pass 1 */
658    switch (type) {
659       case R_DIRECTOR:
660          size = sizeof(DIRRES);
661          break;
662       case R_STORAGE:
663          size = sizeof(STORES);
664          break;
665       case R_DEVICE:
666          size = sizeof(DEVRES);
667          break;
668       case R_MSGS:
669          size = sizeof(MSGS);
670          break;
671       case R_AUTOCHANGER:
672          size = sizeof(AUTOCHANGER);
673          break;
674       default:
675          printf(_("Unknown resource type %d\n"), type);
676          error = 1;
677          size = 1;
678          break;
679    }
680    /* Common */
681    if (!error) {
682       res = (URES *)malloc(size);
683       memcpy(res, &res_all, size);
684       if (!res_head[rindex]) {
685          res_head[rindex] = (RES *)res; /* store first entry */
686       } else {
687          RES *next, *last;
688          /* Add new res to end of chain */
689          for (last=next=res_head[rindex]; next; next=next->next) {
690             last = next;
691             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
692                Emsg2(M_ERROR_TERM, 0,
693                   _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
694                   resources[rindex].name, res->res_dir.hdr.name);
695             }
696          }
697          last->next = (RES *)res;
698          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
699                res->res_dir.hdr.name);
700       }
701    }
702 }
703
704 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
705 {
706    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
707       r_first, r_last, resources, res_head);
708    return config->parse_config();
709 }