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 Kern Sibbald.
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 {"verid", store_str, ITEM(res_store.verid), 0, 0, 0},
93 {NULL, NULL, {0}, 0, 0, 0}
97 /* Directors that can speak to the Storage daemon */
98 static RES_ITEM dir_items[] = {
99 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
100 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
101 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
102 {"monitor", store_bool, ITEM(res_dir.monitor), 0, 0, 0},
103 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
104 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
105 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
106 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1},
107 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
108 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
109 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
110 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
111 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
112 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
113 {NULL, NULL, {0}, 0, 0, 0}
116 /* Device definition */
117 static RES_ITEM dev_items[] = {
118 {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0},
119 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
120 {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0},
121 {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0},
122 {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
123 {"hardwareendoffile", store_bit, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1},
124 {"hardwareendofmedium", store_bit, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1},
125 {"backwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1},
126 {"backwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1},
127 {"bsfateom", store_bit, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
128 {"twoeof", store_bit, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
129 {"forwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1},
130 {"forwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1},
131 {"fastforwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
132 {"removablemedia", store_bit, ITEM(res_dev.cap_bits), CAP_REM, ITEM_DEFAULT, 1},
133 {"randomaccess", store_bit, ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
134 {"automaticmount", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOMOUNT, ITEM_DEFAULT, 0},
135 {"labelmedia", store_bit, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0},
136 {"alwaysopen", store_bit, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
137 {"autochanger", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
138 {"closeonpoll", store_bit, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
139 {"blockpositioning", store_bit, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
140 {"usemtiocget", store_bit, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
141 {"checklabels", store_bit, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
142 {"requiresmount", store_bit, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
143 {"offlineonunmount", store_bit, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
144 {"autoselect", store_bool, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
145 {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
146 {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
147 {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
148 {"maximumchangerwait", store_time, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
149 {"maximumopenwait", store_time, ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
150 {"maximumopenvolumes", store_pint32, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
151 {"maximumnetworkbuffersize", store_pint32, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
152 {"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0},
153 {"maximumrewindwait", store_time, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
154 {"minimumblocksize", store_pint32, ITEM(res_dev.min_block_size), 0, 0, 0},
155 {"maximumblocksize", store_pint32, ITEM(res_dev.max_block_size), 0, 0, 0},
156 {"maximumvolumesize", store_size, ITEM(res_dev.max_volume_size), 0, 0, 0},
157 {"maximumfilesize", store_size, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
158 {"volumecapacity", store_size, ITEM(res_dev.volume_capacity), 0, 0, 0},
159 {"spooldirectory", store_dir, ITEM(res_dev.spool_directory), 0, 0, 0},
160 {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0},
161 {"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0},
162 {"driveindex", store_pint32, ITEM(res_dev.drive_index), 0, 0, 0},
163 {"maximumpartsize", store_size, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
164 {"mountpoint", store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
165 {"mountcommand", store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
166 {"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
167 {"writepartcommand", store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
168 {"freespacecommand", store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
169 {"labeltype", store_label, ITEM(res_dev.label_type), 0, 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 {NULL, NULL, {0}, 0, 0, 0}
184 // {"mountanonymousvolumes", store_bit, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0},
187 /* Message resource */
188 extern RES_ITEM msgs_items[];
191 /* This is the master resource definition */
192 RES_TABLE resources[] = {
193 {"director", dir_items, R_DIRECTOR},
194 {"storage", store_items, R_STORAGE},
195 {"device", dev_items, R_DEVICE},
196 {"messages", msgs_items, R_MSGS},
197 {"autochanger", changer_items, R_AUTOCHANGER},
204 * device type device code = token
211 static s_kw dev_types[] = {
212 {"file", B_FILE_DEV},
213 {"tape", B_TAPE_DEV},
215 {"fifo", B_FIFO_DEV},
217 {"vtape", B_VTAPE_DEV},
223 * Store Device Type (File, FIFO, Tape, DVD)
226 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
230 token = lex_get_token(lc, T_NAME);
231 /* Store the label pass 2 so that type is defined */
232 for (i=0; dev_types[i].name; i++) {
233 if (strcasecmp(lc->str, dev_types[i].name) == 0) {
234 *(uint32_t *)(item->value) = dev_types[i].token;
240 scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
243 set_bit(index, res_all.hdr.item_present);
247 /* Dump contents of resource */
248 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
250 URES *res = (URES *)reshdr;
255 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
258 sendit(sock, _("dump_resource type=%d\n"), type);
259 if (type < 0) { /* no recursion */
265 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
268 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
269 res->res_store.hdr.name,
270 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
271 get_first_port_host_order(res->res_store.sdaddrs),
272 get_first_port_host_order(res->res_store.sddaddrs),
273 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
274 if (res->res_store.sdaddrs) {
275 foreach_dlist(p, res->res_store.sdaddrs) {
276 sendit(sock, " SDaddr=%s SDport=%d\n",
277 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
280 if (res->res_store.sddaddrs) {
281 foreach_dlist(p, res->res_store.sddaddrs) {
282 sendit(sock, " SDDaddr=%s SDDport=%d\n",
283 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
288 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
289 res->res_dev.hdr.name,
290 res->res_dev.media_type, res->res_dev.device_name,
291 res->res_dev.label_type);
292 sendit(sock, " rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
293 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
294 res->res_dev.max_block_size, res->res_dev.max_changer_wait);
295 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
296 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
297 res->res_dev.max_volume_size);
298 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
299 res->res_dev.max_file_size, res->res_dev.volume_capacity);
300 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
301 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
302 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
303 if (res->res_dev.changer_res) {
304 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
306 bstrncpy(buf, " ", sizeof(buf));
307 if (res->res_dev.cap_bits & CAP_EOF) {
308 bstrncat(buf, "CAP_EOF ", sizeof(buf));
310 if (res->res_dev.cap_bits & CAP_BSR) {
311 bstrncat(buf, "CAP_BSR ", sizeof(buf));
313 if (res->res_dev.cap_bits & CAP_BSF) {
314 bstrncat(buf, "CAP_BSF ", sizeof(buf));
316 if (res->res_dev.cap_bits & CAP_FSR) {
317 bstrncat(buf, "CAP_FSR ", sizeof(buf));
319 if (res->res_dev.cap_bits & CAP_FSF) {
320 bstrncat(buf, "CAP_FSF ", sizeof(buf));
322 if (res->res_dev.cap_bits & CAP_EOM) {
323 bstrncat(buf, "CAP_EOM ", sizeof(buf));
325 if (res->res_dev.cap_bits & CAP_REM) {
326 bstrncat(buf, "CAP_REM ", sizeof(buf));
328 if (res->res_dev.cap_bits & CAP_RACCESS) {
329 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
331 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
332 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
334 if (res->res_dev.cap_bits & CAP_LABEL) {
335 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
337 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
338 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
340 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
341 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
343 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
344 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
346 if (res->res_dev.cap_bits & CAP_REQMOUNT) {
347 bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
349 if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
350 bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
352 bstrncat(buf, "\n", sizeof(buf));
357 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
358 res->res_changer.hdr.name,
359 res->res_changer.changer_name, res->res_changer.changer_command);
360 foreach_alist(dev, res->res_changer.device) {
361 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
363 bstrncat(buf, "\n", sizeof(buf));
367 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
368 if (res->res_msgs.mail_cmd)
369 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
370 if (res->res_msgs.operator_cmd)
371 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
374 sendit(sock, _("Warning: unknown resource type %d\n"), type);
377 if (recurse && res->res_dir.hdr.next)
378 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
382 * Free memory of resource.
383 * NB, we don't need to worry about freeing any references
384 * to other resources as they will be freed when that
385 * resource chain is traversed. Mainly we worry about freeing
386 * allocated strings (names).
388 void free_resource(RES *sres, int type)
391 URES *res = (URES *)sres;
396 /* common stuff -- free the resource name */
397 nres = (RES *)res->res_dir.hdr.next;
398 if (res->res_dir.hdr.name) {
399 free(res->res_dir.hdr.name);
401 if (res->res_dir.hdr.desc) {
402 free(res->res_dir.hdr.desc);
408 if (res->res_dir.password) {
409 free(res->res_dir.password);
411 if (res->res_dir.address) {
412 free(res->res_dir.address);
414 if (res->res_dir.tls_ctx) {
415 free_tls_context(res->res_dir.tls_ctx);
417 if (res->res_dir.tls_ca_certfile) {
418 free(res->res_dir.tls_ca_certfile);
420 if (res->res_dir.tls_ca_certdir) {
421 free(res->res_dir.tls_ca_certdir);
423 if (res->res_dir.tls_certfile) {
424 free(res->res_dir.tls_certfile);
426 if (res->res_dir.tls_keyfile) {
427 free(res->res_dir.tls_keyfile);
429 if (res->res_dir.tls_dhfile) {
430 free(res->res_dir.tls_dhfile);
432 if (res->res_dir.tls_allowed_cns) {
433 delete res->res_dir.tls_allowed_cns;
437 if (res->res_changer.changer_name) {
438 free(res->res_changer.changer_name);
440 if (res->res_changer.changer_command) {
441 free(res->res_changer.changer_command);
443 if (res->res_changer.device) {
444 delete res->res_changer.device;
448 if (res->res_store.sdaddrs) {
449 free_addresses(res->res_store.sdaddrs);
451 if (res->res_store.sddaddrs) {
452 free_addresses(res->res_store.sddaddrs);
454 if (res->res_store.working_directory) {
455 free(res->res_store.working_directory);
457 if (res->res_store.pid_directory) {
458 free(res->res_store.pid_directory);
460 if (res->res_store.subsys_directory) {
461 free(res->res_store.subsys_directory);
463 if (res->res_store.scripts_directory) {
464 free(res->res_store.scripts_directory);
466 if (res->res_store.tls_ctx) {
467 free_tls_context(res->res_store.tls_ctx);
469 if (res->res_store.tls_ca_certfile) {
470 free(res->res_store.tls_ca_certfile);
472 if (res->res_store.tls_ca_certdir) {
473 free(res->res_store.tls_ca_certdir);
475 if (res->res_store.tls_certfile) {
476 free(res->res_store.tls_certfile);
478 if (res->res_store.tls_keyfile) {
479 free(res->res_store.tls_keyfile);
481 if (res->res_store.tls_dhfile) {
482 free(res->res_store.tls_dhfile);
484 if (res->res_store.tls_allowed_cns) {
485 delete res->res_store.tls_allowed_cns;
487 if (res->res_store.verid) {
488 free(res->res_store.verid);
492 if (res->res_dev.media_type) {
493 free(res->res_dev.media_type);
495 if (res->res_dev.device_name) {
496 free(res->res_dev.device_name);
498 if (res->res_dev.changer_name) {
499 free(res->res_dev.changer_name);
501 if (res->res_dev.changer_command) {
502 free(res->res_dev.changer_command);
504 if (res->res_dev.alert_command) {
505 free(res->res_dev.alert_command);
507 if (res->res_dev.spool_directory) {
508 free(res->res_dev.spool_directory);
510 if (res->res_dev.mount_point) {
511 free(res->res_dev.mount_point);
513 if (res->res_dev.mount_command) {
514 free(res->res_dev.mount_command);
516 if (res->res_dev.unmount_command) {
517 free(res->res_dev.unmount_command);
519 if (res->res_dev.write_part_command) {
520 free(res->res_dev.write_part_command);
522 if (res->res_dev.free_space_command) {
523 free(res->res_dev.free_space_command);
527 if (res->res_msgs.mail_cmd) {
528 free(res->res_msgs.mail_cmd);
530 if (res->res_msgs.operator_cmd) {
531 free(res->res_msgs.operator_cmd);
533 free_msgs_res((MSGS *)res); /* free message resource */
537 Dmsg1(0, _("Unknown resource type %d\n"), type);
540 /* Common stuff again -- free the resource, recurse to next one */
545 free_resource(nres, type);
549 /* Save the new resource by chaining it into the head list for
550 * the resource. If this is pass 2, we update any resource
553 void save_resource(int type, RES_ITEM *items, int pass)
556 int rindex = type - r_first;
561 * Ensure that all required items are present
563 for (i=0; items[i].name; i++) {
564 if (items[i].flags & ITEM_REQUIRED) {
565 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
566 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
567 items[i].name, resources[rindex]);
570 /* If this triggers, take a look at lib/parse_conf.h */
571 if (i >= MAX_RES_ITEMS) {
572 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
576 /* During pass 2, we looked up pointers to all the resources
577 * referrenced in the current resource, , now we
578 * must copy their address from the static record to the allocated
585 /* Resources not containing a resource */
590 /* Resources containing a resource or an alist */
592 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
593 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
595 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
598 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
599 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
601 res->res_store.messages = res_all.res_store.messages;
602 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
605 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
606 Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
607 res_all.res_changer.hdr.name);
609 /* we must explicitly copy the device alist pointer */
610 res->res_changer.device = res_all.res_changer.device;
612 * Now update each device in this resource to point back
613 * to the changer resource.
615 foreach_alist(dev, res->res_changer.device) {
616 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
618 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
620 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
621 be.bstrerror(errstat));
625 printf(_("Unknown resource type %d\n"), type);
631 if (res_all.res_dir.hdr.name) {
632 free(res_all.res_dir.hdr.name);
633 res_all.res_dir.hdr.name = NULL;
635 if (res_all.res_dir.hdr.desc) {
636 free(res_all.res_dir.hdr.desc);
637 res_all.res_dir.hdr.desc = NULL;
642 /* The following code is only executed on pass 1 */
645 size = sizeof(DIRRES);
648 size = sizeof(STORES);
651 size = sizeof(DEVRES);
657 size = sizeof(AUTOCHANGER);
660 printf(_("Unknown resource type %d\n"), type);
667 res = (URES *)malloc(size);
668 memcpy(res, &res_all, size);
669 if (!res_head[rindex]) {
670 res_head[rindex] = (RES *)res; /* store first entry */
673 /* Add new res to end of chain */
674 for (last=next=res_head[rindex]; next; next=next->next) {
676 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
677 Emsg2(M_ERROR_TERM, 0,
678 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
679 resources[rindex].name, res->res_dir.hdr.name);
682 last->next = (RES *)res;
683 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
684 res->res_dir.hdr.name);
689 bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code)
691 config->init(configfile, NULL, exit_code, (void *)&res_all, res_all_size,
692 r_first, r_last, resources, res_head);
693 return config->parse_config();