OSDN Git Service

* strerror.c (sys_nerr): Hide the OS header version.
[pf3gnuchains/gcc-fork.git] / libiberty / strsignal.c
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
30 extern PTR malloc ();
31 #endif
32
33 #ifdef HAVE_STRING_H
34 #include <string.h>
35 #else
36 extern 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 __STDC__
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
56 static 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
68 struct signal_info
69 {
70   int value;            /* The numeric value from <signal.h> */
71   const char *name;     /* The equivalent symbolic value */
72 #ifndef HAVE_SYS_SIGLIST
73   const char *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
83 static 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
233 static const char **signal_names;
234 static 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
246 static int sys_nsig;
247 static const char **sys_siglist;
248
249 #else
250
251 #ifdef NSIG
252 static int sys_nsig = NSIG;
253 #else
254 #ifdef _NSIG
255 static int sys_nsig = _NSIG;
256 #endif
257 #endif
258 extern const char * const sys_siglist[];
259
260 #endif
261
262
263 /*
264
265 NAME
266
267         init_signal_tables -- initialize the name and message tables
268
269 SYNOPSIS
270
271         static void init_signal_tables ();
272
273 DESCRIPTION
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
279 BUGS
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
291 static void
292 init_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 NAME
354
355         signo_max -- return the max signo value
356
357 SYNOPSIS
358
359         int signo_max ();
360
361 DESCRIPTION
362
363         Returns the maximum signo value for which a corresponding symbolic
364         name or message is available.  Note that in the case where
365         we use the sys_siglist supplied by the system, it is possible for
366         there to be more symbolic names than messages, or vice versa.
367         In fact, the manual page for psignal(3b) explicitly warns that one
368         should check the size of the table (NSIG) before indexing it,
369         since new signal codes may be added to the system before they are
370         added to the table.  Thus NSIG might be smaller than value
371         implied by the largest signo value defined in <signal.h>.
372
373         We return the maximum value that can be used to obtain a meaningful
374         symbolic name or message.
375
376 */
377
378 int
379 signo_max ()
380 {
381   int maxsize;
382
383   if (signal_names == NULL)
384     {
385       init_signal_tables ();
386     }
387   maxsize = MAX (sys_nsig, num_signal_names);
388   return (maxsize - 1);
389 }
390
391
392 /*
393
394 NAME
395
396         strsignal -- map a signal number to a signal message string
397
398 SYNOPSIS
399
400         const char *strsignal (int signo)
401
402 DESCRIPTION
403
404         Maps an signal number to an signal message string, the contents of
405         which are implementation defined.  On systems which have the external
406         variable sys_siglist, these strings will be the same as the ones used
407         by psignal().
408
409         If the supplied signal number is within the valid range of indices
410         for the sys_siglist, but no message is available for the particular
411         signal number, then returns the string "Signal NUM", where NUM is the
412         signal number.
413
414         If the supplied signal number is not a valid index into sys_siglist,
415         returns NULL.
416
417         The returned string is only guaranteed to be valid only until the
418         next call to strsignal.
419
420 */
421
422 #ifndef HAVE_STRSIGNAL
423
424 const char *
425 strsignal (signo)
426   int signo;
427 {
428   const char *msg;
429   static char buf[32];
430
431 #ifndef HAVE_SYS_SIGLIST
432
433   if (signal_names == NULL)
434     {
435       init_signal_tables ();
436     }
437
438 #endif
439
440   if ((signo < 0) || (signo >= sys_nsig))
441     {
442       /* Out of range, just return NULL */
443       msg = NULL;
444     }
445   else if ((sys_siglist == NULL) || (sys_siglist[signo] == NULL))
446     {
447       /* In range, but no sys_siglist or no entry at this index. */
448       sprintf (buf, "Signal %d", signo);
449       msg = (const char *) buf;
450     }
451   else
452     {
453       /* In range, and a valid message.  Just return the message. */
454       msg = (const char *) sys_siglist[signo];
455     }
456   
457   return (msg);
458 }
459
460 #endif /* ! HAVE_STRSIGNAL */
461
462 /*
463
464 NAME
465
466         strsigno -- map an signal number to a symbolic name string
467
468 SYNOPSIS
469
470         const char *strsigno (int signo)
471
472 DESCRIPTION
473
474         Given an signal number, returns a pointer to a string containing
475         the symbolic name of that signal number, as found in <signal.h>.
476
477         If the supplied signal number is within the valid range of indices
478         for symbolic names, but no name is available for the particular
479         signal number, then returns the string "Signal NUM", where NUM is
480         the signal number.
481
482         If the supplied signal number is not within the range of valid
483         indices, then returns NULL.
484
485 BUGS
486
487         The contents of the location pointed to are only guaranteed to be
488         valid until the next call to strsigno.
489
490 */
491
492 const char *
493 strsigno (signo)
494   int signo;
495 {
496   const char *name;
497   static char buf[32];
498
499   if (signal_names == NULL)
500     {
501       init_signal_tables ();
502     }
503
504   if ((signo < 0) || (signo >= num_signal_names))
505     {
506       /* Out of range, just return NULL */
507       name = NULL;
508     }
509   else if ((signal_names == NULL) || (signal_names[signo] == NULL))
510     {
511       /* In range, but no signal_names or no entry at this index. */
512       sprintf (buf, "Signal %d", signo);
513       name = (const char *) buf;
514     }
515   else
516     {
517       /* In range, and a valid name.  Just return the name. */
518       name = signal_names[signo];
519     }
520
521   return (name);
522 }
523
524
525 /*
526
527 NAME
528
529         strtosigno -- map a symbolic signal name to a numeric value
530
531 SYNOPSIS
532
533         int strtosigno (char *name)
534
535 DESCRIPTION
536
537         Given the symbolic name of a signal, map it to a signal number.
538         If no translation is found, returns 0.
539
540 */
541
542 int
543 strtosigno (name)
544      const char *name;
545 {
546   int signo = 0;
547
548   if (name != NULL)
549     {
550       if (signal_names == NULL)
551         {
552           init_signal_tables ();
553         }
554       for (signo = 0; signo < num_signal_names; signo++)
555         {
556           if ((signal_names[signo] != NULL) &&
557               (strcmp (name, signal_names[signo]) == 0))
558             {
559               break;
560             }
561         }
562       if (signo == num_signal_names)
563         {
564           signo = 0;
565         }
566     }
567   return (signo);
568 }
569
570
571 /*
572
573 NAME
574
575         psignal -- print message about signal to stderr
576
577 SYNOPSIS
578
579         void psignal (unsigned signo, char *message);
580
581 DESCRIPTION
582
583         Print to the standard error the message, followed by a colon,
584         followed by the description of the signal specified by signo,
585         followed by a newline.
586 */
587
588 #ifndef HAVE_PSIGNAL
589
590 void
591 psignal (signo, message)
592   unsigned signo;
593   char *message;
594 {
595   if (signal_names == NULL)
596     {
597       init_signal_tables ();
598     }
599   if ((signo <= 0) || (signo >= sys_nsig))
600     {
601       fprintf (stderr, "%s: unknown signal\n", message);
602     }
603   else
604     {
605       fprintf (stderr, "%s: %s\n", message, sys_siglist[signo]);
606     }
607 }
608
609 #endif  /* ! HAVE_PSIGNAL */
610
611
612 /* A simple little main that does nothing but print all the signal translations
613    if MAIN is defined and this file is compiled and linked. */
614
615 #ifdef MAIN
616
617 #include <stdio.h>
618
619 int
620 main ()
621 {
622   int signo;
623   int maxsigno;
624   const char *name;
625   const char *msg;
626
627   maxsigno = signo_max ();
628   printf ("%d entries in names table.\n", num_signal_names);
629   printf ("%d entries in messages table.\n", sys_nsig);
630   printf ("%d is max useful index.\n", maxsigno);
631
632   /* Keep printing values until we get to the end of *both* tables, not
633      *either* table.  Note that knowing the maximum useful index does *not*
634      relieve us of the responsibility of testing the return pointer for
635      NULL. */
636
637   for (signo = 0; signo <= maxsigno; signo++)
638     {
639       name = strsigno (signo);
640       name = (name == NULL) ? "<NULL>" : name;
641       msg = strsignal (signo);
642       msg = (msg == NULL) ? "<NULL>" : msg;
643       printf ("%-4d%-18s%s\n", signo, name, msg);
644     }
645
646   return 0;
647 }
648
649 #endif