| /* Copyright (C) 1991, 1994-2002, 2005, 2008-2021 Free Software Foundation, |
| Inc. |
| This file is part of the GNU C Library. |
| |
| 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/>. */ |
| |
| #ifndef _LIBC |
| # include <config.h> |
| #endif |
| |
| /* Specification. */ |
| #include <string.h> |
| |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| #ifdef _LIBC |
| # include <libintl.h> |
| #else /* !_LIBC */ |
| # include "gettext.h" |
| # define _(msgid) gettext (msgid) |
| # define N_(msgid) gettext_noop (msgid) |
| #endif /* _LIBC */ |
| |
| #ifdef _LIBC |
| # include <bits/libc-lock.h> |
| #else /* !_LIBC */ |
| # include "glthread/lock.h" |
| # include "glthread/tls.h" |
| # define __libc_once_define(CLASS, NAME) gl_once_define (CLASS, NAME) |
| # define __libc_once(NAME, INIT) gl_once ((NAME), (INIT)) |
| # define __libc_key_t gl_tls_key_t |
| # define __libc_getspecific(NAME) gl_tls_get ((NAME)) |
| # define __libc_setspecific(NAME, POINTER) gl_tls_set ((NAME), (POINTER)) |
| # define __snprintf snprintf |
| #endif /* _LIBC */ |
| |
| #ifdef _LIBC |
| |
| /* Defined in siglist.c. */ |
| extern const char *const _sys_siglist[]; |
| extern const char *const _sys_siglist_internal[] attribute_hidden; |
| |
| #else /* !_LIBC */ |
| |
| /* NetBSD declares sys_siglist in unistd.h. */ |
| # if HAVE_UNISTD_H |
| # include <unistd.h> |
| # endif |
| |
| # define INTUSE(x) (x) |
| |
| # if HAVE_DECL_SYS_SIGLIST |
| # undef _sys_siglist |
| # define _sys_siglist sys_siglist |
| # else /* !HAVE_DECL_SYS_SIGLIST */ |
| # ifndef NSIG |
| # define NSIG 32 |
| # endif /* NSIG */ |
| # if !HAVE_DECL__SYS_SIGLIST |
| static const char *_sys_siglist[NSIG]; |
| # endif |
| # endif /* !HAVE_DECL_SYS_SIGLIST */ |
| |
| #endif /* _LIBC */ |
| |
| static __libc_key_t key; |
| |
| /* If nonzero the key allocation failed and we should better use a |
| static buffer than fail. */ |
| #define BUFFERSIZ 100 |
| static char local_buf[BUFFERSIZ]; |
| static char *static_buf; |
| |
| /* Destructor for the thread-specific data. */ |
| static void init (void); |
| static void free_key_mem (void *mem); |
| static char *getbuffer (void); |
| |
| |
| /* Return a string describing the meaning of the signal number SIGNUM. */ |
| char * |
| strsignal (int signum) |
| { |
| const char *desc; |
| __libc_once_define (static, once); |
| |
| /* If we have not yet initialized the buffer do it now. */ |
| __libc_once (once, init); |
| |
| if ( |
| #ifdef SIGRTMIN |
| (signum >= SIGRTMIN && signum <= SIGRTMAX) || |
| #endif |
| signum < 0 || signum >= NSIG |
| || (desc = INTUSE(_sys_siglist)[signum]) == NULL) |
| { |
| char *buffer = getbuffer (); |
| int len; |
| #ifdef SIGRTMIN |
| if (signum >= SIGRTMIN && signum <= SIGRTMAX) |
| len = __snprintf (buffer, BUFFERSIZ - 1, _("Real-time signal %d"), |
| signum - (int) SIGRTMIN); |
| else |
| #endif |
| len = __snprintf (buffer, BUFFERSIZ - 1, _("Unknown signal %d"), |
| signum); |
| if (len >= BUFFERSIZ) |
| buffer = NULL; |
| else |
| buffer[len] = '\0'; |
| |
| return buffer; |
| } |
| |
| return (char *) _(desc); |
| } |
| |
| |
| /* Initialize buffer. */ |
| static void |
| init (void) |
| { |
| #ifdef _LIBC |
| if (__libc_key_create (&key, free_key_mem)) |
| /* Creating the key failed. This means something really went |
| wrong. In any case use a static buffer which is better than |
| nothing. */ |
| static_buf = local_buf; |
| #else /* !_LIBC */ |
| gl_tls_key_init (key, free_key_mem); |
| |
| # if !HAVE_DECL_SYS_SIGLIST |
| memset (_sys_siglist, 0, NSIG * sizeof *_sys_siglist); |
| |
| /* No need to use a do {} while (0) here since init_sig(...) must expand |
| to a complete statement. (We cannot use the ISO C99 designated array |
| initializer syntax since it is not supported by ANSI C compilers and |
| since some signal numbers might exceed NSIG.) */ |
| # define init_sig(sig, abbrev, desc) \ |
| if (sig >= 0 && sig < NSIG) \ |
| _sys_siglist[sig] = desc; |
| |
| # include "siglist.h" |
| |
| # undef init_sig |
| |
| # endif /* !HAVE_DECL_SYS_SIGLIST */ |
| #endif /* !_LIBC */ |
| } |
| |
| |
| /* Free the thread specific data, this is done if a thread terminates. */ |
| static void |
| free_key_mem (void *mem) |
| { |
| free (mem); |
| __libc_setspecific (key, NULL); |
| } |
| |
| |
| /* Return the buffer to be used. */ |
| static char * |
| getbuffer (void) |
| { |
| char *result; |
| |
| if (static_buf != NULL) |
| result = static_buf; |
| else |
| { |
| /* We don't use the static buffer and so we have a key. Use it |
| to get the thread-specific buffer. */ |
| result = __libc_getspecific (key); |
| if (result == NULL) |
| { |
| /* No buffer allocated so far. */ |
| result = malloc (BUFFERSIZ); |
| if (result == NULL) |
| /* No more memory available. We use the static buffer. */ |
| result = local_buf; |
| else |
| __libc_setspecific (key, result); |
| } |
| } |
| |
| return result; |
| } |