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.2 (Berkeley) 6/21/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: }