/* * Copyright 1998-2002 by Albert Cahalan; all rights resered. * This file may be used subject to the terms and conditions of the * GNU Library General Public License Version 2, or any later version * at your option, as published by the Free Software Foundation. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details. */ #include <signal.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include "sig.h" /* Linux signals: * * SIGSYS is required by Unix98. * SIGEMT is part of SysV, BSD, and ancient UNIX tradition. * * They are provided by these Linux ports: alpha, mips, sparc, and sparc64. * You get SIGSTKFLT and SIGUNUSED instead on i386, m68k, ppc, and arm. * (this is a Linux & libc bug -- both must be fixed) * * Total garbage: SIGIO SIGINFO SIGIOT SIGLOST SIGCLD * (popular ones are handled as aliases) * Nearly garbage: SIGSTKFLT SIGUNUSED (nothing else to fill slots) */ /* Linux 2.3.29 replaces SIGUNUSED with the standard SIGSYS signal */ #ifndef SIGSYS #warning Standards require that <signal.h> define SIGSYS #define SIGSYS SIGUNUSED #endif /* If we see both, it is likely SIGSTKFLT (junk) was replaced. */ #ifdef SIGEMT #undef SIGSTKFLT #endif #ifndef SIGRTMIN #warning Standards require that <signal.h> define SIGRTMIN; assuming 32 #define SIGRTMIN 32 #endif /* It seems the SPARC libc does not know the kernel supports SIGPWR. */ #ifndef SIGPWR #warning Your header files lack SIGPWR. (assuming it is number 29) #define SIGPWR 29 #endif typedef struct mapstruct { const char *name; int num; } mapstruct; static const mapstruct sigtable[] = { {"ABRT", SIGABRT}, /* IOT */ {"ALRM", SIGALRM}, {"BUS", SIGBUS}, {"CHLD", SIGCHLD}, /* CLD */ {"CONT", SIGCONT}, #ifdef SIGEMT {"EMT", SIGEMT}, #endif {"FPE", SIGFPE}, {"HUP", SIGHUP}, {"ILL", SIGILL}, {"INT", SIGINT}, {"KILL", SIGKILL}, {"PIPE", SIGPIPE}, {"POLL", SIGPOLL}, /* IO */ {"PROF", SIGPROF}, {"PWR", SIGPWR}, {"QUIT", SIGQUIT}, {"SEGV", SIGSEGV}, #ifdef SIGSTKFLT {"STKFLT", SIGSTKFLT}, #endif {"STOP", SIGSTOP}, {"SYS", SIGSYS}, /* UNUSED */ {"TERM", SIGTERM}, {"TRAP", SIGTRAP}, {"TSTP", SIGTSTP}, {"TTIN", SIGTTIN}, {"TTOU", SIGTTOU}, {"URG", SIGURG}, {"USR1", SIGUSR1}, {"USR2", SIGUSR2}, {"VTALRM", SIGVTALRM}, {"WINCH", SIGWINCH}, {"XCPU", SIGXCPU}, {"XFSZ", SIGXFSZ} }; static const int number_of_signals = sizeof(sigtable) / sizeof(mapstruct); static int compare_signal_names(const void *a, const void *b) { return strcasecmp(((const mapstruct *)a)->name, ((const mapstruct *)b)->name); } /* return -1 on failure */ int signal_name_to_number(const char *restrict name) { long val; int offset; /* clean up name */ if (!strncasecmp(name, "SIG", 3)) name += 3; if (!strcasecmp(name, "CLD")) return SIGCHLD; if (!strcasecmp(name, "IO")) return SIGPOLL; if (!strcasecmp(name, "IOT")) return SIGABRT; /* search the table */ { const mapstruct ms = { name, 0 }; const mapstruct *restrict const ptr = bsearch(&ms, sigtable, number_of_signals, sizeof(mapstruct), compare_signal_names); if (ptr) return ptr->num; } if (!strcasecmp(name, "RTMIN")) return SIGRTMIN; if (!strcasecmp(name, "EXIT")) return 0; if (!strcasecmp(name, "NULL")) return 0; offset = 0; if (!strncasecmp(name, "RTMIN+", 6)) { name += 6; offset = SIGRTMIN; } /* not found, so try as a number */ { char *endp; val = strtol(name, &endp, 10); if (*endp || endp == name) return -1; /* not valid */ } if (val + SIGRTMIN > 127) return -1; /* not valid */ return val + offset; } static const char *signal_number_to_name(int signo) { static char buf[32]; int n = number_of_signals; signo &= 0x7f; /* need to process exit values too */ while (n--) { if (sigtable[n].num == signo) return sigtable[n].name; } if (signo == SIGRTMIN) return "RTMIN"; if (signo) sprintf(buf, "RTMIN+%d", signo - SIGRTMIN); else strcpy(buf, "0"); /* AIX has NULL; Solaris has EXIT */ return buf; } int print_given_signals(int argc, const char *restrict const *restrict argv, int max_line) { char buf[1280]; /* 128 signals, "RTMIN+xx" is largest */ int ret = 0; /* to be used as exit code by caller */ int place = 0; /* position on this line */ int amt; if (argc > 128) return 1; while (argc--) { char tmpbuf[16]; const char *restrict const txt = *argv; if (*txt >= '0' && *txt <= '9') { long val; char *endp; val = strtol(txt, &endp, 10); if (*endp) { fprintf(stderr, "Signal \"%s\" not known.\n", txt); ret = 1; goto end; } amt = sprintf(tmpbuf, "%s", signal_number_to_name(val)); } else { int sno; sno = signal_name_to_number(txt); if (sno == -1) { fprintf(stderr, "Signal \"%s\" not known.\n", txt); ret = 1; goto end; } amt = sprintf(tmpbuf, "%d", sno); } if (!place) { strcpy(buf, tmpbuf); place = amt; goto end; } if (amt + place + 1 > max_line) { printf("%s\n", buf); strcpy(buf, tmpbuf); place = amt; goto end; } sprintf(buf + place, " %s", tmpbuf); place += amt + 1; end: argv++; } if (place) printf("%s\n", buf); return ret; } void pretty_print_signals(void) { int i = 0; while (++i <= number_of_signals) { int n; n = printf("%2d %s", i, signal_number_to_name(i)); if (i % 7) printf (" \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + n); else printf("\n"); } if ((i - 1) % 7) printf("\n"); } void unix_print_signals(void) { int pos = 0; int i = 0; while (++i <= number_of_signals) { if (i - 1) printf("%c", (pos > 73) ? (pos = 0, '\n') : (pos++, ' ')); pos += printf("%s", signal_number_to_name(i)); } printf("\n"); } /* sanity check */ static int init_signal_list(void) __attribute__ ((constructor)); static int init_signal_list(void) { if (number_of_signals != 31) { fprintf(stderr, "WARNING: %d signals -- adjust and recompile.\n", number_of_signals); } return 0; }