xref: /illumos-gate/usr/src/lib/libc/port/sys/signal.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma weak _signal = signal
28 #pragma weak _sighold = sighold
29 #pragma weak _sigrelse = sigrelse
30 #pragma weak _sigignore = sigignore
31 #pragma weak _sigset = sigset
32 
33 #include "lint.h"
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <errno.h>
37 #include <signal.h>
38 #include <wait.h>
39 
40 /*
41  * Check for valid signal number as per SVID.
42  */
43 #define	CHECK_SIG(s, code) \
44 	if ((s) <= 0 || (s) >= NSIG || (s) == SIGKILL || (s) == SIGSTOP) { \
45 		errno = EINVAL; \
46 		return (code); \
47 	}
48 
49 /*
50  * Equivalent to stopdefault set in the kernel implementation (sig.c).
51  */
52 #define	STOPDEFAULT(s) \
53 	((s) == SIGSTOP || (s) == SIGTSTP || (s) == SIGTTOU || (s) == SIGTTIN)
54 
55 
56 /*
57  * SVr3.x signal compatibility routines. They are now
58  * implemented as library routines instead of system
59  * calls.
60  */
61 
62 void(*
signal(int sig,void (* func)(int))63 signal(int sig, void(*func)(int)))(int)
64 {
65 	struct sigaction nact;
66 	struct sigaction oact;
67 
68 	CHECK_SIG(sig, SIG_ERR);
69 
70 	nact.sa_handler = func;
71 	nact.sa_flags = SA_RESETHAND|SA_NODEFER;
72 	(void) sigemptyset(&nact.sa_mask);
73 
74 	/*
75 	 * Pay special attention if sig is SIGCHLD and
76 	 * the disposition is SIG_IGN, per sysV signal man page.
77 	 */
78 	if (sig == SIGCHLD) {
79 		nact.sa_flags |= SA_NOCLDSTOP;
80 		if (func == SIG_IGN)
81 			nact.sa_flags |= SA_NOCLDWAIT;
82 	}
83 
84 	if (STOPDEFAULT(sig))
85 		nact.sa_flags |= SA_RESTART;
86 
87 	if (sigaction(sig, &nact, &oact) < 0)
88 		return (SIG_ERR);
89 
90 	return (oact.sa_handler);
91 }
92 
93 int
sighold(int sig)94 sighold(int sig)
95 {
96 	sigset_t set;
97 
98 	CHECK_SIG(sig, -1);
99 
100 	/*
101 	 * errno set on failure by either sigaddset or sigprocmask.
102 	 */
103 	(void) sigemptyset(&set);
104 	if (sigaddset(&set, sig) < 0)
105 		return (-1);
106 	return (sigprocmask(SIG_BLOCK, &set, (sigset_t *)0));
107 }
108 
109 int
sigrelse(int sig)110 sigrelse(int sig)
111 {
112 	sigset_t set;
113 
114 	CHECK_SIG(sig, -1);
115 
116 	/*
117 	 * errno set on failure by either sigaddset or sigprocmask.
118 	 */
119 	(void) sigemptyset(&set);
120 	if (sigaddset(&set, sig) < 0)
121 		return (-1);
122 	return (sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0));
123 }
124 
125 int
sigignore(int sig)126 sigignore(int sig)
127 {
128 	struct sigaction act;
129 	sigset_t set;
130 
131 	CHECK_SIG(sig, -1);
132 
133 	act.sa_handler = SIG_IGN;
134 	act.sa_flags = 0;
135 	(void) sigemptyset(&act.sa_mask);
136 
137 	/*
138 	 * Pay special attention if sig is SIGCHLD and
139 	 * the disposition is SIG_IGN, per sysV signal man page.
140 	 */
141 	if (sig == SIGCHLD) {
142 		act.sa_flags |= SA_NOCLDSTOP;
143 		act.sa_flags |= SA_NOCLDWAIT;
144 	}
145 
146 	if (STOPDEFAULT(sig))
147 		act.sa_flags |= SA_RESTART;
148 
149 	if (sigaction(sig, &act, (struct sigaction *)0) < 0)
150 		return (-1);
151 
152 	(void) sigemptyset(&set);
153 	if (sigaddset(&set, sig) < 0)
154 		return (-1);
155 	return (sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0));
156 }
157 
158 int
__sigpause(int sig)159 __sigpause(int sig)
160 {
161 	sigset_t set;
162 	int rval;
163 
164 	CHECK_SIG(sig, -1);
165 
166 	/*
167 	 * sigpause() is defined to unblock the signal
168 	 * and not block it again on return.
169 	 * sigsuspend() restores the original signal set,
170 	 * so we have to unblock sig overtly.
171 	 */
172 	(void) sigprocmask(0, (sigset_t *)0, &set);
173 	if (sigdelset(&set, sig) < 0)
174 		return (-1);
175 	rval = sigsuspend(&set);
176 	(void) sigrelse(sig);
177 	return (rval);
178 }
179 
180 void(*
sigset(int sig,void (* func)(int))181 sigset(int sig, void(*func)(int)))(int)
182 {
183 	struct sigaction nact;
184 	struct sigaction oact;
185 	sigset_t nset;
186 	sigset_t oset;
187 	int code;
188 
189 	CHECK_SIG(sig, SIG_ERR);
190 
191 	(void) sigemptyset(&nset);
192 	if (sigaddset(&nset, sig) < 0)
193 		return (SIG_ERR);
194 
195 	if (func == SIG_HOLD) {
196 		if (sigprocmask(SIG_BLOCK, &nset, &oset) < 0)
197 			return (SIG_ERR);
198 		if (sigaction(sig, (struct sigaction *)0, &oact) < 0)
199 			return (SIG_ERR);
200 	} else {
201 		nact.sa_handler = func;
202 		nact.sa_flags = 0;
203 		(void) sigemptyset(&nact.sa_mask);
204 		/*
205 		 * Pay special attention if sig is SIGCHLD and
206 		 * the disposition is SIG_IGN, per sysV signal man page.
207 		 */
208 		if (sig == SIGCHLD) {
209 			nact.sa_flags |= SA_NOCLDSTOP;
210 			if (func == SIG_IGN)
211 				nact.sa_flags |= SA_NOCLDWAIT;
212 		}
213 
214 		if (STOPDEFAULT(sig))
215 			nact.sa_flags |= SA_RESTART;
216 
217 		if (sigaction(sig, &nact, &oact) < 0)
218 			return (SIG_ERR);
219 
220 		if (sigprocmask(SIG_UNBLOCK, &nset, &oset) < 0)
221 			return (SIG_ERR);
222 	}
223 
224 	if ((code = sigismember(&oset, sig)) < 0)
225 		return (SIG_ERR);
226 	else if (code == 1)
227 		return (SIG_HOLD);
228 
229 	return (oact.sa_handler);
230 }
231