/* * signals.c - signal name, and number, conversions * Copyright 1998-2003 by Albert Cahalan * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include #include #include #include #include #include "signals.h" #include "c.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 SIGCLD * (popular ones are handled as aliases) * SIGLOST * (except on the Hurd; reused to mean a server died) * 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 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 define SIGRTMIN; assuming 32 # define SIGRTMIN 32 #endif /* It seems the SPARC libc does not know the kernel supports SIGPWR. */ #if defined(__linux__) && !defined(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}, #if defined(__GNU__) {"LOST", SIGLOST}, /* Hurd-specific */ #endif {"PIPE", SIGPIPE}, {"POLL", SIGPOLL}, /* IO */ {"PROF", SIGPROF}, #ifdef SIGPWR {"PWR", SIGPWR}, #endif {"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} }; #define number_of_signals (sizeof(sigtable)/sizeof(mapstruct)) #define XJOIN(a, b) JOIN(a, b) #define JOIN(a, b) a##b #define STATIC_ASSERT(x) typedef int XJOIN(static_assert_on_line_,__LINE__)[(x) ? 1 : -1] /* sanity check */ #if defined(__linux__) STATIC_ASSERT(number_of_signals == 31); #elif defined(__FreeBSD_kernel__) || defined(__FreeBSD__) STATIC_ASSERT(number_of_signals == 30); #elif defined(__GNU__) STATIC_ASSERT(number_of_signals == 31); #elif defined(__CYGWIN__) STATIC_ASSERT(number_of_signals == 31); #else # warning Unknown operating system; assuming number_of_signals is correct #endif static int compare_signal_names(const void *a, const void *b){ return strcasecmp( ((const mapstruct*)a)->name, ((const mapstruct*)b)->name ); } const char *get_sigtable_name(int row) { if (row < 0 || row >= number_of_signals) return NULL; return sigtable[row].name; } const int get_sigtable_num(int row) { if (row < 0 || row >= number_of_signals) return -1; return sigtable[row].num; } /* 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; } 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 skill_sig_option(int *argc, char **argv) { int i; int signo = -1; for (i = 1; i < *argc; i++) { if (argv[i][0] == '-') { signo = signal_name_to_number(argv[i] + 1); if (-1 < signo) { memmove(argv + i, argv + i + 1, sizeof(char *) * (*argc - i)); (*argc)--; return signo; } } } return signo; } /* strtosig is similar to print_given_signals() with exception, that * this function takes a string, and converts it to a signal name or * a number string depending on which way a round conversion is * queried. Non-existing signals return NULL. Notice that the * returned string should be freed after use. */ char *strtosig(const char *restrict s) { char *converted = NULL, *copy, *p, *endp; int i, numsignal = 0; copy = strdup(s); if (!copy) xerrx(EXIT_FAILURE, "cannot duplicate string"); for (p = copy; *p != '\0'; p++) *p = toupper(*p); p = copy; if (p[0] == 'S' && p[1] == 'I' && p[2] == 'G') p += 3; if (isdigit(*p)){ numsignal = strtol(s,&endp,10); if(*endp || endp==s){ free(p); return NULL; /* not valid */ } } if (numsignal){ for (i = 0; i < number_of_signals; i++){ if (numsignal == get_sigtable_num(i)){ converted = strdup(get_sigtable_name(i)); break; } } } else { for (i = 0; i < number_of_signals; i++){ if (strcmp(p, get_sigtable_name(i)) == 0){ converted = malloc(sizeof(char) * 8); if (converted) snprintf(converted, sizeof(converted) - 1, "%d", get_sigtable_num(i)); break; } } } free(copy); return converted; } 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"); } 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(n>0 && i%7) printf("%s", " \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"); }