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