1/* sig2str.c -- convert between signal names and numbers
2
3   Copyright (C) 2002, 2004, 2006, 2009-2010 Free Software Foundation, Inc.
4
5   This program is free software: you can redistribute it and/or modify
6   it under the terms of the GNU General Public License as published by
7   the Free Software Foundation; either version 3 of the License, or
8   (at your option) any later version.
9
10   This program is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13   GNU General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
17
18/* Written by Paul Eggert.  */
19
20#include <config.h>
21
22#include <limits.h>
23#include <signal.h>
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27
28#include "sig2str.h"
29
30#ifndef SIGRTMIN
31# define SIGRTMIN 0
32# undef SIGRTMAX
33#endif
34#ifndef SIGRTMAX
35# define SIGRTMAX (SIGRTMIN - 1)
36#endif
37
38#define NUMNAME(name) { SIG##name, #name }
39
40/* Signal names and numbers.  Put the preferred name first.  */
41static struct numname { int num; char const name[8]; } numname_table[] =
42  {
43    /* Signals required by POSIX 1003.1-2001 base, listed in
44       traditional numeric order.  */
45#ifdef SIGHUP
46    NUMNAME (HUP),
47#endif
48#ifdef SIGINT
49    NUMNAME (INT),
50#endif
51#ifdef SIGQUIT
52    NUMNAME (QUIT),
53#endif
54#ifdef SIGILL
55    NUMNAME (ILL),
56#endif
57#ifdef SIGTRAP
58    NUMNAME (TRAP),
59#endif
60#ifdef SIGABRT
61    NUMNAME (ABRT),
62#endif
63#ifdef SIGFPE
64    NUMNAME (FPE),
65#endif
66#ifdef SIGKILL
67    NUMNAME (KILL),
68#endif
69#ifdef SIGBUS
70    NUMNAME (BUS),
71#endif
72#ifdef SIGSEGV
73    NUMNAME (SEGV),
74#endif
75#ifdef SIGPIPE
76    NUMNAME (PIPE),
77#endif
78#ifdef SIGALRM
79    NUMNAME (ALRM),
80#endif
81#ifdef SIGTERM
82    NUMNAME (TERM),
83#endif
84#ifdef SIGUSR1
85    NUMNAME (USR1),
86#endif
87#ifdef SIGUSR2
88    NUMNAME (USR2),
89#endif
90#ifdef SIGCHLD
91    NUMNAME (CHLD),
92#endif
93#ifdef SIGURG
94    NUMNAME (URG),
95#endif
96#ifdef SIGSTOP
97    NUMNAME (STOP),
98#endif
99#ifdef SIGTSTP
100    NUMNAME (TSTP),
101#endif
102#ifdef SIGCONT
103    NUMNAME (CONT),
104#endif
105#ifdef SIGTTIN
106    NUMNAME (TTIN),
107#endif
108#ifdef SIGTTOU
109    NUMNAME (TTOU),
110#endif
111
112    /* Signals required by POSIX 1003.1-2001 with the XSI extension.  */
113#ifdef SIGSYS
114    NUMNAME (SYS),
115#endif
116#ifdef SIGPOLL
117    NUMNAME (POLL),
118#endif
119#ifdef SIGVTALRM
120    NUMNAME (VTALRM),
121#endif
122#ifdef SIGPROF
123    NUMNAME (PROF),
124#endif
125#ifdef SIGXCPU
126    NUMNAME (XCPU),
127#endif
128#ifdef SIGXFSZ
129    NUMNAME (XFSZ),
130#endif
131
132    /* Unix Version 7.  */
133#ifdef SIGIOT
134    NUMNAME (IOT),      /* Older name for ABRT.  */
135#endif
136#ifdef SIGEMT
137    NUMNAME (EMT),
138#endif
139
140    /* USG Unix.  */
141#ifdef SIGPHONE
142    NUMNAME (PHONE),
143#endif
144#ifdef SIGWIND
145    NUMNAME (WIND),
146#endif
147
148    /* Unix System V.  */
149#ifdef SIGCLD
150    NUMNAME (CLD),
151#endif
152#ifdef SIGPWR
153    NUMNAME (PWR),
154#endif
155
156    /* GNU/Linux 2.2 and Solaris 8.  */
157#ifdef SIGCANCEL
158    NUMNAME (CANCEL),
159#endif
160#ifdef SIGLWP
161    NUMNAME (LWP),
162#endif
163#ifdef SIGWAITING
164    NUMNAME (WAITING),
165#endif
166#ifdef SIGFREEZE
167    NUMNAME (FREEZE),
168#endif
169#ifdef SIGTHAW
170    NUMNAME (THAW),
171#endif
172#ifdef SIGLOST
173    NUMNAME (LOST),
174#endif
175#ifdef SIGWINCH
176    NUMNAME (WINCH),
177#endif
178
179    /* GNU/Linux 2.2.  */
180#ifdef SIGINFO
181    NUMNAME (INFO),
182#endif
183#ifdef SIGIO
184    NUMNAME (IO),
185#endif
186#ifdef SIGSTKFLT
187    NUMNAME (STKFLT),
188#endif
189
190    /* AIX 5L.  */
191#ifdef SIGDANGER
192    NUMNAME (DANGER),
193#endif
194#ifdef SIGGRANT
195    NUMNAME (GRANT),
196#endif
197#ifdef SIGMIGRATE
198    NUMNAME (MIGRATE),
199#endif
200#ifdef SIGMSG
201    NUMNAME (MSG),
202#endif
203#ifdef SIGPRE
204    NUMNAME (PRE),
205#endif
206#ifdef SIGRETRACT
207    NUMNAME (RETRACT),
208#endif
209#ifdef SIGSAK
210    NUMNAME (SAK),
211#endif
212#ifdef SIGSOUND
213    NUMNAME (SOUND),
214#endif
215
216    /* Older AIX versions.  */
217#ifdef SIGALRM1
218    NUMNAME (ALRM1),    /* unknown; taken from Bash 2.05 */
219#endif
220#ifdef SIGKAP
221    NUMNAME (KAP),      /* Older name for SIGGRANT.  */
222#endif
223#ifdef SIGVIRT
224    NUMNAME (VIRT),     /* unknown; taken from Bash 2.05 */
225#endif
226#ifdef SIGWINDOW
227    NUMNAME (WINDOW),   /* Older name for SIGWINCH.  */
228#endif
229
230    /* BeOS */
231#ifdef SIGKILLTHR
232    NUMNAME (KILLTHR),
233#endif
234
235    /* Older HP-UX versions.  */
236#ifdef SIGDIL
237    NUMNAME (DIL),
238#endif
239
240    /* Korn shell and Bash, of uncertain vintage.  */
241    { 0, "EXIT" }
242  };
243
244#define NUMNAME_ENTRIES (sizeof numname_table / sizeof numname_table[0])
245
246/* ISDIGIT differs from isdigit, as follows:
247   - Its arg may be any int or unsigned int; it need not be an unsigned char
248     or EOF.
249   - It's typically faster.
250   POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
251   isdigit unless it's important to use the locale's definition
252   of `digit' even when the host does not conform to POSIX.  */
253#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
254
255/* Convert the signal name SIGNAME to a signal number.  Return the
256   signal number if successful, -1 otherwise.  */
257
258static int
259str2signum (char const *signame)
260{
261  if (ISDIGIT (*signame))
262    {
263      char *endp;
264      long int n = strtol (signame, &endp, 10);
265      if (! *endp && n <= SIGNUM_BOUND)
266        return n;
267    }
268  else
269    {
270      unsigned int i;
271      for (i = 0; i < NUMNAME_ENTRIES; i++)
272        if (strcmp (numname_table[i].name, signame) == 0)
273          return numname_table[i].num;
274
275      {
276        char *endp;
277        int rtmin = SIGRTMIN;
278        int rtmax = SIGRTMAX;
279
280        if (0 < rtmin && strncmp (signame, "RTMIN", 5) == 0)
281          {
282            long int n = strtol (signame + 5, &endp, 10);
283            if (! *endp && 0 <= n && n <= rtmax - rtmin)
284              return rtmin + n;
285          }
286        else if (0 < rtmax && strncmp (signame, "RTMAX", 5) == 0)
287          {
288            long int n = strtol (signame + 5, &endp, 10);
289            if (! *endp && rtmin - rtmax <= n && n <= 0)
290              return rtmax + n;
291          }
292      }
293    }
294
295  return -1;
296}
297
298/* Convert the signal name SIGNAME to the signal number *SIGNUM.
299   Return 0 if successful, -1 otherwise.  */
300
301int
302str2sig (char const *signame, int *signum)
303{
304  *signum = str2signum (signame);
305  return *signum < 0 ? -1 : 0;
306}
307
308/* Convert SIGNUM to a signal name in SIGNAME.  SIGNAME must point to
309   a buffer of at least SIG2STR_MAX bytes.  Return 0 if successful, -1
310   otherwise.  */
311
312int
313sig2str (int signum, char *signame)
314{
315  unsigned int i;
316  for (i = 0; i < NUMNAME_ENTRIES; i++)
317    if (numname_table[i].num == signum)
318      {
319        strcpy (signame, numname_table[i].name);
320        return 0;
321      }
322
323  {
324    int rtmin = SIGRTMIN;
325    int rtmax = SIGRTMAX;
326
327    if (! (rtmin <= signum && signum <= rtmax))
328      return -1;
329
330    if (signum <= rtmin + (rtmax - rtmin) / 2)
331      {
332        int delta = signum - rtmin;
333        sprintf (signame, delta ? "RTMIN+%d" : "RTMIN", delta);
334      }
335    else
336      {
337        int delta = rtmax - signum;
338        sprintf (signame, delta ? "RTMAX-%d" : "RTMAX", delta);
339      }
340
341    return 0;
342  }
343}
344