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