strsignal.c 5.09 KB
Newer Older
Paul Eggert's avatar
Paul Eggert committed
1
/* Copyright (C) 1991, 1994-2002, 2005, 2008-2016 Free Software Foundation,
2
   Inc.
Colin Watson's avatar
Colin Watson committed
3 4
   This file is part of the GNU C Library.

5 6 7 8
   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.
Colin Watson's avatar
Colin Watson committed
9

10
   This program is distributed in the hope that it will be useful,
Colin Watson's avatar
Colin Watson committed
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12 13
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
Colin Watson's avatar
Colin Watson committed
14

15 16
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Colin Watson's avatar
Colin Watson committed
17 18 19 20 21

#ifndef _LIBC
# include <config.h>
#endif

22 23 24
/* Specification.  */
#include <string.h>

Colin Watson's avatar
Colin Watson committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
#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 */
40 41
# include "glthread/lock.h"
# include "glthread/tls.h"
Colin Watson's avatar
Colin Watson committed
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
# 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. */
59 60 61
# if HAVE_UNISTD_H
#  include <unistd.h>
# endif
Colin Watson's avatar
Colin Watson committed
62 63 64 65 66 67 68 69 70 71

# 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 */
72
#  if !HAVE_DECL__SYS_SIGLIST
Colin Watson's avatar
Colin Watson committed
73
static const char *_sys_siglist[NSIG];
74
#  endif
Colin Watson's avatar
Colin Watson committed
75 76 77 78 79 80 81 82
# 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.  */
83
#define BUFFERSIZ       100
Colin Watson's avatar
Colin Watson committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
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)
114
        len = __snprintf (buffer, BUFFERSIZ - 1, _("Real-time signal %d"),
115
                          signum - (int) SIGRTMIN);
Colin Watson's avatar
Colin Watson committed
116 117
      else
#endif
118 119
        len = __snprintf (buffer, BUFFERSIZ - 1, _("Unknown signal %d"),
                          signum);
Colin Watson's avatar
Colin Watson committed
120
      if (len >= BUFFERSIZ)
121
        buffer = NULL;
Colin Watson's avatar
Colin Watson committed
122
      else
123
        buffer[len] = '\0';
Colin Watson's avatar
Colin Watson committed
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184

      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
185
         to get the thread-specific buffer.  */
Colin Watson's avatar
Colin Watson committed
186 187
      result = __libc_getspecific (key);
      if (result == NULL)
188 189 190 191 192 193 194 195 196
        {
          /* 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);
        }
Colin Watson's avatar
Colin Watson committed
197 198 199 200
    }

  return result;
}