BRL-CAD
bomb.c
Go to the documentation of this file.
1 /* B O M B . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2004-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 
21 #include "common.h"
22 
23 #include <stdlib.h>
24 #include <ctype.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include "bio.h"
28 
29 #include "bu/debug.h"
30 #include "bu/file.h"
31 #include "bu/log.h"
32 #include "bu/parallel.h"
33 
34 /**
35  * list of callbacks to call during bu_bomb.
36  */
38  {
40  &bomb_hook_list.l,
41  &bomb_hook_list.l
42  },
43  NULL,
44  ((void *)0)
45 };
46 
47 
48 /* failsafe storage to help ensure graceful shutdown */
49 static char *bomb_failsafe = NULL;
50 
51 /* used for tty printing */
52 static int fd = -1;
53 
54 #if defined(DEBUG)
55 /* used for crash reporting */
56 static char tracefile[512] = {0};
57 #endif
58 
59 /* release memory on application exit */
60 static void
61 _freebomb_failsafe(void)
62 {
63  if (bomb_failsafe) {
64  free(bomb_failsafe);
65  bomb_failsafe = NULL;
66  }
67 }
68 
69 
70 int
72 {
73  if (bomb_failsafe) {
74  return 1;
75  }
76  /* cannot use bu_*alloc here */
77  bomb_failsafe = (char *)malloc(65536);
78  atexit(_freebomb_failsafe);
79  return 1;
80 }
81 
82 
83 void
85 {
86  bu_hook_add(&bomb_hook_list, func, clientdata);
87 }
88 
89 
90 void
91 bu_bomb(const char *str)
92 {
93 
94  /* First thing, always always always try to print the string.
95  * Avoid passing additional format arguments so as to avoid
96  * buffer allocations inside fprintf().
97  */
98  if (str && (strlen(str) > 0)) {
99  fputc('\n', stderr);
100  fputs(str, stderr);
101  fputc('\n', stderr);
102  fflush(stderr);
103  }
104 
105  /* release the failsafe allocation to help get through to the end */
106  _freebomb_failsafe();
107 
108  /* MGED would like to be able to additional logging, do callbacks. */
109  if (BU_LIST_NON_EMPTY(&bomb_hook_list.l)) {
110  bu_hook_call(&bomb_hook_list, (void *)str);
111  }
112 
114  /* Application is catching fatal errors */
115  longjmp(bu_jmpbuf[bu_parallel_id()], 1);
116  /* NOTREACHED */
117  }
118 
119 #ifdef HAVE_UNISTD_H
120  /*
121  * No application level error handling,
122  * Go to extra pains to ensure that user gets to see this message.
123  * For example, mged hijacks output sent to stderr.
124  */
125  {
126  fd = open("/dev/tty", 1);
127  if (LIKELY(fd > 0)) {
128  if (str && (strlen(str) > 0)) {
129  size_t len;
130  ssize_t ret;
131 
132  len = strlen(str);
133  ret = write(fd, str, len);
134  if (ret != (ssize_t)len)
135  perror("write failed");
136 
137  ret = write(fd, "\n", 1);
138  if (ret != 1)
139  perror("write failed");
140  }
141  close(fd);
142  }
143  }
144 #endif
145 
146 #if defined(DEBUG)
147  /* save a backtrace, should hopefully have debug symbols */
148  {
149  /* If the file already exists, there's probably another thread
150  * writing out a report for the current process. Acquire a
151  * mapped file semaphore so we only have one thread writing to
152  * the file at a time (can't just use BU_SEM_SYSCALL).
153  */
155  snprintf(tracefile, 512, "%s-%d-bomb.log", bu_getprogname(), bu_process_id());
156  if (LIKELY(!bu_file_exists(tracefile, NULL))) {
158  fputs("Saving stack trace to ", stderr);
159  fputs(tracefile, stderr);
160  fputc('\n', stderr);
161  fflush(stderr);
163 
164  bu_crashreport(tracefile);
165  }
167  }
168 #endif
169 
170  /* try to save a core dump */
173  fputs("Causing intentional core dump due to debug flag\n", stdout);
174  fputs("Causing intentional core dump due to debug flag\n", stderr);
175  fflush(stdout);
176  fflush(stderr);
178 
179  fd = open("/dev/tty", 1);
180  if (LIKELY(fd > 0)) {
181  ssize_t ret;
182  ret = write(fd, "Causing intentional core dump due to debug flag\n", 48);
183  if (ret != 48)
184  perror("write failed");
185  close(fd);
186  }
187  abort(); /* should dump if ulimit is non-zero */
188  }
189 
190  exit(12);
191 }
192 
193 
194 void
195 bu_exit(int status, const char *fmt, ...)
196 {
197  if (LIKELY(fmt && strlen(fmt) > 0)) {
198  va_list ap;
199  struct bu_vls message = BU_VLS_INIT_ZERO;
200 
201  va_start(ap, fmt);
202 
203  bu_vls_vprintf(&message, fmt, ap);
204 
205  /* don't dump a backtrace, etc. */
206  if (!BU_SETJUMP) {
207  bu_bomb(bu_vls_addr(&message));
208  }
209  BU_UNSETJUMP;
210 
211  bu_vls_free(&message);
212  }
213 
214  exit(status);
215 }
216 
217 /*
218  * Local Variables:
219  * mode: C
220  * tab-width: 8
221  * indent-tabs-mode: t
222  * c-file-style: "stroustrup"
223  * End:
224  * ex: shiftwidth=4 tabstop=8
225  */
ptrdiff_t ssize_t
Definition: common.h:119
#define LIKELY(expression)
Definition: common.h:261
void bu_semaphore_acquire(unsigned int i)
Definition: semaphore.c:180
void bu_hook_add(struct bu_hook_list *hlp, bu_hook_t func, void *clientdata)
Definition: hook.c:39
int bu_crashreport(const char *filename)
Definition: crashreport.c:44
int bu_process_id(void)
Definition: process.c:31
void * clientdata
Definition: log.h:73
Header file for the BRL-CAD common definitions.
int bu_setjmp_valid[MAX_PSW]
Definition: globals.c:74
#define BU_LIST_NON_EMPTY(hp)
Definition: list.h:296
struct bu_hook_list bomb_hook_list
Definition: bomb.c:37
#define BU_SEM_MAPPEDFILE
Definition: parallel.h:181
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
void bu_exit(int status, const char *fmt,...)
Definition: bomb.c:195
struct bu_list l
Definition: log.h:71
const char * bu_getprogname(void)
Definition: progname.c:96
void bu_hook_call(struct bu_hook_list *hlp, void *buf)
Definition: hook.c:68
int bu_parallel_id(void)
Definition: parallel.c:152
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
void bu_vls_vprintf(struct bu_vls *vls, const char *fmt, va_list ap)
Definition: vls_vprintf.c:380
void bu_semaphore_release(unsigned int i)
Definition: semaphore.c:218
#define BU_DEBUG_COREDUMP
Definition: debug.h:53
int bu_debug
Definition: globals.c:87
#define BU_SEM_SYSCALL
Definition: parallel.h:178
#define BU_UNSETJUMP
Definition: parallel.h:193
int(* bu_hook_t)(void *, void *)
Definition: log.h:68
void bu_bomb_add_hook(bu_hook_t func, void *clientdata)
Definition: bomb.c:84
#define BU_SETJUMP
Definition: parallel.h:192
jmp_buf bu_jmpbuf[MAX_PSW]
Definition: globals.c:84
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int bu_bomb_failsafe_init(void)
Definition: bomb.c:71
#define BU_LIST_HEAD_MAGIC
Definition: magic.h:56
Definition: vls.h:56
void bu_bomb(const char *str)
Definition: bomb.c:91
int bu_file_exists(const char *path, int *fd)
Definition: file.c:57
#define UNLIKELY(expression)
Definition: common.h:282