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