source: trunk/server/source3/lib/fault.c@ 811

Last change on this file since 811 was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 9.5 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 Critical Fault handling
4 Copyright (C) Andrew Tridgell 1992-1998
5 Copyright (C) Tim Prouty 2009
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "includes.h"
22#include "system/filesys.h"
23
24#ifdef HAVE_SYS_SYSCTL_H
25#include <sys/sysctl.h>
26#endif
27
28
29#ifdef HAVE_SYS_PRCTL_H
30#include <sys/prctl.h>
31#endif
32
33static void (*cont_fn)(void *);
34static char *corepath;
35
36/*******************************************************************
37report a fault
38********************************************************************/
39static void fault_report(int sig)
40{
41 static int counter;
42
43 if (counter) _exit(1);
44
45 counter++;
46
47 DEBUGSEP(0);
48 DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)sys_getpid(),samba_version_string()));
49 DEBUG(0,("\nPlease read the Trouble-Shooting section of the Samba3-HOWTO\n"));
50 DEBUG(0,("\nFrom: http://www.samba.org/samba/docs/Samba3-HOWTO.pdf\n"));
51 DEBUGSEP(0);
52
53 smb_panic("internal error");
54
55 if (cont_fn) {
56 cont_fn(NULL);
57#ifndef __OS2__ /* don't use the built in signal capture stuff - prefer native handling of errors */
58#ifdef SIGSEGV
59 CatchSignal(SIGSEGV, SIG_DFL);
60#endif
61#ifdef SIGBUS
62 CatchSignal(SIGBUS, SIG_DFL);
63#endif
64#ifdef SIGABRT
65 CatchSignal(SIGABRT, SIG_DFL);
66#endif
67#endif
68 return; /* this should cause a core dump */
69 }
70 exit(1);
71}
72
73/****************************************************************************
74catch serious errors
75****************************************************************************/
76static void sig_fault(int sig)
77{
78 fault_report(sig);
79}
80
81/*******************************************************************
82setup our fault handlers
83********************************************************************/
84void fault_setup(void (*fn)(void *))
85{
86 cont_fn = fn;
87
88#ifndef __OS2__ /* don't use the built in signal capture stuff - prefer native handling of errors */
89#ifdef SIGSEGV
90 CatchSignal(SIGSEGV, sig_fault);
91#endif
92#ifdef SIGBUS
93 CatchSignal(SIGBUS, sig_fault);
94#endif
95#ifdef SIGABRT
96 CatchSignal(SIGABRT, sig_fault);
97#endif
98#endif
99}
100
101/**
102 * Build up the default corepath as "<logbase>/cores/<progname>"
103 */
104static char *get_default_corepath(const char *logbase, const char *progname)
105{
106 char *tmp_corepath;
107
108 /* Setup core dir in logbase. */
109 tmp_corepath = talloc_asprintf(NULL, "%s/cores", logbase);
110 if (!tmp_corepath)
111 return NULL;
112
113 if ((mkdir(tmp_corepath, 0700) == -1) && errno != EEXIST)
114 goto err_out;
115
116 if (chmod(tmp_corepath, 0700) == -1)
117 goto err_out;
118
119 talloc_free(tmp_corepath);
120
121 /* Setup progname-specific core subdir */
122 tmp_corepath = talloc_asprintf(NULL, "%s/cores/%s", logbase, progname);
123 if (!tmp_corepath)
124 return NULL;
125
126 if (mkdir(tmp_corepath, 0700) == -1 && errno != EEXIST)
127 goto err_out;
128
129 if (chown(tmp_corepath, getuid(), getgid()) == -1)
130 goto err_out;
131
132 if (chmod(tmp_corepath, 0700) == -1)
133 goto err_out;
134
135 return tmp_corepath;
136
137 err_out:
138 talloc_free(tmp_corepath);
139 return NULL;
140}
141
142/**
143 * Get the FreeBSD corepath.
144 *
145 * On FreeBSD the current working directory is ignored when creating a core
146 * file. Instead the core directory is controlled via sysctl. This consults
147 * the value of "kern.corefile" so the correct corepath can be printed out
148 * before dump_core() calls abort.
149 */
150#if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
151static char *get_freebsd_corepath(void)
152{
153 char *tmp_corepath = NULL;
154 char *end = NULL;
155 size_t len = 128;
156 int ret;
157
158 /* Loop with increasing sizes so we don't allocate too much. */
159 do {
160 if (len > 1024) {
161 goto err_out;
162 }
163
164 tmp_corepath = (char *)talloc_realloc(NULL, tmp_corepath,
165 char, len);
166 if (!tmp_corepath) {
167 return NULL;
168 }
169
170 ret = sysctlbyname("kern.corefile", tmp_corepath, &len, NULL,
171 0);
172 if (ret == -1) {
173 if (errno != ENOMEM) {
174 DEBUG(0, ("sysctlbyname failed getting "
175 "kern.corefile %s\n",
176 strerror(errno)));
177 goto err_out;
178 }
179
180 /* Not a large enough array, try a bigger one. */
181 len = len << 1;
182 }
183 } while (ret == -1);
184
185 /* Strip off the common filename expansion */
186 if ((end = strrchr_m(tmp_corepath, '/'))) {
187 *end = '\0';
188 }
189
190 return tmp_corepath;
191
192 err_out:
193 if (tmp_corepath) {
194 talloc_free(tmp_corepath);
195 }
196 return NULL;
197}
198#endif
199
200#if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
201
202/**
203 * Get the Linux corepath.
204 *
205 * On Linux the contents of /proc/sys/kernel/core_pattern indicates the
206 * location of the core path.
207 */
208static char *get_linux_corepath(void)
209{
210 char *end;
211 int fd;
212 char *result;
213
214 fd = open("/proc/sys/kernel/core_pattern", O_RDONLY, 0);
215 if (fd == -1) {
216 return NULL;
217 }
218
219 result = afdgets(fd, NULL, 0);
220 close(fd);
221
222 if (result == NULL) {
223 return NULL;
224 }
225
226 if (result[0] != '/') {
227 /*
228 * No absolute path, use the default (cwd)
229 */
230 TALLOC_FREE(result);
231 return NULL;
232 }
233 /* Strip off the common filename expansion */
234
235 end = strrchr_m(result, '/');
236
237 if ((end != result) /* this would be the only / */
238 && (end != NULL)) {
239 *end = '\0';
240 }
241 return result;
242}
243#endif
244
245
246/**
247 * Try getting system-specific corepath if one exists.
248 *
249 * If the system doesn't define a corepath, then the default is used.
250 */
251static char *get_corepath(const char *logbase, const char *progname)
252{
253#if (defined(FREEBSD) && defined(HAVE_SYSCTLBYNAME))
254 char *tmp_corepath = NULL;
255 tmp_corepath = get_freebsd_corepath();
256
257 /* If this has been set correctly, we're done. */
258 if (tmp_corepath) {
259 return tmp_corepath;
260 }
261#endif
262
263#if defined(HAVE_SYS_KERNEL_PROC_CORE_PATTERN)
264 char *tmp_corepath = NULL;
265 tmp_corepath = get_linux_corepath();
266
267 /* If this has been set correctly, we're done. */
268 if (tmp_corepath) {
269 return tmp_corepath;
270 }
271#endif
272
273 /* Fall back to the default. */
274 return get_default_corepath(logbase, progname);
275}
276
277/*******************************************************************
278make all the preparations to safely dump a core file
279********************************************************************/
280
281void dump_core_setup(const char *progname)
282{
283 char *logbase = NULL;
284 char *end = NULL;
285
286 if (lp_logfile() && *lp_logfile()) {
287 if (asprintf(&logbase, "%s", lp_logfile()) < 0) {
288 return;
289 }
290 if ((end = strrchr_m(logbase, '/'))) {
291 *end = '\0';
292 }
293 } else {
294 /* We will end up here if the log file is given on the command
295 * line by the -l option but the "log file" option is not set
296 * in smb.conf.
297 */
298 if (asprintf(&logbase, "%s", get_dyn_LOGFILEBASE()) < 0) {
299 return;
300 }
301 }
302
303 SMB_ASSERT(progname != NULL);
304
305 corepath = get_corepath(logbase, progname);
306 if (!corepath) {
307 DEBUG(0, ("Unable to setup corepath for %s: %s\n", progname,
308 strerror(errno)));
309 goto out;
310 }
311
312
313#ifdef HAVE_GETRLIMIT
314#ifdef RLIMIT_CORE
315 {
316 struct rlimit rlp;
317 getrlimit(RLIMIT_CORE, &rlp);
318 rlp.rlim_cur = MAX(16*1024*1024,rlp.rlim_cur);
319 setrlimit(RLIMIT_CORE, &rlp);
320 getrlimit(RLIMIT_CORE, &rlp);
321 DEBUG(3,("Maximum core file size limits now %d(soft) %d(hard)\n",
322 (int)rlp.rlim_cur,(int)rlp.rlim_max));
323 }
324#endif
325#endif
326
327 /* FIXME: if we have a core-plus-pid facility, configurably set
328 * this up here.
329 */
330 out:
331 SAFE_FREE(logbase);
332}
333
334 void dump_core(void)
335{
336 static bool called;
337
338 if (called) {
339 DEBUG(0, ("dump_core() called recursive\n"));
340 exit(1);
341 }
342 called = true;
343
344 /* Note that even if core dumping has been disabled, we still set up
345 * the core path. This is to handle the case where core dumping is
346 * turned on in smb.conf and the relevant daemon is not restarted.
347 */
348 if (!lp_enable_core_files()) {
349 DEBUG(0, ("Exiting on internal error (core file administratively disabled)\n"));
350 exit(1);
351 }
352
353#if DUMP_CORE
354 /* If we're running as non root we might not be able to dump the core
355 * file to the corepath. There must not be an unbecome_root() before
356 * we call abort(). */
357 if (geteuid() != sec_initial_uid()) {
358 become_root();
359 }
360
361 if (corepath == NULL) {
362 DEBUG(0, ("Can not dump core: corepath not set up\n"));
363 exit(1);
364 }
365
366 if (*corepath != '\0') {
367 /* The chdir might fail if we dump core before we finish
368 * processing the config file.
369 */
370 if (chdir(corepath) != 0) {
371 DEBUG(0, ("unable to change to %s\n", corepath));
372 DEBUGADD(0, ("refusing to dump core\n"));
373 exit(1);
374 }
375
376 DEBUG(0,("dumping core in %s\n", corepath));
377 }
378
379 umask(~(0700));
380 dbgflush();
381
382#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
383 /* On Linux we lose the ability to dump core when we change our user
384 * ID. We know how to dump core safely, so let's make sure we have our
385 * dumpable flag set.
386 */
387 prctl(PR_SET_DUMPABLE, 1);
388#endif
389
390 /* Ensure we don't have a signal handler for abort. */
391#ifdef SIGABRT
392 CatchSignal(SIGABRT, SIG_DFL);
393#endif
394
395 abort();
396
397#else /* DUMP_CORE */
398 exit(1);
399#endif /* DUMP_CORE */
400}
401
Note: See TracBrowser for help on using the repository browser.