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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 23 /* All Rights Reserved */ 24 25 26 /* 27 * University Copyright- Copyright (c) 1982, 1986, 1988 28 * The Regents of the University of California 29 * All Rights Reserved 30 * 31 * University Acknowledgment- Portions of this document are derived from 32 * software developed by the University of California, Berkeley, and its 33 * contributors. 34 */ 35 36 /* 37 * mailx -- a modified version of a University of California at Berkeley 38 * mail program 39 */ 40 41 /* 42 * This code is only compiled in if SIG_HOLD is not defined! 43 * 44 * Retrofit new signal interface to old signal primitives. 45 * Supported routines: 46 * sigsys(sig, func) 47 * sigset(sig, func) 48 * sighold(sig) 49 * sigrelse(sig) 50 * sigignore(sig) 51 * sigpause(sig) 52 * Also, 53 * sigchild() 54 * to set all held signals to ignored signals in the 55 * child process after fork(2) 56 */ 57 #include <signal.h> 58 59 #ifndef SIG_HOLD 60 # include <errno.h> 61 # include <setjmp.h> 62 # include <stdio.h> 63 64 extern int errno; 65 66 typedef void (*sigtype)(); 67 68 #define SIG_HOLD ((sigtype) 2) 69 #ifndef SIG_ERR 70 # define SIG_ERR ((sigtype) -1) 71 #endif 72 73 sigtype sigdisp(), sighold(), sigignore(); 74 void _Sigtramp(); 75 76 /* 77 * The following helps us keep the extended signal semantics together. 78 * We remember for each signal the address of the function we're 79 * supposed to call. s_func is SIG_DFL / SIG_IGN if appropriate. 80 */ 81 static struct sigtable { 82 sigtype s_func; /* What to call */ 83 int s_flag; /* Signal flags; see below */ 84 } sigtable[NSIG + 1]; 85 86 /* 87 * Signal flag values. 88 */ 89 #define SHELD 1 /* Signal is being held */ 90 #define SDEFER 2 /* Signal occured while held */ 91 #define SSET 4 /* s_func is believable */ 92 #define SPAUSE 8 /* are pausing, waiting for sig */ 93 94 jmp_buf _pause; /* For doing sigpause() */ 95 96 /* 97 * Approximate sigsys() system call 98 * This is almost useless since one only calls sigsys() 99 * in the child of a vfork(). If you have vfork(), you have new signals 100 * anyway. The real sigsys() does all the stuff needed to support 101 * the real sigset() library. We don't bother here, assuming that 102 * you are either ignoring or defaulting a signal in the child. 103 */ 104 sigtype 105 sigsys(int sig, sigtype func) 106 { 107 sigtype old; 108 109 old = sigdisp(sig); 110 signal(sig, func); 111 return(old); 112 } 113 114 115 /* 116 * Set the (permanent) disposition of a signal. 117 * If the signal is subsequently (or even now) held, 118 * the action you set here can be enabled using sigrelse(). 119 */ 120 sigtype 121 sigset(int sig, sigtype func) 122 { 123 sigtype old; 124 125 if (sig < 1 || sig > NSIG) { 126 errno = EINVAL; 127 return(SIG_ERR); 128 } 129 old = sigdisp(sig); 130 /* 131 * Does anyone actually call sigset with SIG_HOLD!? 132 */ 133 if (func == SIG_HOLD) { 134 sighold(sig); 135 return(old); 136 } 137 sigtable[sig].s_flag |= SSET; 138 sigtable[sig].s_func = func; 139 if (func == SIG_DFL) { 140 /* 141 * If signal has been held, must retain 142 * the catch so that we can note occurrance 143 * of signal. 144 */ 145 if ((sigtable[sig].s_flag & SHELD) == 0) 146 signal(sig, SIG_DFL); 147 else 148 signal(sig, _Sigtramp); 149 return(old); 150 } 151 if (func == SIG_IGN) { 152 /* 153 * Clear pending signal 154 */ 155 signal(sig, SIG_IGN); 156 sigtable[sig].s_flag &= ~SDEFER; 157 return(old); 158 } 159 signal(sig, _Sigtramp); 160 return(old); 161 } 162 163 /* 164 * Hold a signal. 165 * This CAN be tricky if the signal's disposition is SIG_DFL. 166 * In that case, we still catch the signal so we can note it 167 */ 168 sigtype 169 sighold(int sig) 170 { 171 sigtype old; 172 173 if (sig < 1 || sig > NSIG) { 174 errno = EINVAL; 175 return(SIG_ERR); 176 } 177 old = sigdisp(sig); 178 if (sigtable[sig].s_flag & SHELD) 179 return(old); 180 /* 181 * When the default action is required, we have to 182 * set up to catch the signal to note signal's occurrance. 183 */ 184 if (old == SIG_DFL) { 185 sigtable[sig].s_flag |= SSET; 186 signal(sig, _Sigtramp); 187 } 188 sigtable[sig].s_flag |= SHELD; 189 return(old); 190 } 191 192 /* 193 * Release a signal 194 * If the signal occurred while we had it held, cause the signal. 195 */ 196 sigtype 197 sigrelse(int sig) 198 { 199 sigtype old; 200 201 if (sig < 1 || sig > NSIG) { 202 errno = EINVAL; 203 return(SIG_ERR); 204 } 205 old = sigdisp(sig); 206 if ((sigtable[sig].s_flag & SHELD) == 0) 207 return(old); 208 sigtable[sig].s_flag &= ~SHELD; 209 if (sigtable[sig].s_flag & SDEFER) 210 _Sigtramp(sig); 211 /* 212 * If disposition was the default, then we can unset the 213 * catch to _Sigtramp() and let the system do the work. 214 */ 215 if (sigtable[sig].s_func == SIG_DFL) 216 signal(sig, SIG_DFL); 217 return(old); 218 } 219 220 /* 221 * Ignore a signal. 222 */ 223 sigtype 224 sigignore(int sig) 225 { 226 return(sigset(sig, SIG_IGN)); 227 } 228 229 /* 230 * Pause, waiting for sig to occur. 231 * We assume LUSER called us with the signal held. 232 * When we got the signal, mark the signal as having 233 * occurred. It will actually cause something when 234 * the signal is released. 235 */ 236 int 237 sigpause(int sig) 238 { 239 if (sig < 1 || sig > NSIG) { 240 errno = EINVAL; 241 return; 242 } 243 sigtable[sig].s_flag |= SHELD|SPAUSE; 244 if (setjmp(_pause) == 0) 245 pause(); 246 sigtable[sig].s_flag &= ~SPAUSE; 247 sigtable[sig].s_flag |= SDEFER; 248 } 249 250 /* 251 * In the child process after fork(2), set the disposition of all held 252 * signals to SIG_IGN. This is a new procedure not in the real sigset() 253 * package, provided for retrofitting purposes. 254 */ 255 int 256 sigchild(void) 257 { 258 register int i; 259 260 for (i = 1; i <= NSIG; i++) 261 if (sigtable[i].s_flag & SHELD) 262 signal(i, SIG_IGN); 263 } 264 265 266 /* 267 * Return the current disposition of a signal 268 * If we have not set this signal before, we have to 269 * ask the system 270 */ 271 sigtype 272 sigdisp(int sig) 273 { 274 sigtype old; 275 276 if (sig < 1 || sig > NSIG) { 277 errno = EINVAL; 278 return(SIG_ERR); 279 } 280 /* 281 * If we have no knowledge of this signal, 282 * ask the system, then save the result for later. 283 */ 284 if ((sigtable[sig].s_flag & SSET) == 0) { 285 old = signal(sig, SIG_IGN); 286 sigtable[sig].s_func = old; 287 sigtable[sig].s_flag |= SSET; 288 signal(sig, old); 289 return(old); 290 } 291 /* 292 * If we have set this signal before, then sigset() 293 * will have been careful to leave something meaningful 294 * in s_func. 295 */ 296 return(sigtable[sig].s_func); 297 } 298 299 /* 300 * The following routine gets called for any signal 301 * that is to be trapped to a user function. 302 */ 303 void 304 _Sigtramp(int sig) 305 { 306 sigtype old; 307 308 if (sig < 1 || sig > NSIG) { 309 errno = EINVAL; 310 return; 311 } 312 313 top: 314 old = signal(sig, SIG_IGN); 315 /* 316 * If signal being paused on, wakeup sigpause() 317 */ 318 if (sigtable[sig].s_flag & SPAUSE) 319 longjmp(_pause, 1); 320 /* 321 * If signal is being held, mark its table entry 322 * so we can trigger it when signal is released. 323 * Then just return. 324 */ 325 if (sigtable[sig].s_flag & SHELD) { 326 sigtable[sig].s_flag |= SDEFER; 327 signal(sig, _Sigtramp); 328 return; 329 } 330 /* 331 * If the signal is being ignored, just return. 332 * This would make SIGCONT more normal, but of course 333 * any system with SIGCONT also has the new signal pkg, so... 334 */ 335 if (sigtable[sig].s_func == SIG_IGN) 336 return; 337 /* 338 * If the signal is SIG_DFL, then we probably got here 339 * by holding the signal, having it happen, then releasing 340 * the signal. 341 */ 342 if (sigtable[sig].s_func == SIG_DFL) { 343 signal(sig, SIG_DFL); 344 kill(getpid(), sig); 345 /* Will we get back here? */ 346 return; 347 } 348 /* 349 * Looks like we should just cause the signal... 350 * We hold the signal for the duration of the user's 351 * code with the signal re-enabled. If the signal 352 * happens again while in user code, we will recursively 353 * trap here and mark that we had another occurance 354 * and return to the user's trap code. When we return 355 * from there, we can cause the signal again. 356 */ 357 sigtable[sig].s_flag &= ~SDEFER; 358 sigtable[sig].s_flag |= SHELD; 359 signal(sig, _Sigtramp); 360 (*sigtable[sig].s_func)(sig); 361 /* 362 * If the signal re-occurred while in the user's routine, 363 * just go try it again... 364 */ 365 sigtable[sig].s_flag &= ~SHELD; 366 if (sigtable[sig].s_flag & SDEFER) 367 goto top; 368 } 369 #endif 370