diff --git a/MCONFIG.in b/MCONFIG.in index 75cf3de6..70a3c0f0 100644 --- a/MCONFIG.in +++ b/MCONFIG.in @@ -59,6 +59,7 @@ ALL_LDFLAGS = $(LDFLAGS) @LDFLAG_DYNAMIC@ LDFLAGS_STATIC = $(LDFLAGS) @LDFLAG_STATIC@ BUILD_CFLAGS = @BUILD_CFLAGS@ BUILD_LDFLAGS = @BUILD_LDFLAGS@ +RDYNAMIC = @RDYNAMIC@ LINK_BUILD_FLAGS = @LINK_BUILD_FLAGS@ LINK_INSTALL_FLAGS = @LINK_INSTALL_FLAGS@ RM = @RM@ diff --git a/configure b/configure index 6dccb3ce..edfed4e1 100755 --- a/configure +++ b/configure @@ -712,6 +712,7 @@ LINUX_INCLUDE EGREP GREP CPP +RDYNAMIC DLOPEN_LIB OBJEXT EXEEXT @@ -4157,6 +4158,10 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test "$GCC" = yes; then + RDYNAMIC="-rdynamic" + +fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -10086,7 +10091,7 @@ fi done fi -for ac_header in dirent.h errno.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h +for ac_header in dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" @@ -10723,7 +10728,7 @@ if test "$ac_res" != no; then : fi fi -for ac_func in chflags getrusage llseek lseek64 open64 fstat64 ftruncate64 getmntinfo strtoull strcasecmp srandom jrand48 fchown mallinfo fdatasync strnlen strptime strdup sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl mmap utime setresuid setresgid usleep nanosleep getdtablesize getrlimit sync_file_range posix_fadvise fallocate fallocate64 blkid_probe_get_topology mbstowcs +for ac_func in chflags getrusage llseek lseek64 open64 fstat64 ftruncate64 getmntinfo strtoull strcasecmp srandom jrand48 fchown mallinfo fdatasync strnlen strptime strdup sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl mmap utime setresuid setresgid usleep nanosleep getdtablesize getrlimit sync_file_range posix_fadvise fallocate fallocate64 blkid_probe_get_topology mbstowcs backtrace do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/configure.in b/configure.in index af639c3f..57d58261 100644 --- a/configure.in +++ b/configure.in @@ -93,6 +93,10 @@ AC_HELP_STRING([--with-ldopts],[no longer supported, use LDFLAGS= instead]), AC_MSG_ERROR([--with-ldopts no longer supported; use LDFLAGS= instead])) dnl AC_PROG_CC +if test "$GCC" = yes; then + RDYNAMIC="-rdynamic" + AC_SUBST(RDYNAMIC) +fi AC_PROG_CPP dnl dnl On systems without linux header files, we add an extra include directory @@ -747,7 +751,7 @@ if test $cross_compiling = no; then else AC_CHECK_PROGS(BUILD_CC, gcc cc) fi -AC_CHECK_HEADERS(dirent.h errno.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h) +AC_CHECK_HEADERS(dirent.h errno.h execinfo.h getopt.h malloc.h mntent.h paths.h semaphore.h setjmp.h signal.h stdarg.h stdint.h stdlib.h termios.h termio.h unistd.h utime.h linux/fd.h linux/major.h net/if_dl.h netinet/in.h sys/disklabel.h sys/file.h sys/ioctl.h sys/mkdev.h sys/mman.h sys/prctl.h sys/queue.h sys/resource.h sys/select.h sys/socket.h sys/sockio.h sys/stat.h sys/syscall.h sys/sysmacros.h sys/time.h sys/types.h sys/un.h sys/wait.h) AC_CHECK_HEADERS(sys/disk.h sys/mount.h,,, [[ #if HAVE_SYS_QUEUE_H @@ -871,7 +875,7 @@ if test -n "$BLKID_CMT"; then AC_SEARCH_LIBS([blkid_probe_all], [blkid]) fi dnl -AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 fstat64 ftruncate64 getmntinfo strtoull strcasecmp srandom jrand48 fchown mallinfo fdatasync strnlen strptime strdup sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl mmap utime setresuid setresgid usleep nanosleep getdtablesize getrlimit sync_file_range posix_fadvise fallocate fallocate64 blkid_probe_get_topology mbstowcs) +AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 fstat64 ftruncate64 getmntinfo strtoull strcasecmp srandom jrand48 fchown mallinfo fdatasync strnlen strptime strdup sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl mmap utime setresuid setresgid usleep nanosleep getdtablesize getrlimit sync_file_range posix_fadvise fallocate fallocate64 blkid_probe_get_topology mbstowcs backtrace) dnl dnl Check to see if -lsocket is required (solaris) to make something dnl that uses socket() to compile; this is needed for the UUID library diff --git a/e2fsck/Makefile.in b/e2fsck/Makefile.in index 315db622..b426eaf6 100644 --- a/e2fsck/Makefile.in +++ b/e2fsck/Makefile.in @@ -64,7 +64,8 @@ COMPILE_ET=$(top_builddir)/lib/et/compile_et --build-tree OBJS= crc32.o dict.o unix.o e2fsck.o super.o pass1.o pass1b.o pass2.o \ pass3.o pass4.o pass5.o journal.o badblocks.o util.o dirinfo.o \ dx_dirinfo.o ehandler.o problem.o message.o recovery.o region.o \ - revoke.o ea_refcount.o rehash.o profile.o prof_err.o $(MTRACE_OBJ) + revoke.o ea_refcount.o rehash.o profile.o prof_err.o sigcatcher.o \ + $(MTRACE_OBJ) PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \ profiled/super.o profiled/pass1.o profiled/pass1b.o \ @@ -74,7 +75,7 @@ PROFILED_OBJS= profiled/dict.o profiled/unix.o profiled/e2fsck.o \ profiled/message.o profiled/problem.o \ profiled/recovery.o profiled/region.o profiled/revoke.o \ profiled/ea_refcount.o profiled/rehash.o profiled/profile.o \ - profiled/crc32.o profiled/prof_err.o + profiled/crc32.o profiled/prof_err.o profiled/sigcatcher.o SRCS= $(srcdir)/e2fsck.c \ $(srcdir)/crc32.c \ @@ -102,6 +103,7 @@ SRCS= $(srcdir)/e2fsck.c \ $(srcdir)/rehash.c \ $(srcdir)/region.c \ $(srcdir)/profile.c \ + $(srcdir)/sigcatcher.c \ prof_err.c \ $(MTRACE_SRC) @@ -115,7 +117,7 @@ prof_err.c prof_err.h: prof_err.et e2fsck: $(OBJS) $(DEPLIBS) $(E) " LD $@" - $(Q) $(LD) $(ALL_LDFLAGS) -o e2fsck $(OBJS) $(LIBS) + $(Q) $(LD) $(ALL_LDFLAGS) $(RDYNAMIC) -o e2fsck $(OBJS) $(LIBS) e2fsck.static: $(OBJS) $(STATIC_DEPLIBS) $(E) " LD $@" @@ -135,6 +137,10 @@ crc32table.h: gen_crc32table $(E) " GEN32TABLE $@" $(Q) ./gen_crc32table > crc32table.h +tst_sigcatcher: $(srcdir)/sigcatcher.c + $(Q) $(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) $(RDYNAMIC) \ + $(srcdir)/sigcatcher.c -DDEBUG -o tst_sigcatcher + tst_problem: $(srcdir)/problem.c $(srcdir)/problem.h $(LIBEXT2FS) \ $(DEPLIBCOM_ERR) $(Q) $(CC) $(BUILD_LDFLAGS) $(ALL_CFLAGS) -o tst_problem \ @@ -438,4 +444,11 @@ region.o: $(srcdir)/region.c $(srcdir)/e2fsck.h \ $(srcdir)/profile.h prof_err.h profile.o: $(srcdir)/profile.c $(top_srcdir)/lib/et/com_err.h \ $(srcdir)/profile.h prof_err.h +sigcatcher.o: $(srcdir)/sigcatcher.c $(srcdir)/e2fsck.h \ + $(top_srcdir)/lib/ext2fs/ext2_fs.h $(top_builddir)/lib/ext2fs/ext2_types.h \ + $(top_srcdir)/lib/ext2fs/ext2fs.h $(top_srcdir)/lib/ext2fs/ext3_extents.h \ + $(top_srcdir)/lib/et/com_err.h $(top_srcdir)/lib/ext2fs/ext2_io.h \ + $(top_builddir)/lib/ext2fs/ext2_err.h \ + $(top_srcdir)/lib/ext2fs/ext2_ext_attr.h $(top_srcdir)/lib/ext2fs/bitops.h \ + $(srcdir)/profile.h prof_err.h prof_err.o: prof_err.c diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index b4a1a88d..f0e1557f 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -475,6 +475,9 @@ extern int region_allocate(region_t region, region_addr_t start, int n); errcode_t e2fsck_rehash_dir(e2fsck_t ctx, ext2_ino_t ino); void e2fsck_rehash_directories(e2fsck_t ctx); +/* sigcatcher.c */ +void sigcatcher_setup(void); + /* super.c */ void check_super_block(e2fsck_t ctx); int check_backup_super_block(e2fsck_t ctx); diff --git a/e2fsck/sigcatcher.c b/e2fsck/sigcatcher.c new file mode 100644 index 00000000..45571ca6 --- /dev/null +++ b/e2fsck/sigcatcher.c @@ -0,0 +1,275 @@ +/* + * sigcatcher.c --- print a backtrace on a SIGSEGV, et. al + * + * Copyright (C) 2011 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include +#include +#include +#include +#ifdef HAVE_EXECINFO_H +#include +#endif + +#include "e2fsck.h" + +struct str_table { + int num; + const char *name; +}; + +#define DEFINE_ENTRY(SYM) { SYM, #SYM }, +#define END_TABLE { 0, 0 } + +static struct str_table sig_table[] = { + DEFINE_ENTRY(SIGHUP) + DEFINE_ENTRY(SIGINT) + DEFINE_ENTRY(SIGQUIT) + DEFINE_ENTRY(SIGILL) + DEFINE_ENTRY(SIGTRAP) + DEFINE_ENTRY(SIGABRT) + DEFINE_ENTRY(SIGIOT) + DEFINE_ENTRY(SIGBUS) + DEFINE_ENTRY(SIGFPE) + DEFINE_ENTRY(SIGKILL) + DEFINE_ENTRY(SIGUSR1) + DEFINE_ENTRY(SIGSEGV) + DEFINE_ENTRY(SIGUSR2) + DEFINE_ENTRY(SIGPIPE) + DEFINE_ENTRY(SIGALRM) + DEFINE_ENTRY(SIGTERM) + DEFINE_ENTRY(SIGSTKFLT) + DEFINE_ENTRY(SIGCHLD) + DEFINE_ENTRY(SIGCONT) + DEFINE_ENTRY(SIGSTOP) + DEFINE_ENTRY(SIGTSTP) + DEFINE_ENTRY(SIGTTIN) + DEFINE_ENTRY(SIGTTOU) + DEFINE_ENTRY(SIGURG) + DEFINE_ENTRY(SIGXCPU) + DEFINE_ENTRY(SIGXFSZ) + DEFINE_ENTRY(SIGVTALRM) + DEFINE_ENTRY(SIGPROF) + DEFINE_ENTRY(SIGWINCH) + DEFINE_ENTRY(SIGIO) + DEFINE_ENTRY(SIGPOLL) + DEFINE_ENTRY(SIGPWR) + DEFINE_ENTRY(SIGSYS) + END_TABLE +}; + +static struct str_table generic_code_table[] = { + DEFINE_ENTRY(SI_ASYNCNL) + DEFINE_ENTRY(SI_TKILL) + DEFINE_ENTRY(SI_SIGIO) + DEFINE_ENTRY(SI_ASYNCIO) + DEFINE_ENTRY(SI_MESGQ) + DEFINE_ENTRY(SI_TIMER) + DEFINE_ENTRY(SI_QUEUE) + DEFINE_ENTRY(SI_USER) + DEFINE_ENTRY(SI_KERNEL) + END_TABLE +}; + +static struct str_table sigill_code_table[] = { + DEFINE_ENTRY(ILL_ILLOPC) + DEFINE_ENTRY(ILL_ILLOPN) + DEFINE_ENTRY(ILL_ILLADR) + DEFINE_ENTRY(ILL_ILLTRP) + DEFINE_ENTRY(ILL_PRVOPC) + DEFINE_ENTRY(ILL_PRVREG) + DEFINE_ENTRY(ILL_COPROC) + DEFINE_ENTRY(ILL_BADSTK) + DEFINE_ENTRY(BUS_ADRALN) + DEFINE_ENTRY(BUS_ADRERR) + DEFINE_ENTRY(BUS_OBJERR) + END_TABLE +}; + +static struct str_table sigfpe_code_table[] = { + DEFINE_ENTRY(FPE_INTDIV) + DEFINE_ENTRY(FPE_INTOVF) + DEFINE_ENTRY(FPE_FLTDIV) + DEFINE_ENTRY(FPE_FLTOVF) + DEFINE_ENTRY(FPE_FLTUND) + DEFINE_ENTRY(FPE_FLTRES) + DEFINE_ENTRY(FPE_FLTINV) + DEFINE_ENTRY(FPE_FLTSUB) + END_TABLE +}; + +static struct str_table sigsegv_code_table[] = { + DEFINE_ENTRY(SEGV_MAPERR) + DEFINE_ENTRY(SEGV_ACCERR) + END_TABLE +}; + + +static struct str_table sigbus_code_table[] = { + DEFINE_ENTRY(BUS_ADRALN) + DEFINE_ENTRY(BUS_ADRERR) + DEFINE_ENTRY(BUS_OBJERR) + END_TABLE +}; + +static struct str_table sigstrap_code_table[] = { + DEFINE_ENTRY(TRAP_BRKPT) + DEFINE_ENTRY(TRAP_TRACE) + END_TABLE +}; + +static struct str_table sigcld_code_table[] = { + DEFINE_ENTRY(CLD_EXITED) + DEFINE_ENTRY(CLD_KILLED) + DEFINE_ENTRY(CLD_DUMPED) + DEFINE_ENTRY(CLD_TRAPPED) + DEFINE_ENTRY(CLD_STOPPED) + DEFINE_ENTRY(CLD_CONTINUED) + END_TABLE +}; + +static struct str_table sigpoll_code_table[] = { + DEFINE_ENTRY(POLL_IN) + DEFINE_ENTRY(POLL_OUT) + DEFINE_ENTRY(POLL_MSG) + DEFINE_ENTRY(POLL_ERR) + DEFINE_ENTRY(POLL_PRI) + DEFINE_ENTRY(POLL_HUP) + END_TABLE +}; + +static const char *lookup_table(int num, struct str_table *table) +{ + struct str_table *p; + + for (p=table; p->name; p++) + if (num == p->num) + return(p->name); + return NULL; +} + +static const char *lookup_table_fallback(int num, struct str_table *table) +{ + static char buf[32]; + const char *ret = lookup_table(num, table); + + if (ret) + return ret; + snprintf(buf, sizeof(buf), "%d", num); + buf[sizeof(buf)-1] = 0; + return buf; +} + +static void die_signal_handler(int signum, siginfo_t *siginfo, void *context) +{ + void *stack_syms[32]; + int frames; + const char *cp; + + fprintf(stderr, "Signal (%d) %s ", signum, + lookup_table_fallback(signum, sig_table)); + if (siginfo->si_code == SI_USER) + fprintf(stderr, "(sent from pid %u) ", siginfo->si_pid); + cp = lookup_table(siginfo->si_code, generic_code_table); + if (cp) + fprintf(stderr, "si_code=%s ", cp); + else if (signum == SIGILL) + fprintf(stderr, "si_code=%s ", + lookup_table_fallback(siginfo->si_code, + sigill_code_table)); + else if (signum == SIGFPE) + fprintf(stderr, "si_code=%s ", + lookup_table_fallback(siginfo->si_code, + sigfpe_code_table)); + else if (signum == SIGSEGV) + fprintf(stderr, "si_code=%s ", + lookup_table_fallback(siginfo->si_code, + sigsegv_code_table)); + else if (signum == SIGBUS) + fprintf(stderr, "si_code=%s ", + lookup_table_fallback(siginfo->si_code, + sigbus_code_table)); + else if (signum == SIGCLD) + fprintf(stderr, "si_code=%s ", + lookup_table_fallback(siginfo->si_code, + sigcld_code_table)); + else + fprintf(stderr, "si code=%d ", siginfo->si_code); + if ((siginfo->si_code != SI_USER) && + (signum == SIGILL || signum == SIGFPE || + signum == SIGSEGV || signum == SIGBUS)) + fprintf(stderr, "fault addr=%p", siginfo->si_addr); + fprintf(stderr, "\n"); + +#ifdef HAVE_BACKTRACE + frames = backtrace(stack_syms, 32); + backtrace_symbols_fd(stack_syms, frames, 2); +#endif + exit(FSCK_ERROR); +} + +void sigcatcher_setup(void) +{ + struct sigaction sa; + + sa.sa_sigaction = die_signal_handler; + sa.sa_flags = SA_SIGINFO; + + sigaction(SIGFPE, &sa, 0); + sigaction(SIGILL, &sa, 0); + sigaction(SIGBUS, &sa, 0); + sigaction(SIGSEGV, &sa, 0); +} + + +#ifdef DEBUG +#include + +void usage(void) +{ + fprintf(stderr, "tst_sigcatcher: [-akfn]\n"); + exit(1); +} + +int main(int argc, char** argv) +{ + struct sigaction sa; + char *p = 0; + int i, c; + volatile x=0; + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_sigaction = die_signal_handler; + sa.sa_flags = SA_SIGINFO; + for (i=1; i < 31; i++) + sigaction(i, &sa, 0); + + while ((c = getopt (argc, argv, "afkn")) != EOF) + switch (c) { + case 'a': + abort(); + break; + case 'f': + printf("%d\n", 42/x); + case 'k': + kill(getpid(), SIGTERM); + break; + case 'n': + *p = 42; + default: + usage (); + } + + printf("Sleeping for 10 seconds, send kill signal to pid %u...\n", + getpid()); + fflush(stdout); + sleep(10); + exit(0); +} +#endif diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 7e95ca88..7f6ee987 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -1024,6 +1024,7 @@ int main (int argc, char *argv[]) char *cp; clear_problem_context(&pctx); + sigcatcher_setup(); #ifdef MTRACE mtrace(); #endif