157901Selan /* Extended support for using signal values. 257901Selan Copyright (C) 1992 Free Software Foundation, Inc. 357901Selan Written by Fred Fish. fnf@cygnus.com 457901Selan 557901Selan This file is part of the libiberty library. 657901Selan Libiberty is free software; you can redistribute it and/or 757901Selan modify it under the terms of the GNU Library General Public 857901Selan License as published by the Free Software Foundation; either 957901Selan version 2 of the License, or (at your option) any later version. 1057901Selan 1157901Selan Libiberty is distributed in the hope that it will be useful, 1257901Selan but WITHOUT ANY WARRANTY; without even the implied warranty of 1357901Selan MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1457901Selan Library General Public License for more details. 1557901Selan 1657901Selan You should have received a copy of the GNU Library General Public 1757901Selan License along with libiberty; see the file COPYING.LIB. If 1857901Selan not, write to the Free Software Foundation, Inc., 675 Mass Ave, 1957901Selan Cambridge, MA 02139, USA. */ 2057901Selan 2157901Selan #include "config.h" 2257901Selan 2357901Selan #include <stdio.h> 2457901Selan #include <signal.h> 2557901Selan 2657901Selan /* Routines imported from standard C runtime libraries. */ 2757901Selan 2857901Selan #ifdef __STDC__ 2957901Selan #include <stddef.h> 3057901Selan extern void *malloc (size_t size); /* 4.10.3.3 */ 3157901Selan extern void *memset (void *s, int c, size_t n); /* 4.11.6.1 */ 3257901Selan #else /* !__STDC__ */ 3357901Selan extern char *malloc (); /* Standard memory allocater */ 3457901Selan extern char *memset (); 3557901Selan #endif /* __STDC__ */ 3657901Selan 3757901Selan #ifndef NULL 3857901Selan # ifdef __STDC__ 3957901Selan # define NULL (void *) 0 4057901Selan # else 4157901Selan # define NULL 0 4257901Selan # endif 4357901Selan #endif 4457901Selan 4557901Selan #ifndef MAX 4657901Selan # define MAX(a,b) ((a) > (b) ? (a) : (b)) 4757901Selan #endif 4857901Selan 4957901Selan /* Translation table for signal values. 5057901Selan 5157901Selan Note that this table is generally only accessed when it is used at runtime 5257901Selan to initialize signal name and message tables that are indexed by signal 5357901Selan value. 5457901Selan 5557901Selan Not all of these signals will exist on all systems. This table is the only 5657901Selan thing that should have to be updated as new signal numbers are introduced. 5757901Selan It's sort of ugly, but at least its portable. */ 5857901Selan 5957901Selan static struct signal_info 6057901Selan { 6157901Selan int value; /* The numeric value from <signal.h> */ 6257901Selan char *name; /* The equivalent symbolic value */ 6357901Selan char *msg; /* Short message about this value */ 6457901Selan } signal_table[] = 6557901Selan { 6657901Selan #if defined (SIGHUP) 6757901Selan SIGHUP, "SIGHUP", "Hangup", 6857901Selan #endif 6957901Selan #if defined (SIGINT) 7057901Selan SIGINT, "SIGINT", "Interrupt", 7157901Selan #endif 7257901Selan #if defined (SIGQUIT) 7357901Selan SIGQUIT, "SIGQUIT", "Quit", 7457901Selan #endif 7557901Selan #if defined (SIGILL) 7657901Selan SIGILL, "SIGILL", "Illegal instruction", 7757901Selan #endif 7857901Selan #if defined (SIGTRAP) 7957901Selan SIGTRAP, "SIGTRAP", "Trace/breakpoint trap", 8057901Selan #endif 8157901Selan /* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT 8257901Selan overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */ 8357901Selan #if defined (SIGIOT) 8457901Selan SIGIOT, "SIGIOT", "IOT trap", 8557901Selan #endif 8657901Selan #if defined (SIGABRT) 8757901Selan SIGABRT, "SIGABRT", "Aborted", 8857901Selan #endif 8957901Selan #if defined (SIGEMT) 9057901Selan SIGEMT, "SIGEMT", "Emulation trap", 9157901Selan #endif 9257901Selan #if defined (SIGFPE) 9357901Selan SIGFPE, "SIGFPE", "Arithmetic exception", 9457901Selan #endif 9557901Selan #if defined (SIGKILL) 9657901Selan SIGKILL, "SIGKILL", "Killed", 9757901Selan #endif 9857901Selan #if defined (SIGBUS) 9957901Selan SIGBUS, "SIGBUS", "Bus error", 10057901Selan #endif 10157901Selan #if defined (SIGSEGV) 10257901Selan SIGSEGV, "SIGSEGV", "Segmentation fault", 10357901Selan #endif 10457901Selan #if defined (SIGSYS) 10557901Selan SIGSYS, "SIGSYS", "Bad system call", 10657901Selan #endif 10757901Selan #if defined (SIGPIPE) 10857901Selan SIGPIPE, "SIGPIPE", "Broken pipe", 10957901Selan #endif 11057901Selan #if defined (SIGALRM) 11157901Selan SIGALRM, "SIGALRM", "Alarm clock", 11257901Selan #endif 11357901Selan #if defined (SIGTERM) 11457901Selan SIGTERM, "SIGTERM", "Terminated", 11557901Selan #endif 11657901Selan #if defined (SIGUSR1) 11757901Selan SIGUSR1, "SIGUSR1", "User defined signal 1", 11857901Selan #endif 11957901Selan #if defined (SIGUSR2) 12057901Selan SIGUSR2, "SIGUSR2", "User defined signal 2", 12157901Selan #endif 12257901Selan /* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD 12357901Selan overrides SIGCLD. SIGCHLD is in POXIX.1 */ 12457901Selan #if defined (SIGCLD) 12557901Selan SIGCLD, "SIGCLD", "Child status changed", 12657901Selan #endif 12757901Selan #if defined (SIGCHLD) 12857901Selan SIGCHLD, "SIGCHLD", "Child status changed", 12957901Selan #endif 13057901Selan #if defined (SIGPWR) 13157901Selan SIGPWR, "SIGPWR", "Power fail/restart", 13257901Selan #endif 13357901Selan #if defined (SIGWINCH) 13457901Selan SIGWINCH, "SIGWINCH", "Window size changed", 13557901Selan #endif 13657901Selan #if defined (SIGURG) 13757901Selan SIGURG, "SIGURG", "Urgent I/O condition", 13857901Selan #endif 13957901Selan #if defined (SIGIO) 14057901Selan /* "I/O pending has also been suggested, but is misleading since the 14157901Selan signal only happens when the process has asked for it, not everytime 14257901Selan I/O is pending. */ 14357901Selan SIGIO, "SIGIO", "I/O possible", 14457901Selan #endif 14557901Selan #if defined (SIGPOLL) 14657901Selan SIGPOLL, "SIGPOLL", "Pollable event occurred", 14757901Selan #endif 14857901Selan #if defined (SIGSTOP) 14957901Selan SIGSTOP, "SIGSTOP", "Stopped (signal)", 15057901Selan #endif 15157901Selan #if defined (SIGTSTP) 15257901Selan SIGTSTP, "SIGTSTP", "Stopped (user)", 15357901Selan #endif 15457901Selan #if defined (SIGCONT) 15557901Selan SIGCONT, "SIGCONT", "Continued", 15657901Selan #endif 15757901Selan #if defined (SIGTTIN) 15857901Selan SIGTTIN, "SIGTTIN", "Stopped (tty input)", 15957901Selan #endif 16057901Selan #if defined (SIGTTOU) 16157901Selan SIGTTOU, "SIGTTOU", "Stopped (tty output)", 16257901Selan #endif 16357901Selan #if defined (SIGVTALRM) 16457901Selan SIGVTALRM, "SIGVTALRM", "Virtual timer expired", 16557901Selan #endif 16657901Selan #if defined (SIGPROF) 16757901Selan SIGPROF, "SIGPROF", "Profiling timer expired", 16857901Selan #endif 16957901Selan #if defined (SIGXCPU) 17057901Selan SIGXCPU, "SIGXCPU", "CPU time limit exceeded", 17157901Selan #endif 17257901Selan #if defined (SIGXFSZ) 17357901Selan SIGXFSZ, "SIGXFSZ", "File size limit exceeded", 17457901Selan #endif 17557901Selan #if defined (SIGWIND) 17657901Selan SIGWIND, "SIGWIND", "SIGWIND", 17757901Selan #endif 17857901Selan #if defined (SIGPHONE) 17957901Selan SIGPHONE, "SIGPHONE", "SIGPHONE", 18057901Selan #endif 18157901Selan #if defined (SIGLOST) 18257901Selan SIGLOST, "SIGLOST", "Resource lost", 18357901Selan #endif 18457901Selan #if defined (SIGWAITING) 18557901Selan SIGWAITING, "SIGWAITING", "Process's LWPs are blocked", 18657901Selan #endif 18757901Selan #if defined (SIGLWP) 18857901Selan SIGLWP, "SIGLWP", "Signal LWP", 18957901Selan #endif 19057901Selan 0, NULL, NULL 19157901Selan }; 19257901Selan 19357901Selan /* Translation table allocated and initialized at runtime. Indexed by the 19457901Selan signal value to find the equivalent symbolic value. */ 19557901Selan 19657901Selan static char **signal_names; 19757901Selan static int num_signal_names = 0; 19857901Selan 19957901Selan /* Translation table allocated and initialized at runtime, if it does not 20057901Selan already exist in the host environment. Indexed by the signal value to find 20157901Selan the descriptive string. 20257901Selan 20357901Selan We don't export it for use in other modules because even though it has the 20457901Selan same name, it differs from other implementations in that it is dynamically 20557901Selan initialized rather than statically initialized. */ 20657901Selan 207*60407Selan #ifdef notdef 20857901Selan #ifdef NEED_sys_siglist 20957901Selan 21057901Selan static int sys_nsig; 21157901Selan static char **sys_siglist; 21257901Selan 21357901Selan #else 21457901Selan 21557901Selan static int sys_nsig = NSIG; 21657901Selan #ifdef __STDC__ 21760390Selan extern char * const sys_siglist[]; 21857901Selan #else 21957901Selan extern char *sys_siglist[]; 22057901Selan #endif 22157901Selan #endif 222*60407Selan #endif 22357901Selan 22457901Selan 22557901Selan /* 22657901Selan 22757901Selan NAME 22857901Selan 22957901Selan init_signal_tables -- initialize the name and message tables 23057901Selan 23157901Selan SYNOPSIS 23257901Selan 23357901Selan static void init_signal_tables (); 23457901Selan 23557901Selan DESCRIPTION 23657901Selan 23757901Selan Using the signal_table, which is initialized at compile time, generate 23857901Selan the signal_names and the sys_siglist (if needed) tables, which are 23957901Selan indexed at runtime by a specific signal value. 24057901Selan 24157901Selan BUGS 24257901Selan 24357901Selan The initialization of the tables may fail under low memory conditions, 24457901Selan in which case we don't do anything particularly useful, but we don't 24557901Selan bomb either. Who knows, it might succeed at a later point if we free 24657901Selan some memory in the meantime. In any case, the other routines know 24757901Selan how to deal with lack of a table after trying to initialize it. This 24857901Selan may or may not be considered to be a bug, that we don't specifically 24957901Selan warn about this particular failure mode. 25057901Selan 25157901Selan */ 25257901Selan 25357901Selan static void 25457901Selan init_signal_tables () 25557901Selan { 25657901Selan struct signal_info *eip; 25757901Selan int nbytes; 25857901Selan 25957901Selan /* If we haven't already scanned the signal_table once to find the maximum 26057901Selan signal value, then go find it now. */ 26157901Selan 26257901Selan if (num_signal_names == 0) 26357901Selan { 26457901Selan for (eip = signal_table; eip -> name != NULL; eip++) 26557901Selan { 26657901Selan if (eip -> value >= num_signal_names) 26757901Selan { 26857901Selan num_signal_names = eip -> value + 1; 26957901Selan } 27057901Selan } 27157901Selan } 27257901Selan 27357901Selan /* Now attempt to allocate the signal_names table, zero it out, and then 27457901Selan initialize it from the statically initialized signal_table. */ 27557901Selan 27657901Selan if (signal_names == NULL) 27757901Selan { 27857901Selan nbytes = num_signal_names * sizeof (char *); 27957901Selan if ((signal_names = (char **) malloc (nbytes)) != NULL) 28057901Selan { 28157901Selan memset (signal_names, 0, nbytes); 28257901Selan for (eip = signal_table; eip -> name != NULL; eip++) 28357901Selan { 28457901Selan signal_names[eip -> value] = eip -> name; 28557901Selan } 28657901Selan } 28757901Selan } 28857901Selan 28957901Selan #ifdef NEED_sys_siglist 29057901Selan 29157901Selan /* Now attempt to allocate the sys_siglist table, zero it out, and then 29257901Selan initialize it from the statically initialized signal_table. */ 29357901Selan 29457901Selan if (sys_siglist == NULL) 29557901Selan { 29657901Selan nbytes = num_signal_names * sizeof (char *); 29757901Selan if ((sys_siglist = (char **) malloc (nbytes)) != NULL) 29857901Selan { 29957901Selan memset (sys_siglist, 0, nbytes); 30057901Selan sys_nsig = num_signal_names; 30157901Selan for (eip = signal_table; eip -> name != NULL; eip++) 30257901Selan { 30357901Selan sys_siglist[eip -> value] = eip -> msg; 30457901Selan } 30557901Selan } 30657901Selan } 30757901Selan 30857901Selan #endif 30957901Selan 31057901Selan } 31157901Selan 31257901Selan 31357901Selan /* 31457901Selan 31557901Selan NAME 31657901Selan 31757901Selan signo_max -- return the max signo value 31857901Selan 31957901Selan SYNOPSIS 32057901Selan 32157901Selan int signo_max (); 32257901Selan 32357901Selan DESCRIPTION 32457901Selan 32557901Selan Returns the maximum signo value for which a corresponding symbolic 32657901Selan name or message is available. Note that in the case where 32757901Selan we use the sys_siglist supplied by the system, it is possible for 32857901Selan there to be more symbolic names than messages, or vice versa. 32957901Selan In fact, the manual page for psignal(3b) explicitly warns that one 33057901Selan should check the size of the table (NSIG) before indexing it, 33157901Selan since new signal codes may be added to the system before they are 33257901Selan added to the table. Thus NSIG might be smaller than value 33357901Selan implied by the largest signo value defined in <signal.h>. 33457901Selan 33557901Selan We return the maximum value that can be used to obtain a meaningful 33657901Selan symbolic name or message. 33757901Selan 33857901Selan */ 33957901Selan 34057901Selan int 34157901Selan signo_max () 34257901Selan { 34357901Selan int maxsize; 34457901Selan 34557901Selan if (signal_names == NULL) 34657901Selan { 34757901Selan init_signal_tables (); 34857901Selan } 34957901Selan maxsize = MAX (sys_nsig, num_signal_names); 35057901Selan return (maxsize - 1); 35157901Selan } 35257901Selan 35357901Selan 35457901Selan /* 35557901Selan 35657901Selan NAME 35757901Selan 35857901Selan strsignal -- map a signal number to a signal message string 35957901Selan 36057901Selan SYNOPSIS 36157901Selan 36257901Selan char *strsignal (int signo) 36357901Selan 36457901Selan DESCRIPTION 36557901Selan 36657901Selan Maps an signal number to an signal message string, the contents of 36757901Selan which are implementation defined. On systems which have the external 36857901Selan variable sys_siglist, these strings will be the same as the ones used 36957901Selan by psignal(). 37057901Selan 37157901Selan If the supplied signal number is within the valid range of indices 37257901Selan for the sys_siglist, but no message is available for the particular 37357901Selan signal number, then returns the string "Signal NUM", where NUM is the 37457901Selan signal number. 37557901Selan 37657901Selan If the supplied signal number is not a valid index into sys_siglist, 37757901Selan returns NULL. 37857901Selan 37957901Selan The returned string is only guaranteed to be valid only until the 38057901Selan next call to strsignal. 38157901Selan 38257901Selan */ 38357901Selan 38457901Selan char * 38557901Selan strsignal (signo) 38657901Selan int signo; 38757901Selan { 38857901Selan char *msg; 38957901Selan static char buf[32]; 39057901Selan 39157901Selan #ifdef NEED_sys_siglist 39257901Selan 39357901Selan if (signal_names == NULL) 39457901Selan { 39557901Selan init_signal_tables (); 39657901Selan } 39757901Selan 39857901Selan #endif 39957901Selan 40057901Selan if ((signo < 0) || (signo >= sys_nsig)) 40157901Selan { 40257901Selan /* Out of range, just return NULL */ 40357901Selan msg = NULL; 40457901Selan } 40557901Selan else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL)) 40657901Selan { 40757901Selan /* In range, but no sys_siglist or no entry at this index. */ 40857901Selan sprintf (buf, "Signal %d", signo); 40957901Selan msg = buf; 41057901Selan } 41157901Selan else 41257901Selan { 41357901Selan /* In range, and a valid message. Just return the message. */ 41457901Selan msg = (char*)sys_siglist[signo]; 41557901Selan } 41657901Selan 41757901Selan return (msg); 41857901Selan } 41957901Selan 42057901Selan 42157901Selan /* 42257901Selan 42357901Selan NAME 42457901Selan 42557901Selan strsigno -- map an signal number to a symbolic name string 42657901Selan 42757901Selan SYNOPSIS 42857901Selan 42957901Selan char *strsigno (int signo) 43057901Selan 43157901Selan DESCRIPTION 43257901Selan 43357901Selan Given an signal number, returns a pointer to a string containing 43457901Selan the symbolic name of that signal number, as found in <signal.h>. 43557901Selan 43657901Selan If the supplied signal number is within the valid range of indices 43757901Selan for symbolic names, but no name is available for the particular 43857901Selan signal number, then returns the string "Signal NUM", where NUM is 43957901Selan the signal number. 44057901Selan 44157901Selan If the supplied signal number is not within the range of valid 44257901Selan indices, then returns NULL. 44357901Selan 44457901Selan BUGS 44557901Selan 44657901Selan The contents of the location pointed to are only guaranteed to be 44757901Selan valid until the next call to strsigno. 44857901Selan 44957901Selan */ 45057901Selan 45157901Selan char * 45257901Selan strsigno (signo) 45357901Selan int signo; 45457901Selan { 45557901Selan char *name; 45657901Selan static char buf[32]; 45757901Selan 45857901Selan if (signal_names == NULL) 45957901Selan { 46057901Selan init_signal_tables (); 46157901Selan } 46257901Selan 46357901Selan if ((signo < 0) || (signo >= num_signal_names)) 46457901Selan { 46557901Selan /* Out of range, just return NULL */ 46657901Selan name = NULL; 46757901Selan } 46857901Selan else if ((signal_names == NULL) || (signal_names[signo] == NULL)) 46957901Selan { 47057901Selan /* In range, but no signal_names or no entry at this index. */ 47157901Selan sprintf (buf, "Signal %d", signo); 47257901Selan name = buf; 47357901Selan } 47457901Selan else 47557901Selan { 47657901Selan /* In range, and a valid name. Just return the name. */ 47757901Selan name = signal_names[signo]; 47857901Selan } 47957901Selan 48057901Selan return (name); 48157901Selan } 48257901Selan 48357901Selan 48457901Selan /* 48557901Selan 48657901Selan NAME 48757901Selan 48857901Selan strtosigno -- map a symbolic signal name to a numeric value 48957901Selan 49057901Selan SYNOPSIS 49157901Selan 49257901Selan int strtosigno (char *name) 49357901Selan 49457901Selan DESCRIPTION 49557901Selan 49657901Selan Given the symbolic name of a signal, map it to a signal number. 49757901Selan If no translation is found, returns 0. 49857901Selan 49957901Selan */ 50057901Selan 50157901Selan int 50257901Selan strtosigno (name) 50357901Selan char *name; 50457901Selan { 50557901Selan int signo = 0; 50657901Selan 50757901Selan if (name != NULL) 50857901Selan { 50957901Selan if (signal_names == NULL) 51057901Selan { 51157901Selan init_signal_tables (); 51257901Selan } 51357901Selan for (signo = 0; signo < num_signal_names; signo++) 51457901Selan { 51557901Selan if ((signal_names[signo] != NULL) && 51657901Selan (strcmp (name, signal_names[signo]) == 0)) 51757901Selan { 51857901Selan break; 51957901Selan } 52057901Selan } 52157901Selan if (signo == num_signal_names) 52257901Selan { 52357901Selan signo = 0; 52457901Selan } 52557901Selan } 52657901Selan return (signo); 52757901Selan } 52857901Selan 52957901Selan 53057901Selan /* 53157901Selan 53257901Selan NAME 53357901Selan 53457901Selan psignal -- print message about signal to stderr 53557901Selan 53657901Selan SYNOPSIS 53757901Selan 53857901Selan void psignal (unsigned signo, char *message); 53957901Selan 54057901Selan DESCRIPTION 54157901Selan 54257901Selan Print to the standard error the message, followed by a colon, 54357901Selan followed by the description of the signal specified by signo, 54457901Selan followed by a newline. 54557901Selan */ 54657901Selan 54757901Selan #ifdef NEED_psignal 54857901Selan 54957901Selan void 55057901Selan psignal (signo, message) 55157901Selan unsigned signo; 55257901Selan char *message; 55357901Selan { 55457901Selan if (signal_names == NULL) 55557901Selan { 55657901Selan init_signal_tables (); 55757901Selan } 55857901Selan if ((signo <= 0) || (signo >= sys_nsig)) 55957901Selan { 56057901Selan fprintf (stderr, "%s: unknown signal\n", message); 56157901Selan } 56257901Selan else 56357901Selan { 56457901Selan fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]); 56557901Selan } 56657901Selan } 56757901Selan 56857901Selan #endif /* NEED_psignal */ 56957901Selan 57057901Selan 57157901Selan /* A simple little main that does nothing but print all the signal translations 57257901Selan if MAIN is defined and this file is compiled and linked. */ 57357901Selan 57457901Selan #ifdef MAIN 57557901Selan 57657901Selan main () 57757901Selan { 57857901Selan int signo; 57957901Selan int maxsigno; 58057901Selan char *name; 58157901Selan char *msg; 58257901Selan char *strsigno (); 58357901Selan char *strsignal (); 58457901Selan 58557901Selan maxsigno = signo_max (); 58657901Selan printf ("%d entries in names table.\n", num_signal_names); 58757901Selan printf ("%d entries in messages table.\n", sys_nsig); 58857901Selan printf ("%d is max useful index.\n", maxsigno); 58957901Selan 59057901Selan /* Keep printing values until we get to the end of *both* tables, not 59157901Selan *either* table. Note that knowing the maximum useful index does *not* 59257901Selan relieve us of the responsibility of testing the return pointer for 59357901Selan NULL. */ 59457901Selan 59557901Selan for (signo = 0; signo <= maxsigno; signo++) 59657901Selan { 59757901Selan name = strsigno (signo); 59857901Selan name = (name == NULL) ? "<NULL>" : name; 59957901Selan msg = strsignal (signo); 60057901Selan msg = (msg == NULL) ? "<NULL>" : msg; 60157901Selan printf ("%-4d%-18s%s\n", signo, name, msg); 60257901Selan } 60357901Selan } 60457901Selan 60557901Selan #endif 606