xref: /illumos-gate/usr/src/lib/libc/port/sys/signal.c (revision 4764d912222e53f8386bae7bf491f5780fd102ec)
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 ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #pragma weak _signal = signal
30 #pragma weak _sighold = sighold
31 #pragma weak _sigrelse = sigrelse
32 #pragma weak _sigignore = sigignore
33 #pragma weak _sigset = sigset
34 
35 #include "lint.h"
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <errno.h>
39 #include <signal.h>
40 #include <wait.h>
41 
42 /*
43  * Check for valid signal number as per SVID.
44  */
45 #define	CHECK_SIG(s, code) \
46 	if ((s) <= 0 || (s) >= NSIG || (s) == SIGKILL || (s) == SIGSTOP) { \
47 		errno = EINVAL; \
48 		return (code); \
49 	}
50 
51 /*
52  * Equivalent to stopdefault set in the kernel implementation (sig.c).
53  */
54 #define	STOPDEFAULT(s) \
55 	((s) == SIGSTOP || (s) == SIGTSTP || (s) == SIGTTOU || (s) == SIGTTIN)
56 
57 
58 /*
59  * SVr3.x signal compatibility routines. They are now
60  * implemented as library routines instead of system
61  * calls.
62  */
63 
64 void(*
65 signal(int sig, void(*func)(int)))(int)
66 {
67 	struct sigaction nact;
68 	struct sigaction oact;
69 
70 	CHECK_SIG(sig, SIG_ERR);
71 
72 	nact.sa_handler = func;
73 	nact.sa_flags = SA_RESETHAND|SA_NODEFER;
74 	(void) sigemptyset(&nact.sa_mask);
75 
76 	/*
77 	 * Pay special attention if sig is SIGCHLD and
78 	 * the disposition is SIG_IGN, per sysV signal man page.
79 	 */
80 	if (sig == SIGCHLD) {
81 		nact.sa_flags |= SA_NOCLDSTOP;
82 		if (func == SIG_IGN)
83 			nact.sa_flags |= SA_NOCLDWAIT;
84 	}
85 
86 	if (STOPDEFAULT(sig))
87 		nact.sa_flags |= SA_RESTART;
88 
89 	if (sigaction(sig, &nact, &oact) < 0)
90 		return (SIG_ERR);
91 
92 	return (oact.sa_handler);
93 }
94 
95 int
96 sighold(int sig)
97 {
98 	sigset_t set;
99 
100 	CHECK_SIG(sig, -1);
101 
102 	/*
103 	 * errno set on failure by either sigaddset or sigprocmask.
104 	 */
105 	(void) sigemptyset(&set);
106 	if (sigaddset(&set, sig) < 0)
107 		return (-1);
108 	return (sigprocmask(SIG_BLOCK, &set, (sigset_t *)0));
109 }
110 
111 int
112 sigrelse(int sig)
113 {
114 	sigset_t set;
115 
116 	CHECK_SIG(sig, -1);
117 
118 	/*
119 	 * errno set on failure by either sigaddset or sigprocmask.
120 	 */
121 	(void) sigemptyset(&set);
122 	if (sigaddset(&set, sig) < 0)
123 		return (-1);
124 	return (sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0));
125 }
126 
127 int
128 sigignore(int sig)
129 {
130 	struct sigaction act;
131 	sigset_t set;
132 
133 	CHECK_SIG(sig, -1);
134 
135 	act.sa_handler = SIG_IGN;
136 	act.sa_flags = 0;
137 	(void) sigemptyset(&act.sa_mask);
138 
139 	/*
140 	 * Pay special attention if sig is SIGCHLD and
141 	 * the disposition is SIG_IGN, per sysV signal man page.
142 	 */
143 	if (sig == SIGCHLD) {
144 		act.sa_flags |= SA_NOCLDSTOP;
145 		act.sa_flags |= SA_NOCLDWAIT;
146 	}
147 
148 	if (STOPDEFAULT(sig))
149 		act.sa_flags |= SA_RESTART;
150 
151 	if (sigaction(sig, &act, (struct sigaction *)0) < 0)
152 		return (-1);
153 
154 	(void) sigemptyset(&set);
155 	if (sigaddset(&set, sig) < 0)
156 		return (-1);
157 	return (sigprocmask(SIG_UNBLOCK, &set, (sigset_t *)0));
158 }
159 
160 int
161 __sigpause(int sig)
162 {
163 	sigset_t set;
164 	int rval;
165 
166 	CHECK_SIG(sig, -1);
167 
168 	/*
169 	 * sigpause() is defined to unblock the signal
170 	 * and not block it again on return.
171 	 * sigsuspend() restores the original signal set,
172 	 * so we have to unblock sig overtly.
173 	 */
174 	(void) sigprocmask(0, (sigset_t *)0, &set);
175 	if (sigdelset(&set, sig) < 0)
176 		return (-1);
177 	rval = sigsuspend(&set);
178 	(void) sigrelse(sig);
179 	return (rval);
180 }
181 
182 void(*
183 sigset(int sig, void(*func)(int)))(int)
184 {
185 	struct sigaction nact;
186 	struct sigaction oact;
187 	sigset_t nset;
188 	sigset_t oset;
189 	int code;
190 
191 	CHECK_SIG(sig, SIG_ERR);
192 
193 	(void) sigemptyset(&nset);
194 	if (sigaddset(&nset, sig) < 0)
195 		return (SIG_ERR);
196 
197 	if (func == SIG_HOLD) {
198 		if (sigprocmask(SIG_BLOCK, &nset, &oset) < 0)
199 			return (SIG_ERR);
200 		if (sigaction(sig, (struct sigaction *)0, &oact) < 0)
201 			return (SIG_ERR);
202 	} else {
203 		nact.sa_handler = func;
204 		nact.sa_flags = 0;
205 		(void) sigemptyset(&nact.sa_mask);
206 		/*
207 		 * Pay special attention if sig is SIGCHLD and
208 		 * the disposition is SIG_IGN, per sysV signal man page.
209 		 */
210 		if (sig == SIGCHLD) {
211 			nact.sa_flags |= SA_NOCLDSTOP;
212 			if (func == SIG_IGN)
213 				nact.sa_flags |= SA_NOCLDWAIT;
214 		}
215 
216 		if (STOPDEFAULT(sig))
217 			nact.sa_flags |= SA_RESTART;
218 
219 		if (sigaction(sig, &nact, &oact) < 0)
220 			return (SIG_ERR);
221 
222 		if (sigprocmask(SIG_UNBLOCK, &nset, &oset) < 0)
223 			return (SIG_ERR);
224 	}
225 
226 	if ((code = sigismember(&oset, sig)) < 0)
227 		return (SIG_ERR);
228 	else if (code == 1)
229 		return (SIG_HOLD);
230 
231 	return (oact.sa_handler);
232 }
233