]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored_conf.c
Apply patches from bugs #2325 and #2326 to fix FIFO bugs
[bacula/bacula] / bacula / src / stored / stored_conf.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 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 #include "cloud_driver.h"
28
29 /* First and last resource ids */
30 int32_t r_first = R_FIRST;
31 int32_t r_last  = R_LAST;
32 RES_HEAD **res_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    {"CommCompression",       store_bool,  ITEM(res_store.comm_compression), 0, ITEM_DEFAULT, true},
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    {"AlignedDevice",         store_strname,ITEM(res_dev.adevice_name), 0, 0, 0},
113    {"HardwareEndOfFile",     store_bit,  ITEM(res_dev.cap_bits), CAP_EOF,  ITEM_DEFAULT, 1},
114    {"HardwareEndOfMedium",   store_bit,  ITEM(res_dev.cap_bits), CAP_EOM,  ITEM_DEFAULT, 1},
115    {"BackwardSpaceRecord",   store_bit,  ITEM(res_dev.cap_bits), CAP_BSR,  ITEM_DEFAULT, 1},
116    {"BackwardSpaceFile",     store_bit,  ITEM(res_dev.cap_bits), CAP_BSF,  ITEM_DEFAULT, 1},
117    {"BsfAtEom",              store_bit,  ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
118    {"TwoEof",                store_bit,  ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
119    {"ForwardSpaceRecord",    store_bit,  ITEM(res_dev.cap_bits), CAP_FSR,  ITEM_DEFAULT, 1},
120    {"ForwardSpaceFile",      store_bit,  ITEM(res_dev.cap_bits), CAP_FSF,  ITEM_DEFAULT, 1},
121    {"FastForwardSpaceFile",  store_bit,  ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
122    {"RemovableMedia",        store_bit,  ITEM(res_dev.cap_bits), CAP_REM,  ITEM_DEFAULT, 1},
123    {"RandomAccess",          store_bit,  ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
124    {"AutomaticMount",        store_bit,  ITEM(res_dev.cap_bits), CAP_AUTOMOUNT,  ITEM_DEFAULT, 0},
125    {"LabelMedia",            store_bit,  ITEM(res_dev.cap_bits), CAP_LABEL,      ITEM_DEFAULT, 0},
126    {"AlwaysOpen",            store_bit,  ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
127    {"Autochanger",           store_bit,  ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
128    {"CloseOnPoll",           store_bit,  ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
129    {"BlockPositioning",      store_bit,  ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
130    {"UseMtiocGet",           store_bit,  ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
131    {"CheckLabels",           store_bit,  ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
132    {"RequiresMount",         store_bit,  ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
133    {"OfflineOnUnmount",      store_bit,  ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
134    {"BlockChecksum",         store_bit,  ITEM(res_dev.cap_bits), CAP_BLOCKCHECKSUM, ITEM_DEFAULT, 1},
135    {"Enabled",               store_bool, ITEM(res_dev.enabled), 0, ITEM_DEFAULT, 1},
136    {"AutoSelect",            store_bool, ITEM(res_dev.autoselect), 0, ITEM_DEFAULT, 1},
137    {"ReadOnly",              store_bool, ITEM(res_dev.read_only), 0, ITEM_DEFAULT, 0},
138    {"ChangerDevice",         store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
139    {"ControlDevice",         store_strname,ITEM(res_dev.control_name), 0, 0, 0},
140    {"ChangerCommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
141    {"AlertCommand",          store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
142    {"LockCommand",           store_strname,ITEM(res_dev.lock_command), 0, 0, 0},
143    {"MaximumChangerWait",    store_time,   ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
144    {"MaximumOpenWait",       store_time,   ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
145    {"MaximumNetworkBufferSize", store_pint32, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
146    {"VolumePollInterval",    store_time,   ITEM(res_dev.vol_poll_interval), 0, ITEM_DEFAULT, 5 * 60},
147    {"MaximumRewindWait",     store_time,   ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
148    {"MinimumBlockSize",      store_size32, ITEM(res_dev.min_block_size), 0, 0, 0},
149    {"MaximumBlockSize",      store_maxblocksize, ITEM(res_dev.max_block_size), 0, 0, 0},
150    {"PaddingSize",           store_size32, ITEM(res_dev.padding_size), 0, ITEM_DEFAULT, 4096},
151    {"FileAlignment",         store_size32, ITEM(res_dev.file_alignment), 0, ITEM_DEFAULT, 4096},
152    {"MinimumAlignedSize",    store_size32, ITEM(res_dev.min_aligned_size), 0, ITEM_DEFAULT, 4096},
153    {"MaximumVolumeSize",     store_size64, ITEM(res_dev.max_volume_size), 0, 0, 0},
154    {"MaximumFileSize",       store_size64, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
155    {"VolumeCapacity",        store_size64, ITEM(res_dev.volume_capacity), 0, 0, 0},
156    {"MinimumFeeSpace",       store_size64, ITEM(res_dev.min_free_space), 0, ITEM_DEFAULT, 5000000},
157    {"MaximumConcurrentJobs", store_pint32, ITEM(res_dev.max_concurrent_jobs), 0, 0, 0},
158    {"SpoolDirectory",        store_dir,    ITEM(res_dev.spool_directory), 0, 0, 0},
159    {"MaximumSpoolSize",      store_size64, ITEM(res_dev.max_spool_size), 0, 0, 0},
160    {"MaximumJobSpoolSize",   store_size64, ITEM(res_dev.max_job_spool_size), 0, 0, 0},
161    {"DriveIndex",            store_pint32, ITEM(res_dev.drive_index), 0, 0, 0},
162    {"MaximumPartSize",       store_size64, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
163    {"MountPoint",            store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
164    {"MountCommand",          store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
165    {"UnmountCommand",        store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
166    {"WritePartCommand",      store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
167    {"FreeSpaceCommand",      store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
168    {"LabelType",             store_label,  ITEM(res_dev.label_type), 0, 0, 0},
169    {"Cloud",                 store_res,    ITEM(res_dev.cloud), R_CLOUD, 0, 0},
170    {NULL, NULL, {0}, 0, 0, 0}
171 };
172
173 /* Autochanger definition */
174 static RES_ITEM changer_items[] = {
175    {"Name",              store_name,      ITEM(res_changer.hdr.name),        0, ITEM_REQUIRED, 0},
176    {"Description",       store_str,       ITEM(res_changer.hdr.desc),        0, 0, 0},
177    {"Device",            store_alist_res, ITEM(res_changer.device),   R_DEVICE, ITEM_REQUIRED, 0},
178    {"ChangerDevice",     store_strname,   ITEM(res_changer.changer_name),    0, ITEM_REQUIRED, 0},
179    {"ChangerCommand",    store_strname,   ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
180    {"LockCommand",           store_strname,ITEM(res_changer.lock_command), 0, 0, 0},
181    {NULL, NULL, {0}, 0, 0, 0}
182 };
183
184 /* Cloud driver definition */
185 static RES_ITEM cloud_items[] = {
186    {"Name",              store_name,      ITEM(res_cloud.hdr.name),        0, ITEM_REQUIRED, 0},
187    {"Description",       store_str,       ITEM(res_cloud.hdr.desc),        0, 0, 0},
188    {"Driver",            store_cloud_driver, ITEM(res_cloud.driver_type), 0, ITEM_REQUIRED, 0},
189    {"HostName",          store_strname,ITEM(res_cloud.host_name), 0, ITEM_REQUIRED, 0},
190    {"BucketName",        store_strname,ITEM(res_cloud.bucket_name), 0, ITEM_REQUIRED, 0},
191    {"Region",            store_strname,ITEM(res_cloud.region), 0, 0, 0},
192    {"AccessKey",         store_strname,ITEM(res_cloud.access_key), 0, ITEM_REQUIRED, 0},
193    {"SecretKey",         store_strname,ITEM(res_cloud.secret_key), 0, ITEM_REQUIRED, 0},
194    {"Protocol",          store_protocol, ITEM(res_cloud.protocol), 0, ITEM_DEFAULT, 0},   /* HTTPS */
195    {"UriStyle",          store_uri_style, ITEM(res_cloud.uri_style), 0, ITEM_DEFAULT, 0}, /* VirtualHost */
196    {"TruncateCache",     store_truncate, ITEM(res_cloud.trunc_opt), 0, ITEM_DEFAULT, TRUNC_NO},
197    {"Upload",            store_upload,   ITEM(res_cloud.upload_opt), 0, ITEM_DEFAULT, UPLOAD_NO},
198    {"MaximumConcurrentUploads", store_pint32, ITEM(res_cloud.max_concurrent_uploads), 0, ITEM_DEFAULT, 0},
199    {"MaximumConcurrentDownloads", store_pint32, ITEM(res_cloud.max_concurrent_downloads), 0, ITEM_DEFAULT, 0},
200    {"MaximumUploadBandwidth", store_speed, ITEM(res_cloud.upload_limit), 0, 0, 0},
201    {"MaximumDownloadBandwidth", store_speed, ITEM(res_cloud.download_limit), 0, 0, 0},
202    {NULL, NULL, {0}, 0, 0, 0}
203 };
204
205
206 /* Message resource */
207 extern RES_ITEM msgs_items[];
208
209
210 /* This is the master resource definition */
211 RES_TABLE resources[] = {
212    {"Director",      dir_items,     R_DIRECTOR},
213    {"Storage",       store_items,   R_STORAGE},
214    {"Device",        dev_items,     R_DEVICE},
215    {"Messages",      msgs_items,    R_MSGS},
216    {"Autochanger",   changer_items, R_AUTOCHANGER},
217    {"Cloud",         cloud_items,   R_CLOUD},
218    {NULL,            NULL,          0}
219 };
220
221 /*
222  * Device types
223  *
224  *   device type     device code = token
225  */
226 s_kw dev_types[] = {
227    {"File",          B_FILE_DEV},
228    {"Tape",          B_TAPE_DEV},
229    {"Fifo",          B_FIFO_DEV},
230    {"VTape",         B_VTAPE_DEV},
231    {"Vtl",           B_VTL_DEV},
232    {"Aligned",       B_ALIGNED_DEV},
233    {"Null",          B_NULL_DEV},
234    {"Cloud",         B_CLOUD_DEV},
235    {NULL,            0}
236 };
237
238
239 /*
240  * Store Device Type (File, FIFO, Tape, Cloud, ...)
241  *
242  */
243 void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
244 {
245    bool found = false;
246
247    lex_get_token(lc, T_NAME);
248    /* Store the label pass 2 so that type is defined */
249    for (int i=0; dev_types[i].name; i++) {
250       if (strcasecmp(lc->str, dev_types[i].name) == 0) {
251          *(uint32_t *)(item->value) = dev_types[i].token;
252          found = true;
253          break;
254       }
255    }
256    if (!found) {
257       scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
258    }
259    scan_to_eol(lc);
260    set_bit(index, res_all.hdr.item_present);
261 }
262
263 /*
264  * Cloud drivers
265  *
266  *  driver     driver code
267  */
268 s_kw cloud_drivers[] = {
269    {"S3",           C_S3_DRIVER},
270    {"File",         C_FILE_DRIVER},
271    {NULL,           0}
272 };
273
274 /*
275  * Store Device Type (File, FIFO, Tape, Cloud, ...)
276  *
277  */
278 void store_cloud_driver(LEX *lc, RES_ITEM *item, int index, int pass)
279 {
280    bool found = false;
281
282    lex_get_token(lc, T_NAME);
283    /* Store the label pass 2 so that type is defined */
284    for (int i=0; cloud_drivers[i].name; i++) {
285       if (strcasecmp(lc->str, cloud_drivers[i].name) == 0) {
286          *(uint32_t *)(item->value) = cloud_drivers[i].token;
287          found = true;
288          break;
289       }
290    }
291    if (!found) {
292       scan_err1(lc, _("Expected a Cloud driver keyword, got: %s"), lc->str);
293    }
294    scan_to_eol(lc);
295    set_bit(index, res_all.hdr.item_present);
296 }
297
298 /*
299  * Cloud Truncate cache options
300  *
301  *   Option       option code = token
302  */
303 s_kw trunc_opts[] = {
304    {"No",           TRUNC_NO},
305    {"AfterUpload",  TRUNC_AFTER_UPLOAD},
306    {"AtEndOfJob",   TRUNC_AT_ENDOFJOB},
307    {NULL,            0}
308 };
309
310 /*
311  * Store Cloud Truncate cache option (AfterUpload, AtEndOfJob, No)
312  *
313  */
314 void store_truncate(LEX *lc, RES_ITEM *item, int index, int pass)
315 {
316    bool found = false;
317
318    lex_get_token(lc, T_NAME);
319    /* Store the label pass 2 so that type is defined */
320    for (int i=0; trunc_opts[i].name; i++) {
321       if (strcasecmp(lc->str, trunc_opts[i].name) == 0) {
322          *(uint32_t *)(item->value) = trunc_opts[i].token;
323          found = true;
324          break;
325       }
326    }
327    if (!found) {
328       scan_err1(lc, _("Expected a Truncate Cache option keyword, got: %s"), lc->str);
329    }
330    scan_to_eol(lc);
331    set_bit(index, res_all.hdr.item_present);
332 }
333
334 /*
335  * Cloud Upload options
336  *
337  *   Option         option code = token
338  */
339 s_kw upload_opts[] = {
340    {"No",            UPLOAD_NO},
341    {"EachPart",      UPLOAD_EACHPART},
342    {"AtEndOfJob",    UPLOAD_AT_ENDOFJOB},
343    {NULL,            0}
344 };
345
346 /*
347  * Store Cloud Upload option (EachPart, AtEndOfJob, No)
348  *
349  */
350 void store_upload(LEX *lc, RES_ITEM *item, int index, int pass)
351 {
352    bool found = false;
353
354    lex_get_token(lc, T_NAME);
355    /* Store the label pass 2 so that type is defined */
356    for (int i=0; upload_opts[i].name; i++) {
357       if (strcasecmp(lc->str, upload_opts[i].name) == 0) {
358          *(uint32_t *)(item->value) = upload_opts[i].token;
359          found = true;
360          break;
361       }
362    }
363    if (!found) {
364       scan_err1(lc, _("Expected a Cloud Upload option keyword, got: %s"), lc->str);
365    }
366    scan_to_eol(lc);
367    set_bit(index, res_all.hdr.item_present);
368 }
369
370 /*
371  * Cloud connection protocol  options
372  *
373  *   Option       option code = token
374  */
375 s_kw proto_opts[] = {
376    {"HTTPS",        0},
377    {"HTTP",         1},
378    {NULL,            0}
379 };
380
381 /*
382  * Store Cloud connect protocol option (HTTPS, HTTP)
383  *
384  */
385 void store_protocol(LEX *lc, RES_ITEM *item, int index, int pass)
386 {
387    bool found = false;
388
389    lex_get_token(lc, T_NAME);
390    /* Store the label pass 2 so that type is defined */
391    for (int i=0; proto_opts[i].name; i++) {
392       if (strcasecmp(lc->str, proto_opts[i].name) == 0) {
393          *(uint32_t *)(item->value) = proto_opts[i].token;
394          found = true;
395          break;
396       }
397    }
398    if (!found) {
399       scan_err1(lc, _("Expected a Cloud communications protocol option keyword, got: %s"), lc->str);
400    }
401    scan_to_eol(lc);
402    set_bit(index, res_all.hdr.item_present);
403 }
404
405 /*
406  * Cloud Uri Style options
407  *
408  *   Option       option code = token
409  */
410 s_kw uri_opts[] = {
411    {"VirtualHost",  0},
412    {"Path",         1},
413    {NULL,            0}
414 };
415
416 /*
417  * Store Cloud Uri Style option
418  *
419  */
420 void store_uri_style(LEX *lc, RES_ITEM *item, int index, int pass)
421 {
422    bool found = false;
423
424    lex_get_token(lc, T_NAME);
425    /* Store the label pass 2 so that type is defined */
426    for (int i=0; uri_opts[i].name; i++) {
427       if (strcasecmp(lc->str, uri_opts[i].name) == 0) {
428          *(uint32_t *)(item->value) = uri_opts[i].token;
429          found = true;
430          break;
431       }
432    }
433    if (!found) {
434       scan_err1(lc, _("Expected a Cloud Uri Style option keyword, got: %s"), lc->str);
435    }
436    scan_to_eol(lc);
437    set_bit(index, res_all.hdr.item_present);
438 }
439
440
441 /*
442  * Store Maximum Block Size, and check it is not greater than MAX_BLOCK_SIZE
443  *
444  */
445 void store_maxblocksize(LEX *lc, RES_ITEM *item, int index, int pass)
446 {
447    store_size32(lc, item, index, pass);
448    if (*(uint32_t *)(item->value) > MAX_BLOCK_SIZE) {
449       scan_err2(lc, _("Maximum Block Size configured value %u is greater than allowed maximum: %u"),
450          *(uint32_t *)(item->value), MAX_BLOCK_SIZE );
451    }
452 }
453
454 /* Dump contents of resource */
455 void dump_resource(int type, RES *rres, void sendit(void *sock, const char *fmt, ...), void *sock)
456 {
457    URES *res = (URES *)rres;
458    char buf[1000];
459    int recurse = 1;
460    IPADDR *p;
461    if (res == NULL) {
462       sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
463       return;
464    }
465    sendit(sock, _("dump_resource type=%d\n"), type);
466    if (type < 0) {                    /* no recursion */
467       type = - type;
468       recurse = 0;
469    }
470    switch (type) {
471    case R_DIRECTOR:
472       sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
473       break;
474    case R_STORAGE:
475       sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
476              res->res_store.hdr.name,
477              NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
478              get_first_port_host_order(res->res_store.sdaddrs),
479              get_first_port_host_order(res->res_store.sddaddrs),
480              edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
481       if (res->res_store.sdaddrs) {
482          foreach_dlist(p, res->res_store.sdaddrs) {
483             sendit(sock, "        SDaddr=%s SDport=%d\n",
484                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
485          }
486       }
487       if (res->res_store.sddaddrs) {
488          foreach_dlist(p, res->res_store.sddaddrs) {
489             sendit(sock, "        SDDaddr=%s SDDport=%d\n",
490                    p->get_address(buf, sizeof(buf)), p->get_port_host_order());
491          }
492       }
493       break;
494    case R_DEVICE:
495       sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
496          res->res_dev.hdr.name,
497          res->res_dev.media_type, res->res_dev.device_name,
498          res->res_dev.label_type);
499       sendit(sock, "        rew_wait=%lld min_bs=%d max_bs=%d chgr_wait=%lld\n",
500          res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
501          res->res_dev.max_block_size, res->res_dev.max_changer_wait);
502       sendit(sock, "        max_jobs=%d max_files=%lld max_size=%lld\n",
503          res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
504          res->res_dev.max_volume_size);
505       sendit(sock, "        min_block_size=%lld max_block_size=%lld\n",
506          res->res_dev.min_block_size, res->res_dev.max_block_size);
507       sendit(sock, "        max_file_size=%lld capacity=%lld\n",
508          res->res_dev.max_file_size, res->res_dev.volume_capacity);
509       sendit(sock, "        spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
510       sendit(sock, "        max_spool_size=%lld max_job_spool_size=%lld\n",
511          res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
512       if (res->res_dev.changer_res) {
513          sendit(sock, "         changer=%p\n", res->res_dev.changer_res);
514       }
515       bstrncpy(buf, "        ", sizeof(buf));
516       if (res->res_dev.cap_bits & CAP_EOF) {
517          bstrncat(buf, "CAP_EOF ", sizeof(buf));
518       }
519       if (res->res_dev.cap_bits & CAP_BSR) {
520          bstrncat(buf, "CAP_BSR ", sizeof(buf));
521       }
522       if (res->res_dev.cap_bits & CAP_BSF) {
523          bstrncat(buf, "CAP_BSF ", sizeof(buf));
524       }
525       if (res->res_dev.cap_bits & CAP_FSR) {
526          bstrncat(buf, "CAP_FSR ", sizeof(buf));
527       }
528       if (res->res_dev.cap_bits & CAP_FSF) {
529          bstrncat(buf, "CAP_FSF ", sizeof(buf));
530       }
531       if (res->res_dev.cap_bits & CAP_EOM) {
532          bstrncat(buf, "CAP_EOM ", sizeof(buf));
533       }
534       if (res->res_dev.cap_bits & CAP_REM) {
535          bstrncat(buf, "CAP_REM ", sizeof(buf));
536       }
537       if (res->res_dev.cap_bits & CAP_RACCESS) {
538          bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
539       }
540       if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
541          bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
542       }
543       if (res->res_dev.cap_bits & CAP_LABEL) {
544          bstrncat(buf, "CAP_LABEL ", sizeof(buf));
545       }
546       if (res->res_dev.cap_bits & CAP_ANONVOLS) {
547          bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
548       }
549       if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
550          bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
551       }
552       if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
553          bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
554       }
555       if (res->res_dev.cap_bits & CAP_REQMOUNT) {
556          bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
557       }
558       if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
559          bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
560       }
561       bstrncat(buf, "\n", sizeof(buf));
562       sendit(sock, buf);  /* Send caps string */
563       if (res->res_dev.cloud) {
564          sendit(sock, "   --->Cloud: name=%s\n", res->res_dev.cloud->hdr.name);
565       }
566       break;
567    case R_CLOUD:
568       sendit(sock, "Cloud: name=%s Driver=%d\n"
569          "      HostName=%s\n"
570          "      BucketName=%s\n"
571          "      AccessKey=%s SecretKey=%s\n"
572          "      AuthRegion=%s\n"
573          "      Protocol=%d UriStyle=%d\n",
574          res->res_cloud.hdr.name, res->res_cloud.driver_type,
575          res->res_cloud.host_name,
576          res->res_cloud.bucket_name,
577          res->res_cloud.access_key, res->res_cloud.secret_key,
578          res->res_cloud.region,
579          res->res_cloud.protocol, res->res_cloud.uri_style);
580       break;
581    case R_AUTOCHANGER:
582       DEVRES *dev;
583       sendit(sock, "Changer: name=%s Changer_devname=%s\n      Changer_cmd=%s\n",
584          res->res_changer.hdr.name,
585          res->res_changer.changer_name, res->res_changer.changer_command);
586       foreach_alist(dev, res->res_changer.device) {
587          sendit(sock, "   --->Device: name=%s\n", dev->hdr.name);
588       }
589       break;
590    case R_MSGS:
591       sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
592       if (res->res_msgs.mail_cmd)
593          sendit(sock, "      mailcmd=%s\n", res->res_msgs.mail_cmd);
594       if (res->res_msgs.operator_cmd)
595          sendit(sock, "      opcmd=%s\n", res->res_msgs.operator_cmd);
596       break;
597    default:
598       sendit(sock, _("Warning: unknown resource type %d\n"), type);
599       break;
600    }
601    rres = GetNextRes(type, rres);
602    if (recurse && rres)
603       dump_resource(type, rres, sendit, sock);
604 }
605
606 /*
607  * Free memory of resource.
608  * NB, we don't need to worry about freeing any references
609  * to other resources as they will be freed when that
610  * resource chain is traversed.  Mainly we worry about freeing
611  * allocated strings (names).
612  */
613 void free_resource(RES *sres, int type)
614 {
615    URES *res = (URES *)sres;
616
617    if (res == NULL)
618       return;
619
620    /* common stuff -- free the resource name */
621    if (res->res_dir.hdr.name) {
622       free(res->res_dir.hdr.name);
623    }
624    if (res->res_dir.hdr.desc) {
625       free(res->res_dir.hdr.desc);
626    }
627
628
629    switch (type) {
630    case R_DIRECTOR:
631       if (res->res_dir.password) {
632          free(res->res_dir.password);
633       }
634       if (res->res_dir.address) {
635          free(res->res_dir.address);
636       }
637       if (res->res_dir.tls_ctx) {
638          free_tls_context(res->res_dir.tls_ctx);
639       }
640       if (res->res_dir.tls_ca_certfile) {
641          free(res->res_dir.tls_ca_certfile);
642       }
643       if (res->res_dir.tls_ca_certdir) {
644          free(res->res_dir.tls_ca_certdir);
645       }
646       if (res->res_dir.tls_certfile) {
647          free(res->res_dir.tls_certfile);
648       }
649       if (res->res_dir.tls_keyfile) {
650          free(res->res_dir.tls_keyfile);
651       }
652       if (res->res_dir.tls_dhfile) {
653          free(res->res_dir.tls_dhfile);
654       }
655       if (res->res_dir.tls_allowed_cns) {
656          delete res->res_dir.tls_allowed_cns;
657       }
658       break;
659    case R_AUTOCHANGER:
660       if (res->res_changer.changer_name) {
661          free(res->res_changer.changer_name);
662       }
663       if (res->res_changer.changer_command) {
664          free(res->res_changer.changer_command);
665       }
666       if (res->res_changer.lock_command) {
667          free(res->res_changer.lock_command);
668       }
669       if (res->res_changer.device) {
670          delete res->res_changer.device;
671       }
672       rwl_destroy(&res->res_changer.changer_lock);
673       break;
674    case R_STORAGE:
675       if (res->res_store.sdaddrs) {
676          free_addresses(res->res_store.sdaddrs);
677       }
678       if (res->res_store.sddaddrs) {
679          free_addresses(res->res_store.sddaddrs);
680       }
681       if (res->res_store.working_directory) {
682          free(res->res_store.working_directory);
683       }
684       if (res->res_store.pid_directory) {
685          free(res->res_store.pid_directory);
686       }
687       if (res->res_store.subsys_directory) {
688          free(res->res_store.subsys_directory);
689       }
690       if (res->res_store.plugin_directory) {
691          free(res->res_store.plugin_directory);
692       }
693       if (res->res_store.scripts_directory) {
694          free(res->res_store.scripts_directory);
695       }
696       if (res->res_store.tls_ctx) {
697          free_tls_context(res->res_store.tls_ctx);
698       }
699       if (res->res_store.tls_ca_certfile) {
700          free(res->res_store.tls_ca_certfile);
701       }
702       if (res->res_store.tls_ca_certdir) {
703          free(res->res_store.tls_ca_certdir);
704       }
705       if (res->res_store.tls_certfile) {
706          free(res->res_store.tls_certfile);
707       }
708       if (res->res_store.tls_keyfile) {
709          free(res->res_store.tls_keyfile);
710       }
711       if (res->res_store.tls_dhfile) {
712          free(res->res_store.tls_dhfile);
713       }
714       if (res->res_store.tls_allowed_cns) {
715          delete res->res_store.tls_allowed_cns;
716       }
717       if (res->res_store.verid) {
718          free(res->res_store.verid);
719       }
720       break;
721    case R_CLOUD:
722       if (res->res_cloud.host_name) {
723          free(res->res_cloud.host_name);
724       }
725       if (res->res_cloud.bucket_name) {
726          free(res->res_cloud.bucket_name);
727       }
728       if (res->res_cloud.access_key) {
729          free(res->res_cloud.access_key);
730       }
731       if (res->res_cloud.secret_key) {
732          free(res->res_cloud.secret_key);
733       }
734       if (res->res_cloud.region) {
735          free(res->res_cloud.region);
736       }
737       break;
738    case R_DEVICE:
739       if (res->res_dev.media_type) {
740          free(res->res_dev.media_type);
741       }
742       if (res->res_dev.device_name) {
743          free(res->res_dev.device_name);
744       }
745       if (res->res_dev.adevice_name) {
746          free(res->res_dev.adevice_name);
747       }
748       if (res->res_dev.control_name) {
749          free(res->res_dev.control_name);
750       }
751       if (res->res_dev.changer_name) {
752          free(res->res_dev.changer_name);
753       }
754       if (res->res_dev.changer_command) {
755          free(res->res_dev.changer_command);
756       }
757       if (res->res_dev.alert_command) {
758          free(res->res_dev.alert_command);
759       }
760       if (res->res_dev.lock_command) {
761          free(res->res_dev.lock_command);
762       }
763       if (res->res_dev.spool_directory) {
764          free(res->res_dev.spool_directory);
765       }
766       if (res->res_dev.mount_point) {
767          free(res->res_dev.mount_point);
768       }
769       if (res->res_dev.mount_command) {
770          free(res->res_dev.mount_command);
771       }
772       if (res->res_dev.unmount_command) {
773          free(res->res_dev.unmount_command);
774       }
775       if (res->res_dev.write_part_command) {
776          free(res->res_dev.write_part_command);
777       }
778       if (res->res_dev.free_space_command) {
779          free(res->res_dev.free_space_command);
780       }
781       break;
782    case R_MSGS:
783       if (res->res_msgs.mail_cmd) {
784          free(res->res_msgs.mail_cmd);
785       }
786       if (res->res_msgs.operator_cmd) {
787          free(res->res_msgs.operator_cmd);
788       }
789       free_msgs_res((MSGS *)res);  /* free message resource */
790       res = NULL;
791       break;
792    default:
793       Dmsg1(0, _("Unknown resource type %d\n"), type);
794       break;
795    }
796    /* Common stuff again -- free the resource, recurse to next one */
797    if (res) {
798       free(res);
799    }
800 }
801
802 /* Save the new resource by chaining it into the head list for
803  * the resource. If this is pass 2, we update any resource
804  * or alist pointers.
805  */
806 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
807 {
808    URES *res;
809    int rindex = type - r_first;
810    int i, size;
811    int error = 0;
812
813    /*
814     * Ensure that all required items are present
815     */
816    for (i=0; items[i].name; i++) {
817       if (items[i].flags & ITEM_REQUIRED) {
818          if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
819             Mmsg(config->m_errmsg, _("\"%s\" directive is required in \"%s\" resource, but not found.\n"),
820                  items[i].name, resources[rindex].name);
821             return false;
822          }
823       }
824       /* If this triggers, take a look at lib/parse_conf.h */
825       if (i >= MAX_RES_ITEMS) {
826          Mmsg(config->m_errmsg, _("Too many directives in \"%s\" resource\n"), resources[rindex].name);
827          return false;
828       }
829    }
830
831    /* During pass 2, we looked up pointers to all the resources
832     * referrenced in the current resource, , now we
833     * must copy their address from the static record to the allocated
834     * record.
835     */
836    if (pass == 2) {
837       DEVRES *dev;
838       int errstat;
839       switch (type) {
840       /* Resources not containing a resource */
841       case R_MSGS:
842       case R_CLOUD:
843          break;
844
845       /* Resources containing a resource or an alist */
846       case R_DIRECTOR:
847          if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
848             Mmsg(config->m_errmsg, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
849             return false;
850          }
851          res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
852          break;
853       case R_STORAGE:
854          if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
855             Mmsg(config->m_errmsg,  _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
856             return false;
857          }
858          res->res_store.messages = res_all.res_store.messages;
859          res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
860          break;
861       case R_AUTOCHANGER:
862          if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
863             Mmsg(config->m_errmsg, _("Cannot find AutoChanger resource %s\n"),
864                  res_all.res_changer.hdr.name);
865             return false;
866          }
867          /* we must explicitly copy the device alist pointer */
868          res->res_changer.device   = res_all.res_changer.device;
869          /*
870           * Now update each device in this resource to point back
871           *  to the changer resource.
872           */
873          foreach_alist(dev, res->res_changer.device) {
874             dev->changer_res = (AUTOCHANGER *)&res->res_changer;
875          }
876          if ((errstat = rwl_init(&res->res_changer.changer_lock, PRIO_SD_ACH_ACCESS)) != 0) {
877             berrno be;
878             Mmsg(config->m_errmsg, _("Unable to init lock for Autochanger=%s: ERR=%s\n"),
879                  res_all.res_changer.hdr.name, be.bstrerror(errstat));
880             return false;
881          }
882          break;
883       case R_DEVICE:
884          if ((res = (URES *)GetResWithName(R_DEVICE, res_all.res_dev.hdr.name)) == NULL) {
885             Mmsg(config->m_errmsg,  _("Cannot find Device resource %s\n"), res_all.res_dir.hdr.name);
886             return false;
887          }
888          res->res_dev.cloud = res_all.res_dev.cloud;
889          break;
890       default:
891          printf(_("Unknown resource type %d\n"), type);
892          error = 1;
893          break;
894       }
895
896
897       if (res_all.res_dir.hdr.name) {
898          free(res_all.res_dir.hdr.name);
899          res_all.res_dir.hdr.name = NULL;
900       }
901       if (res_all.res_dir.hdr.desc) {
902          free(res_all.res_dir.hdr.desc);
903          res_all.res_dir.hdr.desc = NULL;
904       }
905       return true;
906    }
907
908    /* The following code is only executed on pass 1 */
909    switch (type) {
910       case R_DIRECTOR:
911          size = sizeof(DIRRES);
912          break;
913       case R_STORAGE:
914          size = sizeof(STORES);
915          break;
916       case R_DEVICE:
917          size = sizeof(DEVRES);
918          break;
919       case R_MSGS:
920          size = sizeof(MSGS);
921          break;
922       case R_AUTOCHANGER:
923          size = sizeof(AUTOCHANGER);
924          break;
925       case R_CLOUD:
926          size = sizeof(CLOUD);
927          break;
928       default:
929          printf(_("Unknown resource type %d\n"), type);
930          error = 1;
931          size = 1;
932          break;
933    }
934    /* Common */
935    if (!error) {
936       if (!config->insert_res(rindex, size)) {
937          return false;
938       }
939    }
940    return true;
941 }
942
943 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
944 {
945    config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
946       r_first, r_last, resources, &res_head);
947    return config->parse_config();
948 }