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},
63 {"tlsenable", store_yesno, ITEM(res_store.tls_enable), 1, ITEM_DEFAULT, 0},
64 {"tlsrequire", store_yesno, ITEM(res_store.tls_require), 1, ITEM_DEFAULT, 0},
65 {"tlsverifypeer", store_yesno, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 0},
66 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
67 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
68 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
69 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
70 {"tlsdhfile", store_dir, ITEM(res_store.tls_dhfile), 0, 0, 0},
71 {"tlsallowedcn", store_alist_str, ITEM(res_store.tls_allowed_cns), 0, 0, 0},
73 {NULL, NULL, 0, 0, 0, 0}
77 /* Directors that can speak to the Storage daemon */
78 static RES_ITEM dir_items[] = {
79 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
80 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
81 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
82 {"monitor", store_yesno, ITEM(res_dir.monitor), 1, ITEM_DEFAULT, 0},
84 {"tlsenable", store_yesno, ITEM(res_dir.tls_enable), 1, ITEM_DEFAULT, 0},
85 {"tlsrequire", store_yesno, ITEM(res_dir.tls_require), 1, ITEM_DEFAULT, 0},
86 {"tlsverifypeer", store_yesno, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 0},
87 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
88 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
89 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
90 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
91 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
92 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
94 {NULL, NULL, 0, 0, 0, 0}
97 /* Device definition */
98 static RES_ITEM dev_items[] = {
99 {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0},
100 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
101 {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0},
102 {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
103 {"hardwareendoffile", store_yesno, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1},
104 {"hardwareendofmedium", store_yesno, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1},
105 {"backwardspacerecord", store_yesno, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1},
106 {"backwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1},
107 {"bsfateom", store_yesno, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
108 {"twoeof", store_yesno, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
109 {"forwardspacerecord", store_yesno, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1},
110 {"forwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1},
111 {"fastforwardspacefile", store_yesno, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
112 {"removablemedia", store_yesno, ITEM(res_dev.cap_bits), CAP_REM, ITEM_DEFAULT, 1},
113 {"randomaccess", store_yesno, ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
114 {"automaticmount", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOMOUNT, ITEM_DEFAULT, 0},
115 {"labelmedia", store_yesno, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0},
116 {"alwaysopen", store_yesno, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
117 {"autochanger", store_yesno, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
118 {"closeonpoll", store_yesno, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
119 {"blockpositioning", store_yesno, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
120 {"usemtiocget", store_yesno, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
121 {"checklabels", store_yesno, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
122 {"autoselect", store_yesno, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
123 {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
124 {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
125 {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
126 {"maximumchangerwait", store_pint, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
127 {"maximumopenwait", store_pint, ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
128 {"maximumopenvolumes", store_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
129 {"maximumnetworkbuffersize", store_pint, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
130 {"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0},
131 {"offlineonunmount", store_yesno, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
132 {"maximumrewindwait", store_pint, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
133 {"minimumblocksize", store_pint, ITEM(res_dev.min_block_size), 0, 0, 0},
134 {"maximumblocksize", store_pint, ITEM(res_dev.max_block_size), 0, 0, 0},
135 {"maximumvolumesize", store_size, ITEM(res_dev.max_volume_size), 0, 0, 0},
136 {"maximumfilesize", store_size, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
137 {"volumecapacity", store_size, ITEM(res_dev.volume_capacity), 0, 0, 0},
138 {"spooldirectory", store_dir, ITEM(res_dev.spool_directory), 0, 0, 0},
139 {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0},
140 {"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0},
141 {"driveindex", store_pint, ITEM(res_dev.drive_index), 0, 0, 0},
142 {"maximumpartsize", store_size, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
143 {"requiresmount", store_yesno, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
144 {"mountpoint", store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
145 {"mountcommand", store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
146 {"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
147 {"writepartcommand", store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
148 {"freespacecommand", store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
149 {"labeltype", store_label, ITEM(res_dev.label_type), 0, 0, 0},
150 {NULL, NULL, 0, 0, 0, 0}
153 /* Autochanger definition */
154 static RES_ITEM changer_items[] = {
155 {"name", store_name, ITEM(res_changer.hdr.name), 0, ITEM_REQUIRED, 0},
156 {"description", store_str, ITEM(res_changer.hdr.desc), 0, 0, 0},
157 {"device", store_alist_res, ITEM(res_changer.device), R_DEVICE, ITEM_REQUIRED, 0},
158 {"changerdevice", store_strname, ITEM(res_changer.changer_name), 0, ITEM_REQUIRED, 0},
159 {"changercommand", store_strname, ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
160 {NULL, NULL, 0, 0, 0, 0}
164 // {"mountanonymousvolumes", store_yesno, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0},
167 /* Message resource */
168 extern RES_ITEM msgs_items[];
171 /* This is the master resource definition */
172 RES_TABLE resources[] = {
173 {"director", dir_items, R_DIRECTOR},
174 {"storage", store_items, R_STORAGE},
175 {"device", dev_items, R_DEVICE},
176 {"messages", msgs_items, R_MSGS},
177 {"autochanger", changer_items, R_AUTOCHANGER},
184 /* Dump contents of resource */
185 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
187 URES *res = (URES *)reshdr;
192 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
195 sendit(sock, "dump_resource type=%d\n", type);
196 if (type < 0) { /* no recursion */
202 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
205 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
206 res->res_store.hdr.name,
207 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
208 get_first_port_host_order(res->res_store.sdaddrs),
209 get_first_port_host_order(res->res_store.sddaddrs),
210 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
211 if (res->res_store.sdaddrs) {
212 foreach_dlist(p, res->res_store.sdaddrs) {
213 sendit(sock, " SDaddr=%s SDport=%d\n",
214 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
217 if (res->res_store.sddaddrs) {
218 foreach_dlist(p, res->res_store.sddaddrs) {
219 sendit(sock, " SDDaddr=%s SDDport=%d\n",
220 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
225 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
226 res->res_dev.hdr.name,
227 res->res_dev.media_type, res->res_dev.device_name,
228 res->res_dev.label_type);
229 sendit(sock, " rew_wait=%d min_bs=%d max_bs=%d\n",
230 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
231 res->res_dev.max_block_size);
232 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
233 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
234 res->res_dev.max_volume_size);
235 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
236 res->res_dev.max_file_size, res->res_dev.volume_capacity);
237 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
238 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
239 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
240 if (res->res_dev.changer_res) {
241 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
243 bstrncpy(buf, " ", sizeof(buf));
244 if (res->res_dev.cap_bits & CAP_EOF) {
245 bstrncat(buf, "CAP_EOF ", sizeof(buf));
247 if (res->res_dev.cap_bits & CAP_BSR) {
248 bstrncat(buf, "CAP_BSR ", sizeof(buf));
250 if (res->res_dev.cap_bits & CAP_BSF) {
251 bstrncat(buf, "CAP_BSF ", sizeof(buf));
253 if (res->res_dev.cap_bits & CAP_FSR) {
254 bstrncat(buf, "CAP_FSR ", sizeof(buf));
256 if (res->res_dev.cap_bits & CAP_FSF) {
257 bstrncat(buf, "CAP_FSF ", sizeof(buf));
259 if (res->res_dev.cap_bits & CAP_EOM) {
260 bstrncat(buf, "CAP_EOM ", sizeof(buf));
262 if (res->res_dev.cap_bits & CAP_REM) {
263 bstrncat(buf, "CAP_REM ", sizeof(buf));
265 if (res->res_dev.cap_bits & CAP_RACCESS) {
266 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
268 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
269 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
271 if (res->res_dev.cap_bits & CAP_LABEL) {
272 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
274 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
275 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
277 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
278 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
280 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
281 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
283 bstrncat(buf, "\n", sizeof(buf));
288 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
289 res->res_changer.hdr.name,
290 res->res_changer.changer_name, res->res_changer.changer_command);
291 foreach_alist(dev, res->res_changer.device) {
292 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
294 bstrncat(buf, "\n", sizeof(buf));
298 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
299 if (res->res_msgs.mail_cmd)
300 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
301 if (res->res_msgs.operator_cmd)
302 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
305 sendit(sock, _("Warning: unknown resource type %d\n"), type);
308 if (recurse && res->res_dir.hdr.next)
309 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
313 * Free memory of resource.
314 * NB, we don't need to worry about freeing any references
315 * to other resources as they will be freed when that
316 * resource chain is traversed. Mainly we worry about freeing
317 * allocated strings (names).
319 void free_resource(RES *sres, int type)
322 URES *res = (URES *)sres;
327 /* common stuff -- free the resource name */
328 nres = (RES *)res->res_dir.hdr.next;
329 if (res->res_dir.hdr.name) {
330 free(res->res_dir.hdr.name);
332 if (res->res_dir.hdr.desc) {
333 free(res->res_dir.hdr.desc);
339 if (res->res_dir.password) {
340 free(res->res_dir.password);
342 if (res->res_dir.address) {
343 free(res->res_dir.address);
346 if (res->res_dir.tls_ctx) {
347 free_tls_context(res->res_dir.tls_ctx);
349 if (res->res_dir.tls_ca_certfile) {
350 free(res->res_dir.tls_ca_certfile);
352 if (res->res_dir.tls_ca_certdir) {
353 free(res->res_dir.tls_ca_certdir);
355 if (res->res_dir.tls_certfile) {
356 free(res->res_dir.tls_certfile);
358 if (res->res_dir.tls_keyfile) {
359 free(res->res_dir.tls_keyfile);
361 if (res->res_dir.tls_dhfile) {
362 free(res->res_dir.tls_dhfile);
364 if (res->res_dir.tls_allowed_cns) {
365 delete res->res_dir.tls_allowed_cns;
367 #endif /* HAVE_TLS */
370 if (res->res_changer.changer_name) {
371 free(res->res_changer.changer_name);
373 if (res->res_changer.changer_command) {
374 free(res->res_changer.changer_command);
376 if (res->res_changer.device) {
377 delete res->res_changer.device;
381 if (res->res_store.sdaddrs) {
382 free_addresses(res->res_store.sdaddrs);
384 if (res->res_store.sddaddrs) {
385 free_addresses(res->res_store.sddaddrs);
387 if (res->res_store.working_directory) {
388 free(res->res_store.working_directory);
390 if (res->res_store.pid_directory) {
391 free(res->res_store.pid_directory);
393 if (res->res_store.subsys_directory) {
394 free(res->res_store.subsys_directory);
396 if (res->res_store.scripts_directory) {
397 free(res->res_store.scripts_directory);
400 if (res->res_store.tls_ctx) {
401 free_tls_context(res->res_store.tls_ctx);
403 if (res->res_store.tls_ca_certfile) {
404 free(res->res_store.tls_ca_certfile);
406 if (res->res_store.tls_ca_certdir) {
407 free(res->res_store.tls_ca_certdir);
409 if (res->res_store.tls_certfile) {
410 free(res->res_store.tls_certfile);
412 if (res->res_store.tls_keyfile) {
413 free(res->res_store.tls_keyfile);
415 if (res->res_store.tls_dhfile) {
416 free(res->res_store.tls_dhfile);
418 if (res->res_store.tls_allowed_cns) {
419 delete res->res_store.tls_allowed_cns;
421 #endif /* HAVE_TLS */
424 if (res->res_dev.media_type) {
425 free(res->res_dev.media_type);
427 if (res->res_dev.device_name) {
428 free(res->res_dev.device_name);
430 if (res->res_dev.changer_name) {
431 free(res->res_dev.changer_name);
433 if (res->res_dev.changer_command) {
434 free(res->res_dev.changer_command);
436 if (res->res_dev.alert_command) {
437 free(res->res_dev.alert_command);
439 if (res->res_dev.spool_directory) {
440 free(res->res_dev.spool_directory);
442 if (res->res_dev.mount_point) {
443 free(res->res_dev.mount_point);
445 if (res->res_dev.mount_command) {
446 free(res->res_dev.mount_command);
448 if (res->res_dev.unmount_command) {
449 free(res->res_dev.unmount_command);
451 if (res->res_dev.write_part_command) {
452 free(res->res_dev.write_part_command);
454 if (res->res_dev.free_space_command) {
455 free(res->res_dev.free_space_command);
459 if (res->res_msgs.mail_cmd) {
460 free(res->res_msgs.mail_cmd);
462 if (res->res_msgs.operator_cmd) {
463 free(res->res_msgs.operator_cmd);
465 free_msgs_res((MSGS *)res); /* free message resource */
469 Dmsg1(0, "Unknown resource type %d\n", type);
472 /* Common stuff again -- free the resource, recurse to next one */
477 free_resource(nres, type);
481 /* Save the new resource by chaining it into the head list for
482 * the resource. If this is pass 2, we update any resource
485 void save_resource(int type, RES_ITEM *items, int pass)
488 int rindex = type - r_first;
493 * Ensure that all required items are present
495 for (i=0; items[i].name; i++) {
496 if (items[i].flags & ITEM_REQUIRED) {
497 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
498 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
499 items[i].name, resources[rindex]);
502 /* If this triggers, take a look at lib/parse_conf.h */
503 if (i >= MAX_RES_ITEMS) {
504 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
508 /* During pass 2, we looked up pointers to all the resources
509 * referrenced in the current resource, , now we
510 * must copy their address from the static record to the allocated
517 /* Resources not containing a resource */
522 /* Resources containing a resource or an alist */
524 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
525 Emsg1(M_ERROR_TERM, 0, "Cannot find Director resource \"%s\"\n", res_all.res_dir.hdr.name);
528 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
532 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
533 Emsg1(M_ERROR_TERM, 0, "Cannot find Storage resource \"%s\"\n", res_all.res_dir.hdr.name);
535 res->res_store.messages = res_all.res_store.messages;
537 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
541 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
542 Emsg1(M_ERROR_TERM, 0, "Cannot find AutoChanger resource %s\n",
543 res_all.res_changer.hdr.name);
545 /* we must explicitly copy the device alist pointer */
546 res->res_changer.device = res_all.res_changer.device;
548 * Now update each device in this resource to point back
549 * to the changer resource.
551 foreach_alist(dev, res->res_changer.device) {
552 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
554 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
556 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
557 be.strerror(errstat));
561 printf("Unknown resource type %d\n", type);
567 if (res_all.res_dir.hdr.name) {
568 free(res_all.res_dir.hdr.name);
569 res_all.res_dir.hdr.name = NULL;
571 if (res_all.res_dir.hdr.desc) {
572 free(res_all.res_dir.hdr.desc);
573 res_all.res_dir.hdr.desc = NULL;
578 /* The following code is only executed on pass 1 */
581 size = sizeof(DIRRES);
584 size = sizeof(STORES);
587 size = sizeof(DEVRES);
593 size = sizeof(AUTOCHANGER);
596 printf("Unknown resource type %d\n", type);
603 res = (URES *)malloc(size);
604 memcpy(res, &res_all, size);
605 if (!res_head[rindex]) {
606 res_head[rindex] = (RES *)res; /* store first entry */
609 /* Add new res to end of chain */
610 for (next=res_head[rindex]; next->next; next=next->next) {
611 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
612 Emsg2(M_ERROR_TERM, 0,
613 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
614 resources[rindex].name, res->res_dir.hdr.name);
617 next->next = (RES *)res;
618 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
619 res->res_dir.hdr.name);