|
|
1.1 ! root 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) 2/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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.