/* $NetBSD: sigact.c,v 1.3 2008/06/15 14:20:09 tnn Exp $ */ /* NAME: * sigact.c - fake sigaction(2) * * SYNOPSIS: * #include "sigact.h" * * int sigaction(int sig, struct sigaction *act, * struct sigaction *oact); * int sigaddset(sigset_t *mask, int sig); * int sigdelset(sigset_t *mask, int sig); * int sigemptyset(sigset_t *mask); * int sigfillset(sigset_t *mask); * int sigismember(sigset_t *mask, int sig); * int sigpending(sigset_t *set); * int sigprocmask(int how, sigset_t *set, sigset_t *oset); * int sigsuspend(sigset_t *mask); * * RETSIGTYPE (*Signal(int sig, RETSIGTYPE (*disp)(int)))(int); * * DESCRIPTION: * This is a fake sigaction implementation. It uses * sigsetmask(2) et al or sigset(2) and friends if * available, otherwise it just uses signal(2). If it * thinks sigaction(2) really exists it compiles to "almost" * nothing. * * In any case it provides a Signal() function that is * implemented in terms of sigaction(). * If not using signal(2) as part of the underlying * implementation (USE_SIGNAL or USE_SIGMASK), and * NO_SIGNAL is not defined, it also provides a signal() * function that calls Signal(). * * The need for all this mucking about is the problems * caused by mixing various signal handling mechanisms in * the one process. This module allows for a consistent * POSIX compliant interface to whatever is actually * available. * * sigaction() allows the caller to examine and/or set the * action to be associated with a given signal. "act" and * "oact" are pointers to 'sigaction structs': *.nf * * struct sigaction * { * RETSIGTYPE (*sa_handler)(); * sigset_t sa_mask; * int sa_flags; * }; *.fi * * RETSIGTYPE is normally 'void' in the POSIX implementation * and for most current systems. On some older UNIX * systems, signal handlers do not return 'void', so * this implementation keeps 'sa_handler' inline with the * hosts normal signal handling conventions. * 'sa_mask' controls which signals will be blocked while * the selected signal handler is active. It is not used * in this implementation. * 'sa_flags' controls various semantics such as whether * system calls should be automagically restarted * (SA_RESTART) etc. It is not used in this * implementation. * Either "act" or "oact" may be NULL in which case the * appropriate operation is skipped. * * sigaddset() adds "sig" to the sigset_t pointed to by "mask". * * sigdelset() removes "sig" from the sigset_t pointed to * by "mask". * * sigemptyset() makes the sigset_t pointed to by "mask" empty. * * sigfillset() makes the sigset_t pointed to by "mask" * full ie. match all signals. * * sigismember() returns true if "sig" is found in "*mask". * * sigpending() is supposed to return "set" loaded with the * set of signals that are blocked and pending for the * calling process. It does nothing in this impementation. * * sigprocmask() is used to examine and/or change the * signal mask for the calling process. Either "set" or * "oset" may be NULL in which case the appropriate * operation is skipped. "how" may be one of SIG_BLOCK, * SIG_UNBLOCK or SIG_SETMASK. If this package is built * with USE_SIGNAL, then this routine achieves nothing. * * sigsuspend() sets the signal mask to "*mask" and waits * for a signal to be delivered after which the previous * mask is restored. * * * RETURN VALUE: * 0==success, -1==failure * * BUGS: * Since we fake most of this, don't expect fancy usage to * work. * * AUTHOR: * Simon J. Gerraty */ /* COPYRIGHT: * @(#)Copyright (c) 1992 Simon J. Gerraty * * This is free software. It comes with NO WARRANTY. * Permission to use, modify and distribute this source code * is granted subject to the following conditions. * 1/ that that the above copyright notice and this notice * are preserved in all copies and that due credit be given * to the author. * 2/ that any changes to this code are clearly commented * as such so that the author does get blamed for bugs * other than his own. * * Please send copies of changes and bug-fixes to: * sjg@zen.void.oz.au * */ /* Changes to sigact.c for pdksh, Michael Rendell : * - sigsuspend(): pass *mask to bsd4.2 sigpause instead of mask. * - changed SIG_HDLR to RETSIGTYPE for use with GNU autoconf * - added and used RETSIGVAL * - include sh.h instead of signal.h (to get *_SIGNALS macros) * - changed if !SA_NOCLDSTOP ... to USE_FAKE_SIGACT to avoid confusion * - set the USE_* defines using the *_SIGNALS defines from autoconf * - sigaction(): if using BSD signals, use sigvec() (used to use * signal()) and set the SV_INTERRUPT flag (POSIX says syscalls * are interrupted and pdksh needs this behaviour). * - define IS_KSH before including anything; ifdef out routines * not used in ksh if IS_KSH is defined (same in sigact.h). * - use ARGS() instead of __P() * - sigaction(),sigsuspend(),Signal(),signal(): use handler_t typedef * instead of explicit type. */ /* #include */ #define IS_KSH #include "sh.h" /* #ifndef __P # define __P(p) p #endif */ /* * some systems have a faulty sigaction() implementation! * Allow us to bypass it. * Or they may have installed sigact.h as signal.h which is why * we have SA_NOCLDSTOP defined. */ #ifdef USE_FAKE_SIGACT /* let autoconf decide.. */ /* #if !defined(SA_NOCLDSTOP) || defined(_SIGACT_H) || defined(USE_SIGNAL) || defined(USE_SIGSET) || defined(USE_SIGMASK) */ /* Let autoconf decide which to use */ #ifdef BSD42_SIGNALS # define USE_SIGMASK #else # ifdef BSD41_SIGNALS # define USE_SIGSET # else # define USE_SIGNAL # endif #endif /* BSD42_SIGNALS */ /* * if we haven't been told, * try and guess what we should implement with. */ #if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL) # if defined(sigmask) || defined(BSD) || defined(_BSD) && !defined(BSD41) # define USE_SIGMASK # else # ifndef NO_SIGSET # define USE_SIGSET # else # define USE_SIGNAL # endif # endif #endif /* * if we still don't know, we're in trouble */ #if !defined(USE_SIGSET) && !defined(USE_SIGMASK) && !defined(USE_SIGNAL) error must know what to implement with #endif #include "sigact.h" /* * in case signal() has been mapped to our Signal(). */ #undef signal int sigaction(sig, act, oact) int sig; struct sigaction *act, *oact; { handler_t oldh; if (act) { #ifdef USE_SIGSET oldh = sigset(sig, act->sa_handler); #else # ifdef USE_SIGMASK struct sigvec nsv,osv; nsv.sv_handler = act->sa_handler; nsv.sv_mask = 0; /* punt */ nsv.sv_flags = SV_INTERRUPT; /* punt */ sigvec(sig, &nsv, &osv); oldh = osv.sv_handler; # else /* USE_SIGMASK */ oldh = signal(sig, act->sa_handler); # endif /* USE_SIGMASK */ #endif } else { if (oact) { #ifdef USE_SIGSET oldh = sigset(sig, SIG_IGN); #else oldh = signal(sig, SIG_IGN); #endif if (oldh != SIG_IGN && oldh != SIG_ERR) { #ifdef USE_SIGSET (void) sigset(sig, oldh); #else (void) signal(sig, oldh); #endif } } } if (oact) { oact->sa_handler = oldh; } return 0; /* hey we're faking it */ } int sigaddset(mask, sig) sigset_t *mask; int sig; { *mask |= sigmask(sig); return 0; } #ifndef IS_KSH int sigdelset(mask, sig) sigset_t *mask; int sig; { *mask &= ~(sigmask(sig)); return 0; } #endif /* IS_KSH */ int sigemptyset(mask) sigset_t *mask; { *mask = 0; return 0; } #ifndef IS_KSH int sigfillset(mask) sigset_t *mask; { *mask = ~0; return 0; } #endif /* IS_KSH */ #ifndef IS_KSH int sigismember(mask, sig) sigset_t *mask; int sig; { return ((*mask) & sigmask(sig)); } #endif /* IS_KSH */ #ifndef IS_KSH int sigpending(set) sigset_t *set; { return 0; /* faking it! */ } #endif /* IS_KSH */ int sigprocmask(how, set, oset) int how; sigset_t *set, *oset; { #ifdef USE_SIGSET register int i; #endif static sigset_t sm; static int once = 0; if (!once) { /* * initally we clear sm, * there after, it represents the last * thing we did. */ once++; #ifdef USE_SIGMASK sm = sigblock(0); #else sm = 0; #endif } if (oset) *oset = sm; if (set) { switch (how) { case SIG_BLOCK: sm |= *set; break; case SIG_UNBLOCK: sm &= ~(*set); break; case SIG_SETMASK: sm = *set; break; } #ifdef USE_SIGMASK (void) sigsetmask(sm); #else # ifdef USE_SIGSET for (i = 1; i < NSIG; i++) { if (how == SIG_UNBLOCK) { if (*set & sigmask(i)) sigrelse(i); } else if (sm & sigmask(i)) { sighold(i); } } # endif #endif } return 0; } int sigsuspend(mask) sigset_t *mask; { #ifdef USE_SIGMASK sigpause(*mask); #else register int i; # ifdef USE_SIGSET for (i = 1; i < NSIG; i++) { if (*mask & sigmask(i)) { /* not the same sigpause() as above! */ sigpause(i); break; } } # else /* signal(2) only */ handler_t oldh; /* * make sure that signals in mask will not * be ignored. */ for (i = 1; i < NSIG; i++) { if (*mask & sigmask(i)) { if ((oldh = signal(i, SIG_DFL)) != SIG_ERR && oldh != SIG_IGN && oldh != SIG_DFL) (void) signal(i, oldh); /* restore handler */ } } pause(); /* wait for a signal */ # endif #endif return 0; } #endif /* USE_FAKE_SIGACT (was ! SA_NOCLDSTOP) */ #if !defined(RETSIGTYPE) # define RETSIGTYPE void # define RETSIGVAL #endif #if !defined(SIG_ERR) # define SIG_ERR (RETSIGTYPE (*)())-1 #endif /* * an implementation of signal() using sigaction(). */ #ifndef IS_KSH handler_t Signal(sig, handler) int sig; handler_t handler; { struct sigaction act, oact; act.sa_handler = handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(sig, &act, &oact) < 0) return (SIG_ERR); return (oact.sa_handler); } #endif /* IS_KSH */ #ifndef IS_KSH #if !defined(USE_SIGNAL) && !defined(USE_SIGMASK) && !defined(NO_SIGNAL) /* * ensure we avoid signal mayhem */ handler_t signal(sig, handler) int sig; handler_t handler; { return (Signal(sig, handler)); } #endif #endif /* IS_KSH */ /* This lot (for GNU-Emacs) goes at the end of the file. */ /* * Local Variables: * version-control:t * comment-column:40 * End: */