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