strsignal.c revision 130562
1/* Extended support for using signal values.
2   Written by Fred Fish.  fnf@cygnus.com
3   This file is in the public domain.  */
4
5#include "ansidecl.h"
6#include "libiberty.h"
7
8#include "config.h"
9
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
21
22#include <stdio.h>
23#include <signal.h>
24
25/*  Routines imported from standard C runtime libraries. */
26
27#ifdef HAVE_STDLIB_H
28#include <stdlib.h>
29#else
30extern PTR malloc ();
31#endif
32
33#ifdef HAVE_STRING_H
34#include <string.h>
35#else
36extern PTR memset ();
37#endif
38
39/* Undefine the macro we used to hide the definition of sys_siglist
40   found in the system header files.  */
41#undef sys_siglist
42#undef sys_nsig
43
44#ifndef NULL
45#  ifdef ANSI_PROTOTYPES
46#    define NULL (void *) 0
47#  else
48#    define NULL 0
49#  endif
50#endif
51
52#ifndef MAX
53#  define MAX(a,b) ((a) > (b) ? (a) : (b))
54#endif
55
56static void init_signal_tables PARAMS ((void));
57
58/* Translation table for signal values.
59
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
62   value.
63
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. */
67
68struct signal_info
69{
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 */
74#endif
75};
76
77#ifndef HAVE_SYS_SIGLIST
78#   define ENTRY(value, name, msg)	{value, name, msg}
79#else
80#   define ENTRY(value, name, msg)	{value, name}
81#endif
82
83static const struct signal_info signal_table[] =
84{
85#if defined (SIGHUP)
86  ENTRY(SIGHUP, "SIGHUP", "Hangup"),
87#endif
88#if defined (SIGINT)
89  ENTRY(SIGINT, "SIGINT", "Interrupt"),
90#endif
91#if defined (SIGQUIT)
92  ENTRY(SIGQUIT, "SIGQUIT", "Quit"),
93#endif
94#if defined (SIGILL)
95  ENTRY(SIGILL, "SIGILL", "Illegal instruction"),
96#endif
97#if defined (SIGTRAP)
98  ENTRY(SIGTRAP, "SIGTRAP", "Trace/breakpoint trap"),
99#endif
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. */
102#if defined (SIGIOT)
103  ENTRY(SIGIOT, "SIGIOT", "IOT trap"),
104#endif
105#if defined (SIGABRT)
106  ENTRY(SIGABRT, "SIGABRT", "Aborted"),
107#endif
108#if defined (SIGEMT)
109  ENTRY(SIGEMT, "SIGEMT", "Emulation trap"),
110#endif
111#if defined (SIGFPE)
112  ENTRY(SIGFPE, "SIGFPE", "Arithmetic exception"),
113#endif
114#if defined (SIGKILL)
115  ENTRY(SIGKILL, "SIGKILL", "Killed"),
116#endif
117#if defined (SIGBUS)
118  ENTRY(SIGBUS, "SIGBUS", "Bus error"),
119#endif
120#if defined (SIGSEGV)
121  ENTRY(SIGSEGV, "SIGSEGV", "Segmentation fault"),
122#endif
123#if defined (SIGSYS)
124  ENTRY(SIGSYS, "SIGSYS", "Bad system call"),
125#endif
126#if defined (SIGPIPE)
127  ENTRY(SIGPIPE, "SIGPIPE", "Broken pipe"),
128#endif
129#if defined (SIGALRM)
130  ENTRY(SIGALRM, "SIGALRM", "Alarm clock"),
131#endif
132#if defined (SIGTERM)
133  ENTRY(SIGTERM, "SIGTERM", "Terminated"),
134#endif
135#if defined (SIGUSR1)
136  ENTRY(SIGUSR1, "SIGUSR1", "User defined signal 1"),
137#endif
138#if defined (SIGUSR2)
139  ENTRY(SIGUSR2, "SIGUSR2", "User defined signal 2"),
140#endif
141/* Put SIGCLD before SIGCHLD, so that if SIGCLD==SIGCHLD then SIGCHLD
142   overrides SIGCLD.  SIGCHLD is in POXIX.1 */
143#if defined (SIGCLD)
144  ENTRY(SIGCLD, "SIGCLD", "Child status changed"),
145#endif
146#if defined (SIGCHLD)
147  ENTRY(SIGCHLD, "SIGCHLD", "Child status changed"),
148#endif
149#if defined (SIGPWR)
150  ENTRY(SIGPWR, "SIGPWR", "Power fail/restart"),
151#endif
152#if defined (SIGWINCH)
153  ENTRY(SIGWINCH, "SIGWINCH", "Window size changed"),
154#endif
155#if defined (SIGURG)
156  ENTRY(SIGURG, "SIGURG", "Urgent I/O condition"),
157#endif
158#if defined (SIGIO)
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
161     I/O is pending. */
162  ENTRY(SIGIO, "SIGIO", "I/O possible"),
163#endif
164#if defined (SIGPOLL)
165  ENTRY(SIGPOLL, "SIGPOLL", "Pollable event occurred"),
166#endif
167#if defined (SIGSTOP)
168  ENTRY(SIGSTOP, "SIGSTOP", "Stopped (signal)"),
169#endif
170#if defined (SIGTSTP)
171  ENTRY(SIGTSTP, "SIGTSTP", "Stopped (user)"),
172#endif
173#if defined (SIGCONT)
174  ENTRY(SIGCONT, "SIGCONT", "Continued"),
175#endif
176#if defined (SIGTTIN)
177  ENTRY(SIGTTIN, "SIGTTIN", "Stopped (tty input)"),
178#endif
179#if defined (SIGTTOU)
180  ENTRY(SIGTTOU, "SIGTTOU", "Stopped (tty output)"),
181#endif
182#if defined (SIGVTALRM)
183  ENTRY(SIGVTALRM, "SIGVTALRM", "Virtual timer expired"),
184#endif
185#if defined (SIGPROF)
186  ENTRY(SIGPROF, "SIGPROF", "Profiling timer expired"),
187#endif
188#if defined (SIGXCPU)
189  ENTRY(SIGXCPU, "SIGXCPU", "CPU time limit exceeded"),
190#endif
191#if defined (SIGXFSZ)
192  ENTRY(SIGXFSZ, "SIGXFSZ", "File size limit exceeded"),
193#endif
194#if defined (SIGWIND)
195  ENTRY(SIGWIND, "SIGWIND", "SIGWIND"),
196#endif
197#if defined (SIGPHONE)
198  ENTRY(SIGPHONE, "SIGPHONE", "SIGPHONE"),
199#endif
200#if defined (SIGLOST)
201  ENTRY(SIGLOST, "SIGLOST", "Resource lost"),
202#endif
203#if defined (SIGWAITING)
204  ENTRY(SIGWAITING, "SIGWAITING", "Process's LWPs are blocked"),
205#endif
206#if defined (SIGLWP)
207  ENTRY(SIGLWP, "SIGLWP", "Signal LWP"),
208#endif
209#if defined (SIGDANGER)
210  ENTRY(SIGDANGER, "SIGDANGER", "Swap space dangerously low"),
211#endif
212#if defined (SIGGRANT)
213  ENTRY(SIGGRANT, "SIGGRANT", "Monitor mode granted"),
214#endif
215#if defined (SIGRETRACT)
216  ENTRY(SIGRETRACT, "SIGRETRACT", "Need to relinguish monitor mode"),
217#endif
218#if defined (SIGMSG)
219  ENTRY(SIGMSG, "SIGMSG", "Monitor mode data available"),
220#endif
221#if defined (SIGSOUND)
222  ENTRY(SIGSOUND, "SIGSOUND", "Sound completed"),
223#endif
224#if defined (SIGSAK)
225  ENTRY(SIGSAK, "SIGSAK", "Secure attention"),
226#endif
227  ENTRY(0, NULL, NULL)
228};
229
230/* Translation table allocated and initialized at runtime.  Indexed by the
231   signal value to find the equivalent symbolic value. */
232
233static const char **signal_names;
234static int num_signal_names = 0;
235
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.
239
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. */
243
244#ifndef HAVE_SYS_SIGLIST
245
246static int sys_nsig;
247static const char **sys_siglist;
248
249#else
250
251#ifdef NSIG
252static int sys_nsig = NSIG;
253#else
254#ifdef _NSIG
255static int sys_nsig = _NSIG;
256#endif
257#endif
258extern const char * const sys_siglist[];
259
260#endif
261
262
263/*
264
265NAME
266
267	init_signal_tables -- initialize the name and message tables
268
269SYNOPSIS
270
271	static void init_signal_tables ();
272
273DESCRIPTION
274
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.
278
279BUGS
280
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.
288
289*/
290
291static void
292init_signal_tables ()
293{
294  const struct signal_info *eip;
295  int nbytes;
296
297  /* If we haven't already scanned the signal_table once to find the maximum
298     signal value, then go find it now. */
299
300  if (num_signal_names == 0)
301    {
302      for (eip = signal_table; eip -> name != NULL; eip++)
303	{
304	  if (eip -> value >= num_signal_names)
305	    {
306	      num_signal_names = eip -> value + 1;
307	    }
308	}
309    }
310
311  /* Now attempt to allocate the signal_names table, zero it out, and then
312     initialize it from the statically initialized signal_table. */
313
314  if (signal_names == NULL)
315    {
316      nbytes = num_signal_names * sizeof (char *);
317      if ((signal_names = (const char **) malloc (nbytes)) != NULL)
318	{
319	  memset (signal_names, 0, nbytes);
320	  for (eip = signal_table; eip -> name != NULL; eip++)
321	    {
322	      signal_names[eip -> value] = eip -> name;
323	    }
324	}
325    }
326
327#ifndef HAVE_SYS_SIGLIST
328
329  /* Now attempt to allocate the sys_siglist table, zero it out, and then
330     initialize it from the statically initialized signal_table. */
331
332  if (sys_siglist == NULL)
333    {
334      nbytes = num_signal_names * sizeof (char *);
335      if ((sys_siglist = (const char **) malloc (nbytes)) != NULL)
336	{
337	  memset (sys_siglist, 0, nbytes);
338	  sys_nsig = num_signal_names;
339	  for (eip = signal_table; eip -> name != NULL; eip++)
340	    {
341	      sys_siglist[eip -> value] = eip -> msg;
342	    }
343	}
344    }
345
346#endif
347
348}
349
350
351/*
352
353@deftypefn Extension int signo_max (void)
354
355Returns the maximum signal value for which a corresponding symbolic
356name 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
358be more symbolic names than messages, or vice versa.  In fact, the
359manual page for @code{psignal(3b)} explicitly warns that one should
360check the size of the table (@code{NSIG}) before indexing it, since
361new signal codes may be added to the system before they are added to
362the table.  Thus @code{NSIG} might be smaller than value implied by
363the largest signo value defined in @code{<signal.h>}.
364
365We return the maximum value that can be used to obtain a meaningful
366symbolic name or message.
367
368@end deftypefn
369
370*/
371
372int
373signo_max ()
374{
375  int maxsize;
376
377  if (signal_names == NULL)
378    {
379      init_signal_tables ();
380    }
381  maxsize = MAX (sys_nsig, num_signal_names);
382  return (maxsize - 1);
383}
384
385
386/*
387
388@deftypefn Supplemental {const char *} strsignal (int @var{signo})
389
390Maps an signal number to an signal message string, the contents of
391which are implementation defined.  On systems which have the external
392variable @code{sys_siglist}, these strings will be the same as the
393ones used by @code{psignal()}.
394
395If the supplied signal number is within the valid range of indices for
396the @code{sys_siglist}, but no message is available for the particular
397signal number, then returns the string @samp{Signal @var{num}}, where
398@var{num} is the signal number.
399
400If the supplied signal number is not a valid index into
401@code{sys_siglist}, returns @code{NULL}.
402
403The returned string is only guaranteed to be valid only until the next
404call to @code{strsignal}.
405
406@end deftypefn
407
408*/
409
410#ifndef HAVE_STRSIGNAL
411
412const char *
413strsignal (signo)
414  int signo;
415{
416  const char *msg;
417  static char buf[32];
418
419#ifndef HAVE_SYS_SIGLIST
420
421  if (signal_names == NULL)
422    {
423      init_signal_tables ();
424    }
425
426#endif
427
428  if ((signo < 0) || (signo >= sys_nsig))
429    {
430      /* Out of range, just return NULL */
431      msg = NULL;
432    }
433  else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
434    {
435      /* In range, but no sys_siglist or no entry at this index. */
436      sprintf (buf, "Signal %d", signo);
437      msg = (const char *) buf;
438    }
439  else
440    {
441      /* In range, and a valid message.  Just return the message. */
442      msg = (const char *) sys_siglist[signo];
443    }
444
445  return (msg);
446}
447
448#endif /* ! HAVE_STRSIGNAL */
449
450/*
451
452@deftypefn Extension {const char*} strsigno (int @var{signo})
453
454Given an signal number, returns a pointer to a string containing the
455symbolic name of that signal number, as found in @code{<signal.h>}.
456
457If the supplied signal number is within the valid range of indices for
458symbolic names, but no name is available for the particular signal
459number, then returns the string @samp{Signal @var{num}}, where
460@var{num} is the signal number.
461
462If the supplied signal number is not within the range of valid
463indices, then returns @code{NULL}.
464
465The contents of the location pointed to are only guaranteed to be
466valid until the next call to @code{strsigno}.
467
468@end deftypefn
469
470*/
471
472const char *
473strsigno (signo)
474  int signo;
475{
476  const char *name;
477  static char buf[32];
478
479  if (signal_names == NULL)
480    {
481      init_signal_tables ();
482    }
483
484  if ((signo < 0) || (signo >= num_signal_names))
485    {
486      /* Out of range, just return NULL */
487      name = NULL;
488    }
489  else if ((signal_names == NULL) || (signal_names[signo] == NULL))
490    {
491      /* In range, but no signal_names or no entry at this index. */
492      sprintf (buf, "Signal %d", signo);
493      name = (const char *) buf;
494    }
495  else
496    {
497      /* In range, and a valid name.  Just return the name. */
498      name = signal_names[signo];
499    }
500
501  return (name);
502}
503
504
505/*
506
507@deftypefn Extension int strtosigno (const char *@var{name})
508
509Given the symbolic name of a signal, map it to a signal number.  If no
510translation is found, returns 0.
511
512@end deftypefn
513
514*/
515
516int
517strtosigno (name)
518     const char *name;
519{
520  int signo = 0;
521
522  if (name != NULL)
523    {
524      if (signal_names == NULL)
525	{
526	  init_signal_tables ();
527	}
528      for (signo = 0; signo < num_signal_names; signo++)
529	{
530	  if ((signal_names[signo] != NULL) &&
531	      (strcmp (name, signal_names[signo]) == 0))
532	    {
533	      break;
534	    }
535	}
536      if (signo == num_signal_names)
537	{
538	  signo = 0;
539	}
540    }
541  return (signo);
542}
543
544
545/*
546
547@deftypefn Supplemental void psignal (unsigned @var{signo}, char *@var{message})
548
549Print @var{message} to the standard error, followed by a colon,
550followed by the description of the signal specified by @var{signo},
551followed by a newline.
552
553@end deftypefn
554
555*/
556
557#ifndef HAVE_PSIGNAL
558
559void
560psignal (signo, message)
561  unsigned signo;
562  char *message;
563{
564  if (signal_names == NULL)
565    {
566      init_signal_tables ();
567    }
568  if ((signo <= 0) || (signo >= sys_nsig))
569    {
570      fprintf (stderr, "%s: unknown signal\n", message);
571    }
572  else
573    {
574      fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
575    }
576}
577
578#endif	/* ! HAVE_PSIGNAL */
579
580
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. */
583
584#ifdef MAIN
585
586#include <stdio.h>
587
588int
589main ()
590{
591  int signo;
592  int maxsigno;
593  const char *name;
594  const char *msg;
595
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);
600
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
604     NULL. */
605
606  for (signo = 0; signo <= maxsigno; signo++)
607    {
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);
613    }
614
615  return 0;
616}
617
618#endif
619