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
20757901Selan #ifdef NEED_sys_siglist
20857901Selan
20957901Selan static int sys_nsig;
210*60408Selan #ifdef notdef
21157901Selan static char **sys_siglist;
212*60408Selan #endif
21357901Selan
21457901Selan #else
21557901Selan
21657901Selan static int sys_nsig = NSIG;
217*60408Selan #ifdef notdef
21857901Selan #ifdef __STDC__
21960390Selan extern char * const sys_siglist[];
22057901Selan #else
22157901Selan extern char *sys_siglist[];
22257901Selan #endif
22357901Selan #endif
22460407Selan #endif
22557901Selan
22657901Selan
22757901Selan /*
22857901Selan
22957901Selan NAME
23057901Selan
23157901Selan init_signal_tables -- initialize the name and message tables
23257901Selan
23357901Selan SYNOPSIS
23457901Selan
23557901Selan static void init_signal_tables ();
23657901Selan
23757901Selan DESCRIPTION
23857901Selan
23957901Selan Using the signal_table, which is initialized at compile time, generate
24057901Selan the signal_names and the sys_siglist (if needed) tables, which are
24157901Selan indexed at runtime by a specific signal value.
24257901Selan
24357901Selan BUGS
24457901Selan
24557901Selan The initialization of the tables may fail under low memory conditions,
24657901Selan in which case we don't do anything particularly useful, but we don't
24757901Selan bomb either. Who knows, it might succeed at a later point if we free
24857901Selan some memory in the meantime. In any case, the other routines know
24957901Selan how to deal with lack of a table after trying to initialize it. This
25057901Selan may or may not be considered to be a bug, that we don't specifically
25157901Selan warn about this particular failure mode.
25257901Selan
25357901Selan */
25457901Selan
25557901Selan static void
init_signal_tables()25657901Selan init_signal_tables ()
25757901Selan {
25857901Selan struct signal_info *eip;
25957901Selan int nbytes;
26057901Selan
26157901Selan /* If we haven't already scanned the signal_table once to find the maximum
26257901Selan signal value, then go find it now. */
26357901Selan
26457901Selan if (num_signal_names == 0)
26557901Selan {
26657901Selan for (eip = signal_table; eip -> name != NULL; eip++)
26757901Selan {
26857901Selan if (eip -> value >= num_signal_names)
26957901Selan {
27057901Selan num_signal_names = eip -> value + 1;
27157901Selan }
27257901Selan }
27357901Selan }
27457901Selan
27557901Selan /* Now attempt to allocate the signal_names table, zero it out, and then
27657901Selan initialize it from the statically initialized signal_table. */
27757901Selan
27857901Selan if (signal_names == NULL)
27957901Selan {
28057901Selan nbytes = num_signal_names * sizeof (char *);
28157901Selan if ((signal_names = (char **) malloc (nbytes)) != NULL)
28257901Selan {
28357901Selan memset (signal_names, 0, nbytes);
28457901Selan for (eip = signal_table; eip -> name != NULL; eip++)
28557901Selan {
28657901Selan signal_names[eip -> value] = eip -> name;
28757901Selan }
28857901Selan }
28957901Selan }
29057901Selan
29157901Selan #ifdef NEED_sys_siglist
29257901Selan
29357901Selan /* Now attempt to allocate the sys_siglist table, zero it out, and then
29457901Selan initialize it from the statically initialized signal_table. */
29557901Selan
29657901Selan if (sys_siglist == NULL)
29757901Selan {
29857901Selan nbytes = num_signal_names * sizeof (char *);
29957901Selan if ((sys_siglist = (char **) malloc (nbytes)) != NULL)
30057901Selan {
30157901Selan memset (sys_siglist, 0, nbytes);
30257901Selan sys_nsig = num_signal_names;
30357901Selan for (eip = signal_table; eip -> name != NULL; eip++)
30457901Selan {
30557901Selan sys_siglist[eip -> value] = eip -> msg;
30657901Selan }
30757901Selan }
30857901Selan }
30957901Selan
31057901Selan #endif
31157901Selan
31257901Selan }
31357901Selan
31457901Selan
31557901Selan /*
31657901Selan
31757901Selan NAME
31857901Selan
31957901Selan signo_max -- return the max signo value
32057901Selan
32157901Selan SYNOPSIS
32257901Selan
32357901Selan int signo_max ();
32457901Selan
32557901Selan DESCRIPTION
32657901Selan
32757901Selan Returns the maximum signo value for which a corresponding symbolic
32857901Selan name or message is available. Note that in the case where
32957901Selan we use the sys_siglist supplied by the system, it is possible for
33057901Selan there to be more symbolic names than messages, or vice versa.
33157901Selan In fact, the manual page for psignal(3b) explicitly warns that one
33257901Selan should check the size of the table (NSIG) before indexing it,
33357901Selan since new signal codes may be added to the system before they are
33457901Selan added to the table. Thus NSIG might be smaller than value
33557901Selan implied by the largest signo value defined in <signal.h>.
33657901Selan
33757901Selan We return the maximum value that can be used to obtain a meaningful
33857901Selan symbolic name or message.
33957901Selan
34057901Selan */
34157901Selan
34257901Selan int
signo_max()34357901Selan signo_max ()
34457901Selan {
34557901Selan int maxsize;
34657901Selan
34757901Selan if (signal_names == NULL)
34857901Selan {
34957901Selan init_signal_tables ();
35057901Selan }
35157901Selan maxsize = MAX (sys_nsig, num_signal_names);
35257901Selan return (maxsize - 1);
35357901Selan }
35457901Selan
35557901Selan
35657901Selan /*
35757901Selan
35857901Selan NAME
35957901Selan
36057901Selan strsignal -- map a signal number to a signal message string
36157901Selan
36257901Selan SYNOPSIS
36357901Selan
36457901Selan char *strsignal (int signo)
36557901Selan
36657901Selan DESCRIPTION
36757901Selan
36857901Selan Maps an signal number to an signal message string, the contents of
36957901Selan which are implementation defined. On systems which have the external
37057901Selan variable sys_siglist, these strings will be the same as the ones used
37157901Selan by psignal().
37257901Selan
37357901Selan If the supplied signal number is within the valid range of indices
37457901Selan for the sys_siglist, but no message is available for the particular
37557901Selan signal number, then returns the string "Signal NUM", where NUM is the
37657901Selan signal number.
37757901Selan
37857901Selan If the supplied signal number is not a valid index into sys_siglist,
37957901Selan returns NULL.
38057901Selan
38157901Selan The returned string is only guaranteed to be valid only until the
38257901Selan next call to strsignal.
38357901Selan
38457901Selan */
38557901Selan
38657901Selan char *
strsignal(signo)38757901Selan strsignal (signo)
38857901Selan int signo;
38957901Selan {
39057901Selan char *msg;
39157901Selan static char buf[32];
39257901Selan
39357901Selan #ifdef NEED_sys_siglist
39457901Selan
39557901Selan if (signal_names == NULL)
39657901Selan {
39757901Selan init_signal_tables ();
39857901Selan }
39957901Selan
40057901Selan #endif
40157901Selan
40257901Selan if ((signo < 0) || (signo >= sys_nsig))
40357901Selan {
40457901Selan /* Out of range, just return NULL */
40557901Selan msg = NULL;
40657901Selan }
40757901Selan else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
40857901Selan {
40957901Selan /* In range, but no sys_siglist or no entry at this index. */
41057901Selan sprintf (buf, "Signal %d", signo);
41157901Selan msg = buf;
41257901Selan }
41357901Selan else
41457901Selan {
41557901Selan /* In range, and a valid message. Just return the message. */
41657901Selan msg = (char*)sys_siglist[signo];
41757901Selan }
41857901Selan
41957901Selan return (msg);
42057901Selan }
42157901Selan
42257901Selan
42357901Selan /*
42457901Selan
42557901Selan NAME
42657901Selan
42757901Selan strsigno -- map an signal number to a symbolic name string
42857901Selan
42957901Selan SYNOPSIS
43057901Selan
43157901Selan char *strsigno (int signo)
43257901Selan
43357901Selan DESCRIPTION
43457901Selan
43557901Selan Given an signal number, returns a pointer to a string containing
43657901Selan the symbolic name of that signal number, as found in <signal.h>.
43757901Selan
43857901Selan If the supplied signal number is within the valid range of indices
43957901Selan for symbolic names, but no name is available for the particular
44057901Selan signal number, then returns the string "Signal NUM", where NUM is
44157901Selan the signal number.
44257901Selan
44357901Selan If the supplied signal number is not within the range of valid
44457901Selan indices, then returns NULL.
44557901Selan
44657901Selan BUGS
44757901Selan
44857901Selan The contents of the location pointed to are only guaranteed to be
44957901Selan valid until the next call to strsigno.
45057901Selan
45157901Selan */
45257901Selan
45357901Selan char *
strsigno(signo)45457901Selan strsigno (signo)
45557901Selan int signo;
45657901Selan {
45757901Selan char *name;
45857901Selan static char buf[32];
45957901Selan
46057901Selan if (signal_names == NULL)
46157901Selan {
46257901Selan init_signal_tables ();
46357901Selan }
46457901Selan
46557901Selan if ((signo < 0) || (signo >= num_signal_names))
46657901Selan {
46757901Selan /* Out of range, just return NULL */
46857901Selan name = NULL;
46957901Selan }
47057901Selan else if ((signal_names == NULL) || (signal_names[signo] == NULL))
47157901Selan {
47257901Selan /* In range, but no signal_names or no entry at this index. */
47357901Selan sprintf (buf, "Signal %d", signo);
47457901Selan name = buf;
47557901Selan }
47657901Selan else
47757901Selan {
47857901Selan /* In range, and a valid name. Just return the name. */
47957901Selan name = signal_names[signo];
48057901Selan }
48157901Selan
48257901Selan return (name);
48357901Selan }
48457901Selan
48557901Selan
48657901Selan /*
48757901Selan
48857901Selan NAME
48957901Selan
49057901Selan strtosigno -- map a symbolic signal name to a numeric value
49157901Selan
49257901Selan SYNOPSIS
49357901Selan
49457901Selan int strtosigno (char *name)
49557901Selan
49657901Selan DESCRIPTION
49757901Selan
49857901Selan Given the symbolic name of a signal, map it to a signal number.
49957901Selan If no translation is found, returns 0.
50057901Selan
50157901Selan */
50257901Selan
50357901Selan int
strtosigno(name)50457901Selan strtosigno (name)
50557901Selan char *name;
50657901Selan {
50757901Selan int signo = 0;
50857901Selan
50957901Selan if (name != NULL)
51057901Selan {
51157901Selan if (signal_names == NULL)
51257901Selan {
51357901Selan init_signal_tables ();
51457901Selan }
51557901Selan for (signo = 0; signo < num_signal_names; signo++)
51657901Selan {
51757901Selan if ((signal_names[signo] != NULL) &&
51857901Selan (strcmp (name, signal_names[signo]) == 0))
51957901Selan {
52057901Selan break;
52157901Selan }
52257901Selan }
52357901Selan if (signo == num_signal_names)
52457901Selan {
52557901Selan signo = 0;
52657901Selan }
52757901Selan }
52857901Selan return (signo);
52957901Selan }
53057901Selan
53157901Selan
53257901Selan /*
53357901Selan
53457901Selan NAME
53557901Selan
53657901Selan psignal -- print message about signal to stderr
53757901Selan
53857901Selan SYNOPSIS
53957901Selan
54057901Selan void psignal (unsigned signo, char *message);
54157901Selan
54257901Selan DESCRIPTION
54357901Selan
54457901Selan Print to the standard error the message, followed by a colon,
54557901Selan followed by the description of the signal specified by signo,
54657901Selan followed by a newline.
54757901Selan */
54857901Selan
54957901Selan #ifdef NEED_psignal
55057901Selan
55157901Selan void
psignal(signo,message)55257901Selan psignal (signo, message)
55357901Selan unsigned signo;
55457901Selan char *message;
55557901Selan {
55657901Selan if (signal_names == NULL)
55757901Selan {
55857901Selan init_signal_tables ();
55957901Selan }
56057901Selan if ((signo <= 0) || (signo >= sys_nsig))
56157901Selan {
56257901Selan fprintf (stderr, "%s: unknown signal\n", message);
56357901Selan }
56457901Selan else
56557901Selan {
56657901Selan fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
56757901Selan }
56857901Selan }
56957901Selan
57057901Selan #endif /* NEED_psignal */
57157901Selan
57257901Selan
57357901Selan /* A simple little main that does nothing but print all the signal translations
57457901Selan if MAIN is defined and this file is compiled and linked. */
57557901Selan
57657901Selan #ifdef MAIN
57757901Selan
main()57857901Selan main ()
57957901Selan {
58057901Selan int signo;
58157901Selan int maxsigno;
58257901Selan char *name;
58357901Selan char *msg;
58457901Selan char *strsigno ();
58557901Selan char *strsignal ();
58657901Selan
58757901Selan maxsigno = signo_max ();
58857901Selan printf ("%d entries in names table.\n", num_signal_names);
58957901Selan printf ("%d entries in messages table.\n", sys_nsig);
59057901Selan printf ("%d is max useful index.\n", maxsigno);
59157901Selan
59257901Selan /* Keep printing values until we get to the end of *both* tables, not
59357901Selan *either* table. Note that knowing the maximum useful index does *not*
59457901Selan relieve us of the responsibility of testing the return pointer for
59557901Selan NULL. */
59657901Selan
59757901Selan for (signo = 0; signo <= maxsigno; signo++)
59857901Selan {
59957901Selan name = strsigno (signo);
60057901Selan name = (name == NULL) ? "<NULL>" : name;
60157901Selan msg = strsignal (signo);
60257901Selan msg = (msg == NULL) ? "<NULL>" : msg;
60357901Selan printf ("%-4d%-18s%s\n", signo, name, msg);
60457901Selan }
60557901Selan }
60657901Selan
60757901Selan #endif
608