2 * Configuration file parser for Bacula Storage daemon
4 * Kern Sibbald, March MM
9 Copyright (C) 2000-2005 Kern Sibbald
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License
13 version 2 as ammended with additional clauses defined in the
14 file LICENSE in the main source directory.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 the file LICENSE for additional details.
26 extern int debug_level;
29 /* First and last resource ids */
30 int r_first = R_FIRST;
32 static RES *sres_head[R_LAST - R_FIRST + 1];
33 RES **res_head = sres_head;
36 /* Forward referenced subroutines */
38 /* We build the current resource here statically,
39 * then move it to dynamic memory */
41 int res_all_size = sizeof(res_all);
43 /* Definition of records permitted within each
44 * resource with the routine to process the record
48 /* Globals for the Storage daemon. */
49 static RES_ITEM store_items[] = {
50 {"name", store_name, ITEM(res_store.hdr.name), 0, ITEM_REQUIRED, 0},
51 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
52 {"sdaddress", store_addresses_address, ITEM(res_store.sdaddrs), 0, ITEM_DEFAULT, 9103},
53 {"sdaddresses", store_addresses, ITEM(res_store.sdaddrs), 0, ITEM_DEFAULT, 9103},
54 {"messages", store_res, ITEM(res_store.messages), 0, R_MSGS, 0},
55 {"sdport", store_addresses_port, ITEM(res_store.sdaddrs), 0, ITEM_DEFAULT, 9103},
56 {"workingdirectory", store_dir, ITEM(res_store.working_directory), 0, ITEM_REQUIRED, 0},
57 {"piddirectory", store_dir, ITEM(res_store.pid_directory), 0, ITEM_REQUIRED, 0},
58 {"subsysdirectory", store_dir, ITEM(res_store.subsys_directory), 0, 0, 0},
59 {"scriptsdirectory", store_dir, ITEM(res_store.scripts_directory), 0, 0, 0},
60 {"maximumconcurrentjobs", store_pint, ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 10},
61 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
62 {"tlsenable", store_yesno, ITEM(res_store.tls_enable), 1, ITEM_DEFAULT, 0},
63 {"tlsrequire", store_yesno, ITEM(res_store.tls_require), 1, ITEM_DEFAULT, 0},
64 {"tlsverifypeer", store_yesno, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 0},
65 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
66 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
67 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
68 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
69 {"tlsdhfile", store_dir, ITEM(res_store.tls_dhfile), 0, 0, 0},
70 {"tlsallowedcn", store_alist_str, ITEM(res_store.tls_allowed_cns), 0, 0, 0},
71 {NULL, NULL, 0, 0, 0, 0}
75 /* Directors that can speak to the Storage daemon */
76 static RES_ITEM dir_items[] = {
77 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
78 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
79 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
80 {"monitor", store_yesno, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0},
81 {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, ITEM_DEFAULT, 0},
82 {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, ITEM_DEFAULT, 0},
83 {"tlsverifypeer", store_yesno, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 0},
84 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
85 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
86 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
87 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
88 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
89 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
90 {NULL, NULL, 0, 0, 0, 0}
93 /* Device definition */
94 static RES_ITEM dev_items[] = {
95 {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0},
96 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
97 {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0},
98 {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
99 {"hardwareendoffile", store_yesno, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1},
100 {"hardwareendofmedium", store_yesno, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1},
101 {"backwardspacerecord", store_yesno, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1},
102 {"backwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1},
103 {"bsfateom", store_yesno, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
104 {"twoeof", store_yesno, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
105 {"forwardspacerecord", store_yesno, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1},
106 {"forwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1},
107 {"fastforwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
108 {"removablemedia", store_yesno, ITEM(res_dev.cap_bits), CAP_REM, ITEM_DEFAULT, 1},
109 {"randomaccess", store_yesno, ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
110 {"automaticmount", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOMOUNT, ITEM_DEFAULT, 0},
111 {"labelmedia", store_yesno, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0},
112 {"alwaysopen", store_yesno, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
113 {"autochanger", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
114 {"closeonpoll", store_yesno, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
115 {"blockpositioning", store_yesno, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
116 {"usemtiocget", store_yesno, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
117 {"checklabels", store_yesno, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
118 {"autoselect", store_yesno, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
119 {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
120 {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
121 {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
122 {"maximumchangerwait", store_pint, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
123 {"maximumopenwait", store_pint, ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
124 {"maximumopenvolumes", store_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
125 {"maximumnetworkbuffersize", store_pint, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
126 {"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0},
127 {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
128 {"maximumrewindwait", store_pint, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
129 {"minimumblocksize", store_pint, ITEM(res_dev.min_block_size), 0, 0, 0},
130 {"maximumblocksize", store_pint, ITEM(res_dev.max_block_size), 0, 0, 0},
131 {"maximumvolumesize", store_size, ITEM(res_dev.max_volume_size), 0, 0, 0},
132 {"maximumfilesize", store_size, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
133 {"volumecapacity", store_size, ITEM(res_dev.volume_capacity), 0, 0, 0},
134 {"spooldirectory", store_dir, ITEM(res_dev.spool_directory), 0, 0, 0},
135 {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0},
136 {"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0},
137 {"driveindex", store_pint, ITEM(res_dev.drive_index), 0, 0, 0},
138 {"maximumpartsize", store_size, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
139 {"requiresmount", store_yesno, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
140 {"mountpoint", store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
141 {"mountcommand", store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
142 {"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
143 {"writepartcommand", store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
144 {"freespacecommand", store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
145 {"labeltype", store_label, ITEM(res_dev.label_type), 0, 0, 0},
146 {NULL, NULL, 0, 0, 0, 0}
149 /* Autochanger definition */
150 static RES_ITEM changer_items[] = {
151 {"name", store_name, ITEM(res_changer.hdr.name), 0, ITEM_REQUIRED, 0},
152 {"description", store_str, ITEM(res_changer.hdr.desc), 0, 0, 0},
153 {"device", store_alist_res, ITEM(res_changer.device), R_DEVICE, ITEM_REQUIRED, 0},
154 {"changerdevice", store_strname, ITEM(res_changer.changer_name), 0, ITEM_REQUIRED, 0},
155 {"changercommand", store_strname, ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
156 {NULL, NULL, 0, 0, 0, 0}
160 // {"mountanonymousvolumes", store_yesno, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0},
163 /* Message resource */
164 extern RES_ITEM msgs_items[];
167 /* This is the master resource definition */
168 RES_TABLE resources[] = {
169 {"director", dir_items, R_DIRECTOR},
170 {"storage", store_items, R_STORAGE},
171 {"device", dev_items, R_DEVICE},
172 {"messages", msgs_items, R_MSGS},
173 {"autochanger", changer_items, R_AUTOCHANGER},
180 /* Dump contents of resource */
181 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
183 URES *res = (URES *)reshdr;
188 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
191 sendit(sock, "dump_resource type=%d\n", type);
192 if (type < 0) { /* no recursion */
198 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
201 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
202 res->res_store.hdr.name,
203 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
204 get_first_port_host_order(res->res_store.sdaddrs),
205 get_first_port_host_order(res->res_store.sddaddrs),
206 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
207 if (res->res_store.sdaddrs) {
208 foreach_dlist(p, res->res_store.sdaddrs) {
209 sendit(sock, " SDaddr=%s SDport=%d\n",
210 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
213 if (res->res_store.sddaddrs) {
214 foreach_dlist(p, res->res_store.sddaddrs) {
215 sendit(sock, " SDDaddr=%s SDDport=%d\n",
216 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
221 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
222 res->res_dev.hdr.name,
223 res->res_dev.media_type, res->res_dev.device_name,
224 res->res_dev.label_type);
225 sendit(sock, " rew_wait=%d min_bs=%d max_bs=%d\n",
226 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
227 res->res_dev.max_block_size);
228 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
229 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
230 res->res_dev.max_volume_size);
231 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
232 res->res_dev.max_file_size, res->res_dev.volume_capacity);
233 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
234 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
235 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
236 if (res->res_dev.changer_res) {
237 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
239 bstrncpy(buf, " ", sizeof(buf));
240 if (res->res_dev.cap_bits & CAP_EOF) {
241 bstrncat(buf, "CAP_EOF ", sizeof(buf));
243 if (res->res_dev.cap_bits & CAP_BSR) {
244 bstrncat(buf, "CAP_BSR ", sizeof(buf));
246 if (res->res_dev.cap_bits & CAP_BSF) {
247 bstrncat(buf, "CAP_BSF ", sizeof(buf));
249 if (res->res_dev.cap_bits & CAP_FSR) {
250 bstrncat(buf, "CAP_FSR ", sizeof(buf));
252 if (res->res_dev.cap_bits & CAP_FSF) {
253 bstrncat(buf, "CAP_FSF ", sizeof(buf));
255 if (res->res_dev.cap_bits & CAP_EOM) {
256 bstrncat(buf, "CAP_EOM ", sizeof(buf));
258 if (res->res_dev.cap_bits & CAP_REM) {
259 bstrncat(buf, "CAP_REM ", sizeof(buf));
261 if (res->res_dev.cap_bits & CAP_RACCESS) {
262 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
264 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
265 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
267 if (res->res_dev.cap_bits & CAP_LABEL) {
268 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
270 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
271 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
273 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
274 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
276 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
277 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
279 bstrncat(buf, "\n", sizeof(buf));
284 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
285 res->res_changer.hdr.name,
286 res->res_changer.changer_name, res->res_changer.changer_command);
287 foreach_alist(dev, res->res_changer.device) {
288 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
290 bstrncat(buf, "\n", sizeof(buf));
294 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
295 if (res->res_msgs.mail_cmd)
296 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
297 if (res->res_msgs.operator_cmd)
298 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
301 sendit(sock, _("Warning: unknown resource type %d\n"), type);
304 if (recurse && res->res_dir.hdr.next)
305 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
309 * Free memory of resource.
310 * NB, we don't need to worry about freeing any references
311 * to other resources as they will be freed when that
312 * resource chain is traversed. Mainly we worry about freeing
313 * allocated strings (names).
315 void free_resource(RES *sres, int type)
318 URES *res = (URES *)sres;
323 /* common stuff -- free the resource name */
324 nres = (RES *)res->res_dir.hdr.next;
325 if (res->res_dir.hdr.name) {
326 free(res->res_dir.hdr.name);
328 if (res->res_dir.hdr.desc) {
329 free(res->res_dir.hdr.desc);
335 if (res->res_dir.password) {
336 free(res->res_dir.password);
338 if (res->res_dir.address) {
339 free(res->res_dir.address);
341 if (res->res_dir.tls_ctx) {
342 free_tls_context(res->res_dir.tls_ctx);
344 if (res->res_dir.tls_ca_certfile) {
345 free(res->res_dir.tls_ca_certfile);
347 if (res->res_dir.tls_ca_certdir) {
348 free(res->res_dir.tls_ca_certdir);
350 if (res->res_dir.tls_certfile) {
351 free(res->res_dir.tls_certfile);
353 if (res->res_dir.tls_keyfile) {
354 free(res->res_dir.tls_keyfile);
356 if (res->res_dir.tls_dhfile) {
357 free(res->res_dir.tls_dhfile);
359 if (res->res_dir.tls_allowed_cns) {
360 delete res->res_dir.tls_allowed_cns;
364 if (res->res_changer.changer_name) {
365 free(res->res_changer.changer_name);
367 if (res->res_changer.changer_command) {
368 free(res->res_changer.changer_command);
370 if (res->res_changer.device) {
371 delete res->res_changer.device;
375 if (res->res_store.sdaddrs) {
376 free_addresses(res->res_store.sdaddrs);
378 if (res->res_store.sddaddrs) {
379 free_addresses(res->res_store.sddaddrs);
381 if (res->res_store.working_directory) {
382 free(res->res_store.working_directory);
384 if (res->res_store.pid_directory) {
385 free(res->res_store.pid_directory);
387 if (res->res_store.subsys_directory) {
388 free(res->res_store.subsys_directory);
390 if (res->res_store.scripts_directory) {
391 free(res->res_store.scripts_directory);
393 if (res->res_store.tls_ctx) {
394 free_tls_context(res->res_store.tls_ctx);
396 if (res->res_store.tls_ca_certfile) {
397 free(res->res_store.tls_ca_certfile);
399 if (res->res_store.tls_ca_certdir) {
400 free(res->res_store.tls_ca_certdir);
402 if (res->res_store.tls_certfile) {
403 free(res->res_store.tls_certfile);
405 if (res->res_store.tls_keyfile) {
406 free(res->res_store.tls_keyfile);
408 if (res->res_store.tls_dhfile) {
409 free(res->res_store.tls_dhfile);
411 if (res->res_store.tls_allowed_cns) {
412 delete res->res_store.tls_allowed_cns;
416 if (res->res_dev.media_type) {
417 free(res->res_dev.media_type);
419 if (res->res_dev.device_name) {
420 free(res->res_dev.device_name);
422 if (res->res_dev.changer_name) {
423 free(res->res_dev.changer_name);
425 if (res->res_dev.changer_command) {
426 free(res->res_dev.changer_command);
428 if (res->res_dev.alert_command) {
429 free(res->res_dev.alert_command);
431 if (res->res_dev.spool_directory) {
432 free(res->res_dev.spool_directory);
434 if (res->res_dev.mount_point) {
435 free(res->res_dev.mount_point);
437 if (res->res_dev.mount_command) {
438 free(res->res_dev.mount_command);
440 if (res->res_dev.unmount_command) {
441 free(res->res_dev.unmount_command);
443 if (res->res_dev.write_part_command) {
444 free(res->res_dev.write_part_command);
446 if (res->res_dev.free_space_command) {
447 free(res->res_dev.free_space_command);
451 if (res->res_msgs.mail_cmd) {
452 free(res->res_msgs.mail_cmd);
454 if (res->res_msgs.operator_cmd) {
455 free(res->res_msgs.operator_cmd);
457 free_msgs_res((MSGS *)res); /* free message resource */
461 Dmsg1(0, "Unknown resource type %d\n", type);
464 /* Common stuff again -- free the resource, recurse to next one */
469 free_resource(nres, type);
473 /* Save the new resource by chaining it into the head list for
474 * the resource. If this is pass 2, we update any resource
477 void save_resource(int type, RES_ITEM *items, int pass)
480 int rindex = type - r_first;
485 * Ensure that all required items are present
487 for (i=0; items[i].name; i++) {
488 if (items[i].flags & ITEM_REQUIRED) {
489 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
490 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
491 items[i].name, resources[rindex]);
494 /* If this triggers, take a look at lib/parse_conf.h */
495 if (i >= MAX_RES_ITEMS) {
496 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
500 /* During pass 2, we looked up pointers to all the resources
501 * referrenced in the current resource, , now we
502 * must copy their address from the static record to the allocated
509 /* Resources not containing a resource */
514 /* Resources containing a resource or an alist */
516 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
517 Emsg1(M_ERROR_TERM, 0, "Cannot find Director resource \"%s\"\n", res_all.res_dir.hdr.name);
519 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
522 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
523 Emsg1(M_ERROR_TERM, 0, "Cannot find Storage resource \"%s\"\n", res_all.res_dir.hdr.name);
525 res->res_store.messages = res_all.res_store.messages;
526 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
529 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
530 Emsg1(M_ERROR_TERM, 0, "Cannot find AutoChanger resource %s\n",
531 res_all.res_changer.hdr.name);
533 /* we must explicitly copy the device alist pointer */
534 res->res_changer.device = res_all.res_changer.device;
536 * Now update each device in this resource to point back
537 * to the changer resource.
539 foreach_alist(dev, res->res_changer.device) {
540 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
542 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
544 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
545 be.strerror(errstat));
549 printf("Unknown resource type %d\n", type);
555 if (res_all.res_dir.hdr.name) {
556 free(res_all.res_dir.hdr.name);
557 res_all.res_dir.hdr.name = NULL;
559 if (res_all.res_dir.hdr.desc) {
560 free(res_all.res_dir.hdr.desc);
561 res_all.res_dir.hdr.desc = NULL;
566 /* The following code is only executed on pass 1 */
569 size = sizeof(DIRRES);
572 size = sizeof(STORES);
575 size = sizeof(DEVRES);
581 size = sizeof(AUTOCHANGER);
584 printf("Unknown resource type %d\n", type);
591 res = (URES *)malloc(size);
592 memcpy(res, &res_all, size);
593 if (!res_head[rindex]) {
594 res_head[rindex] = (RES *)res; /* store first entry */
597 /* Add new res to end of chain */
598 for (next=res_head[rindex]; next->next; next=next->next) {
599 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
600 Emsg2(M_ERROR_TERM, 0,
601 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
602 resources[rindex].name, res->res_dir.hdr.name);
605 next->next = (RES *)res;
606 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
607 res->res_dir.hdr.name);