1: # 2: 3: #include <signal.h> 4: #include <errno.h> 5: #include <setjmp.h> 6: #include "sigretro.h" 7: 8: static char *SccsID = "@(#)sigretro.c 1.2 3/22/82"; 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: }