2 * Configuration file parser for Bacula Storage daemon
4 * Kern Sibbald, March MM
9 Bacula® - The Network Backup Solution
11 Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
13 The main author of Bacula is Kern Sibbald, with contributions from
14 many others, a complete list can be found in the file AUTHORS.
15 This program is Free Software; you can redistribute it and/or
16 modify it under the terms of version two of the GNU General Public
17 License as published by the Free Software Foundation plus additions
18 that are listed in the file LICENSE.
20 This program is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30 Bacula® is a registered trademark of John Walker.
31 The licensor of Bacula is the Free Software Foundation Europe
32 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33 Switzerland, email:ftf@fsfeurope.org.
39 /* First and last resource ids */
40 int r_first = R_FIRST;
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 int 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 {"scriptsdirectory", store_dir, ITEM(res_store.scripts_directory), 0, 0, 0},
78 {"maximumconcurrentjobs", store_pint, ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 10},
79 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
80 {"tlsenable", store_bit, ITEM(res_store.tls_enable), 1, 0, 0},
81 {"tlsrequire", store_bit, ITEM(res_store.tls_require), 1, 0, 0},
82 {"tlsverifypeer", store_bit, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1},
83 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
84 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
85 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
86 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
87 {"tlsdhfile", store_dir, ITEM(res_store.tls_dhfile), 0, 0, 0},
88 {"tlsallowedcn", store_alist_str, ITEM(res_store.tls_allowed_cns), 0, 0, 0},
89 {NULL, NULL, {0}, 0, 0, 0}
93 /* Directors that can speak to the Storage daemon */
94 static RES_ITEM dir_items[] = {
95 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
96 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
97 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
98 {"monitor", store_bit, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0},
99 {"tlsenable", store_bit, ITEM(res_dir.tls_enable), 1, 0, 0},
100 {"tlsrequire", store_bit, ITEM(res_dir.tls_require), 1, 0, 0},
101 {"tlsverifypeer", store_bit, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1},
102 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
103 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
104 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
105 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
106 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
107 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
108 {NULL, NULL, {0}, 0, 0, 0}
111 /* Device definition */
112 static RES_ITEM dev_items[] = {
113 {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0},
114 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
115 {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0},
116 {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0},
117 {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
118 {"hardwareendoffile", store_bit, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1},
119 {"hardwareendofmedium", store_bit, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1},
120 {"backwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1},
121 {"backwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1},
122 {"bsfateom", store_bit, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
123 {"twoeof", store_bit, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
124 {"forwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1},
125 {"forwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1},
126 {"fastforwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
127 {"removablemedia", store_bit, ITEM(res_dev.cap_bits), CAP_REM, ITEM_DEFAULT, 1},
128 {"randomaccess", store_bit, ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
129 {"automaticmount", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOMOUNT, ITEM_DEFAULT, 0},
130 {"labelmedia", store_bit, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0},
131 {"alwaysopen", store_bit, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
132 {"autochanger", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
133 {"closeonpoll", store_bit, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
134 {"blockpositioning", store_bit, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
135 {"usemtiocget", store_bit, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
136 {"checklabels", store_bit, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
137 {"requiresmount", store_bit, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
138 {"offlineonunmount", store_bit, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
139 {"autoselect", store_bit, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
140 {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
141 {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
142 {"alertcommand", store_strname,ITEM(res_dev.alert_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 {"maximumopenvolumes", store_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
146 {"maximumnetworkbuffersize", store_pint, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
147 {"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0},
148 {"maximumrewindwait", store_time, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
149 {"minimumblocksize", store_pint, ITEM(res_dev.min_block_size), 0, 0, 0},
150 {"maximumblocksize", store_pint, ITEM(res_dev.max_block_size), 0, 0, 0},
151 {"maximumvolumesize", store_size, ITEM(res_dev.max_volume_size), 0, 0, 0},
152 {"maximumfilesize", store_size, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
153 {"volumecapacity", store_size, ITEM(res_dev.volume_capacity), 0, 0, 0},
154 {"spooldirectory", store_dir, ITEM(res_dev.spool_directory), 0, 0, 0},
155 {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0},
156 {"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0},
157 {"driveindex", store_pint, ITEM(res_dev.drive_index), 0, 0, 0},
158 {"maximumpartsize", store_size, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
159 {"mountpoint", store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
160 {"mountcommand", store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
161 {"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
162 {"writepartcommand", store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
163 {"freespacecommand", store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
164 {"labeltype", store_label, ITEM(res_dev.label_type), 0, 0, 0},
165 {NULL, NULL, {0}, 0, 0, 0}
168 /* Autochanger definition */
169 static RES_ITEM changer_items[] = {
170 {"name", store_name, ITEM(res_changer.hdr.name), 0, ITEM_REQUIRED, 0},
171 {"description", store_str, ITEM(res_changer.hdr.desc), 0, 0, 0},
172 {"device", store_alist_res, ITEM(res_changer.device), R_DEVICE, ITEM_REQUIRED, 0},
173 {"changerdevice", store_strname, ITEM(res_changer.changer_name), 0, ITEM_REQUIRED, 0},
174 {"changercommand", store_strname, ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
175 {NULL, NULL, {0}, 0, 0, 0}
179 // {"mountanonymousvolumes", store_bit, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0},
182 /* Message resource */
183 extern RES_ITEM msgs_items[];
186 /* This is the master resource definition */
187 RES_TABLE resources[] = {
188 {"director", dir_items, R_DIRECTOR},
189 {"storage", store_items, R_STORAGE},
190 {"device", dev_items, R_DEVICE},
191 {"messages", msgs_items, R_MSGS},
192 {"autochanger", changer_items, R_AUTOCHANGER},
199 * device type device code = token
206 static s_kw dev_types[] = {
207 {"file", B_FILE_DEV},
208 {"tape", B_TAPE_DEV},
210 {"fifo", B_FIFO_DEV},
216 * Store Device Type (File, FIFO, Tape, DVD)
219 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
223 token = lex_get_token(lc, T_NAME);
224 /* Store the label pass 2 so that type is defined */
225 for (i=0; dev_types[i].name; i++) {
226 if (strcasecmp(lc->str, dev_types[i].name) == 0) {
227 *(int *)(item->value) = dev_types[i].token;
233 scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
236 set_bit(index, res_all.hdr.item_present);
240 /* Dump contents of resource */
241 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
243 URES *res = (URES *)reshdr;
248 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
251 sendit(sock, _("dump_resource type=%d\n"), type);
252 if (type < 0) { /* no recursion */
258 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
261 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
262 res->res_store.hdr.name,
263 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
264 get_first_port_host_order(res->res_store.sdaddrs),
265 get_first_port_host_order(res->res_store.sddaddrs),
266 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
267 if (res->res_store.sdaddrs) {
268 foreach_dlist(p, res->res_store.sdaddrs) {
269 sendit(sock, " SDaddr=%s SDport=%d\n",
270 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
273 if (res->res_store.sddaddrs) {
274 foreach_dlist(p, res->res_store.sddaddrs) {
275 sendit(sock, " SDDaddr=%s SDDport=%d\n",
276 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
281 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
282 res->res_dev.hdr.name,
283 res->res_dev.media_type, res->res_dev.device_name,
284 res->res_dev.label_type);
285 sendit(sock, " rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
286 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
287 res->res_dev.max_block_size, res->res_dev.max_changer_wait);
288 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
289 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
290 res->res_dev.max_volume_size);
291 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
292 res->res_dev.max_file_size, res->res_dev.volume_capacity);
293 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
294 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
295 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
296 if (res->res_dev.changer_res) {
297 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
299 bstrncpy(buf, " ", sizeof(buf));
300 if (res->res_dev.cap_bits & CAP_EOF) {
301 bstrncat(buf, "CAP_EOF ", sizeof(buf));
303 if (res->res_dev.cap_bits & CAP_BSR) {
304 bstrncat(buf, "CAP_BSR ", sizeof(buf));
306 if (res->res_dev.cap_bits & CAP_BSF) {
307 bstrncat(buf, "CAP_BSF ", sizeof(buf));
309 if (res->res_dev.cap_bits & CAP_FSR) {
310 bstrncat(buf, "CAP_FSR ", sizeof(buf));
312 if (res->res_dev.cap_bits & CAP_FSF) {
313 bstrncat(buf, "CAP_FSF ", sizeof(buf));
315 if (res->res_dev.cap_bits & CAP_EOM) {
316 bstrncat(buf, "CAP_EOM ", sizeof(buf));
318 if (res->res_dev.cap_bits & CAP_REM) {
319 bstrncat(buf, "CAP_REM ", sizeof(buf));
321 if (res->res_dev.cap_bits & CAP_RACCESS) {
322 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
324 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
325 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
327 if (res->res_dev.cap_bits & CAP_LABEL) {
328 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
330 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
331 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
333 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
334 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
336 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
337 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
339 if (res->res_dev.cap_bits & CAP_REQMOUNT) {
340 bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
342 if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
343 bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
345 bstrncat(buf, "\n", sizeof(buf));
350 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
351 res->res_changer.hdr.name,
352 res->res_changer.changer_name, res->res_changer.changer_command);
353 foreach_alist(dev, res->res_changer.device) {
354 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
356 bstrncat(buf, "\n", sizeof(buf));
360 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
361 if (res->res_msgs.mail_cmd)
362 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
363 if (res->res_msgs.operator_cmd)
364 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
367 sendit(sock, _("Warning: unknown resource type %d\n"), type);
370 if (recurse && res->res_dir.hdr.next)
371 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
375 * Free memory of resource.
376 * NB, we don't need to worry about freeing any references
377 * to other resources as they will be freed when that
378 * resource chain is traversed. Mainly we worry about freeing
379 * allocated strings (names).
381 void free_resource(RES *sres, int type)
384 URES *res = (URES *)sres;
389 /* common stuff -- free the resource name */
390 nres = (RES *)res->res_dir.hdr.next;
391 if (res->res_dir.hdr.name) {
392 free(res->res_dir.hdr.name);
394 if (res->res_dir.hdr.desc) {
395 free(res->res_dir.hdr.desc);
401 if (res->res_dir.password) {
402 free(res->res_dir.password);
404 if (res->res_dir.address) {
405 free(res->res_dir.address);
407 if (res->res_dir.tls_ctx) {
408 free_tls_context(res->res_dir.tls_ctx);
410 if (res->res_dir.tls_ca_certfile) {
411 free(res->res_dir.tls_ca_certfile);
413 if (res->res_dir.tls_ca_certdir) {
414 free(res->res_dir.tls_ca_certdir);
416 if (res->res_dir.tls_certfile) {
417 free(res->res_dir.tls_certfile);
419 if (res->res_dir.tls_keyfile) {
420 free(res->res_dir.tls_keyfile);
422 if (res->res_dir.tls_dhfile) {
423 free(res->res_dir.tls_dhfile);
425 if (res->res_dir.tls_allowed_cns) {
426 delete res->res_dir.tls_allowed_cns;
430 if (res->res_changer.changer_name) {
431 free(res->res_changer.changer_name);
433 if (res->res_changer.changer_command) {
434 free(res->res_changer.changer_command);
436 if (res->res_changer.device) {
437 delete res->res_changer.device;
441 if (res->res_store.sdaddrs) {
442 free_addresses(res->res_store.sdaddrs);
444 if (res->res_store.sddaddrs) {
445 free_addresses(res->res_store.sddaddrs);
447 if (res->res_store.working_directory) {
448 free(res->res_store.working_directory);
450 if (res->res_store.pid_directory) {
451 free(res->res_store.pid_directory);
453 if (res->res_store.subsys_directory) {
454 free(res->res_store.subsys_directory);
456 if (res->res_store.scripts_directory) {
457 free(res->res_store.scripts_directory);
459 if (res->res_store.tls_ctx) {
460 free_tls_context(res->res_store.tls_ctx);
462 if (res->res_store.tls_ca_certfile) {
463 free(res->res_store.tls_ca_certfile);
465 if (res->res_store.tls_ca_certdir) {
466 free(res->res_store.tls_ca_certdir);
468 if (res->res_store.tls_certfile) {
469 free(res->res_store.tls_certfile);
471 if (res->res_store.tls_keyfile) {
472 free(res->res_store.tls_keyfile);
474 if (res->res_store.tls_dhfile) {
475 free(res->res_store.tls_dhfile);
477 if (res->res_store.tls_allowed_cns) {
478 delete res->res_store.tls_allowed_cns;
482 if (res->res_dev.media_type) {
483 free(res->res_dev.media_type);
485 if (res->res_dev.device_name) {
486 free(res->res_dev.device_name);
488 if (res->res_dev.changer_name) {
489 free(res->res_dev.changer_name);
491 if (res->res_dev.changer_command) {
492 free(res->res_dev.changer_command);
494 if (res->res_dev.alert_command) {
495 free(res->res_dev.alert_command);
497 if (res->res_dev.spool_directory) {
498 free(res->res_dev.spool_directory);
500 if (res->res_dev.mount_point) {
501 free(res->res_dev.mount_point);
503 if (res->res_dev.mount_command) {
504 free(res->res_dev.mount_command);
506 if (res->res_dev.unmount_command) {
507 free(res->res_dev.unmount_command);
509 if (res->res_dev.write_part_command) {
510 free(res->res_dev.write_part_command);
512 if (res->res_dev.free_space_command) {
513 free(res->res_dev.free_space_command);
517 if (res->res_msgs.mail_cmd) {
518 free(res->res_msgs.mail_cmd);
520 if (res->res_msgs.operator_cmd) {
521 free(res->res_msgs.operator_cmd);
523 free_msgs_res((MSGS *)res); /* free message resource */
527 Dmsg1(0, _("Unknown resource type %d\n"), type);
530 /* Common stuff again -- free the resource, recurse to next one */
535 free_resource(nres, type);
539 /* Save the new resource by chaining it into the head list for
540 * the resource. If this is pass 2, we update any resource
543 void save_resource(int type, RES_ITEM *items, int pass)
546 int rindex = type - r_first;
551 * Ensure that all required items are present
553 for (i=0; items[i].name; i++) {
554 if (items[i].flags & ITEM_REQUIRED) {
555 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
556 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
557 items[i].name, resources[rindex]);
560 /* If this triggers, take a look at lib/parse_conf.h */
561 if (i >= MAX_RES_ITEMS) {
562 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
566 /* During pass 2, we looked up pointers to all the resources
567 * referrenced in the current resource, , now we
568 * must copy their address from the static record to the allocated
575 /* Resources not containing a resource */
580 /* Resources containing a resource or an alist */
582 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
583 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
585 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
588 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
589 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
591 res->res_store.messages = res_all.res_store.messages;
592 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
595 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
596 Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
597 res_all.res_changer.hdr.name);
599 /* we must explicitly copy the device alist pointer */
600 res->res_changer.device = res_all.res_changer.device;
602 * Now update each device in this resource to point back
603 * to the changer resource.
605 foreach_alist(dev, res->res_changer.device) {
606 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
608 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
610 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
611 be.strerror(errstat));
615 printf(_("Unknown resource type %d\n"), type);
621 if (res_all.res_dir.hdr.name) {
622 free(res_all.res_dir.hdr.name);
623 res_all.res_dir.hdr.name = NULL;
625 if (res_all.res_dir.hdr.desc) {
626 free(res_all.res_dir.hdr.desc);
627 res_all.res_dir.hdr.desc = NULL;
632 /* The following code is only executed on pass 1 */
635 size = sizeof(DIRRES);
638 size = sizeof(STORES);
641 size = sizeof(DEVRES);
647 size = sizeof(AUTOCHANGER);
650 printf(_("Unknown resource type %d\n"), type);
657 res = (URES *)malloc(size);
658 memcpy(res, &res_all, size);
659 if (!res_head[rindex]) {
660 res_head[rindex] = (RES *)res; /* store first entry */
663 /* Add new res to end of chain */
664 for (last=next=res_head[rindex]; next; next=next->next) {
666 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
667 Emsg2(M_ERROR_TERM, 0,
668 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
669 resources[rindex].name, res->res_dir.hdr.name);
672 last->next = (RES *)res;
673 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
674 res->res_dir.hdr.name);