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