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