BRL-CAD
crashreport.c
Go to the documentation of this file.
1 /* C R A S H R E P O R T . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2007-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 /* system headers */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 
29 #include "bu/file.h"
30 #include "bu/log.h"
31 #include "bu/parallel.h"
32 #include "brlcad_ident.h"
33 
34 
35 #define CR_BUFSIZE 2048
36 static char buffer[CR_BUFSIZE] = {0};
37 static FILE *fp = NULL;
38 static FILE *popenfp = NULL;
39 static time_t now;
40 static const char *path = NULL;
41 
42 
43 int
45 {
46  if (UNLIKELY(!filename || strlen(filename) == 0)) {
47  return 0;
48  }
49 
50  /* vat time ist? */
51  (void)time(&now);
52 
53  path = bu_argv0_full_path();
54 
55  /* do our own expansion to avoid heap allocation */
56  snprintf(buffer, CR_BUFSIZE, "******************************************\n\n"
57  "%s\n" /* version info */
58  "Command: %s\n" /* program name */
59  "Process: %d\n" /* pid */
60  "Path: %s\n" /* which binary */
61  "Date: %s\n", /* date/time */
62  brlcad_ident("Crash Report"),
64  bu_process_id(),
65  path ? path : "Unknown",
66  ctime(&now));
67 
68  fp = fopen(filename, "ab");
69  if (UNLIKELY(!fp || ferror(fp))) {
70  perror("unable to open crash report file");
71  bu_log("ERROR: Unable to open crash report file [%s]\n", filename);
72  return 0;
73  }
74 
75  /* make the file stream unbuffered */
76  if (setvbuf(fp, (char *)NULL, _IONBF, 0) != 0) {
77  perror("unable to make stream unbuffered");
78  }
79 
80  /* print the report header */
81  if (fwrite(buffer, 1, strlen(buffer), fp) != strlen(buffer)) {
82  /* cannot bomb */
83  bu_log("ERROR: Unable to write to crash report file [%s]\n", filename);
84  (void)fclose(fp);
85  fp = NULL;
86  return 0;
87  }
88 
89  /* write out the backtrace */
90  fprintf(fp, "Call stack backtrace (thread %d):\n", bu_parallel_id());
91  fflush(fp);
92  if (bu_backtrace(fp) == 0) {
93  bu_log("WARNING: Unable to obtain a call stack backtrace\n");
94  }
95 
96  /* write out operating system information */
97  path = bu_which("uname");
98  if (path) {
99  snprintf(buffer, CR_BUFSIZE, "%s -a 2>&1", path);
100 #if defined(HAVE_POPEN) && !defined(STRICT_FLAGS)
101  popenfp = popen(buffer, "r");
102  if (!popenfp) {
103  perror("unable to popen uname");
104  bu_log("WARNING: Unable to obtain uname information\n");
105  }
106 #endif
107  if (popenfp) {
108  fprintf(fp, "\nSystem characteristics:\n");
109  fflush(fp);
110  while (bu_fgets(buffer, CR_BUFSIZE, popenfp)) {
111  size_t ret;
112  size_t len;
113 
114  len = strlen(buffer);
115  ret = fwrite(buffer, 1, len, fp);
116  if (ret != len)
117  perror("fwrite failed");
118  }
119  }
120 #if defined(HAVE_POPEN) && !defined(STRICT_FLAGS)
121  (void)pclose(popenfp);
122 #endif
123  popenfp = NULL;
124  path = NULL;
125  }
126 
127  /* write out kernel and hardware information */
128  path = bu_which("sysctl");
129  if (path) {
130  /* need 2>&1 to capture stderr junk from sysctl on Mac OS X for kern.exec */
131  snprintf(buffer, CR_BUFSIZE, "%s -a 2>&1", path);
132 #if defined(HAVE_POPEN) && !defined(STRICT_FLAGS)
133  popenfp = popen(buffer, "r");
134  if (popenfp == (FILE *)NULL) {
135  perror("unable to popen sysctl");
136  bu_log("WARNING: Unable to obtain sysctl information\n");
137  }
138 #endif
139  if (popenfp != (FILE *)NULL) {
140  fprintf(fp, "\nSystem information:\n");
141  fflush(fp);
142  while (bu_fgets(buffer, CR_BUFSIZE, popenfp)) {
143  size_t ret;
144  size_t len;
145 
146  len = strlen(buffer);
147  if ((len == 0)
148  || ((len == 1) && (buffer[0] == '\n')))
149  {
150  continue;
151  }
152 
153  ret = fwrite(buffer, 1, len, fp);
154  if (ret != len)
155  perror("fwrite failed");
156  }
157  }
158 #if defined(HAVE_POPEN) && !defined(STRICT_FLAGS)
159  (void)pclose(popenfp);
160 #endif
161  popenfp = NULL;
162  path = NULL;
163  }
164 
165  memset(buffer, 0, CR_BUFSIZE);
166  fprintf(fp, "\n");
167  fflush(fp);
168  (void)fclose(fp);
169  fp = NULL;
170 
171  /* success */
172  return 1;
173 }
174 
175 /*
176  * Local Variables:
177  * tab-width: 8
178  * mode: C
179  * indent-tabs-mode: t
180  * c-file-style: "stroustrup"
181  * End:
182  * ex: shiftwidth=4 tabstop=8
183  */
char filename[MAXLENGTH]
Definition: human.c:105
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int bu_crashreport(const char *filename)
Definition: crashreport.c:44
int bu_process_id(void)
Definition: process.c:31
Header file for the BRL-CAD common definitions.
long time(time_t *)
void * memset(void *s, int c, size_t n)
const char * bu_which(const char *cmd)
Definition: which.c:43
const char * bu_getprogname(void)
Definition: progname.c:96
int bu_parallel_id(void)
Definition: parallel.c:152
int bu_backtrace(FILE *fp)
Definition: backtrace.c:300
#define CR_BUFSIZE
Definition: crashreport.c:35
char * bu_fgets(char *s, int size, FILE *stream)
Definition: fgets.c:31
const char * bu_argv0_full_path(void)
Definition: progname.c:48
#define UNLIKELY(expression)
Definition: common.h:282