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 #include <signal.h>
63 #include <string.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 
67 #define SPACES_TO_N 6 /* Allows indexing to RT Signal number in str2sig */
68 #define NUM_OF_SIGS (sizeof(sig_array) / sizeof(sig_name_and_num))
69 
70 typedef struct sig_name_and_num {
71   const char sig_name[8];
72   const int  sig_num;
73 } sig_name_and_num;
74 
75 static const sig_name_and_num sig_array[] = {
76       { "EXIT", 0 },
77     #ifdef SIGHUP
78       { "HUP", SIGHUP },
79     #endif
80     #ifdef SIGINT
81       { "INT", SIGINT },
82     #endif
83     #ifdef SIGQUIT
84       { "QUIT", SIGQUIT },
85     #endif
86     #ifdef SIGILL
87       { "ILL", SIGILL },
88     #endif
89     #ifdef SIGTRAP
90       { "TRAP", SIGTRAP },
91     #endif
92     #ifdef SIGABRT
93       { "ABRT", SIGABRT },
94     #endif
95     #ifdef SIGIOT
96       { "IOT", SIGIOT},
97     #endif
98     #ifdef SIGEMT
99       { "EMT", SIGEMT },
100     #endif
101     #ifdef SIGFPE
102       { "FPE", SIGFPE },
103     #endif
104     #ifdef SIGKILL
105       { "KILL", SIGKILL },
106     #endif
107     #ifdef SIGBUS
108       { "BUS", SIGBUS },
109     #endif
110     #ifdef SIGSEGV
111       { "SEGV", SIGSEGV },
112     #endif
113     #ifdef SIGSYS
114       { "SYS", SIGSYS },
115     #endif
116     #ifdef SIGPIPE
117       { "PIPE", SIGPIPE },
118     #endif
119     #ifdef SIGALRM
120       { "ALRM", SIGALRM },
121     #endif
122     #ifdef SIGTERM
123       { "TERM", SIGTERM },
124     #endif
125     #ifdef SIGURG
126       { "URG", SIGURG },
127     #endif
128     #ifdef SIGSTOP
129       { "STOP", SIGSTOP },
130     #endif
131     #ifdef SIGTSTP
132       { "TSTP", SIGTSTP },
133     #endif
134     #ifdef SIGCONT
135       { "CONT", SIGCONT },
136     #endif
137     #ifdef SIGCHLD
138       { "CHLD", SIGCHLD },
139     #endif
140     #ifdef SIGCLD
141       { "CLD", SIGCLD },
142     #endif
143     #ifdef SIGTTIN
144       { "TTIN", SIGTTIN },
145     #endif
146     #ifdef SIGTTOU
147       { "TTOU", SIGTTOU },
148     #endif
149     #ifdef SIGIO
150       { "IO", SIGIO },
151     #endif
152     #ifdef SIGPOLL
153       { "POLL", SIGPOLL },
154     #endif
155     #ifdef SIGWINCH
156       { "WINCH", SIGWINCH },
157     #endif
158     #ifdef SIGUSR1
159       { "USR1", SIGUSR1 },
160     #endif
161     #ifdef SIGUSR2
162       { "USR2", SIGUSR2 },
163     #endif
164     #ifdef SIGPWR
165       { "PWR", SIGPWR },
166     #endif
167     #ifdef SIGXCPU
168       { "XCPU", SIGXCPU },
169     #endif
170     #ifdef SIGXFSZ
171       { "XFSZ", SIGXFSZ },
172     #endif
173     #ifdef SIGVTALRM
174       { "VTALRM", SIGVTALRM },
175     #endif
176     #ifdef SIGPROF
177       { "PROF", SIGPROF },
178     #endif
179     #ifdef SIGLOST
180       { "LOST", SIGLOST },
181     #endif
182     /* The Issue 8 standard requires that SIGRTMIN and SIGRTMAX be included
183      * as valid results to be saved from calls to sig2str/str2sig.  */
184     #ifdef SIGRTMIN
185       { "RTMIN", SIGRTMIN },
186     #endif
187     #ifdef SIGRTMAX
188       { "RTMAX", SIGRTMAX }
189     #endif
190 };
191 
192 int
sig2str(int signum,char * str)193 sig2str(int signum, char *str)
194 {
195   const sig_name_and_num *sptr;
196 
197 #if defined (SIGRTMIN) && defined (SIGRTMAX)
198   /* If signum falls in lower half of the real time signals range, define
199    * the saved str value as "RTMIN+n" according to the Issue 8 standard */
200   if ((SIGRTMIN + 1) <= signum &&
201       signum <= (SIGRTMIN + SIGRTMAX) / 2) {
202     sprintf(str, "RTMIN+%d", (signum-SIGRTMIN));
203     return 0;
204   }
205 
206   /* If signum falls in upper half of the real time signals range, define
207    * the saved str value as "RTMAX-m" according to the Issue 8 standard */
208   if ((((SIGRTMIN + SIGRTMAX) / 2) + 1) <= signum &&
209          signum <= (SIGRTMAX - 1)) {
210     sprintf(str, "RTMAX-%d", (SIGRTMAX - signum));
211     return 0;
212   }
213 #endif
214 
215   /* Otherwise, search for signal matching signum in sig_array. If found,
216    * save its string value in str. */
217   for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {
218     if (sptr->sig_num == signum) {
219       strcpy(str, sptr->sig_name);
220       return 0;
221     }
222   }
223 
224   /* If signum is not a recognized signal number, return -1 */
225   return -1;
226 }
227 
228 int
str2sig(const char * __restrict str,int * __restrict pnum)229 str2sig(const char *__restrict str, int *__restrict pnum)
230 {
231   char *endp;
232   const sig_name_and_num *sptr;
233   unsigned long is_valid_decimal;
234 
235 #if defined (SIGRTMIN) && defined (SIGRTMAX)
236   /* i686 Cygwin only supports one RT signal. For this case, skip checks
237    * for "RTMIN+n" and "RTMAX-m". */
238   if (SIGRTMIN != SIGRTMAX) {
239 
240     /* If str is in RT signal range, get number of of RT signal, save it as an
241     * integer. */
242     if (strncmp(str, "RTMIN+", SPACES_TO_N) == 0) {
243       unsigned long j = strtoul(&str[SPACES_TO_N], &endp, 10);
244 
245       /* If number is valid, save it in pnum. */
246       if (*endp == '\0') {
247         if (1 <= j &&
248             j <= ((SIGRTMAX - SIGRTMIN)-1)) {
249           *pnum = (SIGRTMIN + j);
250           return 0;
251         }
252         return -1;
253       }
254       return -1;
255     }
256 
257     /* If str is in RT signal range, get number of of RT signal, save it as an
258     * integer. */
259     if (strncmp(str, "RTMAX-", SPACES_TO_N) == 0) {
260       unsigned long j = strtoul(&str[SPACES_TO_N], &endp, 10); // and endptr null check
261 
262       /* If number is valid, save it in pnum. */
263       if (*endp == '\0') {
264         if (1 <= j &&
265             j <= ((SIGRTMAX - SIGRTMIN)-1)) {
266           *pnum = (SIGRTMAX - j);
267           return 0;
268         }
269         return -1;
270       }
271       return -1;
272     }
273   }
274 #endif
275 
276   /*If str is a valid signal name, save its corresponding number in pnum. */
277   for (sptr = sig_array; sptr < &sig_array[NUM_OF_SIGS]; sptr++) {
278     if (strcmp(sptr->sig_name, str) == 0) {
279       *pnum = sptr->sig_num;
280       return 0;
281     }
282   }
283 
284   /* str was not found in sig_array. Check whether str is a string
285    * representation of a valid integer. */
286   is_valid_decimal = strtoul(str, &endp, 10);
287 
288   if (*endp != '\0') {
289     return -1;
290   }
291 
292   /* If str is a representation of a decimal value, save its integer value
293    * in pnum. */
294   if (1 <= is_valid_decimal &&
295       is_valid_decimal <= (NSIG - 1)) {
296     *pnum = is_valid_decimal;
297     return 0;
298   }
299 
300   return -1;
301 }
302