2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of John Walker.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
29 * Configuration file parser for Bacula Storage daemon
31 * Kern Sibbald, March MM
39 /* First and last resource ids */
40 int32_t r_first = R_FIRST;
41 int32_t r_last = R_LAST;
42 static RES *sres_head[R_LAST - R_FIRST + 1];
43 RES **res_head = sres_head;
46 /* Forward referenced subroutines */
47 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass);
50 /* We build the current resource here statically,
51 * then move it to dynamic memory */
53 extern "C" { // work around visual compiler mangling variables
59 int32_t res_all_size = sizeof(res_all);
61 /* Definition of records permitted within each
62 * resource with the routine to process the record
66 /* Globals for the Storage daemon. */
67 static RES_ITEM store_items[] = {
68 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
69 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
70 {"sdaddress", store_addresses_address, ITEM(res_store.sdaddrs), 0, ITEM_DEFAULT, 9103},
71 {"sdaddresses", store_addresses, ITEM(res_store.sdaddrs), 0, ITEM_DEFAULT, 9103},
72 {"messages", store_res, ITEM(res_store.messages), R_MSGS, 0, 0},
73 {"sdport", store_addresses_port, ITEM(res_store.sdaddrs), 0, ITEM_DEFAULT, 9103},
74 {"workingdirectory", store_dir, ITEM(res_store.working_directory), 0, ITEM_REQUIRED, 0},
75 {"piddirectory", store_dir, ITEM(res_store.pid_directory), 0, ITEM_REQUIRED, 0},
76 {"subsysdirectory", store_dir, ITEM(res_store.subsys_directory), 0, 0, 0},
77 {"plugindirectory", store_dir, ITEM(res_store.plugin_directory), 0, 0, 0},
78 {"scriptsdirectory", store_dir, ITEM(res_store.scripts_directory), 0, 0, 0},
79 {"maximumconcurrentjobs", store_pint32, ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 20},
80 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
81 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
82 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
83 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
84 {"tlsverifypeer", store_bool, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1},
85 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
86 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
87 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
88 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
89 {"tlsdhfile", store_dir, ITEM(res_store.tls_dhfile), 0, 0, 0},
90 {"tlsallowedcn", store_alist_str, ITEM(res_store.tls_allowed_cns), 0, 0, 0},
91 {"clientconnectwait", store_time, ITEM(res_store.client_wait), 0, ITEM_DEFAULT, 30 * 60},
92 {NULL, NULL, {0}, 0, 0, 0}
96 /* Directors that can speak to the Storage daemon */
97 static RES_ITEM dir_items[] = {
98 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
99 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
100 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
101 {"monitor", store_bool, ITEM(res_dir.monitor), 0, 0, 0},
102 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
103 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
104 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
105 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1},
106 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
107 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
108 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
109 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
110 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
111 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
112 {NULL, NULL, {0}, 0, 0, 0}
115 /* Device definition */
116 static RES_ITEM dev_items[] = {
117 {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0},
118 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
119 {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0},
120 {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0},
121 {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
122 {"hardwareendoffile", store_bit, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1},
123 {"hardwareendofmedium", store_bit, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1},
124 {"backwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1},
125 {"backwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1},
126 {"bsfateom", store_bit, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
127 {"twoeof", store_bit, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
128 {"forwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1},
129 {"forwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1},
130 {"fastforwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
131 {"removablemedia", store_bit, ITEM(res_dev.cap_bits), CAP_REM, ITEM_DEFAULT, 1},
132 {"randomaccess", store_bit, ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
133 {"automaticmount", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOMOUNT, ITEM_DEFAULT, 0},
134 {"labelmedia", store_bit, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0},
135 {"alwaysopen", store_bit, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
136 {"autochanger", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
137 {"closeonpoll", store_bit, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
138 {"blockpositioning", store_bit, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
139 {"usemtiocget", store_bit, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
140 {"checklabels", store_bit, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
141 {"requiresmount", store_bit, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
142 {"offlineonunmount", store_bit, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
143 {"autoselect", store_bool, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
144 {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
145 {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
146 {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
147 {"maximumchangerwait", store_time, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
148 {"maximumopenwait", store_time, ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
149 {"maximumopenvolumes", store_pint32, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
150 {"maximumnetworkbuffersize", store_pint32, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
151 {"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0},
152 {"maximumrewindwait", store_time, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
153 {"minimumblocksize", store_pint32, ITEM(res_dev.min_block_size), 0, 0, 0},
154 {"maximumblocksize", store_pint32, ITEM(res_dev.max_block_size), 0, 0, 0},
155 {"maximumvolumesize", store_size, ITEM(res_dev.max_volume_size), 0, 0, 0},
156 {"maximumfilesize", store_size, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
157 {"volumecapacity", store_size, ITEM(res_dev.volume_capacity), 0, 0, 0},
158 {"spooldirectory", store_dir, ITEM(res_dev.spool_directory), 0, 0, 0},
159 {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0},
160 {"maximumjobspoolsize", store_size, 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_size, 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 {NULL, NULL, {0}, 0, 0, 0}
172 /* Autochanger definition */
173 static RES_ITEM changer_items[] = {
174 {"name", store_name, ITEM(res_changer.hdr.name), 0, ITEM_REQUIRED, 0},
175 {"description", store_str, ITEM(res_changer.hdr.desc), 0, 0, 0},
176 {"device", store_alist_res, ITEM(res_changer.device), R_DEVICE, ITEM_REQUIRED, 0},
177 {"changerdevice", store_strname, ITEM(res_changer.changer_name), 0, ITEM_REQUIRED, 0},
178 {"changercommand", store_strname, ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
179 {NULL, NULL, {0}, 0, 0, 0}
183 // {"mountanonymousvolumes", store_bit, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0},
186 /* Message resource */
187 extern RES_ITEM msgs_items[];
190 /* This is the master resource definition */
191 RES_TABLE resources[] = {
192 {"director", dir_items, R_DIRECTOR},
193 {"storage", store_items, R_STORAGE},
194 {"device", dev_items, R_DEVICE},
195 {"messages", msgs_items, R_MSGS},
196 {"autochanger", changer_items, R_AUTOCHANGER},
203 * device type device code = token
210 static s_kw dev_types[] = {
211 {"file", B_FILE_DEV},
212 {"tape", B_TAPE_DEV},
214 {"fifo", B_FIFO_DEV},
216 {"vtape", B_VTAPE_DEV},
222 * Store Device Type (File, FIFO, Tape, DVD)
225 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
229 token = lex_get_token(lc, T_NAME);
230 /* Store the label pass 2 so that type is defined */
231 for (i=0; dev_types[i].name; i++) {
232 if (strcasecmp(lc->str, dev_types[i].name) == 0) {
233 *(uint32_t *)(item->value) = dev_types[i].token;
239 scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
242 set_bit(index, res_all.hdr.item_present);
246 /* Dump contents of resource */
247 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
249 URES *res = (URES *)reshdr;
254 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
257 sendit(sock, _("dump_resource type=%d\n"), type);
258 if (type < 0) { /* no recursion */
264 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
267 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
268 res->res_store.hdr.name,
269 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
270 get_first_port_host_order(res->res_store.sdaddrs),
271 get_first_port_host_order(res->res_store.sddaddrs),
272 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
273 if (res->res_store.sdaddrs) {
274 foreach_dlist(p, res->res_store.sdaddrs) {
275 sendit(sock, " SDaddr=%s SDport=%d\n",
276 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
279 if (res->res_store.sddaddrs) {
280 foreach_dlist(p, res->res_store.sddaddrs) {
281 sendit(sock, " SDDaddr=%s SDDport=%d\n",
282 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
287 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
288 res->res_dev.hdr.name,
289 res->res_dev.media_type, res->res_dev.device_name,
290 res->res_dev.label_type);
291 sendit(sock, " rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
292 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
293 res->res_dev.max_block_size, res->res_dev.max_changer_wait);
294 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
295 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
296 res->res_dev.max_volume_size);
297 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
298 res->res_dev.max_file_size, res->res_dev.volume_capacity);
299 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
300 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
301 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
302 if (res->res_dev.changer_res) {
303 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
305 bstrncpy(buf, " ", sizeof(buf));
306 if (res->res_dev.cap_bits & CAP_EOF) {
307 bstrncat(buf, "CAP_EOF ", sizeof(buf));
309 if (res->res_dev.cap_bits & CAP_BSR) {
310 bstrncat(buf, "CAP_BSR ", sizeof(buf));
312 if (res->res_dev.cap_bits & CAP_BSF) {
313 bstrncat(buf, "CAP_BSF ", sizeof(buf));
315 if (res->res_dev.cap_bits & CAP_FSR) {
316 bstrncat(buf, "CAP_FSR ", sizeof(buf));
318 if (res->res_dev.cap_bits & CAP_FSF) {
319 bstrncat(buf, "CAP_FSF ", sizeof(buf));
321 if (res->res_dev.cap_bits & CAP_EOM) {
322 bstrncat(buf, "CAP_EOM ", sizeof(buf));
324 if (res->res_dev.cap_bits & CAP_REM) {
325 bstrncat(buf, "CAP_REM ", sizeof(buf));
327 if (res->res_dev.cap_bits & CAP_RACCESS) {
328 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
330 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
331 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
333 if (res->res_dev.cap_bits & CAP_LABEL) {
334 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
336 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
337 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
339 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
340 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
342 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
343 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
345 if (res->res_dev.cap_bits & CAP_REQMOUNT) {
346 bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
348 if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
349 bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
351 bstrncat(buf, "\n", sizeof(buf));
356 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
357 res->res_changer.hdr.name,
358 res->res_changer.changer_name, res->res_changer.changer_command);
359 foreach_alist(dev, res->res_changer.device) {
360 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
362 bstrncat(buf, "\n", sizeof(buf));
366 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
367 if (res->res_msgs.mail_cmd)
368 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
369 if (res->res_msgs.operator_cmd)
370 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
373 sendit(sock, _("Warning: unknown resource type %d\n"), type);
376 if (recurse && res->res_dir.hdr.next)
377 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
381 * Free memory of resource.
382 * NB, we don't need to worry about freeing any references
383 * to other resources as they will be freed when that
384 * resource chain is traversed. Mainly we worry about freeing
385 * allocated strings (names).
387 void free_resource(RES *sres, int type)
390 URES *res = (URES *)sres;
395 /* common stuff -- free the resource name */
396 nres = (RES *)res->res_dir.hdr.next;
397 if (res->res_dir.hdr.name) {
398 free(res->res_dir.hdr.name);
400 if (res->res_dir.hdr.desc) {
401 free(res->res_dir.hdr.desc);
407 if (res->res_dir.password) {
408 free(res->res_dir.password);
410 if (res->res_dir.address) {
411 free(res->res_dir.address);
413 if (res->res_dir.tls_ctx) {
414 free_tls_context(res->res_dir.tls_ctx);
416 if (res->res_dir.tls_ca_certfile) {
417 free(res->res_dir.tls_ca_certfile);
419 if (res->res_dir.tls_ca_certdir) {
420 free(res->res_dir.tls_ca_certdir);
422 if (res->res_dir.tls_certfile) {
423 free(res->res_dir.tls_certfile);
425 if (res->res_dir.tls_keyfile) {
426 free(res->res_dir.tls_keyfile);
428 if (res->res_dir.tls_dhfile) {
429 free(res->res_dir.tls_dhfile);
431 if (res->res_dir.tls_allowed_cns) {
432 delete res->res_dir.tls_allowed_cns;
436 if (res->res_changer.changer_name) {
437 free(res->res_changer.changer_name);
439 if (res->res_changer.changer_command) {
440 free(res->res_changer.changer_command);
442 if (res->res_changer.device) {
443 delete res->res_changer.device;
447 if (res->res_store.sdaddrs) {
448 free_addresses(res->res_store.sdaddrs);
450 if (res->res_store.sddaddrs) {
451 free_addresses(res->res_store.sddaddrs);
453 if (res->res_store.working_directory) {
454 free(res->res_store.working_directory);
456 if (res->res_store.pid_directory) {
457 free(res->res_store.pid_directory);
459 if (res->res_store.subsys_directory) {
460 free(res->res_store.subsys_directory);
462 if (res->res_store.scripts_directory) {
463 free(res->res_store.scripts_directory);
465 if (res->res_store.tls_ctx) {
466 free_tls_context(res->res_store.tls_ctx);
468 if (res->res_store.tls_ca_certfile) {
469 free(res->res_store.tls_ca_certfile);
471 if (res->res_store.tls_ca_certdir) {
472 free(res->res_store.tls_ca_certdir);
474 if (res->res_store.tls_certfile) {
475 free(res->res_store.tls_certfile);
477 if (res->res_store.tls_keyfile) {
478 free(res->res_store.tls_keyfile);
480 if (res->res_store.tls_dhfile) {
481 free(res->res_store.tls_dhfile);
483 if (res->res_store.tls_allowed_cns) {
484 delete res->res_store.tls_allowed_cns;
488 if (res->res_dev.media_type) {
489 free(res->res_dev.media_type);
491 if (res->res_dev.device_name) {
492 free(res->res_dev.device_name);
494 if (res->res_dev.changer_name) {
495 free(res->res_dev.changer_name);
497 if (res->res_dev.changer_command) {
498 free(res->res_dev.changer_command);
500 if (res->res_dev.alert_command) {
501 free(res->res_dev.alert_command);
503 if (res->res_dev.spool_directory) {
504 free(res->res_dev.spool_directory);
506 if (res->res_dev.mount_point) {
507 free(res->res_dev.mount_point);
509 if (res->res_dev.mount_command) {
510 free(res->res_dev.mount_command);
512 if (res->res_dev.unmount_command) {
513 free(res->res_dev.unmount_command);
515 if (res->res_dev.write_part_command) {
516 free(res->res_dev.write_part_command);
518 if (res->res_dev.free_space_command) {
519 free(res->res_dev.free_space_command);
523 if (res->res_msgs.mail_cmd) {
524 free(res->res_msgs.mail_cmd);
526 if (res->res_msgs.operator_cmd) {
527 free(res->res_msgs.operator_cmd);
529 free_msgs_res((MSGS *)res); /* free message resource */
533 Dmsg1(0, _("Unknown resource type %d\n"), type);
536 /* Common stuff again -- free the resource, recurse to next one */
541 free_resource(nres, type);
545 /* Save the new resource by chaining it into the head list for
546 * the resource. If this is pass 2, we update any resource
549 void save_resource(int type, RES_ITEM *items, int pass)
552 int rindex = type - r_first;
557 * Ensure that all required items are present
559 for (i=0; items[i].name; i++) {
560 if (items[i].flags & ITEM_REQUIRED) {
561 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
562 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
563 items[i].name, resources[rindex]);
566 /* If this triggers, take a look at lib/parse_conf.h */
567 if (i >= MAX_RES_ITEMS) {
568 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
572 /* During pass 2, we looked up pointers to all the resources
573 * referrenced in the current resource, , now we
574 * must copy their address from the static record to the allocated
581 /* Resources not containing a resource */
586 /* Resources containing a resource or an alist */
588 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
589 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
591 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
594 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
595 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
597 res->res_store.messages = res_all.res_store.messages;
598 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
601 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
602 Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
603 res_all.res_changer.hdr.name);
605 /* we must explicitly copy the device alist pointer */
606 res->res_changer.device = res_all.res_changer.device;
608 * Now update each device in this resource to point back
609 * to the changer resource.
611 foreach_alist(dev, res->res_changer.device) {
612 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
614 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
616 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
617 be.bstrerror(errstat));
621 printf(_("Unknown resource type %d\n"), type);
627 if (res_all.res_dir.hdr.name) {
628 free(res_all.res_dir.hdr.name);
629 res_all.res_dir.hdr.name = NULL;
631 if (res_all.res_dir.hdr.desc) {
632 free(res_all.res_dir.hdr.desc);
633 res_all.res_dir.hdr.desc = NULL;
638 /* The following code is only executed on pass 1 */
641 size = sizeof(DIRRES);
644 size = sizeof(STORES);
647 size = sizeof(DEVRES);
653 size = sizeof(AUTOCHANGER);
656 printf(_("Unknown resource type %d\n"), type);
663 res = (URES *)malloc(size);
664 memcpy(res, &res_all, size);
665 if (!res_head[rindex]) {
666 res_head[rindex] = (RES *)res; /* store first entry */
669 /* Add new res to end of chain */
670 for (last=next=res_head[rindex]; next; next=next->next) {
672 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
673 Emsg2(M_ERROR_TERM, 0,
674 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
675 resources[rindex].name, res->res_dir.hdr.name);
678 last->next = (RES *)res;
679 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
680 res->res_dir.hdr.name);
685 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
687 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
688 r_first, r_last, resources, res_head);
689 return config->parse_config();