1 /*
2 Bacula(R) - The Network Backup Solution
3
4 Copyright (C) 2000-2020 Kern Sibbald
5
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
8
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
13
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
16
17 Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20 * Bacula conf to json
21 *
22 * Kern Sibbald, MMXII
23 *
24 */
25
26 #include "bacula.h"
27 #include "stored.h"
28
29 /* Imported functions */
30 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
31
32 /* Imported variables */
33 #if defined(_MSC_VER)
34 extern "C" { // work around visual compiler mangling variables
35 extern URES res_all;
36 }
37 #else
38 extern URES res_all;
39 #endif
40 extern s_kw msg_types[];
41 extern s_kw dev_types[];
42 extern s_kw tapelabels[];
43 extern s_kw cloud_drivers[];
44 extern s_kw dedup_drivers[];
45 extern s_kw trunc_opts[];
46 extern s_kw upload_opts[];
47 extern s_kw proto_opts[];
48 extern s_kw uri_opts[];
49 extern s_kw restore_prio_opts[];
50
51 extern RES_TABLE resources[];
52
53 typedef struct
54 {
55 bool do_list;
56 bool do_one;
57 bool do_only_data;
58 char *resource_type;
59 char *resource_name;
60 regex_t directive_reg;
61 } display_filter;
62
63 /* Forward referenced functions */
64 void terminate_stored(int sig);
65 static int check_resources();
66 static void dump_json(display_filter *filter);
67
68 #define CONFIG_FILE "bacula-sd.conf" /* Default config file */
69
70 /* Global variables exported */
71 STORES *me = NULL; /* our Global resource */
72
73 char *configfile = NULL;
74
75 /* Global static variables */
76 static CONFIG *config;
77 static void sendit(void *sock, const char *fmt, ...);
78
usage()79 static void usage()
80 {
81 fprintf(stderr, _(
82 PROG_COPYRIGHT
83 "\n%sVersion: %s (%s)\n\n"
84 "Usage: bsdjson [options] [config_file]\n"
85 " -r <res> get resource type <res>\n"
86 " -n <name> get resource <name>\n"
87 " -l <dirs> get only directives matching dirs (use with -r)\n"
88 " -D get only data\n"
89 " -c <file> use <file> as configuration file\n"
90 " -d <nn> set debug level to <nn>\n"
91 " -dt print timestamp in debug output\n"
92 " -t test - read config and exit\n"
93 " -v verbose user messages\n"
94 " -? print this message.\n"
95 "\n"), 2012, BDEMO, VERSION, BDATE);
96
97 exit(1);
98 }
99
100 /*********************************************************************
101 *
102 * Main Bacula Unix Storage Daemon
103 *
104 */
105 #if defined(HAVE_WIN32)
106 #define main BaculaMain
107 #endif
108
main(int argc,char * argv[])109 int main (int argc, char *argv[])
110 {
111 int ch;
112 bool test_config = false;
113 display_filter filter;
114 memset(&filter, 0, sizeof(filter));
115
116 setlocale(LC_ALL, "");
117 bindtextdomain("bacula", LOCALEDIR);
118 textdomain("bacula");
119
120 my_name_is(argc, argv, "bacula-sd");
121 init_msg(NULL, NULL);
122
123 while ((ch = getopt(argc, argv, "Dc:d:tv?r:n:l:")) != -1) {
124 switch (ch) {
125 case 'D':
126 filter.do_only_data = true;
127 break;
128
129 case 'l':
130 filter.do_list = true;
131 /* Might use something like -l '^(Name|Description)$' */
132 filter.do_list = true;
133 if (regcomp(&filter.directive_reg, optarg, REG_EXTENDED) != 0) {
134 Jmsg((JCR *)NULL, M_ERROR_TERM, 0,
135 _("Please use valid -l argument: %s\n"), optarg);
136 }
137 break;
138
139 case 'r':
140 filter.resource_type = optarg;
141 break;
142
143 case 'n':
144 filter.resource_name = optarg;
145 break;
146
147 case 'c': /* configuration file */
148 if (configfile != NULL) {
149 free(configfile);
150 }
151 configfile = bstrdup(optarg);
152 break;
153
154 case 'd': /* debug level */
155 if (*optarg == 't') {
156 dbg_timestamp = true;
157 } else {
158 debug_level = atoi(optarg);
159 if (debug_level <= 0) {
160 debug_level = 1;
161 }
162 }
163 break;
164
165 case 't':
166 test_config = true;
167 break;
168
169 case 'v': /* verbose */
170 verbose++;
171 break;
172
173 case '?':
174 default:
175 usage();
176 break;
177 }
178 }
179 argc -= optind;
180 argv += optind;
181
182 if (argc) {
183 if (configfile != NULL) {
184 free(configfile);
185 }
186 configfile = bstrdup(*argv);
187 argc--;
188 argv++;
189 }
190
191 if (argc) {
192 usage();
193 }
194
195 if (filter.do_list && !filter.resource_type) {
196 usage();
197 }
198
199 if (filter.resource_type && filter.resource_name) {
200 filter.do_one = true;
201 }
202
203 if (configfile == NULL || configfile[0] == 0) {
204 configfile = bstrdup(CONFIG_FILE);
205 }
206
207 if (test_config && verbose > 0) {
208 char buf[1024];
209 find_config_file(configfile, buf, sizeof(buf));
210 sendit(NULL, "config_file=%s\n", buf);
211 }
212
213 config = New(CONFIG());
214 config->encode_password(false);
215 parse_sd_config(config, configfile, M_ERROR_TERM);
216
217 if (!check_resources()) {
218 Jmsg((JCR *)NULL, M_ERROR_TERM, 0, _("Please correct configuration file: %s\n"), configfile);
219 }
220
221 if (test_config) {
222 terminate_stored(0);
223 }
224
225 my_name_is(0, (char **)NULL, me->hdr.name); /* Set our real name */
226
227 dump_json(&filter);
228
229 if (filter.do_list) {
230 regfree(&filter.directive_reg);
231 }
232
233 terminate_stored(0);
234 }
235
display_devtype(HPKT & hpkt)236 static void display_devtype(HPKT &hpkt)
237 {
238 int i;
239 for (i=0; dev_types[i].name; i++) {
240 if (*(int32_t *)(hpkt.ritem->value) == dev_types[i].token) {
241 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
242 dev_types[i].name);
243 return;
244 }
245 }
246 }
247
display_label(HPKT & hpkt)248 static void display_label(HPKT &hpkt)
249 {
250 int i;
251 for (i=0; tapelabels[i].name; i++) {
252 if (*(int32_t *)(hpkt.ritem->value) == tapelabels[i].token) {
253 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
254 tapelabels[i].name);
255 return;
256 }
257 }
258 }
259
display_cloud_driver(HPKT & hpkt)260 static void display_cloud_driver(HPKT &hpkt)
261 {
262 int i;
263 for (i=0; cloud_drivers[i].name; i++) {
264 if (*(int32_t *)(hpkt.ritem->value) == cloud_drivers[i].token) {
265 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
266 cloud_drivers[i].name);
267 return;
268 }
269 }
270 }
271
272 #ifdef SD_DEDUP_SUPPORT
display_dedup_driver(HPKT & hpkt)273 static void display_dedup_driver(HPKT &hpkt)
274 {
275 int i;
276 for (i=0; dedup_drivers[i].name; i++) {
277 if (*(int32_t *)(hpkt.ritem->value) == dedup_drivers[i].token) {
278 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
279 dedup_drivers[i].name);
280 return;
281 }
282 }
283 }
284 #endif
285
display_protocol(HPKT & hpkt)286 static void display_protocol(HPKT &hpkt)
287 {
288 int i;
289 for (i=0; proto_opts[i].name; i++) {
290 if (*(int32_t *)(hpkt.ritem->value) == proto_opts[i].token) {
291 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
292 proto_opts[i].name);
293 return;
294 }
295 }
296 }
297
display_truncate_cache(HPKT & hpkt)298 static void display_truncate_cache(HPKT &hpkt)
299 {
300 int i;
301 for (i=0; trunc_opts[i].name; i++) {
302 if (*(int32_t *)(hpkt.ritem->value) == trunc_opts[i].token) {
303 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
304 trunc_opts[i].name);
305 return;
306 }
307 }
308 }
309
display_uri_style(HPKT & hpkt)310 static void display_uri_style(HPKT &hpkt)
311 {
312 int i;
313 for (i=0; uri_opts[i].name; i++) {
314 if (*(int32_t *)(hpkt.ritem->value) == uri_opts[i].token) {
315 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
316 uri_opts[i].name);
317 return;
318 }
319 }
320 }
321
display_upload(HPKT & hpkt)322 static void display_upload(HPKT &hpkt)
323 {
324 int i;
325 for (i=0; upload_opts[i].name; i++) {
326 if (*(int32_t *)(hpkt.ritem->value) == upload_opts[i].token) {
327 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
328 upload_opts[i].name);
329 return;
330 }
331 }
332 }
333
334
display_transfer_priority(HPKT & hpkt)335 static void display_transfer_priority(HPKT &hpkt)
336 {
337 int i;
338 for (i=0; restore_prio_opts[i].name; i++) {
339 if (*(int32_t *)(hpkt.ritem->value) == restore_prio_opts[i].token) {
340 hpkt.sendit(hpkt, "\n \"%s\": \"%s\"", hpkt.ritem->name,
341 restore_prio_opts[i].name);
342 return;
343 }
344 }
345 }
346 /*
347 * Dump out all resources in json format.
348 * Note!!!! This routine must be in this file rather
349 * than in src/lib/parser_conf.c otherwise the pointers
350 * will be all messed up.
351 */
dump_json(display_filter * filter)352 static void dump_json(display_filter *filter)
353 {
354 int resinx, item, directives, first_directive;
355 bool first_res;
356 RES_ITEM *items;
357 RES *res;
358 HPKT hpkt;
359 regmatch_t pmatch[32];
360 STORES *me = (STORES *)GetNextRes(R_STORAGE, NULL);
361
362 if (init_crypto() != 0) {
363 Emsg0(M_ERROR_TERM, 0, _("Cryptography library initialization failed.\n"));
364 }
365
366 init_hpkt(hpkt);
367
368 if (filter->do_only_data) {
369 hpkt.sendit(hpkt, "[");
370
371 /* List resources and directives */
372 /* { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... }
373 * or print a single item
374 */
375 } else if (filter->do_one || filter->do_list) {
376 hpkt.sendit(hpkt, "{");
377
378 } else {
379 /* [ { "Device": { "Name": "aa",.. } }, { "Director": { "Name": "bb", ... } } ]*/
380 hpkt.sendit(hpkt, "[");
381 }
382
383 first_res = true;
384 /* Loop over all resource types */
385 for (resinx=0; resources[resinx].name; resinx++) {
386 if (!resources[resinx].items) {
387 continue; /* skip dummy entries */
388 }
389
390 /* Skip this resource type */
391 if (filter->resource_type &&
392 strcasecmp(filter->resource_type, resources[resinx].name) != 0) {
393 continue;
394 }
395
396 directives = 0;
397 /* Loop over all resources of this type */
398 foreach_rblist(res, res_head[resinx]->res_list) {
399 hpkt.res = res;
400 items = resources[resinx].items;
401 if (!items) {
402 continue;
403 }
404
405 /* Copy the resource into res_all */
406 memcpy(&res_all, res, sizeof(res_all));
407
408 if (filter->resource_name) {
409 bool skip=true;
410 /* The Name should be at the first place, so this is not a real loop */
411 for (item=0; items[item].name; item++) {
412 if (strcasecmp(items[item].name, "Name") == 0) {
413 if (strcasecmp(*(items[item].value), filter->resource_name) == 0) {
414 skip = false;
415 }
416 break;
417 }
418 }
419 if (skip) { /* The name doesn't match, so skip it */
420 continue;
421 }
422 }
423
424 if (first_res) {
425 hpkt.sendit(hpkt, "\n");
426 } else {
427 hpkt.sendit(hpkt, ",\n");
428 }
429
430 if (filter->do_only_data) {
431 hpkt.sendit(hpkt, " {");
432
433 } else if (filter->do_one) {
434 /* Nothing to print */
435
436 /* When sending the list, the form is:
437 * { aa: { Name: aa, Description: aadesc...}, bb: { Name: bb
438 */
439 } else if (filter->do_list) {
440 /* Search and display Name, should be the first item */
441 for (item=0; items[item].name; item++) {
442 if (strcmp(items[item].name, "Name") == 0) {
443 hpkt.sendit(hpkt, "%s: {\n", quote_string(hpkt.edbuf2, *items[item].value));
444 break;
445 }
446 }
447 } else {
448 /* Begin new resource */
449 hpkt.sendit(hpkt, "{\n \"%s\": {", resources[resinx].name);
450 }
451
452 first_res = false;
453 first_directive = 0;
454 directives = 0;
455 for (item=0; items[item].name; item++) {
456 /* Check user argument -l */
457 if (filter->do_list &&
458 regexec(&filter->directive_reg,
459 items[item].name, 32, pmatch, 0) != 0)
460 {
461 continue;
462 }
463
464 hpkt.ritem = &items[item];
465 if (bit_is_set(item, res_all.hdr.item_present)) {
466 if (first_directive++ > 0) printf(",");
467
468 /* 1: found, 0: not found, -1 found but empty */
469 int ret = display_global_item(hpkt);
470 if (ret == -1) {
471 /* Do not print a comma after this empty directive */
472 first_directive = 0;
473 } else if (ret == 1) {
474 /* Fall-through wanted */
475
476 } else if (items[item].handler == store_maxblocksize) {
477 display_int32_pair(hpkt);
478 } else if (items[item].handler == store_devtype) {
479 display_devtype(hpkt);
480 } else if (items[item].handler == store_label) {
481 display_label(hpkt);
482 } else if (items[item].handler == store_cloud_driver) {
483 display_cloud_driver(hpkt);
484 #ifdef SD_DEDUP_SUPPORT
485 } else if (items[item].handler == store_dedup_driver) {
486 display_dedup_driver(hpkt);
487 #endif
488 } else if (items[item].handler == store_protocol) {
489 display_protocol(hpkt);
490 } else if (items[item].handler == store_uri_style) {
491 display_uri_style(hpkt);
492 } else if (items[item].handler == store_truncate) {
493 display_truncate_cache(hpkt);
494 } else if (items[item].handler == store_upload) {
495 display_upload(hpkt);
496 } else if (items[item].handler == store_coll_type) {
497 display_collector_types(hpkt);
498 } else if (items[item].handler == store_transfer_priority) {
499 display_transfer_priority(hpkt);
500 } else {
501 printf("\n \"%s\": \"null\"", items[item].name);
502 }
503 directives++;
504 } else { /* end if is present */
505 /* For some directive, the bitmap is not set (like addresses) */
506 if (me && strcmp(resources[resinx].name, "Storage") == 0) {
507 if (strcmp(items[item].name, "SdPort") == 0) {
508 if (get_first_port_host_order(me->sdaddrs) != items[item].default_value) {
509 if (first_directive++ > 0) hpkt.sendit(hpkt, ",");
510 hpkt.sendit(hpkt, "\n \"SdPort\": %d",
511 get_first_port_host_order(me->sdaddrs));
512 }
513 } else if (me && strcmp(items[item].name, "SdAddress") == 0) {
514 char buf[500];
515 get_first_address(me->sdaddrs, buf, sizeof(buf));
516 if (strcmp(buf, "0.0.0.0") != 0) {
517 if (first_directive++ > 0) hpkt.sendit(hpkt, ",");
518 hpkt.sendit(hpkt, "\n \"SdAddress\": \"%s\"", buf);
519 }
520 }
521 }
522 }
523 if (items[item].flags & ITEM_LAST) {
524 display_last(hpkt); /* If last bit set always call to cleanup */
525 }
526 }
527
528 /* { "aa": { "Name": "aa",.. }, "bb": { "Name": "bb", ... } */
529 if (filter->do_only_data || filter->do_list) {
530 hpkt.sendit(hpkt, "\n }"); /* Finish the Resource with a single } */
531
532 } else {
533 if (filter->do_one) {
534 /* don't print anything */
535
536 } else if (first_directive > 0) {
537 hpkt.sendit(hpkt, "\n }\n}"); /* end of resource */
538
539 } else {
540 hpkt.sendit(hpkt, "}\n }");
541 }
542 }
543
544 } /* End loop over all resources of this type */
545 } /* End loop all resource types */
546
547 if (filter->do_only_data) {
548 hpkt.sendit(hpkt, "\n]\n");
549
550 /* In list context, we are dealing with a hash */
551 } else if (filter->do_one || filter->do_list) {
552 hpkt.sendit(hpkt, "\n}\n");
553
554 } else {
555 hpkt.sendit(hpkt, "\n]\n");
556 }
557 term_hpkt(hpkt);
558 }
559
560
561 /* Check Configuration file for necessary info */
check_resources()562 static int check_resources()
563 {
564 bool OK = true;
565 bool tls_needed;
566 AUTOCHANGER *changer;
567 DEVRES *device;
568
569 me = (STORES *)GetNextRes(R_STORAGE, NULL);
570 if (!me) {
571 Jmsg1(NULL, M_ERROR, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
572 configfile);
573 OK = false;
574 }
575
576 if (GetNextRes(R_STORAGE, (RES *)me) != NULL) {
577 Jmsg1(NULL, M_ERROR, 0, _("Only one Storage resource permitted in %s\n"),
578 configfile);
579 OK = false;
580 }
581 if (GetNextRes(R_DIRECTOR, NULL) == NULL) {
582 Jmsg1(NULL, M_ERROR, 0, _("No Director resource defined in %s. Cannot continue.\n"),
583 configfile);
584 OK = false;
585 }
586 if (GetNextRes(R_DEVICE, NULL) == NULL){
587 Jmsg1(NULL, M_ERROR, 0, _("No Device resource defined in %s. Cannot continue.\n"),
588 configfile);
589 OK = false;
590 }
591
592 if (!me->messages) {
593 me->messages = (MSGS *)GetNextRes(R_MSGS, NULL);
594 if (!me->messages) {
595 Jmsg1(NULL, M_ERROR, 0, _("No Messages resource defined in %s. Cannot continue.\n"),
596 configfile);
597 OK = false;
598 }
599 }
600
601 if (!me->working_directory) {
602 Jmsg1(NULL, M_ERROR, 0, _("No Working Directory defined in %s. Cannot continue.\n"),
603 configfile);
604 OK = false;
605 }
606
607 DIRRES *director;
608 STORES *store;
609 foreach_res(store, R_STORAGE) {
610 /* tls_require implies tls_enable */
611 if (store->tls_require) {
612 if (have_tls) {
613 if (store->tls_certfile || store->tls_keyfile) {
614 store->tls_enable = true;
615 }
616 } else {
617 Jmsg(NULL, M_FATAL, 0, _("TLS required but not configured in Bacula.\n"));
618 OK = false;
619 continue;
620 }
621 }
622
623 tls_needed = store->tls_enable || store->tls_authenticate;
624
625 if (!store->tls_certfile && tls_needed) {
626 Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Storage \"%s\" in %s.\n"),
627 store->hdr.name, configfile);
628 OK = false;
629 }
630
631 if (!store->tls_keyfile && tls_needed) {
632 Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Storage \"%s\" in %s.\n"),
633 store->hdr.name, configfile);
634 OK = false;
635 }
636
637 if ((!store->tls_ca_certfile && !store->tls_ca_certdir) && tls_needed && store->tls_verify_peer) {
638 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
639 " or \"TLS CA Certificate Dir\" are defined for Storage \"%s\" in %s."
640 " At least one CA certificate store is required"
641 " when using \"TLS Verify Peer\".\n"),
642 store->hdr.name, configfile);
643 OK = false;
644 }
645 }
646
647 foreach_res(director, R_DIRECTOR) {
648 /* tls_require implies tls_enable */
649 if (director->tls_require) {
650 if (director->tls_certfile || director->tls_keyfile) {
651 director->tls_enable = true;
652 }
653 }
654
655 tls_needed = director->tls_enable || director->tls_authenticate;
656
657 if (!director->tls_certfile && tls_needed) {
658 Jmsg(NULL, M_FATAL, 0, _("\"TLS Certificate\" file not defined for Director \"%s\" in %s.\n"),
659 director->hdr.name, configfile);
660 OK = false;
661 }
662
663 if (!director->tls_keyfile && tls_needed) {
664 Jmsg(NULL, M_FATAL, 0, _("\"TLS Key\" file not defined for Director \"%s\" in %s.\n"),
665 director->hdr.name, configfile);
666 OK = false;
667 }
668
669 if ((!director->tls_ca_certfile && !director->tls_ca_certdir) && tls_needed && director->tls_verify_peer) {
670 Jmsg(NULL, M_FATAL, 0, _("Neither \"TLS CA Certificate\""
671 " or \"TLS CA Certificate Dir\" are defined for Director \"%s\" in %s."
672 " At least one CA certificate store is required"
673 " when using \"TLS Verify Peer\".\n"),
674 director->hdr.name, configfile);
675 OK = false;
676 }
677 }
678
679 CLOUD *cloud;
680 /* TODO: Can use a table */
681 foreach_res(cloud, R_CLOUD) {
682 if (cloud->driver_type == C_S3_DRIVER ||
683 cloud->driver_type == C_FILE_DRIVER)
684 {
685 if (cloud->host_name == NULL) {
686 Jmsg(NULL, M_FATAL, 0,
687 _("Failed to initialize Cloud. Hostname not defined for Cloud \"%s\"\n"),
688 cloud->hdr.name);
689 OK = false;
690 }
691 }
692 if (cloud->driver_type == C_WAS_DRIVER ||
693 cloud->driver_type == C_S3_DRIVER)
694 {
695 if (cloud->access_key == NULL) {
696 Jmsg(NULL, M_FATAL, 0,
697 _("Failed to initialize Cloud. AccessKey not set for Cloud \"%s\"\n"),
698 cloud->hdr.name);
699 OK = false;
700 }
701 if (cloud->secret_key == NULL) {
702 Jmsg(NULL, M_FATAL, 0,
703 _("Failed to initialize Cloud. SecretKey not set for Cloud \"%s\"\n"),
704 cloud->hdr.name);
705 OK = false;
706 }
707 }
708 }
709 #ifdef SD_DEDUP_SUPPORT
710 DEDUPRES *dedup;
711 foreach_res(dedup, R_DEDUP) {
712 if (dedup->driver_type == D_LEGACY_DRIVER)
713 {
714 if (dedup->dedup_dir == NULL) {
715 Jmsg(NULL, M_FATAL, 0,
716 _("Failed to initialize Dedup. DedupDirectory not defined for Dedup \"%s\"\n"),
717 dedup->hdr.name);
718 OK = false;
719 }
720 }
721 }
722 #endif
723 foreach_res(changer, R_AUTOCHANGER) {
724 foreach_alist(device, changer->device) {
725 device->cap_bits |= CAP_AUTOCHANGER;
726 }
727 }
728
729 return OK;
730 }
731
732 /* Clean up and then exit */
terminate_stored(int sig)733 void terminate_stored(int sig)
734 {
735 static bool in_here = false;
736
737 if (in_here) { /* prevent loops */
738 bmicrosleep(2, 0); /* yield */
739 exit(1);
740 }
741 in_here = true;
742 debug_level = 0; /* turn off any debug */
743
744 if (configfile) {
745 free(configfile);
746 configfile = NULL;
747 }
748 if (config) {
749 delete config;
750 config = NULL;
751 }
752
753 if (debug_level > 10) {
754 print_memory_pool_stats();
755 }
756 term_msg();
757 free(res_head);
758 res_head = NULL;
759 close_memory_pool();
760
761 //sm_dump(false); /* dump orphaned buffers */
762 exit(sig);
763 }
764
sendit(void * sock,const char * fmt,...)765 static void sendit(void *sock, const char *fmt, ...)
766 {
767 char buf[3000];
768 va_list arg_ptr;
769
770 va_start(arg_ptr, fmt);
771 bvsnprintf(buf, sizeof(buf), (char *)fmt, arg_ptr);
772 va_end(arg_ptr);
773 fputs(buf, stdout);
774 fflush(stdout);
775 }
776