1 /* Extended support for using signal values.
2 Written by Fred Fish. fnf@cygnus.com
3 This file is in the public domain. */
10 /* We need to declare sys_siglist, because even if the system provides
11 it we can't assume that it is declared in <signal.h> (for example,
12 SunOS provides sys_siglist, but it does not declare it in any
13 header file). fHowever, we can't declare sys_siglist portably,
14 because on some systems it is declared with const and on some
15 systems it is declared without const. If we were using autoconf,
16 we could work out the right declaration. Until, then we just
17 ignore any declaration in the system header files, and always
18 declare it ourselves. With luck, this will always work. */
19 #define sys_siglist no_such_symbol
20 #define sys_nsig sys_nsig__no_such_symbol
25 /* Routines imported from standard C runtime libraries. */
39 /* Undefine the macro we used to hide the definition of sys_siglist
40 found in the system header files. */
45 # ifdef ANSI_PROTOTYPES
46 # define NULL (void *) 0
53 # define MAX(a,b) ((a) > (b) ? (a) : (b))
56 static void init_signal_tables
PARAMS ((void));
58 /* Translation table for signal values.
60 Note that this table is generally only accessed when it is used at runtime
61 to initialize signal name and message tables that are indexed by signal
64 Not all of these signals will exist on all systems. This table is the only
65 thing that should have to be updated as new signal numbers are introduced.
66 It's sort of ugly, but at least its portable. */
70 const int value
; /* The numeric value from <signal.h> */
71 const char *const name
; /* The equivalent symbolic value */
72 #ifndef HAVE_SYS_SIGLIST
73 const char *const msg
; /* Short message about this value */
77 #ifndef HAVE_SYS_SIGLIST
78 # define ENTRY(value, name, msg) {value, name, msg}
80 # define ENTRY(value, name, msg) {value, name}
83 static const struct signal_info signal_table
[] =
86 ENTRY(SIGHUP
, "SIGHUP", "Hangup"),
89 ENTRY(SIGINT
, "SIGINT", "Interrupt"),
92 ENTRY(SIGQUIT
, "SIGQUIT", "Quit"),
95 ENTRY(SIGILL
, "SIGILL", "Illegal instruction"),
98 ENTRY(SIGTRAP
, "SIGTRAP", "Trace/breakpoint trap"),
100 /* Put SIGIOT before SIGABRT, so that if SIGIOT==SIGABRT then SIGABRT
101 overrides SIGIOT. SIGABRT is in ANSI and POSIX.1, and SIGIOT isn't. */
103 ENTRY(SIGIOT
, "SIGIOT", "IOT trap"),
105 #if defined (SIGABRT)
106 ENTRY(SIGABRT
, "SIGABRT", "Aborted"),
109 ENTRY(SIGEMT
, "SIGEMT", "Emulation trap"),
112 ENTRY(SIGFPE
, "SIGFPE", "Arithmetic exception"),
114 #if defined (SIGKILL)
115 ENTRY(SIGKILL
, "SIGKILL", "Killed"),
118 ENTRY(SIGBUS
, "SIGBUS", "Bus error"),
120 #if defined (SIGSEGV)
121 ENTRY(SIGSEGV
, "SIGSEGV", "Segmentation fault"),
124 ENTRY(SIGSYS
, "SIGSYS", "Bad system call"),
126 #if defined (SIGPIPE)
127 ENTRY(SIGPIPE
, "SIGPIPE", "Broken pipe"),
129 #if defined (SIGALRM)
130 ENTRY(SIGALRM
, "SIGALRM", "Alarm clock"),
132 #if defined (SIGTERM)
133 ENTRY(SIGTERM
, "SIGTERM", "Terminated"),
135 #if defined (SIGUSR1)
136 ENTRY(SIGUSR1
, "SIGUSR1", "User defined signal 1"),
138 #if defined (SIGUSR2)
139 ENTRY(SIGUSR2
, "SIGUSR2", "User defined signal 2"),
141 /* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD
142 overrides SIGCLD. SIGCHLD is in POXIX.1 */
144 ENTRY(SIGCLD
, "SIGCLD", "Child status changed"),
146 #if defined (SIGCHLD)
147 ENTRY(SIGCHLD
, "SIGCHLD", "Child status changed"),
150 ENTRY(SIGPWR
, "SIGPWR", "Power fail/restart"),
152 #if defined (SIGWINCH)
153 ENTRY(SIGWINCH
, "SIGWINCH", "Window size changed"),
156 ENTRY(SIGURG
, "SIGURG", "Urgent I/O condition"),
159 /* "I/O pending" has also been suggested, but is misleading since the
160 signal only happens when the process has asked for it, not everytime
162 ENTRY(SIGIO
, "SIGIO", "I/O possible"),
164 #if defined (SIGPOLL)
165 ENTRY(SIGPOLL
, "SIGPOLL", "Pollable event occurred"),
167 #if defined (SIGSTOP)
168 ENTRY(SIGSTOP
, "SIGSTOP", "Stopped (signal)"),
170 #if defined (SIGTSTP)
171 ENTRY(SIGTSTP
, "SIGTSTP", "Stopped (user)"),
173 #if defined (SIGCONT)
174 ENTRY(SIGCONT
, "SIGCONT", "Continued"),
176 #if defined (SIGTTIN)
177 ENTRY(SIGTTIN
, "SIGTTIN", "Stopped (tty input)"),
179 #if defined (SIGTTOU)
180 ENTRY(SIGTTOU
, "SIGTTOU", "Stopped (tty output)"),
182 #if defined (SIGVTALRM)
183 ENTRY(SIGVTALRM
, "SIGVTALRM", "Virtual timer expired"),
185 #if defined (SIGPROF)
186 ENTRY(SIGPROF
, "SIGPROF", "Profiling timer expired"),
188 #if defined (SIGXCPU)
189 ENTRY(SIGXCPU
, "SIGXCPU", "CPU time limit exceeded"),
191 #if defined (SIGXFSZ)
192 ENTRY(SIGXFSZ
, "SIGXFSZ", "File size limit exceeded"),
194 #if defined (SIGWIND)
195 ENTRY(SIGWIND
, "SIGWIND", "SIGWIND"),
197 #if defined (SIGPHONE)
198 ENTRY(SIGPHONE
, "SIGPHONE", "SIGPHONE"),
200 #if defined (SIGLOST)
201 ENTRY(SIGLOST
, "SIGLOST", "Resource lost"),
203 #if defined (SIGWAITING)
204 ENTRY(SIGWAITING
, "SIGWAITING", "Process's LWPs are blocked"),
207 ENTRY(SIGLWP
, "SIGLWP", "Signal LWP"),
209 #if defined (SIGDANGER)
210 ENTRY(SIGDANGER
, "SIGDANGER", "Swap space dangerously low"),
212 #if defined (SIGGRANT)
213 ENTRY(SIGGRANT
, "SIGGRANT", "Monitor mode granted"),
215 #if defined (SIGRETRACT)
216 ENTRY(SIGRETRACT
, "SIGRETRACT", "Need to relinguish monitor mode"),
219 ENTRY(SIGMSG
, "SIGMSG", "Monitor mode data available"),
221 #if defined (SIGSOUND)
222 ENTRY(SIGSOUND
, "SIGSOUND", "Sound completed"),
225 ENTRY(SIGSAK
, "SIGSAK", "Secure attention"),
230 /* Translation table allocated and initialized at runtime. Indexed by the
231 signal value to find the equivalent symbolic value. */
233 static const char **signal_names
;
234 static int num_signal_names
= 0;
236 /* Translation table allocated and initialized at runtime, if it does not
237 already exist in the host environment. Indexed by the signal value to find
238 the descriptive string.
240 We don't export it for use in other modules because even though it has the
241 same name, it differs from other implementations in that it is dynamically
242 initialized rather than statically initialized. */
244 #ifndef HAVE_SYS_SIGLIST
247 static const char **sys_siglist
;
252 static int sys_nsig
= NSIG
;
255 static int sys_nsig
= _NSIG
;
258 extern const char * const sys_siglist
[];
267 init_signal_tables -- initialize the name and message tables
271 static void init_signal_tables ();
275 Using the signal_table, which is initialized at compile time, generate
276 the signal_names and the sys_siglist (if needed) tables, which are
277 indexed at runtime by a specific signal value.
281 The initialization of the tables may fail under low memory conditions,
282 in which case we don't do anything particularly useful, but we don't
283 bomb either. Who knows, it might succeed at a later point if we free
284 some memory in the meantime. In any case, the other routines know
285 how to deal with lack of a table after trying to initialize it. This
286 may or may not be considered to be a bug, that we don't specifically
287 warn about this particular failure mode.
292 init_signal_tables ()
294 const struct signal_info
*eip
;
297 /* If we haven't already scanned the signal_table once to find the maximum
298 signal value, then go find it now. */
300 if (num_signal_names
== 0)
302 for (eip
= signal_table
; eip
-> name
!= NULL
; eip
++)
304 if (eip
-> value
>= num_signal_names
)
306 num_signal_names
= eip
-> value
+ 1;
311 /* Now attempt to allocate the signal_names table, zero it out, and then
312 initialize it from the statically initialized signal_table. */
314 if (signal_names
== NULL
)
316 nbytes
= num_signal_names
* sizeof (char *);
317 if ((signal_names
= (const char **) malloc (nbytes
)) != NULL
)
319 memset (signal_names
, 0, nbytes
);
320 for (eip
= signal_table
; eip
-> name
!= NULL
; eip
++)
322 signal_names
[eip
-> value
] = eip
-> name
;
327 #ifndef HAVE_SYS_SIGLIST
329 /* Now attempt to allocate the sys_siglist table, zero it out, and then
330 initialize it from the statically initialized signal_table. */
332 if (sys_siglist
== NULL
)
334 nbytes
= num_signal_names
* sizeof (char *);
335 if ((sys_siglist
= (const char **) malloc (nbytes
)) != NULL
)
337 memset (sys_siglist
, 0, nbytes
);
338 sys_nsig
= num_signal_names
;
339 for (eip
= signal_table
; eip
-> name
!= NULL
; eip
++)
341 sys_siglist
[eip
-> value
] = eip
-> msg
;
353 @deftypefn Extension int signo_max (void)
355 Returns the maximum signal value for which a corresponding symbolic
356 name or message is available. Note that in the case where we use the
357 @code{sys_siglist} supplied by the system, it is possible for there to
358 be more symbolic names than messages, or vice versa. In fact, the
359 manual page for @code{psignal(3b)} explicitly warns that one should
360 check the size of the table (@code{NSIG}) before indexing it, since
361 new signal codes may be added to the system before they are added to
362 the table. Thus @code{NSIG} might be smaller than value implied by
363 the largest signo value defined in @code{<signal.h>}.
365 We return the maximum value that can be used to obtain a meaningful
366 symbolic name or message.
377 if (signal_names
== NULL
)
379 init_signal_tables ();
381 maxsize
= MAX (sys_nsig
, num_signal_names
);
382 return (maxsize
- 1);
388 @deftypefn Supplemental {const char *} strsignal (int @var{signo})
390 Maps an signal number to an signal message string, the contents of
391 which are implementation defined. On systems which have the external
392 variable @code{sys_siglist}, these strings will be the same as the
393 ones used by @code{psignal()}.
395 If the supplied signal number is within the valid range of indices for
396 the @code{sys_siglist}, but no message is available for the particular
397 signal number, then returns the string @samp{Signal @var{num}}, where
398 @var{num} is the signal number.
400 If the supplied signal number is not a valid index into
401 @code{sys_siglist}, returns @code{NULL}.
403 The returned string is only guaranteed to be valid only until the next
404 call to @code{strsignal}.
410 #ifndef HAVE_STRSIGNAL
419 #ifndef HAVE_SYS_SIGLIST
421 if (signal_names
== NULL
)
423 init_signal_tables ();
428 if ((signo
< 0) || (signo
>= sys_nsig
))
430 /* Out of range, just return NULL */
433 else if ((sys_siglist
== NULL
) || (sys_siglist
[signo
] == NULL
))
435 /* In range, but no sys_siglist or no entry at this index. */
436 sprintf (buf
, "Signal %d", signo
);
437 msg
= (const char *) buf
;
441 /* In range, and a valid message. Just return the message. */
442 msg
= (const char *) sys_siglist
[signo
];
448 #endif /* ! HAVE_STRSIGNAL */
452 @deftypefn Extension {const char*} strsigno (int @var{signo})
454 Given an signal number, returns a pointer to a string containing the
455 symbolic name of that signal number, as found in @code{<signal.h>}.
457 If the supplied signal number is within the valid range of indices for
458 symbolic names, but no name is available for the particular signal
459 number, then returns the string @samp{Signal @var{num}}, where
460 @var{num} is the signal number.
462 If the supplied signal number is not within the range of valid
463 indices, then returns @code{NULL}.
465 The contents of the location pointed to are only guaranteed to be
466 valid until the next call to @code{strsigno}.
479 if (signal_names
== NULL
)
481 init_signal_tables ();
484 if ((signo
< 0) || (signo
>= num_signal_names
))
486 /* Out of range, just return NULL */
489 else if ((signal_names
== NULL
) || (signal_names
[signo
] == NULL
))
491 /* In range, but no signal_names or no entry at this index. */
492 sprintf (buf
, "Signal %d", signo
);
493 name
= (const char *) buf
;
497 /* In range, and a valid name. Just return the name. */
498 name
= signal_names
[signo
];
507 @deftypefn Extension int strtosigno (const char *@var{name})
509 Given the symbolic name of a signal, map it to a signal number. If no
510 translation is found, returns 0.
524 if (signal_names
== NULL
)
526 init_signal_tables ();
528 for (signo
= 0; signo
< num_signal_names
; signo
++)
530 if ((signal_names
[signo
] != NULL
) &&
531 (strcmp (name
, signal_names
[signo
]) == 0))
536 if (signo
== num_signal_names
)
547 @deftypefn Supplemental void psignal (unsigned @var{signo}, char *@var{message})
549 Print @var{message} to the standard error, followed by a colon,
550 followed by the description of the signal specified by @var{signo},
551 followed by a newline.
560 psignal (signo
, message
)
564 if (signal_names
== NULL
)
566 init_signal_tables ();
568 if ((signo
<= 0) || (signo
>= sys_nsig
))
570 fprintf (stderr
, "%s: unknown signal\n", message
);
574 fprintf (stderr
, "%s: %s\n", message
, sys_siglist
[signo
]);
578 #endif /* ! HAVE_PSIGNAL */
581 /* A simple little main that does nothing but print all the signal translations
582 if MAIN is defined and this file is compiled and linked. */
596 maxsigno
= signo_max ();
597 printf ("%d entries in names table.\n", num_signal_names
);
598 printf ("%d entries in messages table.\n", sys_nsig
);
599 printf ("%d is max useful index.\n", maxsigno
);
601 /* Keep printing values until we get to the end of *both* tables, not
602 *either* table. Note that knowing the maximum useful index does *not*
603 relieve us of the responsibility of testing the return pointer for
606 for (signo
= 0; signo
<= maxsigno
; signo
++)
608 name
= strsigno (signo
);
609 name
= (name
== NULL
) ? "<NULL>" : name
;
610 msg
= strsignal (signo
);
611 msg
= (msg
== NULL
) ? "<NULL>" : msg
;
612 printf ("%-4d%-18s%s\n", signo
, name
, msg
);