/* * Signal handling for Plan 9 programs. * We stubbornly use the strings from Plan 9 instead * of the enumerated Unix constants. * There are some weird translations. In particular, * a "kill" note is the same as SIGTERM in Unix. * There is no equivalent note to Unix's SIGKILL, since * it's not a deliverable signal anyway. * * We do not handle SIGABRT or SIGSEGV, mainly so that * stack traces show the original source of the signal instead * of notifysigf. * * We have to add some extra entry points to provide the * ability to tweak which signals are deliverable and which * are acted upon. Notifydisable and notifyenable play with * the process signal mask. Notifyignore enables the signal * but will not call notifyf when it comes in. This is occasionally * useful. */ #include #include #define NOPLAN9DEFINES #include extern char *_p9sigstr(int, char*); extern int _p9strsig(char*); typedef struct Sig Sig; struct Sig { int sig; /* signal number */ int restart; /* do we restart the system call after this signal is handled? */ int enabled; /* is this signal enabled (not masked)? */ int notified; /* do we call the notify function for this signal? */ }; /* initial settings; for current status, ask the kernel */ static Sig sigs[] = { SIGHUP, 0, 1, 1, SIGINT, 0, 1, 1, SIGQUIT, 0, 1, 1, SIGILL, 0, 1, 1, SIGTRAP, 0, 1, 1, /* SIGABRT, 0, 1, 1, */ #ifdef SIGEMT SIGEMT, 0, 1, 1, #endif SIGFPE, 0, 1, 1, SIGBUS, 0, 1, 1, /* SIGSEGV, 0, 1, 1, */ SIGCHLD, 1, 0, 1, SIGSYS, 0, 1, 1, SIGPIPE, 0, 0, 1, SIGALRM, 0, 1, 1, SIGTERM, 0, 1, 1, SIGTSTP, 1, 0, 1, SIGTTIN, 1, 0, 1, SIGTTOU, 1, 0, 1, SIGXCPU, 0, 1, 1, SIGXFSZ, 0, 1, 1, SIGVTALRM, 0, 1, 1, SIGUSR1, 0, 1, 1, SIGUSR2, 0, 1, 1, SIGWINCH, 1, 0, 1, #ifdef SIGINFO SIGINFO, 1, 1, 1, #endif }; static Sig* findsig(int s) { int i; for(i=0; ib)){ case 0: if(notifyf) (*notifyf)(nil, _p9sigstr(sig, tmp)); /* fall through */ case 1: /* noted(NDFLT) */ if(0)print("DEFAULT %d\n", sig); signal(sig, SIG_DFL); raise(sig); _exit(1); case 2: /* noted(NCONT) */ if(0)print("HANDLED %d\n", sig); return; } } static void signonotify(int sig) { USED(sig); } int noted(int v) { p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1); abort(); return 0; } int notify(void (*f)(void*, char*)) { int i; static int init; notifyf = f; if(!init){ init = 1; noteinit(); } return 0; } /* * Nonsense about enabling and disabling signals. */ static void(*)(int) handler(int s) { struct sigaction sa; sigaction(s, nil, &sa); return sa.sa_handler; } static void notifysetenable(int sig, int enabled) { sigset_t mask; if(sig == 0) return; sigemptyset(&mask); sigaddset(&mask, sig); sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, nil); } void notifyenable(char *msg) { notifyenablex(_p9strsig(msg), 1); } void notifydisable(char *msg) { notifyenablex(_p9strsig(msg), 0); } static void notifyseton(int s, int on) { Sig *sig; struct sigaction sa; sig = findsig(s); if(sig == nil) return; notifyenable(msg); memset(&sa, 0, sizeof sa); sa.sa_handler = on ? signotify : signonotify; if(sig->restart) sa.sa_flags |= SA_RESTART; /* * We can't allow signals within signals because there's * only one jump buffer. */ sigfillset(&sa.sa_mask); /* * Install handler. */ sigaction(sig->sig, &sa, nil); } void notifyon(char *msg) { notifyseton(_p9strsig(msg), 1); } void notifyoff(char *msg) { notifysetoff(_p9strsig(msg), 0); } /* * Initialization follows sigs table. */ static void noteinit(void) { int i; Sig *sig; for(i=0; isig) != SIG_DFL) continue; /* * Should we only disable and not enable signals? * (I.e. if parent has disabled for us, should we still enable?) * Right now we always initialize to the state we want. */ notifysetenable(sig->sig, sig->enabled); notifyseton(sig->sig, sig->notified); } }