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 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 {"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_pint, 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_bit, 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_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
150 {"maximumnetworkbuffersize", store_pint, 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_pint, ITEM(res_dev.min_block_size), 0, 0, 0},
154 {"maximumblocksize", store_pint, 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_pint, 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},
221 * Store Device Type (File, FIFO, Tape, DVD)
224 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
228 token = lex_get_token(lc, T_NAME);
229 /* Store the label pass 2 so that type is defined */
230 for (i=0; dev_types[i].name; i++) {
231 if (strcasecmp(lc->str, dev_types[i].name) == 0) {
232 *(int *)(item->value) = dev_types[i].token;
238 scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
241 set_bit(index, res_all.hdr.item_present);
245 /* Dump contents of resource */
246 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
248 URES *res = (URES *)reshdr;
253 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
256 sendit(sock, _("dump_resource type=%d\n"), type);
257 if (type < 0) { /* no recursion */
263 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
266 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
267 res->res_store.hdr.name,
268 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
269 get_first_port_host_order(res->res_store.sdaddrs),
270 get_first_port_host_order(res->res_store.sddaddrs),
271 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
272 if (res->res_store.sdaddrs) {
273 foreach_dlist(p, res->res_store.sdaddrs) {
274 sendit(sock, " SDaddr=%s SDport=%d\n",
275 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
278 if (res->res_store.sddaddrs) {
279 foreach_dlist(p, res->res_store.sddaddrs) {
280 sendit(sock, " SDDaddr=%s SDDport=%d\n",
281 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
286 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
287 res->res_dev.hdr.name,
288 res->res_dev.media_type, res->res_dev.device_name,
289 res->res_dev.label_type);
290 sendit(sock, " rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
291 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
292 res->res_dev.max_block_size, res->res_dev.max_changer_wait);
293 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
294 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
295 res->res_dev.max_volume_size);
296 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
297 res->res_dev.max_file_size, res->res_dev.volume_capacity);
298 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
299 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
300 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
301 if (res->res_dev.changer_res) {
302 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
304 bstrncpy(buf, " ", sizeof(buf));
305 if (res->res_dev.cap_bits & CAP_EOF) {
306 bstrncat(buf, "CAP_EOF ", sizeof(buf));
308 if (res->res_dev.cap_bits & CAP_BSR) {
309 bstrncat(buf, "CAP_BSR ", sizeof(buf));
311 if (res->res_dev.cap_bits & CAP_BSF) {
312 bstrncat(buf, "CAP_BSF ", sizeof(buf));
314 if (res->res_dev.cap_bits & CAP_FSR) {
315 bstrncat(buf, "CAP_FSR ", sizeof(buf));
317 if (res->res_dev.cap_bits & CAP_FSF) {
318 bstrncat(buf, "CAP_FSF ", sizeof(buf));
320 if (res->res_dev.cap_bits & CAP_EOM) {
321 bstrncat(buf, "CAP_EOM ", sizeof(buf));
323 if (res->res_dev.cap_bits & CAP_REM) {
324 bstrncat(buf, "CAP_REM ", sizeof(buf));
326 if (res->res_dev.cap_bits & CAP_RACCESS) {
327 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
329 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
330 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
332 if (res->res_dev.cap_bits & CAP_LABEL) {
333 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
335 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
336 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
338 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
339 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
341 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
342 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
344 if (res->res_dev.cap_bits & CAP_REQMOUNT) {
345 bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
347 if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
348 bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
350 bstrncat(buf, "\n", sizeof(buf));
355 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
356 res->res_changer.hdr.name,
357 res->res_changer.changer_name, res->res_changer.changer_command);
358 foreach_alist(dev, res->res_changer.device) {
359 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
361 bstrncat(buf, "\n", sizeof(buf));
365 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
366 if (res->res_msgs.mail_cmd)
367 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
368 if (res->res_msgs.operator_cmd)
369 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
372 sendit(sock, _("Warning: unknown resource type %d\n"), type);
375 if (recurse && res->res_dir.hdr.next)
376 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
380 * Free memory of resource.
381 * NB, we don't need to worry about freeing any references
382 * to other resources as they will be freed when that
383 * resource chain is traversed. Mainly we worry about freeing
384 * allocated strings (names).
386 void free_resource(RES *sres, int type)
389 URES *res = (URES *)sres;
394 /* common stuff -- free the resource name */
395 nres = (RES *)res->res_dir.hdr.next;
396 if (res->res_dir.hdr.name) {
397 free(res->res_dir.hdr.name);
399 if (res->res_dir.hdr.desc) {
400 free(res->res_dir.hdr.desc);
406 if (res->res_dir.password) {
407 free(res->res_dir.password);
409 if (res->res_dir.address) {
410 free(res->res_dir.address);
412 if (res->res_dir.tls_ctx) {
413 free_tls_context(res->res_dir.tls_ctx);
415 if (res->res_dir.tls_ca_certfile) {
416 free(res->res_dir.tls_ca_certfile);
418 if (res->res_dir.tls_ca_certdir) {
419 free(res->res_dir.tls_ca_certdir);
421 if (res->res_dir.tls_certfile) {
422 free(res->res_dir.tls_certfile);
424 if (res->res_dir.tls_keyfile) {
425 free(res->res_dir.tls_keyfile);
427 if (res->res_dir.tls_dhfile) {
428 free(res->res_dir.tls_dhfile);
430 if (res->res_dir.tls_allowed_cns) {
431 delete res->res_dir.tls_allowed_cns;
435 if (res->res_changer.changer_name) {
436 free(res->res_changer.changer_name);
438 if (res->res_changer.changer_command) {
439 free(res->res_changer.changer_command);
441 if (res->res_changer.device) {
442 delete res->res_changer.device;
446 if (res->res_store.sdaddrs) {
447 free_addresses(res->res_store.sdaddrs);
449 if (res->res_store.sddaddrs) {
450 free_addresses(res->res_store.sddaddrs);
452 if (res->res_store.working_directory) {
453 free(res->res_store.working_directory);
455 if (res->res_store.pid_directory) {
456 free(res->res_store.pid_directory);
458 if (res->res_store.subsys_directory) {
459 free(res->res_store.subsys_directory);
461 if (res->res_store.scripts_directory) {
462 free(res->res_store.scripts_directory);
464 if (res->res_store.tls_ctx) {
465 free_tls_context(res->res_store.tls_ctx);
467 if (res->res_store.tls_ca_certfile) {
468 free(res->res_store.tls_ca_certfile);
470 if (res->res_store.tls_ca_certdir) {
471 free(res->res_store.tls_ca_certdir);
473 if (res->res_store.tls_certfile) {
474 free(res->res_store.tls_certfile);
476 if (res->res_store.tls_keyfile) {
477 free(res->res_store.tls_keyfile);
479 if (res->res_store.tls_dhfile) {
480 free(res->res_store.tls_dhfile);
482 if (res->res_store.tls_allowed_cns) {
483 delete res->res_store.tls_allowed_cns;
487 if (res->res_dev.media_type) {
488 free(res->res_dev.media_type);
490 if (res->res_dev.device_name) {
491 free(res->res_dev.device_name);
493 if (res->res_dev.changer_name) {
494 free(res->res_dev.changer_name);
496 if (res->res_dev.changer_command) {
497 free(res->res_dev.changer_command);
499 if (res->res_dev.alert_command) {
500 free(res->res_dev.alert_command);
502 if (res->res_dev.spool_directory) {
503 free(res->res_dev.spool_directory);
505 if (res->res_dev.mount_point) {
506 free(res->res_dev.mount_point);
508 if (res->res_dev.mount_command) {
509 free(res->res_dev.mount_command);
511 if (res->res_dev.unmount_command) {
512 free(res->res_dev.unmount_command);
514 if (res->res_dev.write_part_command) {
515 free(res->res_dev.write_part_command);
517 if (res->res_dev.free_space_command) {
518 free(res->res_dev.free_space_command);
522 if (res->res_msgs.mail_cmd) {
523 free(res->res_msgs.mail_cmd);
525 if (res->res_msgs.operator_cmd) {
526 free(res->res_msgs.operator_cmd);
528 free_msgs_res((MSGS *)res); /* free message resource */
532 Dmsg1(0, _("Unknown resource type %d\n"), type);
535 /* Common stuff again -- free the resource, recurse to next one */
540 free_resource(nres, type);
544 /* Save the new resource by chaining it into the head list for
545 * the resource. If this is pass 2, we update any resource
548 void save_resource(int type, RES_ITEM *items, int pass)
551 int rindex = type - r_first;
556 * Ensure that all required items are present
558 for (i=0; items[i].name; i++) {
559 if (items[i].flags & ITEM_REQUIRED) {
560 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
561 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
562 items[i].name, resources[rindex]);
565 /* If this triggers, take a look at lib/parse_conf.h */
566 if (i >= MAX_RES_ITEMS) {
567 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
571 /* During pass 2, we looked up pointers to all the resources
572 * referrenced in the current resource, , now we
573 * must copy their address from the static record to the allocated
580 /* Resources not containing a resource */
585 /* Resources containing a resource or an alist */
587 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
588 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
590 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
593 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
594 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
596 res->res_store.messages = res_all.res_store.messages;
597 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
600 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
601 Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
602 res_all.res_changer.hdr.name);
604 /* we must explicitly copy the device alist pointer */
605 res->res_changer.device = res_all.res_changer.device;
607 * Now update each device in this resource to point back
608 * to the changer resource.
610 foreach_alist(dev, res->res_changer.device) {
611 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
613 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
615 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
616 be.bstrerror(errstat));
620 printf(_("Unknown resource type %d\n"), type);
626 if (res_all.res_dir.hdr.name) {
627 free(res_all.res_dir.hdr.name);
628 res_all.res_dir.hdr.name = NULL;
630 if (res_all.res_dir.hdr.desc) {
631 free(res_all.res_dir.hdr.desc);
632 res_all.res_dir.hdr.desc = NULL;
637 /* The following code is only executed on pass 1 */
640 size = sizeof(DIRRES);
643 size = sizeof(STORES);
646 size = sizeof(DEVRES);
652 size = sizeof(AUTOCHANGER);
655 printf(_("Unknown resource type %d\n"), type);
662 res = (URES *)malloc(size);
663 memcpy(res, &res_all, size);
664 if (!res_head[rindex]) {
665 res_head[rindex] = (RES *)res; /* store first entry */
668 /* Add new res to end of chain */
669 for (last=next=res_head[rindex]; next; next=next->next) {
671 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
672 Emsg2(M_ERROR_TERM, 0,
673 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
674 resources[rindex].name, res->res_dir.hdr.name);
677 last->next = (RES *)res;
678 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
679 res->res_dir.hdr.name);