2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Configuration file parser for Bacula Storage daemon
22 * Kern Sibbald, March MM
27 #include "cloud_driver.h"
29 /* First and last resource ids */
30 int32_t r_first = R_FIRST;
31 int32_t r_last = R_LAST;
34 /* We build the current resource here statically,
35 * then move it to dynamic memory */
37 extern "C" { // work around visual compiler mangling variables
43 int32_t res_all_size = sizeof(res_all);
45 /* Definition of records permitted within each
46 * resource with the routine to process the record
51 * Globals for the Storage daemon.
52 * name handler value code flags default_value
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}
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}
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}
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}
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}
206 /* Message resource */
207 extern RES_ITEM msgs_items[];
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},
224 * device type device code = token
227 {"File", B_FILE_DEV},
228 {"Tape", B_TAPE_DEV},
229 {"Fifo", B_FIFO_DEV},
230 {"VTape", B_VTAPE_DEV},
232 {"Aligned", B_ALIGNED_DEV},
233 {"Null", B_NULL_DEV},
234 {"Cloud", B_CLOUD_DEV},
240 * Store Device Type (File, FIFO, Tape, Cloud, ...)
243 void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
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;
257 scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
260 set_bit(index, res_all.hdr.item_present);
268 s_kw cloud_drivers[] = {
270 {"File", C_FILE_DRIVER},
275 * Store Device Type (File, FIFO, Tape, Cloud, ...)
278 void store_cloud_driver(LEX *lc, RES_ITEM *item, int index, int pass)
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;
292 scan_err1(lc, _("Expected a Cloud driver keyword, got: %s"), lc->str);
295 set_bit(index, res_all.hdr.item_present);
299 * Cloud Truncate cache options
301 * Option option code = token
303 s_kw trunc_opts[] = {
305 {"AfterUpload", TRUNC_AFTER_UPLOAD},
306 {"AtEndOfJob", TRUNC_AT_ENDOFJOB},
311 * Store Cloud Truncate cache option (AfterUpload, AtEndOfJob, No)
314 void store_truncate(LEX *lc, RES_ITEM *item, int index, int pass)
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;
328 scan_err1(lc, _("Expected a Truncate Cache option keyword, got: %s"), lc->str);
331 set_bit(index, res_all.hdr.item_present);
335 * Cloud Upload options
337 * Option option code = token
339 s_kw upload_opts[] = {
341 {"EachPart", UPLOAD_EACHPART},
342 {"AtEndOfJob", UPLOAD_AT_ENDOFJOB},
347 * Store Cloud Upload option (EachPart, AtEndOfJob, No)
350 void store_upload(LEX *lc, RES_ITEM *item, int index, int pass)
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;
364 scan_err1(lc, _("Expected a Cloud Upload option keyword, got: %s"), lc->str);
367 set_bit(index, res_all.hdr.item_present);
371 * Cloud connection protocol options
373 * Option option code = token
375 s_kw proto_opts[] = {
382 * Store Cloud connect protocol option (HTTPS, HTTP)
385 void store_protocol(LEX *lc, RES_ITEM *item, int index, int pass)
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;
399 scan_err1(lc, _("Expected a Cloud communications protocol option keyword, got: %s"), lc->str);
402 set_bit(index, res_all.hdr.item_present);
406 * Cloud Uri Style options
408 * Option option code = token
417 * Store Cloud Uri Style option
420 void store_uri_style(LEX *lc, RES_ITEM *item, int index, int pass)
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;
434 scan_err1(lc, _("Expected a Cloud Uri Style option keyword, got: %s"), lc->str);
437 set_bit(index, res_all.hdr.item_present);
442 * Store Maximum Block Size, and check it is not greater than MAX_BLOCK_SIZE
445 void store_maxblocksize(LEX *lc, RES_ITEM *item, int index, int pass)
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 );
454 /* Dump contents of resource */
455 void dump_resource(int type, RES *rres, void sendit(void *sock, const char *fmt, ...), void *sock)
457 URES *res = (URES *)rres;
462 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
465 sendit(sock, _("dump_resource type=%d\n"), type);
466 if (type < 0) { /* no recursion */
472 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
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());
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());
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);
515 bstrncpy(buf, " ", sizeof(buf));
516 if (res->res_dev.cap_bits & CAP_EOF) {
517 bstrncat(buf, "CAP_EOF ", sizeof(buf));
519 if (res->res_dev.cap_bits & CAP_BSR) {
520 bstrncat(buf, "CAP_BSR ", sizeof(buf));
522 if (res->res_dev.cap_bits & CAP_BSF) {
523 bstrncat(buf, "CAP_BSF ", sizeof(buf));
525 if (res->res_dev.cap_bits & CAP_FSR) {
526 bstrncat(buf, "CAP_FSR ", sizeof(buf));
528 if (res->res_dev.cap_bits & CAP_FSF) {
529 bstrncat(buf, "CAP_FSF ", sizeof(buf));
531 if (res->res_dev.cap_bits & CAP_EOM) {
532 bstrncat(buf, "CAP_EOM ", sizeof(buf));
534 if (res->res_dev.cap_bits & CAP_REM) {
535 bstrncat(buf, "CAP_REM ", sizeof(buf));
537 if (res->res_dev.cap_bits & CAP_RACCESS) {
538 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
540 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
541 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
543 if (res->res_dev.cap_bits & CAP_LABEL) {
544 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
546 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
547 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
549 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
550 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
552 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
553 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
555 if (res->res_dev.cap_bits & CAP_REQMOUNT) {
556 bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
558 if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
559 bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
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);
568 sendit(sock, "Cloud: name=%s Driver=%d\n"
571 " AccessKey=%s SecretKey=%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);
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);
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);
598 sendit(sock, _("Warning: unknown resource type %d\n"), type);
601 rres = GetNextRes(type, rres);
603 dump_resource(type, rres, sendit, sock);
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).
613 void free_resource(RES *sres, int type)
615 URES *res = (URES *)sres;
620 /* common stuff -- free the resource name */
621 if (res->res_dir.hdr.name) {
622 free(res->res_dir.hdr.name);
624 if (res->res_dir.hdr.desc) {
625 free(res->res_dir.hdr.desc);
631 if (res->res_dir.password) {
632 free(res->res_dir.password);
634 if (res->res_dir.address) {
635 free(res->res_dir.address);
637 if (res->res_dir.tls_ctx) {
638 free_tls_context(res->res_dir.tls_ctx);
640 if (res->res_dir.tls_ca_certfile) {
641 free(res->res_dir.tls_ca_certfile);
643 if (res->res_dir.tls_ca_certdir) {
644 free(res->res_dir.tls_ca_certdir);
646 if (res->res_dir.tls_certfile) {
647 free(res->res_dir.tls_certfile);
649 if (res->res_dir.tls_keyfile) {
650 free(res->res_dir.tls_keyfile);
652 if (res->res_dir.tls_dhfile) {
653 free(res->res_dir.tls_dhfile);
655 if (res->res_dir.tls_allowed_cns) {
656 delete res->res_dir.tls_allowed_cns;
660 if (res->res_changer.changer_name) {
661 free(res->res_changer.changer_name);
663 if (res->res_changer.changer_command) {
664 free(res->res_changer.changer_command);
666 if (res->res_changer.lock_command) {
667 free(res->res_changer.lock_command);
669 if (res->res_changer.device) {
670 delete res->res_changer.device;
672 rwl_destroy(&res->res_changer.changer_lock);
675 if (res->res_store.sdaddrs) {
676 free_addresses(res->res_store.sdaddrs);
678 if (res->res_store.sddaddrs) {
679 free_addresses(res->res_store.sddaddrs);
681 if (res->res_store.working_directory) {
682 free(res->res_store.working_directory);
684 if (res->res_store.pid_directory) {
685 free(res->res_store.pid_directory);
687 if (res->res_store.subsys_directory) {
688 free(res->res_store.subsys_directory);
690 if (res->res_store.plugin_directory) {
691 free(res->res_store.plugin_directory);
693 if (res->res_store.scripts_directory) {
694 free(res->res_store.scripts_directory);
696 if (res->res_store.tls_ctx) {
697 free_tls_context(res->res_store.tls_ctx);
699 if (res->res_store.tls_ca_certfile) {
700 free(res->res_store.tls_ca_certfile);
702 if (res->res_store.tls_ca_certdir) {
703 free(res->res_store.tls_ca_certdir);
705 if (res->res_store.tls_certfile) {
706 free(res->res_store.tls_certfile);
708 if (res->res_store.tls_keyfile) {
709 free(res->res_store.tls_keyfile);
711 if (res->res_store.tls_dhfile) {
712 free(res->res_store.tls_dhfile);
714 if (res->res_store.tls_allowed_cns) {
715 delete res->res_store.tls_allowed_cns;
717 if (res->res_store.verid) {
718 free(res->res_store.verid);
722 if (res->res_cloud.host_name) {
723 free(res->res_cloud.host_name);
725 if (res->res_cloud.bucket_name) {
726 free(res->res_cloud.bucket_name);
728 if (res->res_cloud.access_key) {
729 free(res->res_cloud.access_key);
731 if (res->res_cloud.secret_key) {
732 free(res->res_cloud.secret_key);
734 if (res->res_cloud.region) {
735 free(res->res_cloud.region);
739 if (res->res_dev.media_type) {
740 free(res->res_dev.media_type);
742 if (res->res_dev.device_name) {
743 free(res->res_dev.device_name);
745 if (res->res_dev.adevice_name) {
746 free(res->res_dev.adevice_name);
748 if (res->res_dev.control_name) {
749 free(res->res_dev.control_name);
751 if (res->res_dev.changer_name) {
752 free(res->res_dev.changer_name);
754 if (res->res_dev.changer_command) {
755 free(res->res_dev.changer_command);
757 if (res->res_dev.alert_command) {
758 free(res->res_dev.alert_command);
760 if (res->res_dev.lock_command) {
761 free(res->res_dev.lock_command);
763 if (res->res_dev.spool_directory) {
764 free(res->res_dev.spool_directory);
766 if (res->res_dev.mount_point) {
767 free(res->res_dev.mount_point);
769 if (res->res_dev.mount_command) {
770 free(res->res_dev.mount_command);
772 if (res->res_dev.unmount_command) {
773 free(res->res_dev.unmount_command);
775 if (res->res_dev.write_part_command) {
776 free(res->res_dev.write_part_command);
778 if (res->res_dev.free_space_command) {
779 free(res->res_dev.free_space_command);
783 if (res->res_msgs.mail_cmd) {
784 free(res->res_msgs.mail_cmd);
786 if (res->res_msgs.operator_cmd) {
787 free(res->res_msgs.operator_cmd);
789 free_msgs_res((MSGS *)res); /* free message resource */
793 Dmsg1(0, _("Unknown resource type %d\n"), type);
796 /* Common stuff again -- free the resource, recurse to next one */
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
806 bool save_resource(CONFIG *config, int type, RES_ITEM *items, int pass)
809 int rindex = type - r_first;
814 * Ensure that all required items are present
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);
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);
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
840 /* Resources not containing a resource */
845 /* Resources containing a resource or an alist */
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);
851 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
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);
858 res->res_store.messages = res_all.res_store.messages;
859 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
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);
867 /* we must explicitly copy the device alist pointer */
868 res->res_changer.device = res_all.res_changer.device;
870 * Now update each device in this resource to point back
871 * to the changer resource.
873 foreach_alist(dev, res->res_changer.device) {
874 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
876 if ((errstat = rwl_init(&res->res_changer.changer_lock, PRIO_SD_ACH_ACCESS)) != 0) {
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));
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);
888 res->res_dev.cloud = res_all.res_dev.cloud;
891 printf(_("Unknown resource type %d\n"), type);
897 if (res_all.res_dir.hdr.name) {
898 free(res_all.res_dir.hdr.name);
899 res_all.res_dir.hdr.name = NULL;
901 if (res_all.res_dir.hdr.desc) {
902 free(res_all.res_dir.hdr.desc);
903 res_all.res_dir.hdr.desc = NULL;
908 /* The following code is only executed on pass 1 */
911 size = sizeof(DIRRES);
914 size = sizeof(STORES);
917 size = sizeof(DEVRES);
923 size = sizeof(AUTOCHANGER);
926 size = sizeof(CLOUD);
929 printf(_("Unknown resource type %d\n"), type);
936 if (!config->insert_res(rindex, size)) {
943 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
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();