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