2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2007 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},
220 * Store Device Type (File, FIFO, Tape, DVD)
223 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
227 token = lex_get_token(lc, T_NAME);
228 /* Store the label pass 2 so that type is defined */
229 for (i=0; dev_types[i].name; i++) {
230 if (strcasecmp(lc->str, dev_types[i].name) == 0) {
231 *(int *)(item->value) = dev_types[i].token;
237 scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
240 set_bit(index, res_all.hdr.item_present);
244 /* Dump contents of resource */
245 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
247 URES *res = (URES *)reshdr;
252 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
255 sendit(sock, _("dump_resource type=%d\n"), type);
256 if (type < 0) { /* no recursion */
262 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
265 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
266 res->res_store.hdr.name,
267 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
268 get_first_port_host_order(res->res_store.sdaddrs),
269 get_first_port_host_order(res->res_store.sddaddrs),
270 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
271 if (res->res_store.sdaddrs) {
272 foreach_dlist(p, res->res_store.sdaddrs) {
273 sendit(sock, " SDaddr=%s SDport=%d\n",
274 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
277 if (res->res_store.sddaddrs) {
278 foreach_dlist(p, res->res_store.sddaddrs) {
279 sendit(sock, " SDDaddr=%s SDDport=%d\n",
280 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
285 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
286 res->res_dev.hdr.name,
287 res->res_dev.media_type, res->res_dev.device_name,
288 res->res_dev.label_type);
289 sendit(sock, " rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
290 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
291 res->res_dev.max_block_size, res->res_dev.max_changer_wait);
292 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
293 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
294 res->res_dev.max_volume_size);
295 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
296 res->res_dev.max_file_size, res->res_dev.volume_capacity);
297 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
298 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
299 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
300 if (res->res_dev.changer_res) {
301 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
303 bstrncpy(buf, " ", sizeof(buf));
304 if (res->res_dev.cap_bits & CAP_EOF) {
305 bstrncat(buf, "CAP_EOF ", sizeof(buf));
307 if (res->res_dev.cap_bits & CAP_BSR) {
308 bstrncat(buf, "CAP_BSR ", sizeof(buf));
310 if (res->res_dev.cap_bits & CAP_BSF) {
311 bstrncat(buf, "CAP_BSF ", sizeof(buf));
313 if (res->res_dev.cap_bits & CAP_FSR) {
314 bstrncat(buf, "CAP_FSR ", sizeof(buf));
316 if (res->res_dev.cap_bits & CAP_FSF) {
317 bstrncat(buf, "CAP_FSF ", sizeof(buf));
319 if (res->res_dev.cap_bits & CAP_EOM) {
320 bstrncat(buf, "CAP_EOM ", sizeof(buf));
322 if (res->res_dev.cap_bits & CAP_REM) {
323 bstrncat(buf, "CAP_REM ", sizeof(buf));
325 if (res->res_dev.cap_bits & CAP_RACCESS) {
326 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
328 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
329 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
331 if (res->res_dev.cap_bits & CAP_LABEL) {
332 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
334 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
335 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
337 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
338 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
340 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
341 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
343 if (res->res_dev.cap_bits & CAP_REQMOUNT) {
344 bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
346 if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
347 bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
349 bstrncat(buf, "\n", sizeof(buf));
354 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
355 res->res_changer.hdr.name,
356 res->res_changer.changer_name, res->res_changer.changer_command);
357 foreach_alist(dev, res->res_changer.device) {
358 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
360 bstrncat(buf, "\n", sizeof(buf));
364 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
365 if (res->res_msgs.mail_cmd)
366 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
367 if (res->res_msgs.operator_cmd)
368 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
371 sendit(sock, _("Warning: unknown resource type %d\n"), type);
374 if (recurse && res->res_dir.hdr.next)
375 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
379 * Free memory of resource.
380 * NB, we don't need to worry about freeing any references
381 * to other resources as they will be freed when that
382 * resource chain is traversed. Mainly we worry about freeing
383 * allocated strings (names).
385 void free_resource(RES *sres, int type)
388 URES *res = (URES *)sres;
393 /* common stuff -- free the resource name */
394 nres = (RES *)res->res_dir.hdr.next;
395 if (res->res_dir.hdr.name) {
396 free(res->res_dir.hdr.name);
398 if (res->res_dir.hdr.desc) {
399 free(res->res_dir.hdr.desc);
405 if (res->res_dir.password) {
406 free(res->res_dir.password);
408 if (res->res_dir.address) {
409 free(res->res_dir.address);
411 if (res->res_dir.tls_ctx) {
412 free_tls_context(res->res_dir.tls_ctx);
414 if (res->res_dir.tls_ca_certfile) {
415 free(res->res_dir.tls_ca_certfile);
417 if (res->res_dir.tls_ca_certdir) {
418 free(res->res_dir.tls_ca_certdir);
420 if (res->res_dir.tls_certfile) {
421 free(res->res_dir.tls_certfile);
423 if (res->res_dir.tls_keyfile) {
424 free(res->res_dir.tls_keyfile);
426 if (res->res_dir.tls_dhfile) {
427 free(res->res_dir.tls_dhfile);
429 if (res->res_dir.tls_allowed_cns) {
430 delete res->res_dir.tls_allowed_cns;
434 if (res->res_changer.changer_name) {
435 free(res->res_changer.changer_name);
437 if (res->res_changer.changer_command) {
438 free(res->res_changer.changer_command);
440 if (res->res_changer.device) {
441 delete res->res_changer.device;
445 if (res->res_store.sdaddrs) {
446 free_addresses(res->res_store.sdaddrs);
448 if (res->res_store.sddaddrs) {
449 free_addresses(res->res_store.sddaddrs);
451 if (res->res_store.working_directory) {
452 free(res->res_store.working_directory);
454 if (res->res_store.pid_directory) {
455 free(res->res_store.pid_directory);
457 if (res->res_store.subsys_directory) {
458 free(res->res_store.subsys_directory);
460 if (res->res_store.scripts_directory) {
461 free(res->res_store.scripts_directory);
463 if (res->res_store.tls_ctx) {
464 free_tls_context(res->res_store.tls_ctx);
466 if (res->res_store.tls_ca_certfile) {
467 free(res->res_store.tls_ca_certfile);
469 if (res->res_store.tls_ca_certdir) {
470 free(res->res_store.tls_ca_certdir);
472 if (res->res_store.tls_certfile) {
473 free(res->res_store.tls_certfile);
475 if (res->res_store.tls_keyfile) {
476 free(res->res_store.tls_keyfile);
478 if (res->res_store.tls_dhfile) {
479 free(res->res_store.tls_dhfile);
481 if (res->res_store.tls_allowed_cns) {
482 delete res->res_store.tls_allowed_cns;
486 if (res->res_dev.media_type) {
487 free(res->res_dev.media_type);
489 if (res->res_dev.device_name) {
490 free(res->res_dev.device_name);
492 if (res->res_dev.changer_name) {
493 free(res->res_dev.changer_name);
495 if (res->res_dev.changer_command) {
496 free(res->res_dev.changer_command);
498 if (res->res_dev.alert_command) {
499 free(res->res_dev.alert_command);
501 if (res->res_dev.spool_directory) {
502 free(res->res_dev.spool_directory);
504 if (res->res_dev.mount_point) {
505 free(res->res_dev.mount_point);
507 if (res->res_dev.mount_command) {
508 free(res->res_dev.mount_command);
510 if (res->res_dev.unmount_command) {
511 free(res->res_dev.unmount_command);
513 if (res->res_dev.write_part_command) {
514 free(res->res_dev.write_part_command);
516 if (res->res_dev.free_space_command) {
517 free(res->res_dev.free_space_command);
521 if (res->res_msgs.mail_cmd) {
522 free(res->res_msgs.mail_cmd);
524 if (res->res_msgs.operator_cmd) {
525 free(res->res_msgs.operator_cmd);
527 free_msgs_res((MSGS *)res); /* free message resource */
531 Dmsg1(0, _("Unknown resource type %d\n"), type);
534 /* Common stuff again -- free the resource, recurse to next one */
539 free_resource(nres, type);
543 /* Save the new resource by chaining it into the head list for
544 * the resource. If this is pass 2, we update any resource
547 void save_resource(int type, RES_ITEM *items, int pass)
550 int rindex = type - r_first;
555 * Ensure that all required items are present
557 for (i=0; items[i].name; i++) {
558 if (items[i].flags & ITEM_REQUIRED) {
559 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
560 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
561 items[i].name, resources[rindex]);
564 /* If this triggers, take a look at lib/parse_conf.h */
565 if (i >= MAX_RES_ITEMS) {
566 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
570 /* During pass 2, we looked up pointers to all the resources
571 * referrenced in the current resource, , now we
572 * must copy their address from the static record to the allocated
579 /* Resources not containing a resource */
584 /* Resources containing a resource or an alist */
586 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
587 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
589 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
592 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
593 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
595 res->res_store.messages = res_all.res_store.messages;
596 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
599 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
600 Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
601 res_all.res_changer.hdr.name);
603 /* we must explicitly copy the device alist pointer */
604 res->res_changer.device = res_all.res_changer.device;
606 * Now update each device in this resource to point back
607 * to the changer resource.
609 foreach_alist(dev, res->res_changer.device) {
610 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
612 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
614 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
615 be.bstrerror(errstat));
619 printf(_("Unknown resource type %d\n"), type);
625 if (res_all.res_dir.hdr.name) {
626 free(res_all.res_dir.hdr.name);
627 res_all.res_dir.hdr.name = NULL;
629 if (res_all.res_dir.hdr.desc) {
630 free(res_all.res_dir.hdr.desc);
631 res_all.res_dir.hdr.desc = NULL;
636 /* The following code is only executed on pass 1 */
639 size = sizeof(DIRRES);
642 size = sizeof(STORES);
645 size = sizeof(DEVRES);
651 size = sizeof(AUTOCHANGER);
654 printf(_("Unknown resource type %d\n"), type);
661 res = (URES *)malloc(size);
662 memcpy(res, &res_all, size);
663 if (!res_head[rindex]) {
664 res_head[rindex] = (RES *)res; /* store first entry */
667 /* Add new res to end of chain */
668 for (last=next=res_head[rindex]; next; next=next->next) {
670 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
671 Emsg2(M_ERROR_TERM, 0,
672 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
673 resources[rindex].name, res->res_dir.hdr.name);
676 last->next = (RES *)res;
677 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
678 res->res_dir.hdr.name);