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