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 {"scriptsdirectory", store_dir, ITEM(res_store.scripts_directory), 0, 0, 0},
78 {"maximumconcurrentjobs", store_pint, ITEM(res_store.max_concurrent_jobs), 0, ITEM_DEFAULT, 20},
79 {"heartbeatinterval", store_time, ITEM(res_store.heartbeat_interval), 0, ITEM_DEFAULT, 0},
80 {"tlsauthenticate", store_bool, ITEM(res_store.tls_authenticate), 0, 0, 0},
81 {"tlsenable", store_bool, ITEM(res_store.tls_enable), 0, 0, 0},
82 {"tlsrequire", store_bool, ITEM(res_store.tls_require), 0, 0, 0},
83 {"tlsverifypeer", store_bool, ITEM(res_store.tls_verify_peer), 1, ITEM_DEFAULT, 1},
84 {"tlscacertificatefile", store_dir, ITEM(res_store.tls_ca_certfile), 0, 0, 0},
85 {"tlscacertificatedir", store_dir, ITEM(res_store.tls_ca_certdir), 0, 0, 0},
86 {"tlscertificate", store_dir, ITEM(res_store.tls_certfile), 0, 0, 0},
87 {"tlskey", store_dir, ITEM(res_store.tls_keyfile), 0, 0, 0},
88 {"tlsdhfile", store_dir, ITEM(res_store.tls_dhfile), 0, 0, 0},
89 {"tlsallowedcn", store_alist_str, ITEM(res_store.tls_allowed_cns), 0, 0, 0},
90 {"clientconnectwait", store_time, ITEM(res_store.client_wait), 0, ITEM_DEFAULT, 30 * 60},
91 {NULL, NULL, {0}, 0, 0, 0}
95 /* Directors that can speak to the Storage daemon */
96 static RES_ITEM dir_items[] = {
97 {"name", store_name, ITEM(res_dir.hdr.name), 0, ITEM_REQUIRED, 0},
98 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
99 {"password", store_password, ITEM(res_dir.password), 0, ITEM_REQUIRED, 0},
100 {"monitor", store_bool, ITEM(res_dir.monitor), 0, 0, 0},
101 {"tlsauthenticate", store_bool, ITEM(res_dir.tls_authenticate), 0, 0, 0},
102 {"tlsenable", store_bool, ITEM(res_dir.tls_enable), 0, 0, 0},
103 {"tlsrequire", store_bool, ITEM(res_dir.tls_require), 0, 0, 0},
104 {"tlsverifypeer", store_bool, ITEM(res_dir.tls_verify_peer), 1, ITEM_DEFAULT, 1},
105 {"tlscacertificatefile", store_dir, ITEM(res_dir.tls_ca_certfile), 0, 0, 0},
106 {"tlscacertificatedir", store_dir, ITEM(res_dir.tls_ca_certdir), 0, 0, 0},
107 {"tlscertificate", store_dir, ITEM(res_dir.tls_certfile), 0, 0, 0},
108 {"tlskey", store_dir, ITEM(res_dir.tls_keyfile), 0, 0, 0},
109 {"tlsdhfile", store_dir, ITEM(res_dir.tls_dhfile), 0, 0, 0},
110 {"tlsallowedcn", store_alist_str, ITEM(res_dir.tls_allowed_cns), 0, 0, 0},
111 {NULL, NULL, {0}, 0, 0, 0}
114 /* Device definition */
115 static RES_ITEM dev_items[] = {
116 {"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0},
117 {"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
118 {"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0},
119 {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0},
120 {"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
121 {"hardwareendoffile", store_bit, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1},
122 {"hardwareendofmedium", store_bit, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1},
123 {"backwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_BSR, ITEM_DEFAULT, 1},
124 {"backwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_BSF, ITEM_DEFAULT, 1},
125 {"bsfateom", store_bit, ITEM(res_dev.cap_bits), CAP_BSFATEOM, ITEM_DEFAULT, 0},
126 {"twoeof", store_bit, ITEM(res_dev.cap_bits), CAP_TWOEOF, ITEM_DEFAULT, 0},
127 {"forwardspacerecord", store_bit, ITEM(res_dev.cap_bits), CAP_FSR, ITEM_DEFAULT, 1},
128 {"forwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FSF, ITEM_DEFAULT, 1},
129 {"fastforwardspacefile", store_bit, ITEM(res_dev.cap_bits), CAP_FASTFSF, ITEM_DEFAULT, 1},
130 {"removablemedia", store_bit, ITEM(res_dev.cap_bits), CAP_REM, ITEM_DEFAULT, 1},
131 {"randomaccess", store_bit, ITEM(res_dev.cap_bits), CAP_RACCESS, 0, 0},
132 {"automaticmount", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOMOUNT, ITEM_DEFAULT, 0},
133 {"labelmedia", store_bit, ITEM(res_dev.cap_bits), CAP_LABEL, ITEM_DEFAULT, 0},
134 {"alwaysopen", store_bit, ITEM(res_dev.cap_bits), CAP_ALWAYSOPEN, ITEM_DEFAULT, 1},
135 {"autochanger", store_bit, ITEM(res_dev.cap_bits), CAP_AUTOCHANGER, ITEM_DEFAULT, 0},
136 {"closeonpoll", store_bit, ITEM(res_dev.cap_bits), CAP_CLOSEONPOLL, ITEM_DEFAULT, 0},
137 {"blockpositioning", store_bit, ITEM(res_dev.cap_bits), CAP_POSITIONBLOCKS, ITEM_DEFAULT, 1},
138 {"usemtiocget", store_bit, ITEM(res_dev.cap_bits), CAP_MTIOCGET, ITEM_DEFAULT, 1},
139 {"checklabels", store_bit, ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
140 {"requiresmount", store_bit, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
141 {"offlineonunmount", store_bit, ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
142 {"autoselect", store_bit, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
143 {"changerdevice", store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
144 {"changercommand", store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
145 {"alertcommand", store_strname,ITEM(res_dev.alert_command), 0, 0, 0},
146 {"maximumchangerwait", store_time, ITEM(res_dev.max_changer_wait), 0, ITEM_DEFAULT, 5 * 60},
147 {"maximumopenwait", store_time, ITEM(res_dev.max_open_wait), 0, ITEM_DEFAULT, 5 * 60},
148 {"maximumopenvolumes", store_pint, ITEM(res_dev.max_open_vols), 0, ITEM_DEFAULT, 1},
149 {"maximumnetworkbuffersize", store_pint, ITEM(res_dev.max_network_buffer_size), 0, 0, 0},
150 {"volumepollinterval", store_time, ITEM(res_dev.vol_poll_interval), 0, 0, 0},
151 {"maximumrewindwait", store_time, ITEM(res_dev.max_rewind_wait), 0, ITEM_DEFAULT, 5 * 60},
152 {"minimumblocksize", store_pint, ITEM(res_dev.min_block_size), 0, 0, 0},
153 {"maximumblocksize", store_pint, ITEM(res_dev.max_block_size), 0, 0, 0},
154 {"maximumvolumesize", store_size, ITEM(res_dev.max_volume_size), 0, 0, 0},
155 {"maximumfilesize", store_size, ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
156 {"volumecapacity", store_size, ITEM(res_dev.volume_capacity), 0, 0, 0},
157 {"spooldirectory", store_dir, ITEM(res_dev.spool_directory), 0, 0, 0},
158 {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0},
159 {"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0},
160 {"driveindex", store_pint, ITEM(res_dev.drive_index), 0, 0, 0},
161 {"maximumpartsize", store_size, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0},
162 {"mountpoint", store_strname,ITEM(res_dev.mount_point), 0, 0, 0},
163 {"mountcommand", store_strname,ITEM(res_dev.mount_command), 0, 0, 0},
164 {"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0},
165 {"writepartcommand", store_strname,ITEM(res_dev.write_part_command), 0, 0, 0},
166 {"freespacecommand", store_strname,ITEM(res_dev.free_space_command), 0, 0, 0},
167 {"labeltype", store_label, ITEM(res_dev.label_type), 0, 0, 0},
168 {NULL, NULL, {0}, 0, 0, 0}
171 /* Autochanger definition */
172 static RES_ITEM changer_items[] = {
173 {"name", store_name, ITEM(res_changer.hdr.name), 0, ITEM_REQUIRED, 0},
174 {"description", store_str, ITEM(res_changer.hdr.desc), 0, 0, 0},
175 {"device", store_alist_res, ITEM(res_changer.device), R_DEVICE, ITEM_REQUIRED, 0},
176 {"changerdevice", store_strname, ITEM(res_changer.changer_name), 0, ITEM_REQUIRED, 0},
177 {"changercommand", store_strname, ITEM(res_changer.changer_command), 0, ITEM_REQUIRED, 0},
178 {NULL, NULL, {0}, 0, 0, 0}
182 // {"mountanonymousvolumes", store_bit, ITEM(res_dev.cap_bits), CAP_ANONVOLS, ITEM_DEFAULT, 0},
185 /* Message resource */
186 extern RES_ITEM msgs_items[];
189 /* This is the master resource definition */
190 RES_TABLE resources[] = {
191 {"director", dir_items, R_DIRECTOR},
192 {"storage", store_items, R_STORAGE},
193 {"device", dev_items, R_DEVICE},
194 {"messages", msgs_items, R_MSGS},
195 {"autochanger", changer_items, R_AUTOCHANGER},
202 * device type device code = token
209 static s_kw dev_types[] = {
210 {"file", B_FILE_DEV},
211 {"tape", B_TAPE_DEV},
213 {"fifo", B_FIFO_DEV},
219 * Store Device Type (File, FIFO, Tape, DVD)
222 static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
226 token = lex_get_token(lc, T_NAME);
227 /* Store the label pass 2 so that type is defined */
228 for (i=0; dev_types[i].name; i++) {
229 if (strcasecmp(lc->str, dev_types[i].name) == 0) {
230 *(int *)(item->value) = dev_types[i].token;
236 scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
239 set_bit(index, res_all.hdr.item_present);
243 /* Dump contents of resource */
244 void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock)
246 URES *res = (URES *)reshdr;
251 sendit(sock, _("Warning: no \"%s\" resource (%d) defined.\n"), res_to_str(type), type);
254 sendit(sock, _("dump_resource type=%d\n"), type);
255 if (type < 0) { /* no recursion */
261 sendit(sock, "Director: name=%s\n", res->res_dir.hdr.name);
264 sendit(sock, "Storage: name=%s SDaddr=%s SDport=%d SDDport=%d HB=%s\n",
265 res->res_store.hdr.name,
266 NPRT(get_first_address(res->res_store.sdaddrs, buf, sizeof(buf))),
267 get_first_port_host_order(res->res_store.sdaddrs),
268 get_first_port_host_order(res->res_store.sddaddrs),
269 edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf)));
270 if (res->res_store.sdaddrs) {
271 foreach_dlist(p, res->res_store.sdaddrs) {
272 sendit(sock, " SDaddr=%s SDport=%d\n",
273 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
276 if (res->res_store.sddaddrs) {
277 foreach_dlist(p, res->res_store.sddaddrs) {
278 sendit(sock, " SDDaddr=%s SDDport=%d\n",
279 p->get_address(buf, sizeof(buf)), p->get_port_host_order());
284 sendit(sock, "Device: name=%s MediaType=%s Device=%s LabelType=%d\n",
285 res->res_dev.hdr.name,
286 res->res_dev.media_type, res->res_dev.device_name,
287 res->res_dev.label_type);
288 sendit(sock, " rew_wait=%" lld " min_bs=%d max_bs=%d chgr_wait=%" lld "\n",
289 res->res_dev.max_rewind_wait, res->res_dev.min_block_size,
290 res->res_dev.max_block_size, res->res_dev.max_changer_wait);
291 sendit(sock, " max_jobs=%d max_files=%" lld " max_size=%" lld "\n",
292 res->res_dev.max_volume_jobs, res->res_dev.max_volume_files,
293 res->res_dev.max_volume_size);
294 sendit(sock, " max_file_size=%" lld " capacity=%" lld "\n",
295 res->res_dev.max_file_size, res->res_dev.volume_capacity);
296 sendit(sock, " spool_directory=%s\n", NPRT(res->res_dev.spool_directory));
297 sendit(sock, " max_spool_size=%" lld " max_job_spool_size=%" lld "\n",
298 res->res_dev.max_spool_size, res->res_dev.max_job_spool_size);
299 if (res->res_dev.changer_res) {
300 sendit(sock, " changer=%p\n", res->res_dev.changer_res);
302 bstrncpy(buf, " ", sizeof(buf));
303 if (res->res_dev.cap_bits & CAP_EOF) {
304 bstrncat(buf, "CAP_EOF ", sizeof(buf));
306 if (res->res_dev.cap_bits & CAP_BSR) {
307 bstrncat(buf, "CAP_BSR ", sizeof(buf));
309 if (res->res_dev.cap_bits & CAP_BSF) {
310 bstrncat(buf, "CAP_BSF ", sizeof(buf));
312 if (res->res_dev.cap_bits & CAP_FSR) {
313 bstrncat(buf, "CAP_FSR ", sizeof(buf));
315 if (res->res_dev.cap_bits & CAP_FSF) {
316 bstrncat(buf, "CAP_FSF ", sizeof(buf));
318 if (res->res_dev.cap_bits & CAP_EOM) {
319 bstrncat(buf, "CAP_EOM ", sizeof(buf));
321 if (res->res_dev.cap_bits & CAP_REM) {
322 bstrncat(buf, "CAP_REM ", sizeof(buf));
324 if (res->res_dev.cap_bits & CAP_RACCESS) {
325 bstrncat(buf, "CAP_RACCESS ", sizeof(buf));
327 if (res->res_dev.cap_bits & CAP_AUTOMOUNT) {
328 bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf));
330 if (res->res_dev.cap_bits & CAP_LABEL) {
331 bstrncat(buf, "CAP_LABEL ", sizeof(buf));
333 if (res->res_dev.cap_bits & CAP_ANONVOLS) {
334 bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf));
336 if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) {
337 bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf));
339 if (res->res_dev.cap_bits & CAP_CHECKLABELS) {
340 bstrncat(buf, "CAP_CHECKLABELS ", sizeof(buf));
342 if (res->res_dev.cap_bits & CAP_REQMOUNT) {
343 bstrncat(buf, "CAP_REQMOUNT ", sizeof(buf));
345 if (res->res_dev.cap_bits & CAP_OFFLINEUNMOUNT) {
346 bstrncat(buf, "CAP_OFFLINEUNMOUNT ", sizeof(buf));
348 bstrncat(buf, "\n", sizeof(buf));
353 sendit(sock, "Changer: name=%s Changer_devname=%s\n Changer_cmd=%s\n",
354 res->res_changer.hdr.name,
355 res->res_changer.changer_name, res->res_changer.changer_command);
356 foreach_alist(dev, res->res_changer.device) {
357 sendit(sock, " --->Device: name=%s\n", dev->hdr.name);
359 bstrncat(buf, "\n", sizeof(buf));
363 sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name);
364 if (res->res_msgs.mail_cmd)
365 sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd);
366 if (res->res_msgs.operator_cmd)
367 sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd);
370 sendit(sock, _("Warning: unknown resource type %d\n"), type);
373 if (recurse && res->res_dir.hdr.next)
374 dump_resource(type, (RES *)res->res_dir.hdr.next, sendit, sock);
378 * Free memory of resource.
379 * NB, we don't need to worry about freeing any references
380 * to other resources as they will be freed when that
381 * resource chain is traversed. Mainly we worry about freeing
382 * allocated strings (names).
384 void free_resource(RES *sres, int type)
387 URES *res = (URES *)sres;
392 /* common stuff -- free the resource name */
393 nres = (RES *)res->res_dir.hdr.next;
394 if (res->res_dir.hdr.name) {
395 free(res->res_dir.hdr.name);
397 if (res->res_dir.hdr.desc) {
398 free(res->res_dir.hdr.desc);
404 if (res->res_dir.password) {
405 free(res->res_dir.password);
407 if (res->res_dir.address) {
408 free(res->res_dir.address);
410 if (res->res_dir.tls_ctx) {
411 free_tls_context(res->res_dir.tls_ctx);
413 if (res->res_dir.tls_ca_certfile) {
414 free(res->res_dir.tls_ca_certfile);
416 if (res->res_dir.tls_ca_certdir) {
417 free(res->res_dir.tls_ca_certdir);
419 if (res->res_dir.tls_certfile) {
420 free(res->res_dir.tls_certfile);
422 if (res->res_dir.tls_keyfile) {
423 free(res->res_dir.tls_keyfile);
425 if (res->res_dir.tls_dhfile) {
426 free(res->res_dir.tls_dhfile);
428 if (res->res_dir.tls_allowed_cns) {
429 delete res->res_dir.tls_allowed_cns;
433 if (res->res_changer.changer_name) {
434 free(res->res_changer.changer_name);
436 if (res->res_changer.changer_command) {
437 free(res->res_changer.changer_command);
439 if (res->res_changer.device) {
440 delete res->res_changer.device;
444 if (res->res_store.sdaddrs) {
445 free_addresses(res->res_store.sdaddrs);
447 if (res->res_store.sddaddrs) {
448 free_addresses(res->res_store.sddaddrs);
450 if (res->res_store.working_directory) {
451 free(res->res_store.working_directory);
453 if (res->res_store.pid_directory) {
454 free(res->res_store.pid_directory);
456 if (res->res_store.subsys_directory) {
457 free(res->res_store.subsys_directory);
459 if (res->res_store.scripts_directory) {
460 free(res->res_store.scripts_directory);
462 if (res->res_store.tls_ctx) {
463 free_tls_context(res->res_store.tls_ctx);
465 if (res->res_store.tls_ca_certfile) {
466 free(res->res_store.tls_ca_certfile);
468 if (res->res_store.tls_ca_certdir) {
469 free(res->res_store.tls_ca_certdir);
471 if (res->res_store.tls_certfile) {
472 free(res->res_store.tls_certfile);
474 if (res->res_store.tls_keyfile) {
475 free(res->res_store.tls_keyfile);
477 if (res->res_store.tls_dhfile) {
478 free(res->res_store.tls_dhfile);
480 if (res->res_store.tls_allowed_cns) {
481 delete res->res_store.tls_allowed_cns;
485 if (res->res_dev.media_type) {
486 free(res->res_dev.media_type);
488 if (res->res_dev.device_name) {
489 free(res->res_dev.device_name);
491 if (res->res_dev.changer_name) {
492 free(res->res_dev.changer_name);
494 if (res->res_dev.changer_command) {
495 free(res->res_dev.changer_command);
497 if (res->res_dev.alert_command) {
498 free(res->res_dev.alert_command);
500 if (res->res_dev.spool_directory) {
501 free(res->res_dev.spool_directory);
503 if (res->res_dev.mount_point) {
504 free(res->res_dev.mount_point);
506 if (res->res_dev.mount_command) {
507 free(res->res_dev.mount_command);
509 if (res->res_dev.unmount_command) {
510 free(res->res_dev.unmount_command);
512 if (res->res_dev.write_part_command) {
513 free(res->res_dev.write_part_command);
515 if (res->res_dev.free_space_command) {
516 free(res->res_dev.free_space_command);
520 if (res->res_msgs.mail_cmd) {
521 free(res->res_msgs.mail_cmd);
523 if (res->res_msgs.operator_cmd) {
524 free(res->res_msgs.operator_cmd);
526 free_msgs_res((MSGS *)res); /* free message resource */
530 Dmsg1(0, _("Unknown resource type %d\n"), type);
533 /* Common stuff again -- free the resource, recurse to next one */
538 free_resource(nres, type);
542 /* Save the new resource by chaining it into the head list for
543 * the resource. If this is pass 2, we update any resource
546 void save_resource(int type, RES_ITEM *items, int pass)
549 int rindex = type - r_first;
554 * Ensure that all required items are present
556 for (i=0; items[i].name; i++) {
557 if (items[i].flags & ITEM_REQUIRED) {
558 if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) {
559 Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"),
560 items[i].name, resources[rindex]);
563 /* If this triggers, take a look at lib/parse_conf.h */
564 if (i >= MAX_RES_ITEMS) {
565 Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]);
569 /* During pass 2, we looked up pointers to all the resources
570 * referrenced in the current resource, , now we
571 * must copy their address from the static record to the allocated
578 /* Resources not containing a resource */
583 /* Resources containing a resource or an alist */
585 if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) {
586 Emsg1(M_ERROR_TERM, 0, _("Cannot find Director resource %s\n"), res_all.res_dir.hdr.name);
588 res->res_dir.tls_allowed_cns = res_all.res_dir.tls_allowed_cns;
591 if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) {
592 Emsg1(M_ERROR_TERM, 0, _("Cannot find Storage resource %s\n"), res_all.res_dir.hdr.name);
594 res->res_store.messages = res_all.res_store.messages;
595 res->res_store.tls_allowed_cns = res_all.res_store.tls_allowed_cns;
598 if ((res = (URES *)GetResWithName(type, res_all.res_changer.hdr.name)) == NULL) {
599 Emsg1(M_ERROR_TERM, 0, _("Cannot find AutoChanger resource %s\n"),
600 res_all.res_changer.hdr.name);
602 /* we must explicitly copy the device alist pointer */
603 res->res_changer.device = res_all.res_changer.device;
605 * Now update each device in this resource to point back
606 * to the changer resource.
608 foreach_alist(dev, res->res_changer.device) {
609 dev->changer_res = (AUTOCHANGER *)&res->res_changer;
611 if ((errstat = pthread_mutex_init(&res->res_changer.changer_mutex, NULL)) != 0) {
613 Jmsg1(NULL, M_ERROR_TERM, 0, _("Unable to init mutex: ERR=%s\n"),
614 be.bstrerror(errstat));
618 printf(_("Unknown resource type %d\n"), type);
624 if (res_all.res_dir.hdr.name) {
625 free(res_all.res_dir.hdr.name);
626 res_all.res_dir.hdr.name = NULL;
628 if (res_all.res_dir.hdr.desc) {
629 free(res_all.res_dir.hdr.desc);
630 res_all.res_dir.hdr.desc = NULL;
635 /* The following code is only executed on pass 1 */
638 size = sizeof(DIRRES);
641 size = sizeof(STORES);
644 size = sizeof(DEVRES);
650 size = sizeof(AUTOCHANGER);
653 printf(_("Unknown resource type %d\n"), type);
660 res = (URES *)malloc(size);
661 memcpy(res, &res_all, size);
662 if (!res_head[rindex]) {
663 res_head[rindex] = (RES *)res; /* store first entry */
666 /* Add new res to end of chain */
667 for (last=next=res_head[rindex]; next; next=next->next) {
669 if (strcmp(next->name, res->res_dir.hdr.name) == 0) {
670 Emsg2(M_ERROR_TERM, 0,
671 _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"),
672 resources[rindex].name, res->res_dir.hdr.name);
675 last->next = (RES *)res;
676 Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type),
677 res->res_dir.hdr.name);