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