📄 kern_sig.c
字号:
/* * Copyright (c) 1982, 1986, 1989, 1991, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)kern_sig.c 8.7 (Berkeley) 4/18/94 */#define SIGPROP /* include signal properties table */#include <sys/param.h>#include <sys/signalvar.h>#include <sys/resourcevar.h>#include <sys/namei.h>#include <sys/vnode.h>#include <sys/proc.h>#include <sys/systm.h>#include <sys/timeb.h>#include <sys/times.h>#include <sys/buf.h>#include <sys/acct.h>#include <sys/file.h>#include <sys/kernel.h>#include <sys/wait.h>#include <sys/ktrace.h>#include <sys/syslog.h>#include <sys/stat.h>#include <machine/cpu.h>#include <vm/vm.h>#include <sys/user.h> /* for coredump *//* * Can process p, with pcred pc, send the signal signum to process q? */#define CANSIGNAL(p, pc, q, signum) \ ((pc)->pc_ucred->cr_uid == 0 || \ (pc)->p_ruid == (q)->p_cred->p_ruid || \ (pc)->pc_ucred->cr_uid == (q)->p_cred->p_ruid || \ (pc)->p_ruid == (q)->p_ucred->cr_uid || \ (pc)->pc_ucred->cr_uid == (q)->p_ucred->cr_uid || \ ((signum) == SIGCONT && (q)->p_session == (p)->p_session))struct sigaction_args { int signum; struct sigaction *nsa; struct sigaction *osa;};/* ARGSUSED */sigaction(p, uap, retval) struct proc *p; register struct sigaction_args *uap; int *retval;{ struct sigaction vec; register struct sigaction *sa; register struct sigacts *ps = p->p_sigacts; register int signum; int bit, error; signum = uap->signum; if (signum <= 0 || signum >= NSIG || signum == SIGKILL || signum == SIGSTOP) return (EINVAL); sa = &vec; if (uap->osa) { sa->sa_handler = ps->ps_sigact[signum]; sa->sa_mask = ps->ps_catchmask[signum]; bit = sigmask(signum); sa->sa_flags = 0; if ((ps->ps_sigonstack & bit) != 0) sa->sa_flags |= SA_ONSTACK; if ((ps->ps_sigintr & bit) == 0) sa->sa_flags |= SA_RESTART; if (p->p_flag & P_NOCLDSTOP) sa->sa_flags |= SA_NOCLDSTOP; if (error = copyout((caddr_t)sa, (caddr_t)uap->osa, sizeof (vec))) return (error); } if (uap->nsa) { if (error = copyin((caddr_t)uap->nsa, (caddr_t)sa, sizeof (vec))) return (error); setsigvec(p, signum, sa); } return (0);}setsigvec(p, signum, sa) register struct proc *p; int signum; register struct sigaction *sa;{ register struct sigacts *ps = p->p_sigacts; register int bit; bit = sigmask(signum); /* * Change setting atomically. */ (void) splhigh(); ps->ps_sigact[signum] = sa->sa_handler; ps->ps_catchmask[signum] = sa->sa_mask &~ sigcantmask; if ((sa->sa_flags & SA_RESTART) == 0) ps->ps_sigintr |= bit; else ps->ps_sigintr &= ~bit; if (sa->sa_flags & SA_ONSTACK) ps->ps_sigonstack |= bit; else ps->ps_sigonstack &= ~bit;#ifdef COMPAT_SUNOS if (sa->sa_flags & SA_USERTRAMP) ps->ps_usertramp |= bit; else ps->ps_usertramp &= ~bit;#endif if (signum == SIGCHLD) { if (sa->sa_flags & SA_NOCLDSTOP) p->p_flag |= P_NOCLDSTOP; else p->p_flag &= ~P_NOCLDSTOP; } /* * Set bit in p_sigignore for signals that are set to SIG_IGN, * and for signals set to SIG_DFL where the default is to ignore. * However, don't put SIGCONT in p_sigignore, * as we have to restart the process. */ if (sa->sa_handler == SIG_IGN || (sigprop[signum] & SA_IGNORE && sa->sa_handler == SIG_DFL)) { p->p_siglist &= ~bit; /* never to be seen again */ if (signum != SIGCONT) p->p_sigignore |= bit; /* easier in psignal */ p->p_sigcatch &= ~bit; } else { p->p_sigignore &= ~bit; if (sa->sa_handler == SIG_DFL) p->p_sigcatch &= ~bit; else p->p_sigcatch |= bit; } (void) spl0();}/* * Initialize signal state for process 0; * set to ignore signals that are ignored by default. */voidsiginit(p) struct proc *p;{ register int i; for (i = 0; i < NSIG; i++) if (sigprop[i] & SA_IGNORE && i != SIGCONT) p->p_sigignore |= sigmask(i);}/* * Reset signals for an exec of the specified process. */voidexecsigs(p) register struct proc *p;{ register struct sigacts *ps = p->p_sigacts; register int nc, mask; /* * Reset caught signals. Held signals remain held * through p_sigmask (unless they were caught, * and are now ignored by default). */ while (p->p_sigcatch) { nc = ffs((long)p->p_sigcatch); mask = sigmask(nc); p->p_sigcatch &= ~mask; if (sigprop[nc] & SA_IGNORE) { if (nc != SIGCONT) p->p_sigignore |= mask; p->p_siglist &= ~mask; } ps->ps_sigact[nc] = SIG_DFL; } /* * Reset stack state to the user stack. * Clear set of signals caught on the signal stack. */ ps->ps_sigstk.ss_flags = SA_DISABLE; ps->ps_sigstk.ss_size = 0; ps->ps_sigstk.ss_base = 0; ps->ps_flags = 0;}/* * Manipulate signal mask. * Note that we receive new mask, not pointer, * and return old mask as return value; * the library stub does the rest. */struct sigprocmask_args { int how; sigset_t mask;};sigprocmask(p, uap, retval) register struct proc *p; struct sigprocmask_args *uap; int *retval;{ int error = 0; *retval = p->p_sigmask; (void) splhigh(); switch (uap->how) { case SIG_BLOCK: p->p_sigmask |= uap->mask &~ sigcantmask; break; case SIG_UNBLOCK: p->p_sigmask &= ~uap->mask; break; case SIG_SETMASK: p->p_sigmask = uap->mask &~ sigcantmask; break; default: error = EINVAL; break; } (void) spl0(); return (error);}struct sigpending_args { int dummy;};/* ARGSUSED */sigpending(p, uap, retval) struct proc *p; struct sigpending_args *uap; int *retval;{ *retval = p->p_siglist; return (0);}#if defined(COMPAT_43) || defined(COMPAT_SUNOS)/* * Generalized interface signal handler, 4.3-compatible. */struct osigvec_args { int signum; struct sigvec *nsv; struct sigvec *osv;};/* ARGSUSED */osigvec(p, uap, retval) struct proc *p; register struct osigvec_args *uap; int *retval;{ struct sigvec vec; register struct sigacts *ps = p->p_sigacts; register struct sigvec *sv; register int signum; int bit, error; signum = uap->signum; if (signum <= 0 || signum >= NSIG || signum == SIGKILL || signum == SIGSTOP) return (EINVAL); sv = &vec; if (uap->osv) { *(sig_t *)&sv->sv_handler = ps->ps_sigact[signum]; sv->sv_mask = ps->ps_catchmask[signum]; bit = sigmask(signum); sv->sv_flags = 0; if ((ps->ps_sigonstack & bit) != 0) sv->sv_flags |= SV_ONSTACK; if ((ps->ps_sigintr & bit) != 0) sv->sv_flags |= SV_INTERRUPT;#ifndef COMPAT_SUNOS if (p->p_flag & P_NOCLDSTOP) sv->sv_flags |= SA_NOCLDSTOP;#endif if (error = copyout((caddr_t)sv, (caddr_t)uap->osv, sizeof (vec))) return (error); } if (uap->nsv) { if (error = copyin((caddr_t)uap->nsv, (caddr_t)sv, sizeof (vec))) return (error);#ifdef COMPAT_SUNOS /* * SunOS uses this bit (4, aka SA_DISABLE) as SV_RESETHAND, * `reset to SIG_DFL on delivery'. We have no such option * now or ever! */ if (sv->sv_flags & SA_DISABLE) return (EINVAL); sv->sv_flags |= SA_USERTRAMP;#endif sv->sv_flags ^= SA_RESTART; /* opposite of SV_INTERRUPT */ setsigvec(p, signum, (struct sigaction *)sv); } return (0);}struct osigblock_args { int mask;};osigblock(p, uap, retval) register struct proc *p; struct osigblock_args *uap; int *retval;{ (void) splhigh(); *retval = p->p_sigmask; p->p_sigmask |= uap->mask &~ sigcantmask; (void) spl0(); return (0);}struct osigsetmask_args { int mask;};osigsetmask(p, uap, retval) struct proc *p; struct osigsetmask_args *uap; int *retval;{ (void) splhigh(); *retval = p->p_sigmask; p->p_sigmask = uap->mask &~ sigcantmask; (void) spl0(); return (0);}#endif /* COMPAT_43 || COMPAT_SUNOS *//* * Suspend process until signal, providing mask to be set * in the meantime. Note nonstandard calling convention: * libc stub passes mask, not pointer, to save a copyin. */struct sigsuspend_args { sigset_t mask;};/* ARGSUSED */sigsuspend(p, uap, retval) register struct proc *p; struct sigsuspend_args *uap; int *retval;{ register struct sigacts *ps = p->p_sigacts; /* * When returning from sigpause, we want * the old mask to be restored after the * signal handler has finished. Thus, we * save it here and mark the sigacts structure * to indicate this. */ ps->ps_oldmask = p->p_sigmask; ps->ps_flags |= SAS_OLDMASK; p->p_sigmask = uap->mask &~ sigcantmask; while (tsleep((caddr_t) ps, PPAUSE|PCATCH, "pause", 0) == 0) /* void */; /* always return EINTR rather than ERESTART... */ return (EINTR);}#if defined(COMPAT_43) || defined(COMPAT_SUNOS)struct osigstack_args { struct sigstack *nss; struct sigstack *oss;};/* ARGSUSED */osigstack(p, uap, retval) struct proc *p; register struct osigstack_args *uap; int *retval;{ struct sigstack ss; struct sigacts *psp; int error = 0; psp = p->p_sigacts; ss.ss_sp = psp->ps_sigstk.ss_base; ss.ss_onstack = psp->ps_sigstk.ss_flags & SA_ONSTACK; if (uap->oss && (error = copyout((caddr_t)&ss, (caddr_t)uap->oss, sizeof (struct sigstack)))) return (error); if (uap->nss && (error = copyin((caddr_t)uap->nss, (caddr_t)&ss, sizeof (ss))) == 0) { psp->ps_sigstk.ss_base = ss.ss_sp; psp->ps_sigstk.ss_size = 0; psp->ps_sigstk.ss_flags |= ss.ss_onstack & SA_ONSTACK; psp->ps_flags |= SAS_ALTSTACK; } return (error);}#endif /* COMPAT_43 || COMPAT_SUNOS */struct sigaltstack_args { struct sigaltstack *nss; struct sigaltstack *oss;};/* ARGSUSED */sigaltstack(p, uap, retval) struct proc *p; register struct sigaltstack_args *uap; int *retval;{ struct sigacts *psp; struct sigaltstack ss; int error; psp = p->p_sigacts; if ((psp->ps_flags & SAS_ALTSTACK) == 0) psp->ps_sigstk.ss_flags |= SA_DISABLE; if (uap->oss && (error = copyout((caddr_t)&psp->ps_sigstk, (caddr_t)uap->oss, sizeof (struct sigaltstack)))) return (error); if (uap->nss == 0) return (0); if (error = copyin((caddr_t)uap->nss, (caddr_t)&ss, sizeof (ss))) return (error); if (ss.ss_flags & SA_DISABLE) { if (psp->ps_sigstk.ss_flags & SA_ONSTACK) return (EINVAL); psp->ps_flags &= ~SAS_ALTSTACK; psp->ps_sigstk.ss_flags = ss.ss_flags; return (0); } if (ss.ss_size < MINSIGSTKSZ) return (ENOMEM); psp->ps_flags |= SAS_ALTSTACK; psp->ps_sigstk= ss; return (0);}struct kill_args { int pid; int signum;};/* ARGSUSED */kill(cp, uap, retval) register struct proc *cp; register struct kill_args *uap; int *retval;{ register struct proc *p; register struct pcred *pc = cp->p_cred; if ((u_int)uap->signum >= NSIG) return (EINVAL); if (uap->pid > 0) { /* kill single process */ if ((p = pfind(uap->pid)) == NULL) return (ESRCH); if (!CANSIGNAL(cp, pc, p, uap->signum)) return (EPERM); if (uap->signum) psignal(p, uap->signum); return (0); } switch (uap->pid) { case -1: /* broadcast signal */ return (killpg1(cp, uap->signum, 0, 1)); case 0: /* signal own process group */ return (killpg1(cp, uap->signum, 0, 0)); default: /* negative explicit process group */ return (killpg1(cp, uap->signum, -uap->pid, 0)); } /* NOTREACHED */}#if defined(COMPAT_43) || defined(COMPAT_SUNOS)struct okillpg_args { int pgid; int signum;};/* ARGSUSED */okillpg(p, uap, retval) struct proc *p; register struct okillpg_args *uap; int *retval;{ if ((u_int)uap->signum >= NSIG) return (EINVAL); return (killpg1(p, uap->signum, uap->pgid, 0));}#endif /* COMPAT_43 || COMPAT_SUNOS *//* * Common code for kill process group/broadcast kill. * cp is calling process. */killpg1(cp, signum, pgid, all) register struct proc *cp; int signum, pgid, all;{ register struct proc *p; register struct pcred *pc = cp->p_cred; struct pgrp *pgrp; int nfound = 0; if (all) /* * broadcast */ for (p = (struct proc *)allproc; p != NULL; p = p->p_next) { if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || p == cp || !CANSIGNAL(cp, pc, p, signum)) continue; nfound++; if (signum) psignal(p, signum); } else { if (pgid == 0) /* * zero pgid means send to my process group. */ pgrp = cp->p_pgrp; else { pgrp = pgfind(pgid); if (pgrp == NULL) return (ESRCH); } for (p = pgrp->pg_mem; p != NULL; p = p->p_pgrpnxt) { if (p->p_pid <= 1 || p->p_flag & P_SYSTEM || p->p_stat == SZOMB || !CANSIGNAL(cp, pc, p, signum)) continue; nfound++; if (signum) psignal(p, signum); } } return (nfound ? 0 : ESRCH);}/* * Send a signal to a process group. */voidgsignal(pgid, signum) int pgid, signum;{ struct pgrp *pgrp; if (pgid && (pgrp = pgfind(pgid))) pgsignal(pgrp, signum, 0);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -