1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * Copyright (C) 2021 Matthew Joyce
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 /*
28 FUNCTION
29 <<sig2str>>, <<str2sig>>---Translate between signal number and name
30 
31 INDEX
32           sig2str
33 INDEX
34           str2sig
35 
36 SYNOPSIS
37           #include <signal.h>
38           int sig2str(int <[signum]>, char *<[str]>);
39 
40           int str2sig(const char *restrict <[str]>, int *restrict <[pnum]>);
41 
42 DESCRIPTION
43 The <<sig2str>> function translates the signal number specified by <[signum]> to
44 a signal name and stores this string in the location specified by <[str]>. The
45 application must ensure that <[str]> points to a location that can store the
46 string including the terminating null byte. The symbolic constant
47 <[SIG2STR_MAX]> defined in `<<signal.h>>' gives the maximum number of bytes
48 required.
49 
50 The <<str2sig>> function translates the signal name in the string pointed to by
51 <[str]> to a signal number and stores this value in the location specified by
52 <[pnum]>.
53 
54 RETURNS
55 <<sig2str>> returns <<0>> if <[signum]>> is a valid, supported signal number.
56 Otherwise, it returns <<-1>>.
57 
58 <<str2sig>> returns <<0>> if it stores a value in the location pointed to by
59 <[pnum]>. Otherwise it returns <<-1>>.
60 */
61 
62 #define _DEFAULT_SOURCE
63 #include <signal.h>
64 #include <string.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 
68 #define SPACES_TO_N 6 /* Allows indexing to RT Signal number in str2sig */
69 #define NUM_OF_SIGS (sizeof(sig_array) / sizeof(sig_name_and_num))
70 
71 typedef struct sig_name_and_num {
72   const char sig_name[8];
73   const int  sig_num;
74 } sig_name_and_num;
75 
76 static const sig_name_and_num sig_array[] = {
77       { "EXIT", 0 },
78     #ifdef SIGHUP
79       { "HUP", SIGHUP },
80     #endif
81     #ifdef SIGINT
82       { "INT", SIGINT },
83     #endif
84     #ifdef SIGQUIT
85       { "QUIT", SIGQUIT },
86     #endif
87     #ifdef SIGILL
88       { "ILL", SIGILL },
89     #endif
90     #ifdef SIGTRAP
91       { "TRAP", SIGTRAP },
92     #endif
93     #ifdef SIGABRT
94       { "ABRT", SIGABRT },
95     #endif
96     #ifdef SIGIOT
97       { "IOT", SIGIOT},
98     #endif
99     #ifdef SIGEMT
100       { "EMT", SIGEMT },
101     #endif
102     #ifdef SIGFPE
103       { "FPE", SIGFPE },
104     #endif
105     #ifdef SIGKILL
106       { "KILL", SIGKILL },
107     #endif
108     #ifdef SIGBUS
109       { "BUS", SIGBUS },
110     #endif
111     #ifdef SIGSEGV
112       { "SEGV", SIGSEGV },
113     #endif
114     #ifdef SIGSYS
115       { "SYS", SIGSYS },
116     #endif
117     #ifdef SIGPIPE
118       { "PIPE", SIGPIPE },
119     #endif
120     #ifdef SIGALRM
121       { "ALRM", SIGALRM },
122     #endif
123     #ifdef SIGTERM
124       { "TERM", SIGTERM },
125     #endif
126     #ifdef SIGURG
127       { "URG", SIGURG },
128     #endif
129     #ifdef SIGSTOP
130       { "STOP", SIGSTOP },
131     #endif
132     #ifdef SIGTSTP
133       { "TSTP", SIGTSTP },
134     #endif
135     #ifdef SIGCONT
136       { "CONT", SIGCONT },
137     #endif
138     #ifdef SIGCHLD
139       { "CHLD", SIGCHLD },
140     #endif
141     #ifdef SIGCLD
142       { "CLD", SIGCLD },
143     #endif
144     #ifdef SIGTTIN
145       { "TTIN", SIGTTIN },
146     #endif
147     #ifdef SIGTTOU
148       { "TTOU", SIGTTOU },
149     #endif
150     #ifdef SIGIO
151       { "IO", SIGIO },
152     #endif
153     #ifdef SIGPOLL
154       { "POLL", SIGPOLL },
155     #endif
156     #ifdef SIGWINCH
157       { "WINCH", SIGWINCH },
158     #endif
159     #ifdef SIGUSR1
160       { "USR1", SIGUSR1 },
161     #endif
162     #ifdef SIGUSR2
163       { "USR2", SIGUSR2 },
164     #endif
165     #ifdef SIGPWR
166       { "PWR", SIGPWR },
167     #endif
168     #ifdef SIGXCPU
169       { "XCPU", SIGXCPU },
170     #endif
171     #ifdef SIGXFSZ
172       { "XFSZ", SIGXFSZ },
173     #endif
174     #ifdef SIGVTALRM
175       { "VTALRM", SIGVTALRM },
176     #endif
177     #ifdef SIGPROF
178       { "PROF", SIGPROF },
179     #endif
180     #ifdef SIGLOST
181       { "LOST", SIGLOST },
182     #endif
183     /* The Issue 8 standard requires that SIGRTMIN and SIGRTMAX be included
184      * as valid results to be saved from calls to sig2str/str2sig.  */
185     #ifdef SIGRTMIN
186       { "RTMIN", SIGRTMIN },
187     #endif
188     #ifdef SIGRTMAX
189       { "RTMAX", SIGRTMAX }
190     #endif
191 };
192 
193 int
sig2str(int signum,char * str)194 sig2str(int signum, char *str)
195 {
196   const sig_name_and_num *sptr;
197 
198 #if defined (SIGRTMIN) && defined (SIGRTMAX)
199   /* If signum falls in lower half of the real time signals range, define
200    * the saved str value as "RTMIN+n" according to the Issue 8 standard */
201   if ((SIGRTMIN + 1) <= signum &&
202       signum <= (SIGRTMIN + SIGRTMAX) / 2) {
203     sprintf(str, "RTMIN+%d", (signum-SIGRTMIN));
204     return 0;
205   }
206 
207   /* If signum falls in upper half of the real time signals range, define
208    * the saved str value as "RTMAX-m" according to the Issue 8 standard */
209   if ((((SIGRTMIN + SIGRTMAX) / 2) + 1) <= signum &&
210          signum <= (SIGRTMAX - 1)) {
211     sprintf(str, "RTMAX-%d", (SIGRTMAX - signum));
212     return 0;
213   }
214 #endif
215 
216   /* Otherwise, search for signal matching signum in sig_array. If found,
217    * save its string value in str. */
218   for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {
219     if (sptr->sig_num == signum) {
220       strcpy(str, sptr->sig_name);
221       return 0;
222     }
223   }
224 
225   /* If signum is not a recognized signal number, return -1 */
226   return -1;
227 }
228 
229 int
str2sig(const char * __restrict str,int * __restrict pnum)230 str2sig(const char *__restrict str, int *__restrict pnum)
231 {
232   char *endp;
233   const sig_name_and_num *sptr;
234   unsigned long is_valid_decimal;
235 
236 #if defined (SIGRTMIN) && defined (SIGRTMAX)
237   /* i686 Cygwin only supports one RT signal. For this case, skip checks
238    * for "RTMIN+n" and "RTMAX-m". */
239   if (SIGRTMIN != SIGRTMAX) {
240 
241     /* If str is in RT signal range, get number of of RT signal, save it as an
242     * integer. */
243     if (strncmp(str, "RTMIN+", SPACES_TO_N) == 0) {
244       unsigned long j = strtoul(&str[SPACES_TO_N], &endp, 10);
245 
246       /* If number is valid, save it in pnum. */
247       if (*endp == '\0') {
248         if (1 <= j &&
249             j <= ((SIGRTMAX - SIGRTMIN)-1)) {
250           *pnum = (SIGRTMIN + j);
251           return 0;
252         }
253         return -1;
254       }
255       return -1;
256     }
257 
258     /* If str is in RT signal range, get number of of RT signal, save it as an
259     * integer. */
260     if (strncmp(str, "RTMAX-", SPACES_TO_N) == 0) {
261       unsigned long j = strtoul(&str[SPACES_TO_N], &endp, 10); // and endptr null check
262 
263       /* If number is valid, save it in pnum. */
264       if (*endp == '\0') {
265         if (1 <= j &&
266             j <= ((SIGRTMAX - SIGRTMIN)-1)) {
267           *pnum = (SIGRTMAX - j);
268           return 0;
269         }
270         return -1;
271       }
272       return -1;
273     }
274   }
275 #endif
276 
277   /*If str is a valid signal name, save its corresponding number in pnum. */
278   for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {
279     if (strcmp(sptr->sig_name, str) == 0) {
280       *pnum = sptr->sig_num;
281       return 0;
282     }
283   }
284 
285   /* str was not found in sig_array. Check whether str is a string
286    * representation of a valid integer. */
287   is_valid_decimal = strtoul(str, &endp, 10);
288 
289   if (*endp != '\0') {
290     return -1;
291   }
292 
293   /* If str is a representation of a decimal value, save its integer value
294    * in pnum. */
295   if (1 <= is_valid_decimal &&
296       is_valid_decimal <= (_NSIG - 1)) {
297     *pnum = is_valid_decimal;
298     return 0;
299   }
300 
301   return -1;
302 }
303