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