]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored_conf.c
Add %D option to edit_job_code, simplify callbacks on director side
[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 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       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.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 = rwl_init(&res->res_changer.changer_lock, 
634                                  PRIO_SD_ACH_ACCESS)) != 0)
635          {
636             berrno be;
637             Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init lock: ERR=%s\n"), 
638                   be.bstrerror(errstat));
639          }
640          break;
641       default:
642          printf(_("Unknown resource type %d\n"), type);
643          error = 1;
644          break;
645       }
646
647
648       if (res_all.res_dir.hdr.name) {
649          free(res_all.res_dir.hdr.name);
650          res_all.res_dir.hdr.name = NULL;
651       }
652       if (res_all.res_dir.hdr.desc) {
653          free(res_all.res_dir.hdr.desc);
654          res_all.res_dir.hdr.desc = NULL;
655       }
656       return;
657    }
658
659    /* The following code is only executed on pass 1 */
660    switch (type) {
661       case R_DIRECTOR:
662          size = sizeof(DIRRES);
663          break;
664       case R_STORAGE:
665          size = sizeof(STORES);
666          break;
667       case R_DEVICE:
668          size = sizeof(DEVRES);
669          break;
670       case R_MSGS:
671          size = sizeof(MSGS);
672          break;
673       case R_AUTOCHANGER:
674          size = sizeof(AUTOCHANGER);
675          break;
676       default:
677          printf(_("Unknown resource type %d\n"), type);
678          error = 1;
679          size = 1;
680          break;
681    }
682    /* Common */
683    if (!error) {
684       res = (URES *)malloc(size);
685       memcpy(res, &res_all, size);
686       if (!res_head[rindex]) {
687          res_head[rindex] = (RES *)res; /* store first entry */
688       } else {
689          RES *next, *last;
690          /* Add new res to end of chain */
691          for (last=next=res_head[rindex]; next; next=next->next) {
692             last = next;
693             if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
694                Emsg2(M_ERROR_TERM, 0,
695                   _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
696                   resources[rindex].name, res->res_dir.hdr.name);
697             }
698          }
699          last->next = (RES *)res;
700          Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
701                res->res_dir.hdr.name);
702       }
703    }
704 }
705
706 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
707 {
708    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
709       r_first, r_last, resources, res_head);
710    return config->parse_config();
711 }