1 /* Extended support for using signal values.
2 Written by Fred Fish. fnf@cygnus.com
3 This file is in the public domain. */
9 /* We need to declare sys_siglist, because even if the system provides
10 it we can't assume that it is declared in <signal.h> (for example,
11 SunOS provides sys_siglist, but it does not declare it in any
12 header file). fHowever, we can't declare sys_siglist portably,
13 because on some systems it is declared with const and on some
14 systems it is declared without const. If we were using autoconf,
15 we could work out the right declaration. Until, then we just
16 ignore any declaration in the system header files, and always
17 declare it ourselves. With luck, this will always work. */
18 #define sys_siglist no_such_symbol
19 #define sys_nsig sys_nsig__no_such_symbol
24 /* Routines imported from standard C runtime libraries. */
38 /* Undefine the macro we used to hide the definition of sys_siglist
39 found in the system header files. */
44 # ifdef ANSI_PROTOTYPES
45 # define NULL (void *) 0
52 # define MAX(a,b) ((a) > (b) ? (a) : (b))
55 static void init_signal_tables PARAMS ((void));
57 /* Translation table for signal values.
59 Note that this table is generally only accessed when it is used at runtime
60 to initialize signal name and message tables that are indexed by signal
63 Not all of these signals will exist on all systems. This table is the only
64 thing that should have to be updated as new signal numbers are introduced.
65 It's sort of ugly, but at least its portable. */
69 const int value; /* The numeric value from <signal.h> */
70 const char *const name; /* The equivalent symbolic value */
71 #ifndef HAVE_SYS_SIGLIST
72 const char *const msg; /* Short message about this value */
76 #ifndef HAVE_SYS_SIGLIST
77 # define ENTRY(value, name, msg) {value, name, msg}
79 # define ENTRY(value, name, msg) {value, name}
82 static const struct signal_info signal_table[] =
85 ENTRY(SIGHUP, "SIGHUP", "Hangup"),
88 ENTRY(SIGINT, "SIGINT", "Interrupt"),
91 ENTRY(SIGQUIT, "SIGQUIT", "Quit"),
94 ENTRY(SIGILL, "SIGILL", "Illegal instruction"),
97 ENTRY(SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"),
99 /* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT
100 overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */
102 ENTRY(SIGIOT, "SIGIOT", "IOT trap"),
104 #if defined (SIGABRT)
105 ENTRY(SIGABRT, "SIGABRT", "Aborted"),
108 ENTRY(SIGEMT, "SIGEMT", "Emulation trap"),
111 ENTRY(SIGFPE, "SIGFPE", "Arithmetic exception"),
113 #if defined (SIGKILL)
114 ENTRY(SIGKILL, "SIGKILL", "Killed"),
117 ENTRY(SIGBUS, "SIGBUS", "Bus error"),
119 #if defined (SIGSEGV)
120 ENTRY(SIGSEGV, "SIGSEGV", "Segmentation fault"),
123 ENTRY(SIGSYS, "SIGSYS", "Bad system call"),
125 #if defined (SIGPIPE)
126 ENTRY(SIGPIPE, "SIGPIPE", "Broken pipe"),
128 #if defined (SIGALRM)
129 ENTRY(SIGALRM, "SIGALRM", "Alarm clock"),
131 #if defined (SIGTERM)
132 ENTRY(SIGTERM, "SIGTERM", "Terminated"),
134 #if defined (SIGUSR1)
135 ENTRY(SIGUSR1, "SIGUSR1", "User defined signal 1"),
137 #if defined (SIGUSR2)
138 ENTRY(SIGUSR2, "SIGUSR2", "User defined signal 2"),
140 /* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD
141 overrides SIGCLD. SIGCHLD is in POXIX.1 */
143 ENTRY(SIGCLD, "SIGCLD", "Child status changed"),
145 #if defined (SIGCHLD)
146 ENTRY(SIGCHLD, "SIGCHLD", "Child status changed"),
149 ENTRY(SIGPWR, "SIGPWR", "Power fail/restart"),
151 #if defined (SIGWINCH)
152 ENTRY(SIGWINCH, "SIGWINCH", "Window size changed"),
155 ENTRY(SIGURG, "SIGURG", "Urgent I/O condition"),
158 /* "I/O pending" has also been suggested, but is misleading since the
159 signal only happens when the process has asked for it, not everytime
161 ENTRY(SIGIO, "SIGIO", "I/O possible"),
163 #if defined (SIGPOLL)
164 ENTRY(SIGPOLL, "SIGPOLL", "Pollable event occurred"),
166 #if defined (SIGSTOP)
167 ENTRY(SIGSTOP, "SIGSTOP", "Stopped (signal)"),
169 #if defined (SIGTSTP)
170 ENTRY(SIGTSTP, "SIGTSTP", "Stopped (user)"),
172 #if defined (SIGCONT)
173 ENTRY(SIGCONT, "SIGCONT", "Continued"),
175 #if defined (SIGTTIN)
176 ENTRY(SIGTTIN, "SIGTTIN", "Stopped (tty input)"),
178 #if defined (SIGTTOU)
179 ENTRY(SIGTTOU, "SIGTTOU", "Stopped (tty output)"),
181 #if defined (SIGVTALRM)
182 ENTRY(SIGVTALRM, "SIGVTALRM", "Virtual timer expired"),
184 #if defined (SIGPROF)
185 ENTRY(SIGPROF, "SIGPROF", "Profiling timer expired"),
187 #if defined (SIGXCPU)
188 ENTRY(SIGXCPU, "SIGXCPU", "CPU time limit exceeded"),
190 #if defined (SIGXFSZ)
191 ENTRY(SIGXFSZ, "SIGXFSZ", "File size limit exceeded"),
193 #if defined (SIGWIND)
194 ENTRY(SIGWIND, "SIGWIND", "SIGWIND"),
196 #if defined (SIGPHONE)
197 ENTRY(SIGPHONE, "SIGPHONE", "SIGPHONE"),
199 #if defined (SIGLOST)
200 ENTRY(SIGLOST, "SIGLOST", "Resource lost"),
202 #if defined (SIGWAITING)
203 ENTRY(SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"),
206 ENTRY(SIGLWP, "SIGLWP", "Signal LWP"),
208 #if defined (SIGDANGER)
209 ENTRY(SIGDANGER, "SIGDANGER", "Swap space dangerously low"),
211 #if defined (SIGGRANT)
212 ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"),
214 #if defined (SIGRETRACT)
215 ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"),
218 ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"),
220 #if defined (SIGSOUND)
221 ENTRY(SIGSOUND, "SIGSOUND", "Sound completed"),
224 ENTRY(SIGSAK, "SIGSAK", "Secure attention"),
229 /* Translation table allocated and initialized at runtime. Indexed by the
230 signal value to find the equivalent symbolic value. */
232 static const char **signal_names;
233 static int num_signal_names = 0;
235 /* Translation table allocated and initialized at runtime, if it does not
236 already exist in the host environment. Indexed by the signal value to find
237 the descriptive string.
239 We don't export it for use in other modules because even though it has the
240 same name, it differs from other implementations in that it is dynamically
241 initialized rather than statically initialized. */
243 #ifndef HAVE_SYS_SIGLIST
246 static const char **sys_siglist;
251 static int sys_nsig = NSIG;
254 static int sys_nsig = _NSIG;
257 extern const char * const sys_siglist[];
266 init_signal_tables -- initialize the name and message tables
270 static void init_signal_tables ();
274 Using the signal_table, which is initialized at compile time, generate
275 the signal_names and the sys_siglist (if needed) tables, which are
276 indexed at runtime by a specific signal value.
280 The initialization of the tables may fail under low memory conditions,
281 in which case we don't do anything particularly useful, but we don't
282 bomb either. Who knows, it might succeed at a later point if we free
283 some memory in the meantime. In any case, the other routines know
284 how to deal with lack of a table after trying to initialize it. This
285 may or may not be considered to be a bug, that we don't specifically
286 warn about this particular failure mode.
291 init_signal_tables ()
293 const struct signal_info *eip;
296 /* If we haven't already scanned the signal_table once to find the maximum
297 signal value, then go find it now. */
299 if (num_signal_names == 0)
301 for (eip = signal_table; eip -> name != NULL; eip++)
303 if (eip -> value >= num_signal_names)
305 num_signal_names = eip -> value + 1;
310 /* Now attempt to allocate the signal_names table, zero it out, and then
311 initialize it from the statically initialized signal_table. */
313 if (signal_names == NULL)
315 nbytes = num_signal_names * sizeof (char *);
316 if ((signal_names = (const char **) malloc (nbytes)) != NULL)
318 memset (signal_names, 0, nbytes);
319 for (eip = signal_table; eip -> name != NULL; eip++)
321 signal_names[eip -> value] = eip -> name;
326 #ifndef HAVE_SYS_SIGLIST
328 /* Now attempt to allocate the sys_siglist table, zero it out, and then
329 initialize it from the statically initialized signal_table. */
331 if (sys_siglist == NULL)
333 nbytes = num_signal_names * sizeof (char *);
334 if ((sys_siglist = (const char **) malloc (nbytes)) != NULL)
336 memset (sys_siglist, 0, nbytes);
337 sys_nsig = num_signal_names;
338 for (eip = signal_table; eip -> name != NULL; eip++)
340 sys_siglist[eip -> value] = eip -> msg;
352 @deftypefn Extension int signo_max (void)
354 Returns the maximum signal value for which a corresponding symbolic
355 name or message is available. Note that in the case where we use the
356 @code{sys_siglist} supplied by the system, it is possible for there to
357 be more symbolic names than messages, or vice versa. In fact, the
358 manual page for @code{psignal(3b)} explicitly warns that one should
359 check the size of the table (@code{NSIG}) before indexing it, since
360 new signal codes may be added to the system before they are added to
361 the table. Thus @code{NSIG} might be smaller than value implied by
362 the largest signo value defined in @code{<signal.h>}.
364 We return the maximum value that can be used to obtain a meaningful
365 symbolic name or message.
376 if (signal_names == NULL)
378 init_signal_tables ();
380 maxsize = MAX (sys_nsig, num_signal_names);
381 return (maxsize - 1);
387 @deftypefn Supplemental {const char *} strsignal (int @var{signo})
389 Maps an signal number to an signal message string, the contents of
390 which are implementation defined. On systems which have the external
391 variable @code{sys_siglist}, these strings will be the same as the
392 ones used by @code{psignal()}.
394 If the supplied signal number is within the valid range of indices for
395 the @code{sys_siglist}, but no message is available for the particular
396 signal number, then returns the string @samp{Signal @var{num}}, where
397 @var{num} is the signal number.
399 If the supplied signal number is not a valid index into
400 @code{sys_siglist}, returns @code{NULL}.
402 The returned string is only guaranteed to be valid only until the next
403 call to @code{strsignal}.
409 #ifndef HAVE_STRSIGNAL
418 #ifndef HAVE_SYS_SIGLIST
420 if (signal_names == NULL)
422 init_signal_tables ();
427 if ((signo < 0) || (signo >= sys_nsig))
429 /* Out of range, just return NULL */
432 else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
434 /* In range, but no sys_siglist or no entry at this index. */
435 sprintf (buf, "Signal %d", signo);
436 msg = (const char *) buf;
440 /* In range, and a valid message. Just return the message. */
441 msg = (const char *) sys_siglist[signo];
447 #endif /* ! HAVE_STRSIGNAL */
451 @deftypefn Extension {const char*} strsigno (int @var{signo})
453 Given an signal number, returns a pointer to a string containing the
454 symbolic name of that signal number, as found in @code{<signal.h>}.
456 If the supplied signal number is within the valid range of indices for
457 symbolic names, but no name is available for the particular signal
458 number, then returns the string @samp{Signal @var{num}}, where
459 @var{num} is the signal number.
461 If the supplied signal number is not within the range of valid
462 indices, then returns @code{NULL}.
464 The contents of the location pointed to are only guaranteed to be
465 valid until the next call to @code{strsigno}.
478 if (signal_names == NULL)
480 init_signal_tables ();
483 if ((signo < 0) || (signo >= num_signal_names))
485 /* Out of range, just return NULL */
488 else if ((signal_names == NULL) || (signal_names[signo] == NULL))
490 /* In range, but no signal_names or no entry at this index. */
491 sprintf (buf, "Signal %d", signo);
492 name = (const char *) buf;
496 /* In range, and a valid name. Just return the name. */
497 name = signal_names[signo];
506 @deftypefn Extension int strtosigno (const char *@var{name})
508 Given the symbolic name of a signal, map it to a signal number. If no
509 translation is found, returns 0.
523 if (signal_names == NULL)
525 init_signal_tables ();
527 for (signo = 0; signo < num_signal_names; signo++)
529 if ((signal_names[signo] != NULL) &&
530 (strcmp (name, signal_names[signo]) == 0))
535 if (signo == num_signal_names)
546 @deftypefn Supplemental void psignal (unsigned @var{signo}, char *@var{message})
548 Print @var{message} to the standard error, followed by a colon,
549 followed by the description of the signal specified by @var{signo},
550 followed by a newline.
559 psignal (signo, message)
563 if (signal_names == NULL)
565 init_signal_tables ();
567 if ((signo <= 0) || (signo >= sys_nsig))
569 fprintf (stderr, "%s: unknown signal\n", message);
573 fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
577 #endif /* ! HAVE_PSIGNAL */
580 /* A simple little main that does nothing but print all the signal translations
581 if MAIN is defined and this file is compiled and linked. */
595 maxsigno = signo_max ();
596 printf ("%d entries in names table.\n", num_signal_names);
597 printf ("%d entries in messages table.\n", sys_nsig);
598 printf ("%d is max useful index.\n", maxsigno);
600 /* Keep printing values until we get to the end of *both* tables, not
601 *either* table. Note that knowing the maximum useful index does *not*
602 relieve us of the responsibility of testing the return pointer for
605 for (signo = 0; signo <= maxsigno; signo++)
607 name = strsigno (signo);
608 name = (name == NULL) ? "<NULL>" : name;
609 msg = strsignal (signo);
610 msg = (msg == NULL) ? "<NULL>" : msg;
611 printf ("%-4d%-18s%s\n", signo, name, msg);