| /* sig2str.c -- convert between signal names and numbers | |
| Copyright (C) 2002, 2004, 2006, 2009-2026 Free Software Foundation, Inc. | |
| This program is free software: you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation, either version 3 of the License, or | |
| (at your option) any later version. | |
| This program is distributed in the hope that it will be useful, | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| GNU General Public License for more details. | |
| You should have received a copy of the GNU General Public License | |
| along with this program. If not, see <https://www.gnu.org/licenses/>. */ | |
| /* Written by Paul Eggert. */ | |
| #include <config.h> | |
| /* Specification. */ | |
| #include <signal.h> | |
| #include <limits.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include "sig2str.h" | |
| #ifndef SIGRTMIN | |
| # define SIGRTMIN 0 | |
| # undef SIGRTMAX | |
| #endif | |
| #ifndef SIGRTMAX | |
| # define SIGRTMAX (SIGRTMIN - 1) | |
| #endif | |
| #define NUMNAME(name) { SIG##name, #name } | |
| /* Signal names and numbers. Put the preferred name first. */ | |
| static struct numname { int num; char const name[8]; } numname_table[] = | |
| { | |
| /* Signals required by POSIX 1003.1-2001 base, listed in | |
| traditional numeric order where possible. */ | |
| #ifdef SIGHUP | |
| NUMNAME (HUP), | |
| #endif | |
| #ifdef SIGINT | |
| NUMNAME (INT), | |
| #endif | |
| #ifdef SIGQUIT | |
| NUMNAME (QUIT), | |
| #endif | |
| #ifdef SIGILL | |
| NUMNAME (ILL), | |
| #endif | |
| #ifdef SIGTRAP | |
| NUMNAME (TRAP), | |
| #endif | |
| #ifdef SIGABRT | |
| NUMNAME (ABRT), | |
| #endif | |
| #ifdef SIGFPE | |
| NUMNAME (FPE), | |
| #endif | |
| #ifdef SIGKILL | |
| NUMNAME (KILL), | |
| #endif | |
| #ifdef SIGSEGV | |
| NUMNAME (SEGV), | |
| #endif | |
| /* On Haiku, SIGSEGV == SIGBUS, but we prefer SIGSEGV to match | |
| strsignal.c output, so SIGBUS must be listed second. */ | |
| #ifdef SIGBUS | |
| NUMNAME (BUS), | |
| #endif | |
| #ifdef SIGPIPE | |
| NUMNAME (PIPE), | |
| #endif | |
| #ifdef SIGALRM | |
| NUMNAME (ALRM), | |
| #endif | |
| #ifdef SIGTERM | |
| NUMNAME (TERM), | |
| #endif | |
| #ifdef SIGUSR1 | |
| NUMNAME (USR1), | |
| #endif | |
| #ifdef SIGUSR2 | |
| NUMNAME (USR2), | |
| #endif | |
| #ifdef SIGCHLD | |
| NUMNAME (CHLD), | |
| #endif | |
| #ifdef SIGURG | |
| NUMNAME (URG), | |
| #endif | |
| #ifdef SIGSTOP | |
| NUMNAME (STOP), | |
| #endif | |
| #ifdef SIGTSTP | |
| NUMNAME (TSTP), | |
| #endif | |
| #ifdef SIGCONT | |
| NUMNAME (CONT), | |
| #endif | |
| #ifdef SIGTTIN | |
| NUMNAME (TTIN), | |
| #endif | |
| #ifdef SIGTTOU | |
| NUMNAME (TTOU), | |
| #endif | |
| /* Signals required by POSIX 1003.1-2001 with the XSI extension. */ | |
| #ifdef SIGSYS | |
| NUMNAME (SYS), | |
| #endif | |
| #ifdef SIGPOLL | |
| NUMNAME (POLL), | |
| #endif | |
| #ifdef SIGVTALRM | |
| NUMNAME (VTALRM), | |
| #endif | |
| #ifdef SIGPROF | |
| NUMNAME (PROF), | |
| #endif | |
| #ifdef SIGXCPU | |
| NUMNAME (XCPU), | |
| #endif | |
| #ifdef SIGXFSZ | |
| NUMNAME (XFSZ), | |
| #endif | |
| /* Unix Version 7. */ | |
| #ifdef SIGIOT | |
| NUMNAME (IOT), /* Older name for ABRT. */ | |
| #endif | |
| #ifdef SIGEMT | |
| NUMNAME (EMT), | |
| #endif | |
| /* USG Unix. */ | |
| #ifdef SIGPHONE | |
| NUMNAME (PHONE), | |
| #endif | |
| #ifdef SIGWIND | |
| NUMNAME (WIND), | |
| #endif | |
| /* Unix System V. */ | |
| #ifdef SIGCLD | |
| NUMNAME (CLD), | |
| #endif | |
| #ifdef SIGPWR | |
| NUMNAME (PWR), | |
| #endif | |
| /* GNU/Linux 2.2 and Solaris 8. */ | |
| #ifdef SIGCANCEL | |
| NUMNAME (CANCEL), | |
| #endif | |
| #ifdef SIGLWP | |
| NUMNAME (LWP), | |
| #endif | |
| #ifdef SIGWAITING | |
| NUMNAME (WAITING), | |
| #endif | |
| #ifdef SIGFREEZE | |
| NUMNAME (FREEZE), | |
| #endif | |
| #ifdef SIGTHAW | |
| NUMNAME (THAW), | |
| #endif | |
| #ifdef SIGLOST | |
| NUMNAME (LOST), | |
| #endif | |
| #ifdef SIGWINCH | |
| NUMNAME (WINCH), | |
| #endif | |
| /* GNU/Linux 2.2. */ | |
| #ifdef SIGINFO | |
| NUMNAME (INFO), | |
| #endif | |
| #ifdef SIGIO | |
| NUMNAME (IO), | |
| #endif | |
| #ifdef SIGSTKFLT | |
| NUMNAME (STKFLT), | |
| #endif | |
| /* AIX 7. */ | |
| #ifdef SIGCPUFAIL | |
| NUMNAME (CPUFAIL), | |
| #endif | |
| /* AIX 5L. */ | |
| #ifdef SIGDANGER | |
| NUMNAME (DANGER), | |
| #endif | |
| #ifdef SIGGRANT | |
| NUMNAME (GRANT), | |
| #endif | |
| #ifdef SIGMIGRATE | |
| NUMNAME (MIGRATE), | |
| #endif | |
| #ifdef SIGMSG | |
| NUMNAME (MSG), | |
| #endif | |
| #ifdef SIGPRE | |
| NUMNAME (PRE), | |
| #endif | |
| #ifdef SIGRETRACT | |
| NUMNAME (RETRACT), | |
| #endif | |
| #ifdef SIGSAK | |
| NUMNAME (SAK), | |
| #endif | |
| #ifdef SIGSOUND | |
| NUMNAME (SOUND), | |
| #endif | |
| /* Older AIX versions. */ | |
| #ifdef SIGALRM1 | |
| NUMNAME (ALRM1), /* unknown; taken from Bash 2.05 */ | |
| #endif | |
| #ifdef SIGKAP | |
| NUMNAME (KAP), /* Older name for SIGGRANT. */ | |
| #endif | |
| #ifdef SIGVIRT | |
| NUMNAME (VIRT), /* unknown; taken from Bash 2.05 */ | |
| #endif | |
| #ifdef SIGWINDOW | |
| NUMNAME (WINDOW), /* Older name for SIGWINCH. */ | |
| #endif | |
| /* OpenBSD. */ | |
| #ifdef SIGTHR | |
| NUMNAME (THR), | |
| #endif | |
| /* BeOS, Haiku */ | |
| #ifdef SIGKILLTHR | |
| NUMNAME (KILLTHR), | |
| #endif | |
| /* Older HP-UX versions. */ | |
| #ifdef SIGDIL | |
| NUMNAME (DIL), | |
| #endif | |
| /* native Windows */ | |
| #ifdef SIGBREAK | |
| NUMNAME (BREAK), | |
| #endif | |
| /* Korn shell and Bash, of uncertain vintage. */ | |
| { 0, "EXIT" } | |
| }; | |
| #define NUMNAME_ENTRIES (sizeof numname_table / sizeof numname_table[0]) | |
| /* ISDIGIT differs from isdigit, as follows: | |
| - Its arg may be any int or unsigned int; it need not be an unsigned char | |
| or EOF. | |
| - It's typically faster. | |
| POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to | |
| isdigit unless it's important to use the locale's definition | |
| of "digit" even when the host does not conform to POSIX. */ | |
| #define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9) | |
| /* Convert the signal name SIGNAME to a signal number. Return the | |
| signal number if successful, -1 otherwise. */ | |
| static int | |
| str2signum (char const *signame) | |
| { | |
| if (ISDIGIT (*signame)) | |
| { | |
| char *endp; | |
| long int n = strtol (signame, &endp, 10); | |
| if (! *endp && n <= SIGNUM_BOUND) | |
| return n; | |
| } | |
| else | |
| { | |
| for (unsigned int i = 0; i < NUMNAME_ENTRIES; i++) | |
| if (streq (numname_table[i].name, signame)) | |
| return numname_table[i].num; | |
| { | |
| int rtmin = SIGRTMIN; | |
| int rtmax = SIGRTMAX; | |
| if (0 < rtmin && strncmp (signame, "RTMIN", 5) == 0) | |
| { | |
| char *endp; | |
| long int n = strtol (signame + 5, &endp, 10); | |
| if (! *endp && 0 <= n && n <= rtmax - rtmin) | |
| return rtmin + n; | |
| } | |
| else if (0 < rtmax && strncmp (signame, "RTMAX", 5) == 0) | |
| { | |
| char *endp; | |
| long int n = strtol (signame + 5, &endp, 10); | |
| if (! *endp && rtmin - rtmax <= n && n <= 0) | |
| return rtmax + n; | |
| } | |
| } | |
| } | |
| return -1; | |
| } | |
| /* Convert the signal name SIGNAME to the signal number *SIGNUM. | |
| Return 0 if successful, -1 otherwise. */ | |
| int | |
| str2sig (char const *signame, int *signum) | |
| { | |
| *signum = str2signum (signame); | |
| return *signum < 0 ? -1 : 0; | |
| } | |
| /* Convert SIGNUM to a signal name in SIGNAME. SIGNAME must point to | |
| a buffer of at least SIG2STR_MAX bytes. Return 0 if successful, -1 | |
| otherwise. */ | |
| int | |
| sig2str (int signum, char *signame) | |
| { | |
| for (unsigned int i = 0; i < NUMNAME_ENTRIES; i++) | |
| if (numname_table[i].num == signum) | |
| { | |
| strcpy (signame, numname_table[i].name); | |
| return 0; | |
| } | |
| { | |
| int rtmin = SIGRTMIN; | |
| int rtmax = SIGRTMAX; | |
| if (! (rtmin <= signum && signum <= rtmax)) | |
| return -1; | |
| int base; | |
| if (signum <= rtmin + (rtmax - rtmin) / 2) | |
| { | |
| strcpy (signame, "RTMIN"); | |
| base = rtmin; | |
| } | |
| else | |
| { | |
| strcpy (signame, "RTMAX"); | |
| base = rtmax; | |
| } | |
| int delta = signum - base; | |
| if (delta != 0) | |
| sprintf (signame + 5, "%+d", delta); | |
| return 0; | |
| } | |
| } |