2003-06-30 02:28:00 +04:00
|
|
|
/* $NetBSD: kern_sig.c,v 1.143 2003/06/29 22:31:22 fvdl Exp $ */
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*
|
1998-03-01 05:20:01 +03:00
|
|
|
* @(#)kern_sig.c 8.14 (Berkeley) 5/14/95
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
|
|
|
|
2001-11-12 18:25:01 +03:00
|
|
|
#include <sys/cdefs.h>
|
2003-06-30 02:28:00 +04:00
|
|
|
__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.143 2003/06/29 22:31:22 fvdl Exp $");
|
2001-11-12 18:25:01 +03:00
|
|
|
|
1998-06-26 01:17:15 +04:00
|
|
|
#include "opt_ktrace.h"
|
1998-06-26 03:40:33 +04:00
|
|
|
#include "opt_compat_sunos.h"
|
1999-12-30 19:00:23 +03:00
|
|
|
#include "opt_compat_netbsd32.h"
|
1998-02-10 17:08:44 +03:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
#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 <sys/core.h>
|
1996-10-24 03:13:19 +04:00
|
|
|
#include <sys/filedesc.h>
|
1999-05-01 01:23:49 +04:00
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/pool.h>
|
2003-01-18 13:06:22 +03:00
|
|
|
#include <sys/ucontext.h>
|
|
|
|
#include <sys/sa.h>
|
|
|
|
#include <sys/savar.h>
|
2001-12-08 03:35:25 +03:00
|
|
|
#include <sys/exec.h>
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1994-10-20 07:22:35 +03:00
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <sys/syscallargs.h>
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
#include <machine/cpu.h>
|
|
|
|
|
|
|
|
#include <sys/user.h> /* for coredump */
|
|
|
|
|
1998-02-05 10:59:28 +03:00
|
|
|
#include <uvm/uvm_extern.h>
|
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
static void proc_stop(struct proc *p);
|
|
|
|
static int build_corename(struct proc *, char [MAXPATHLEN]);
|
|
|
|
sigset_t contsigmask, stopsigmask, sigcantmask;
|
1998-10-03 18:29:02 +04:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
struct pool sigacts_pool; /* memory pool for sigacts structures */
|
2003-01-18 13:06:22 +03:00
|
|
|
struct pool siginfo_pool; /* memory pool for siginfo structures */
|
1999-05-01 01:23:49 +04:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Can process p, with pcred pc, send the signal signum to process q?
|
|
|
|
*/
|
2001-02-27 00:58:30 +03:00
|
|
|
#define CANSIGNAL(p, pc, q, signum) \
|
1994-06-29 10:29:24 +04:00
|
|
|
((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))
|
|
|
|
|
1999-05-01 01:23:49 +04:00
|
|
|
/*
|
|
|
|
* Initialize signal-related data structures.
|
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
signal_init(void)
|
1999-05-01 01:23:49 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
|
1999-05-01 01:23:49 +04:00
|
|
|
pool_init(&sigacts_pool, sizeof(struct sigacts), 0, 0, 0, "sigapl",
|
2002-03-08 23:48:27 +03:00
|
|
|
&pool_allocator_nointr);
|
2003-01-18 13:06:22 +03:00
|
|
|
pool_init(&siginfo_pool, sizeof(siginfo_t), 0, 0, 0, "siginfo",
|
|
|
|
&pool_allocator_nointr);
|
1999-05-01 01:23:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-12-23 01:58:52 +03:00
|
|
|
* Create an initial sigctx structure, using the same signal state
|
|
|
|
* as p. If 'share' is set, share the sigctx_proc part, otherwise just
|
|
|
|
* copy it from parent.
|
1999-05-01 01:23:49 +04:00
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
sigactsinit(struct proc *np, struct proc *pp, int share)
|
1999-05-01 01:23:49 +04:00
|
|
|
{
|
2000-12-23 01:58:52 +03:00
|
|
|
struct sigacts *ps;
|
1999-05-01 01:23:49 +04:00
|
|
|
|
2000-12-23 01:58:52 +03:00
|
|
|
if (share) {
|
|
|
|
np->p_sigacts = pp->p_sigacts;
|
|
|
|
pp->p_sigacts->sa_refcnt++;
|
|
|
|
} else {
|
|
|
|
ps = pool_get(&sigacts_pool, PR_WAITOK);
|
|
|
|
if (pp)
|
|
|
|
memcpy(ps, pp->p_sigacts, sizeof(struct sigacts));
|
|
|
|
else
|
|
|
|
memset(ps, '\0', sizeof(struct sigacts));
|
|
|
|
ps->sa_refcnt = 1;
|
|
|
|
np->p_sigacts = ps;
|
|
|
|
}
|
1999-05-01 01:23:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-12-23 01:58:52 +03:00
|
|
|
* Make this process not share its sigctx, maintaining all
|
1999-05-01 01:23:49 +04:00
|
|
|
* signal state.
|
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
sigactsunshare(struct proc *p)
|
1999-05-01 01:23:49 +04:00
|
|
|
{
|
2000-12-23 01:58:52 +03:00
|
|
|
struct sigacts *oldps;
|
1999-05-01 01:23:49 +04:00
|
|
|
|
2000-12-23 01:58:52 +03:00
|
|
|
if (p->p_sigacts->sa_refcnt == 1)
|
1999-05-01 01:23:49 +04:00
|
|
|
return;
|
|
|
|
|
2000-12-23 01:58:52 +03:00
|
|
|
oldps = p->p_sigacts;
|
|
|
|
sigactsinit(p, NULL, 0);
|
|
|
|
|
|
|
|
if (--oldps->sa_refcnt == 0)
|
|
|
|
pool_put(&sigacts_pool, oldps);
|
1999-05-01 01:23:49 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-12-23 01:58:52 +03:00
|
|
|
* Release a sigctx structure.
|
1999-05-01 01:23:49 +04:00
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
sigactsfree(struct proc *p)
|
1999-05-01 01:23:49 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
struct sigacts *ps;
|
1999-05-01 01:23:49 +04:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
ps = p->p_sigacts;
|
2000-12-23 01:58:52 +03:00
|
|
|
if (--ps->sa_refcnt > 0)
|
1999-05-01 01:23:49 +04:00
|
|
|
return;
|
|
|
|
|
|
|
|
pool_put(&sigacts_pool, ps);
|
|
|
|
}
|
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
int
|
2001-02-27 00:58:30 +03:00
|
|
|
sigaction1(struct proc *p, int signum, const struct sigaction *nsa,
|
2002-07-05 03:32:02 +04:00
|
|
|
struct sigaction *osa, void *tramp, int vers)
|
1998-09-11 16:50:05 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
struct sigacts *ps;
|
|
|
|
int prop;
|
1998-09-11 16:50:05 +04:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
ps = p->p_sigacts;
|
1998-09-11 16:50:05 +04:00
|
|
|
if (signum <= 0 || signum >= NSIG)
|
|
|
|
return (EINVAL);
|
|
|
|
|
2002-07-05 03:32:02 +04:00
|
|
|
/*
|
|
|
|
* Trampoline ABI version 0 is reserved for the legacy
|
|
|
|
* kernel-provided on-stack trampoline. Conversely, if
|
|
|
|
* we are using a non-0 ABI version, we must have a
|
|
|
|
* trampoline.
|
|
|
|
*/
|
|
|
|
if ((vers != 0 && tramp == NULL) ||
|
|
|
|
(vers == 0 && tramp != NULL))
|
|
|
|
return (EINVAL);
|
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
if (osa)
|
2000-12-23 01:58:52 +03:00
|
|
|
*osa = SIGACTION_PS(ps, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
|
|
|
|
if (nsa) {
|
|
|
|
if (nsa->sa_flags & ~SA_ALLBITS)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
prop = sigprop[signum];
|
|
|
|
if (prop & SA_CANTMASK)
|
|
|
|
return (EINVAL);
|
|
|
|
|
2000-08-21 06:09:33 +04:00
|
|
|
(void) splsched(); /* XXXSMP */
|
2000-12-23 01:58:52 +03:00
|
|
|
SIGACTION_PS(ps, signum) = *nsa;
|
2002-07-05 03:32:02 +04:00
|
|
|
ps->sa_sigdesc[signum].sd_tramp = tramp;
|
|
|
|
ps->sa_sigdesc[signum].sd_vers = vers;
|
2000-12-23 01:58:52 +03:00
|
|
|
sigminusset(&sigcantmask, &SIGACTION_PS(ps, signum).sa_mask);
|
1998-09-11 16:50:05 +04:00
|
|
|
if ((prop & SA_NORESET) != 0)
|
2000-12-23 01:58:52 +03:00
|
|
|
SIGACTION_PS(ps, signum).sa_flags &= ~SA_RESETHAND;
|
1998-09-11 16:50:05 +04:00
|
|
|
if (signum == SIGCHLD) {
|
|
|
|
if (nsa->sa_flags & SA_NOCLDSTOP)
|
|
|
|
p->p_flag |= P_NOCLDSTOP;
|
|
|
|
else
|
|
|
|
p->p_flag &= ~P_NOCLDSTOP;
|
1998-09-19 06:00:52 +04:00
|
|
|
if (nsa->sa_flags & SA_NOCLDWAIT) {
|
1998-09-18 22:48:22 +04:00
|
|
|
/*
|
|
|
|
* Paranoia: since SA_NOCLDWAIT is implemented
|
|
|
|
* by reparenting the dying child to PID 1 (and
|
2001-02-27 00:58:30 +03:00
|
|
|
* trust it to reap the zombie), PID 1 itself
|
|
|
|
* is forbidden to set SA_NOCLDWAIT.
|
1998-09-18 22:48:22 +04:00
|
|
|
*/
|
|
|
|
if (p->p_pid == 1)
|
|
|
|
p->p_flag &= ~P_NOCLDWAIT;
|
|
|
|
else
|
|
|
|
p->p_flag |= P_NOCLDWAIT;
|
|
|
|
} else
|
|
|
|
p->p_flag &= ~P_NOCLDWAIT;
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
|
|
|
if ((nsa->sa_flags & SA_NODEFER) == 0)
|
2000-12-23 01:58:52 +03:00
|
|
|
sigaddset(&SIGACTION_PS(ps, signum).sa_mask, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
else
|
2000-12-23 01:58:52 +03:00
|
|
|
sigdelset(&SIGACTION_PS(ps, signum).sa_mask, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
/*
|
2001-02-27 00:58:30 +03:00
|
|
|
* Set bit in p_sigctx.ps_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_sigctx.ps_sigignore, as we have to restart the process.
|
|
|
|
*/
|
1998-09-11 16:50:05 +04:00
|
|
|
if (nsa->sa_handler == SIG_IGN ||
|
|
|
|
(nsa->sa_handler == SIG_DFL && (prop & SA_IGNORE) != 0)) {
|
2001-02-27 00:58:30 +03:00
|
|
|
/* never to be seen again */
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
|
|
|
if (signum != SIGCONT) {
|
|
|
|
/* easier in psignal */
|
|
|
|
sigaddset(&p->p_sigctx.ps_sigignore, signum);
|
|
|
|
}
|
2000-12-23 01:58:52 +03:00
|
|
|
sigdelset(&p->p_sigctx.ps_sigcatch, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
} else {
|
2000-12-23 01:58:52 +03:00
|
|
|
sigdelset(&p->p_sigctx.ps_sigignore, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
if (nsa->sa_handler == SIG_DFL)
|
2000-12-23 01:58:52 +03:00
|
|
|
sigdelset(&p->p_sigctx.ps_sigcatch, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
else
|
2000-12-23 01:58:52 +03:00
|
|
|
sigaddset(&p->p_sigctx.ps_sigcatch, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
|
|
|
(void) spl0();
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/* ARGSUSED */
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys___sigaction14(struct lwp *l, void *v, register_t *retval)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct sys___sigaction14_args /* {
|
2001-02-27 00:58:30 +03:00
|
|
|
syscallarg(int) signum;
|
|
|
|
syscallarg(const struct sigaction *) nsa;
|
|
|
|
syscallarg(struct sigaction *) osa;
|
1995-09-20 01:40:36 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
2001-02-27 00:58:30 +03:00
|
|
|
struct sigaction nsa, osa;
|
|
|
|
int error;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
if (SCARG(uap, nsa)) {
|
|
|
|
error = copyin(SCARG(uap, nsa), &nsa, sizeof(nsa));
|
1996-02-04 05:15:01 +03:00
|
|
|
if (error)
|
1994-06-29 10:29:24 +04:00
|
|
|
return (error);
|
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
1998-09-11 16:50:05 +04:00
|
|
|
error = sigaction1(p, SCARG(uap, signum),
|
2002-07-05 03:32:02 +04:00
|
|
|
SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0,
|
|
|
|
NULL, 0);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
if (SCARG(uap, osa)) {
|
|
|
|
error = copyout(&osa, SCARG(uap, osa), sizeof(osa));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys___sigaction_sigtramp(struct lwp *l, void *v, register_t *retval)
|
2002-07-05 03:32:02 +04:00
|
|
|
{
|
|
|
|
struct sys___sigaction_sigtramp_args /* {
|
|
|
|
syscallarg(int) signum;
|
|
|
|
syscallarg(const struct sigaction *) nsa;
|
|
|
|
syscallarg(struct sigaction *) osa;
|
|
|
|
syscallarg(void *) tramp;
|
|
|
|
syscallarg(int) vers;
|
|
|
|
} */ *uap = v;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2002-07-05 03:32:02 +04:00
|
|
|
struct sigaction nsa, osa;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (SCARG(uap, nsa)) {
|
|
|
|
error = copyin(SCARG(uap, nsa), &nsa, sizeof(nsa));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
error = sigaction1(p, SCARG(uap, signum),
|
|
|
|
SCARG(uap, nsa) ? &nsa : 0, SCARG(uap, osa) ? &osa : 0,
|
|
|
|
SCARG(uap, tramp), SCARG(uap, vers));
|
1998-09-11 16:50:05 +04:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
if (SCARG(uap, osa)) {
|
|
|
|
error = copyout(&osa, SCARG(uap, osa), sizeof(osa));
|
1996-02-04 05:15:01 +03:00
|
|
|
if (error)
|
1994-06-29 10:29:24 +04:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize signal state for process 0;
|
1998-09-11 16:50:05 +04:00
|
|
|
* set to ignore signals that are ignored by default and disable the signal
|
|
|
|
* stack.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
siginit(struct proc *p)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
struct sigacts *ps;
|
|
|
|
int signum, prop;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
ps = p->p_sigacts;
|
1998-09-11 16:50:05 +04:00
|
|
|
sigemptyset(&contsigmask);
|
|
|
|
sigemptyset(&stopsigmask);
|
|
|
|
sigemptyset(&sigcantmask);
|
1998-11-13 20:23:52 +03:00
|
|
|
for (signum = 1; signum < NSIG; signum++) {
|
1998-09-11 16:50:05 +04:00
|
|
|
prop = sigprop[signum];
|
|
|
|
if (prop & SA_CONT)
|
|
|
|
sigaddset(&contsigmask, signum);
|
|
|
|
if (prop & SA_STOP)
|
|
|
|
sigaddset(&stopsigmask, signum);
|
|
|
|
if (prop & SA_CANTMASK)
|
|
|
|
sigaddset(&sigcantmask, signum);
|
|
|
|
if (prop & SA_IGNORE && signum != SIGCONT)
|
2000-12-23 01:58:52 +03:00
|
|
|
sigaddset(&p->p_sigctx.ps_sigignore, signum);
|
|
|
|
sigemptyset(&SIGACTION_PS(ps, signum).sa_mask);
|
|
|
|
SIGACTION_PS(ps, signum).sa_flags = SA_RESTART;
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
2000-12-23 01:58:52 +03:00
|
|
|
sigemptyset(&p->p_sigctx.ps_sigcatch);
|
2003-02-15 23:54:38 +03:00
|
|
|
p->p_sigctx.ps_sigwaited = 0;
|
1998-09-11 16:50:05 +04:00
|
|
|
p->p_flag &= ~P_NOCLDSTOP;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset stack state to the user stack.
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sigstk.ss_flags = SS_DISABLE;
|
|
|
|
p->p_sigctx.ps_sigstk.ss_size = 0;
|
|
|
|
p->p_sigctx.ps_sigstk.ss_sp = 0;
|
1999-05-01 01:23:49 +04:00
|
|
|
|
|
|
|
/* One reference. */
|
2000-12-23 01:58:52 +03:00
|
|
|
ps->sa_refcnt = 1;
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Reset signals for an exec of the specified process.
|
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
execsigs(struct proc *p)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
struct sigacts *ps;
|
|
|
|
int signum, prop;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2001-07-18 09:34:58 +04:00
|
|
|
sigactsunshare(p);
|
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
ps = p->p_sigacts;
|
2001-07-18 09:34:58 +04:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Reset caught signals. Held signals remain held
|
2000-12-23 01:58:52 +03:00
|
|
|
* through p_sigctx.ps_sigmask (unless they were caught,
|
1994-06-29 10:29:24 +04:00
|
|
|
* and are now ignored by default).
|
|
|
|
*/
|
1998-11-13 20:23:52 +03:00
|
|
|
for (signum = 1; signum < NSIG; signum++) {
|
2000-12-23 01:58:52 +03:00
|
|
|
if (sigismember(&p->p_sigctx.ps_sigcatch, signum)) {
|
1998-09-11 16:50:05 +04:00
|
|
|
prop = sigprop[signum];
|
|
|
|
if (prop & SA_IGNORE) {
|
|
|
|
if ((prop & SA_CONT) == 0)
|
2001-02-27 00:58:30 +03:00
|
|
|
sigaddset(&p->p_sigctx.ps_sigignore,
|
|
|
|
signum);
|
2000-12-23 01:58:52 +03:00
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
2000-12-23 01:58:52 +03:00
|
|
|
SIGACTION_PS(ps, signum).sa_handler = SIG_DFL;
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
2000-12-23 01:58:52 +03:00
|
|
|
sigemptyset(&SIGACTION_PS(ps, signum).sa_mask);
|
|
|
|
SIGACTION_PS(ps, signum).sa_flags = SA_RESTART;
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
2000-12-23 01:58:52 +03:00
|
|
|
sigemptyset(&p->p_sigctx.ps_sigcatch);
|
2003-02-15 23:54:38 +03:00
|
|
|
p->p_sigctx.ps_sigwaited = 0;
|
1998-09-11 16:50:05 +04:00
|
|
|
p->p_flag &= ~P_NOCLDSTOP;
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Reset stack state to the user stack.
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sigstk.ss_flags = SS_DISABLE;
|
|
|
|
p->p_sigctx.ps_sigstk.ss_size = 0;
|
|
|
|
p->p_sigctx.ps_sigstk.ss_sp = 0;
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
int
|
2001-02-27 00:58:30 +03:00
|
|
|
sigprocmask1(struct proc *p, int how, const sigset_t *nss, sigset_t *oss)
|
1998-09-11 16:50:05 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
if (oss)
|
2000-12-23 01:58:52 +03:00
|
|
|
*oss = p->p_sigctx.ps_sigmask;
|
1998-09-11 16:50:05 +04:00
|
|
|
|
|
|
|
if (nss) {
|
2000-08-21 06:09:33 +04:00
|
|
|
(void)splsched(); /* XXXSMP */
|
1998-09-11 16:50:05 +04:00
|
|
|
switch (how) {
|
|
|
|
case SIG_BLOCK:
|
2000-12-23 01:58:52 +03:00
|
|
|
sigplusset(nss, &p->p_sigctx.ps_sigmask);
|
1998-09-11 16:50:05 +04:00
|
|
|
break;
|
|
|
|
case SIG_UNBLOCK:
|
2000-12-23 01:58:52 +03:00
|
|
|
sigminusset(nss, &p->p_sigctx.ps_sigmask);
|
2001-01-15 01:31:58 +03:00
|
|
|
CHECKSIGS(p);
|
1998-09-11 16:50:05 +04:00
|
|
|
break;
|
|
|
|
case SIG_SETMASK:
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sigmask = *nss;
|
2001-01-15 01:31:58 +03:00
|
|
|
CHECKSIGS(p);
|
1998-09-11 16:50:05 +04:00
|
|
|
break;
|
|
|
|
default:
|
2000-08-21 01:50:06 +04:00
|
|
|
(void)spl0(); /* XXXSMP */
|
1998-09-11 16:50:05 +04:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
2000-12-23 01:58:52 +03:00
|
|
|
sigminusset(&sigcantmask, &p->p_sigctx.ps_sigmask);
|
2000-08-21 01:50:06 +04:00
|
|
|
(void)spl0(); /* XXXSMP */
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Manipulate signal mask.
|
|
|
|
* Note that we receive new mask, not pointer,
|
|
|
|
* and return old mask as return value;
|
|
|
|
* the library stub does the rest.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys___sigprocmask14(struct lwp *l, void *v, register_t *retval)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
1998-09-11 16:50:05 +04:00
|
|
|
struct sys___sigprocmask14_args /* {
|
2001-02-27 00:58:30 +03:00
|
|
|
syscallarg(int) how;
|
|
|
|
syscallarg(const sigset_t *) set;
|
|
|
|
syscallarg(sigset_t *) oset;
|
1995-09-20 01:40:36 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
2001-02-27 00:58:30 +03:00
|
|
|
sigset_t nss, oss;
|
|
|
|
int error;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
if (SCARG(uap, set)) {
|
|
|
|
error = copyin(SCARG(uap, set), &nss, sizeof(nss));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
1998-09-11 16:50:05 +04:00
|
|
|
error = sigprocmask1(p, SCARG(uap, how),
|
|
|
|
SCARG(uap, set) ? &nss : 0, SCARG(uap, oset) ? &oss : 0);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
if (SCARG(uap, oset)) {
|
|
|
|
error = copyout(&oss, SCARG(uap, oset), sizeof(oss));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
sigpending1(struct proc *p, sigset_t *ss)
|
1998-09-11 16:50:05 +04:00
|
|
|
{
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2000-12-23 01:58:52 +03:00
|
|
|
*ss = p->p_sigctx.ps_siglist;
|
|
|
|
sigminusset(&p->p_sigctx.ps_sigmask, ss);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys___sigpending14(struct lwp *l, void *v, register_t *retval)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct sys___sigpending14_args /* {
|
2001-02-27 00:58:30 +03:00
|
|
|
syscallarg(sigset_t *) set;
|
1998-09-11 16:50:05 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
|
|
|
sigset_t ss;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
1998-09-11 16:50:05 +04:00
|
|
|
sigpending1(p, &ss);
|
|
|
|
return (copyout(&ss, SCARG(uap, set), sizeof(ss)));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2001-02-27 00:58:30 +03:00
|
|
|
sigsuspend1(struct proc *p, const sigset_t *ss)
|
1998-09-11 16:50:05 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
struct sigacts *ps;
|
1998-09-11 16:50:05 +04:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
ps = p->p_sigacts;
|
1998-09-11 16:50:05 +04:00
|
|
|
if (ss) {
|
|
|
|
/*
|
|
|
|
* When returning from sigpause, we want
|
|
|
|
* the old mask to be restored after the
|
|
|
|
* signal handler has finished. Thus, we
|
2000-12-23 01:58:52 +03:00
|
|
|
* save it here and mark the sigctx structure
|
1998-09-11 16:50:05 +04:00
|
|
|
* to indicate this.
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_oldmask = p->p_sigctx.ps_sigmask;
|
|
|
|
p->p_sigctx.ps_flags |= SAS_OLDMASK;
|
2000-08-21 06:09:33 +04:00
|
|
|
(void) splsched(); /* XXXSMP */
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sigmask = *ss;
|
2001-01-15 01:31:58 +03:00
|
|
|
CHECKSIGS(p);
|
2000-12-23 01:58:52 +03:00
|
|
|
sigminusset(&sigcantmask, &p->p_sigctx.ps_sigmask);
|
2000-08-21 01:50:06 +04:00
|
|
|
(void) spl0(); /* XXXSMP */
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
while (tsleep((caddr_t) ps, PPAUSE|PCATCH, "pause", 0) == 0)
|
|
|
|
/* void */;
|
|
|
|
/* always return EINTR rather than ERESTART... */
|
|
|
|
return (EINTR);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys___sigsuspend14(struct lwp *l, void *v, register_t *retval)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
1998-09-11 16:50:05 +04:00
|
|
|
struct sys___sigsuspend14_args /* {
|
2001-02-27 00:58:30 +03:00
|
|
|
syscallarg(const sigset_t *) set;
|
1995-09-20 01:40:36 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
2001-02-27 00:58:30 +03:00
|
|
|
sigset_t ss;
|
|
|
|
int error;
|
1998-09-11 16:50:05 +04:00
|
|
|
|
|
|
|
if (SCARG(uap, set)) {
|
|
|
|
error = copyin(SCARG(uap, set), &ss, sizeof(ss));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
1998-09-11 16:50:05 +04:00
|
|
|
return (sigsuspend1(p, SCARG(uap, set) ? &ss : 0));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2001-02-27 00:58:30 +03:00
|
|
|
sigaltstack1(struct proc *p, const struct sigaltstack *nss,
|
|
|
|
struct sigaltstack *oss)
|
1998-09-11 16:50:05 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
if (oss)
|
2000-12-23 01:58:52 +03:00
|
|
|
*oss = p->p_sigctx.ps_sigstk;
|
1998-09-11 16:50:05 +04:00
|
|
|
|
|
|
|
if (nss) {
|
|
|
|
if (nss->ss_flags & ~SS_ALLBITS)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
if (nss->ss_flags & SS_DISABLE) {
|
2000-12-23 01:58:52 +03:00
|
|
|
if (p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK)
|
1998-09-11 16:50:05 +04:00
|
|
|
return (EINVAL);
|
|
|
|
} else {
|
|
|
|
if (nss->ss_size < MINSIGSTKSZ)
|
|
|
|
return (ENOMEM);
|
|
|
|
}
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sigstk = *nss;
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys___sigaltstack14(struct lwp *l, void *v, register_t *retval)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct sys___sigaltstack14_args /* {
|
2001-02-27 00:58:30 +03:00
|
|
|
syscallarg(const struct sigaltstack *) nss;
|
|
|
|
syscallarg(struct sigaltstack *) oss;
|
1995-09-20 01:40:36 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
2001-02-27 00:58:30 +03:00
|
|
|
struct sigaltstack nss, oss;
|
|
|
|
int error;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
if (SCARG(uap, nss)) {
|
|
|
|
error = copyin(SCARG(uap, nss), &nss, sizeof(nss));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
1998-09-11 16:50:05 +04:00
|
|
|
error = sigaltstack1(p,
|
|
|
|
SCARG(uap, nss) ? &nss : 0, SCARG(uap, oss) ? &oss : 0);
|
1996-02-04 05:15:01 +03:00
|
|
|
if (error)
|
1994-06-29 10:29:24 +04:00
|
|
|
return (error);
|
1998-09-11 16:50:05 +04:00
|
|
|
if (SCARG(uap, oss)) {
|
|
|
|
error = copyout(&oss, SCARG(uap, oss), sizeof(oss));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys_kill(struct lwp *l, void *v, register_t *retval)
|
1995-09-20 01:40:36 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct sys_kill_args /* {
|
2001-02-27 00:58:30 +03:00
|
|
|
syscallarg(int) pid;
|
|
|
|
syscallarg(int) signum;
|
1995-09-20 01:40:36 +04:00
|
|
|
} */ *uap = v;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *cp, *p;
|
2001-02-27 00:58:30 +03:00
|
|
|
struct pcred *pc;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
cp = l->l_proc;
|
2001-02-27 00:58:30 +03:00
|
|
|
pc = cp->p_cred;
|
1994-10-20 07:22:35 +03:00
|
|
|
if ((u_int)SCARG(uap, signum) >= NSIG)
|
1994-06-29 10:29:24 +04:00
|
|
|
return (EINVAL);
|
1994-10-20 07:22:35 +03:00
|
|
|
if (SCARG(uap, pid) > 0) {
|
1994-06-29 10:29:24 +04:00
|
|
|
/* kill single process */
|
1994-10-20 07:22:35 +03:00
|
|
|
if ((p = pfind(SCARG(uap, pid))) == NULL)
|
1994-06-29 10:29:24 +04:00
|
|
|
return (ESRCH);
|
1994-10-20 07:22:35 +03:00
|
|
|
if (!CANSIGNAL(cp, pc, p, SCARG(uap, signum)))
|
1994-06-29 10:29:24 +04:00
|
|
|
return (EPERM);
|
1994-10-20 07:22:35 +03:00
|
|
|
if (SCARG(uap, signum))
|
|
|
|
psignal(p, SCARG(uap, signum));
|
1994-06-29 10:29:24 +04:00
|
|
|
return (0);
|
|
|
|
}
|
1994-10-20 07:22:35 +03:00
|
|
|
switch (SCARG(uap, pid)) {
|
1994-06-29 10:29:24 +04:00
|
|
|
case -1: /* broadcast signal */
|
1994-10-20 07:22:35 +03:00
|
|
|
return (killpg1(cp, SCARG(uap, signum), 0, 1));
|
1994-06-29 10:29:24 +04:00
|
|
|
case 0: /* signal own process group */
|
1994-10-20 07:22:35 +03:00
|
|
|
return (killpg1(cp, SCARG(uap, signum), 0, 0));
|
1994-06-29 10:29:24 +04:00
|
|
|
default: /* negative explicit process group */
|
1994-10-20 07:22:35 +03:00
|
|
|
return (killpg1(cp, SCARG(uap, signum), -SCARG(uap, pid), 0));
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common code for kill process group/broadcast kill.
|
|
|
|
* cp is calling process.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
int
|
2001-02-27 00:58:30 +03:00
|
|
|
killpg1(struct proc *cp, int signum, int pgid, int all)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
struct proc *p;
|
|
|
|
struct pcred *pc;
|
|
|
|
struct pgrp *pgrp;
|
|
|
|
int nfound;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
pc = cp->p_cred;
|
|
|
|
nfound = 0;
|
1999-07-23 01:08:30 +04:00
|
|
|
if (all) {
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* broadcast
|
|
|
|
*/
|
1999-07-25 10:30:33 +04:00
|
|
|
proclist_lock_read();
|
2002-09-04 05:32:31 +04:00
|
|
|
LIST_FOREACH(p, &allproc, p_list) {
|
1994-06-29 10:29:24 +04:00
|
|
|
if (p->p_pid <= 1 || p->p_flag & P_SYSTEM ||
|
|
|
|
p == cp || !CANSIGNAL(cp, pc, p, signum))
|
|
|
|
continue;
|
|
|
|
nfound++;
|
|
|
|
if (signum)
|
|
|
|
psignal(p, signum);
|
|
|
|
}
|
1999-07-23 01:08:30 +04:00
|
|
|
proclist_unlock_read();
|
|
|
|
} else {
|
1994-06-29 10:29:24 +04:00
|
|
|
if (pgid == 0)
|
|
|
|
/*
|
|
|
|
* zero pgid means send to my process group.
|
|
|
|
*/
|
|
|
|
pgrp = cp->p_pgrp;
|
|
|
|
else {
|
|
|
|
pgrp = pgfind(pgid);
|
|
|
|
if (pgrp == NULL)
|
|
|
|
return (ESRCH);
|
|
|
|
}
|
2002-09-04 05:32:31 +04:00
|
|
|
LIST_FOREACH(p, &pgrp->pg_members, p_pglist) {
|
1994-06-29 10:29:24 +04:00
|
|
|
if (p->p_pid <= 1 || p->p_flag & P_SYSTEM ||
|
|
|
|
!CANSIGNAL(cp, pc, p, signum))
|
|
|
|
continue;
|
|
|
|
nfound++;
|
1999-07-22 22:13:36 +04:00
|
|
|
if (signum && P_ZOMBIE(p) == 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
psignal(p, signum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (nfound ? 0 : ESRCH);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send a signal to a process group.
|
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
gsignal(int pgid, int signum)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
|
|
|
struct pgrp *pgrp;
|
|
|
|
|
|
|
|
if (pgid && (pgrp = pgfind(pgid)))
|
|
|
|
pgsignal(pgrp, signum, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1998-03-01 05:20:01 +03:00
|
|
|
* Send a signal to a process group. If checktty is 1,
|
1994-06-29 10:29:24 +04:00
|
|
|
* limit to members which have a controlling terminal.
|
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
pgsignal(struct pgrp *pgrp, int signum, int checkctty)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2000-03-30 13:27:11 +04:00
|
|
|
struct proc *p;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
if (pgrp)
|
2002-09-04 05:32:31 +04:00
|
|
|
LIST_FOREACH(p, &pgrp->pg_members, p_pglist)
|
1994-06-29 10:29:24 +04:00
|
|
|
if (checkctty == 0 || p->p_flag & P_CONTROLT)
|
|
|
|
psignal(p, signum);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send a signal caused by a trap to the current process.
|
|
|
|
* If it will be caught immediately, deliver it with correct code.
|
|
|
|
* Otherwise, post it normally.
|
|
|
|
*/
|
|
|
|
void
|
2003-01-18 13:06:22 +03:00
|
|
|
trapsignal(struct lwp *l, int signum, u_long code)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
|
|
|
struct sigacts *ps;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
2001-02-27 00:58:30 +03:00
|
|
|
ps = p->p_sigacts;
|
1998-09-11 16:50:05 +04:00
|
|
|
if ((p->p_flag & P_TRACED) == 0 &&
|
2000-12-23 01:58:52 +03:00
|
|
|
sigismember(&p->p_sigctx.ps_sigcatch, signum) &&
|
|
|
|
!sigismember(&p->p_sigctx.ps_sigmask, signum)) {
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_stats->p_ru.ru_nsignals++;
|
|
|
|
#ifdef KTRACE
|
|
|
|
if (KTRPOINT(p, KTR_PSIG))
|
2003-06-30 02:28:00 +04:00
|
|
|
ktrpsig(p, signum,
|
2000-12-23 01:58:52 +03:00
|
|
|
SIGACTION_PS(ps, signum).sa_handler,
|
|
|
|
&p->p_sigctx.ps_sigmask, code);
|
1994-06-29 10:29:24 +04:00
|
|
|
#endif
|
2003-01-18 13:06:22 +03:00
|
|
|
psendsig(l, signum, &p->p_sigctx.ps_sigmask, code);
|
2000-08-21 06:09:33 +04:00
|
|
|
(void) splsched(); /* XXXSMP */
|
2001-02-27 00:58:30 +03:00
|
|
|
sigplusset(&SIGACTION_PS(ps, signum).sa_mask,
|
|
|
|
&p->p_sigctx.ps_sigmask);
|
2000-12-23 01:58:52 +03:00
|
|
|
if (SIGACTION_PS(ps, signum).sa_flags & SA_RESETHAND) {
|
|
|
|
sigdelset(&p->p_sigctx.ps_sigcatch, signum);
|
1995-08-14 02:53:59 +04:00
|
|
|
if (signum != SIGCONT && sigprop[signum] & SA_IGNORE)
|
2000-12-23 01:58:52 +03:00
|
|
|
sigaddset(&p->p_sigctx.ps_sigignore, signum);
|
|
|
|
SIGACTION_PS(ps, signum).sa_handler = SIG_DFL;
|
1995-08-14 02:53:59 +04:00
|
|
|
}
|
2000-08-21 01:50:06 +04:00
|
|
|
(void) spl0(); /* XXXSMP */
|
1994-06-29 10:29:24 +04:00
|
|
|
} else {
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_code = code; /* XXX for core dump/debugger */
|
|
|
|
p->p_sigctx.ps_sig = signum; /* XXX to verify code */
|
2003-05-20 21:42:51 +04:00
|
|
|
p->p_sigctx.ps_lwp = l->l_lid;
|
1994-06-29 10:29:24 +04:00
|
|
|
psignal(p, signum);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Send the signal to the process. If the signal has an action, the action
|
|
|
|
* is usually performed by the target process rather than the caller; we add
|
|
|
|
* the signal to the set of pending signals for the process.
|
|
|
|
*
|
|
|
|
* Exceptions:
|
|
|
|
* o When a stop signal is sent to a sleeping process that takes the
|
|
|
|
* default action, the process is stopped without awakening it.
|
|
|
|
* o SIGCONT restarts stopped processes (or puts them back to sleep)
|
|
|
|
* regardless of the signal action (eg, blocked or ignored).
|
|
|
|
*
|
|
|
|
* Other ignored signals are discarded immediately.
|
2000-08-21 01:50:06 +04:00
|
|
|
*
|
|
|
|
* XXXSMP: Invoked as psignal() or sched_psignal().
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
psignal1(struct proc *p, int signum,
|
|
|
|
int dolock) /* XXXSMP: works, but icky */
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2003-01-18 13:06:22 +03:00
|
|
|
struct lwp *l, *suspended;
|
|
|
|
int s = 0, prop, allsusp;
|
2001-02-27 00:58:30 +03:00
|
|
|
sig_t action;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1998-09-11 16:50:05 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (signum <= 0 || signum >= NSIG)
|
1994-06-29 10:29:24 +04:00
|
|
|
panic("psignal signal number");
|
2000-08-21 01:50:06 +04:00
|
|
|
|
|
|
|
/* XXXSMP: works, but icky */
|
|
|
|
if (dolock)
|
|
|
|
SCHED_ASSERT_UNLOCKED();
|
|
|
|
else
|
|
|
|
SCHED_ASSERT_LOCKED();
|
1998-09-11 16:50:05 +04:00
|
|
|
#endif
|
2002-10-23 13:10:23 +04:00
|
|
|
/*
|
|
|
|
* Notify any interested parties in the signal.
|
|
|
|
*/
|
|
|
|
KNOTE(&p->p_klist, NOTE_SIGNAL | signum);
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
prop = sigprop[signum];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If proc is traced, always give parent a chance.
|
|
|
|
*/
|
|
|
|
if (p->p_flag & P_TRACED)
|
|
|
|
action = SIG_DFL;
|
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* If the signal is being ignored,
|
|
|
|
* then we forget about it immediately.
|
2000-12-23 01:58:52 +03:00
|
|
|
* (Note: we don't set SIGCONT in p_sigctx.ps_sigignore,
|
1994-06-29 10:29:24 +04:00
|
|
|
* and if it is set to SIG_IGN,
|
|
|
|
* action will be SIG_DFL here.)
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
if (sigismember(&p->p_sigctx.ps_sigignore, signum))
|
1994-06-29 10:29:24 +04:00
|
|
|
return;
|
2000-12-23 01:58:52 +03:00
|
|
|
if (sigismember(&p->p_sigctx.ps_sigmask, signum))
|
1994-06-29 10:29:24 +04:00
|
|
|
action = SIG_HOLD;
|
2000-12-23 01:58:52 +03:00
|
|
|
else if (sigismember(&p->p_sigctx.ps_sigcatch, signum))
|
1994-06-29 10:29:24 +04:00
|
|
|
action = SIG_CATCH;
|
1995-07-24 07:18:42 +04:00
|
|
|
else {
|
1994-06-29 10:29:24 +04:00
|
|
|
action = SIG_DFL;
|
|
|
|
|
1995-07-24 07:18:42 +04:00
|
|
|
if (prop & SA_KILL && p->p_nice > NZERO)
|
|
|
|
p->p_nice = NZERO;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If sending a tty stop signal to a member of an
|
|
|
|
* orphaned process group, discard the signal here if
|
|
|
|
* the action is default; don't stop the process below
|
|
|
|
* if sleeping, and don't clear any pending SIGCONT.
|
|
|
|
*/
|
|
|
|
if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
if (prop & SA_CONT)
|
2000-12-23 01:58:52 +03:00
|
|
|
sigminusset(&stopsigmask, &p->p_sigctx.ps_siglist);
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1995-07-24 07:18:42 +04:00
|
|
|
if (prop & SA_STOP)
|
2000-12-23 01:58:52 +03:00
|
|
|
sigminusset(&contsigmask, &p->p_sigctx.ps_siglist);
|
1995-07-24 07:18:42 +04:00
|
|
|
|
2000-12-23 01:58:52 +03:00
|
|
|
sigaddset(&p->p_sigctx.ps_siglist, signum);
|
2001-01-15 01:31:58 +03:00
|
|
|
|
|
|
|
/* CHECKSIGS() is "inlined" here. */
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sigcheck = 1;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-02-15 23:54:38 +03:00
|
|
|
/*
|
|
|
|
* If the signal doesn't have SA_CANTMASK (no override for SIGKILL,
|
|
|
|
* please!), check if anything waits on it. If yes, clear the
|
|
|
|
* pending signal from siglist set, save it to ps_sigwaited,
|
|
|
|
* clear sigwait list, and wakeup any sigwaiters.
|
|
|
|
* The signal won't be processed further here.
|
|
|
|
*/
|
|
|
|
if ((prop & SA_CANTMASK) == 0
|
|
|
|
&& p->p_sigctx.ps_sigwaited < 0
|
|
|
|
&& sigismember(&p->p_sigctx.ps_sigwait, signum)) {
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
|
|
|
p->p_sigctx.ps_sigwaited = signum;
|
|
|
|
sigemptyset(&p->p_sigctx.ps_sigwait);
|
|
|
|
|
|
|
|
if (dolock)
|
|
|
|
wakeup_one(&p->p_sigctx.ps_sigwait);
|
|
|
|
else
|
|
|
|
sched_wakeup(&p->p_sigctx.ps_sigwait);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Defer further processing for signals which are held,
|
|
|
|
* except that stopped processes must be continued by SIGCONT.
|
|
|
|
*/
|
|
|
|
if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP))
|
|
|
|
return;
|
2000-08-21 01:50:06 +04:00
|
|
|
/* XXXSMP: works, but icky */
|
|
|
|
if (dolock)
|
|
|
|
SCHED_LOCK(s);
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
if (p->p_nrlwps > 0) {
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
2003-01-18 13:06:22 +03:00
|
|
|
* At least one LWP is running or on a run queue.
|
|
|
|
* The signal will be noticed when one of them returns
|
|
|
|
* to userspace.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
signotify(p);
|
|
|
|
/*
|
|
|
|
* The signal will be noticed very soon.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
goto out;
|
|
|
|
} else {
|
|
|
|
/* Process is sleeping or stopped */
|
|
|
|
if (p->p_flag & P_SA) {
|
|
|
|
l = p->p_sa->sa_idle;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Find out if any of the sleeps are interruptable,
|
|
|
|
* and if all the live LWPs remaining are suspended.
|
|
|
|
*/
|
|
|
|
allsusp = 1;
|
2003-02-04 01:56:23 +03:00
|
|
|
LIST_FOREACH(l, &p->p_lwps, l_sibling) {
|
2003-01-18 13:06:22 +03:00
|
|
|
if (l->l_stat == LSSLEEP &&
|
|
|
|
l->l_flag & L_SINTR)
|
|
|
|
break;
|
|
|
|
if (l->l_stat == LSSUSPENDED)
|
|
|
|
suspended = l;
|
|
|
|
else if ((l->l_stat != LSZOMB) &&
|
|
|
|
(l->l_stat != LSDEAD))
|
|
|
|
allsusp = 0;
|
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
if (p->p_stat == SACTIVE) {
|
|
|
|
/* All LWPs must be sleeping */
|
|
|
|
KDASSERT(((p->p_flag & P_SA) == 0) || (l != NULL));
|
|
|
|
|
|
|
|
if (l != NULL && (p->p_flag & P_TRACED))
|
|
|
|
goto run;
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
2003-01-18 13:06:22 +03:00
|
|
|
* If SIGCONT is default (or ignored) and process is
|
|
|
|
* asleep, we are finished; the process should not
|
|
|
|
* be awakened.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
if ((prop & SA_CONT) && action == SIG_DFL) {
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
1994-06-29 10:29:24 +04:00
|
|
|
goto out;
|
2003-01-18 13:06:22 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* When a sleeping process receives a stop
|
|
|
|
* signal, process immediately if possible.
|
|
|
|
*/
|
|
|
|
if ((prop & SA_STOP) && action == SIG_DFL) {
|
2000-08-21 01:50:06 +04:00
|
|
|
/*
|
2003-01-18 13:06:22 +03:00
|
|
|
* If a child holding parent blocked,
|
|
|
|
* stopping could cause deadlock.
|
2000-08-21 01:50:06 +04:00
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
if (p->p_flag & P_PPWAIT)
|
|
|
|
goto out;
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
|
|
|
p->p_xstat = signum;
|
|
|
|
if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0) {
|
|
|
|
/*
|
|
|
|
* XXXSMP: recursive call; don't lock
|
|
|
|
* the second time around.
|
|
|
|
*/
|
|
|
|
sched_psignal(p->p_pptr, SIGCHLD);
|
|
|
|
}
|
|
|
|
proc_stop(p); /* XXXSMP: recurse? */
|
|
|
|
goto out;
|
2000-08-21 01:50:06 +04:00
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
if (l == NULL) {
|
|
|
|
/*
|
|
|
|
* Special case: SIGKILL of a process
|
|
|
|
* which is entirely composed of
|
|
|
|
* suspended LWPs should succeed. We
|
|
|
|
* make this happen by unsuspending one of
|
|
|
|
* them.
|
|
|
|
*/
|
|
|
|
if (allsusp && (signum == SIGKILL))
|
|
|
|
lwp_continue(suspended);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* All other (caught or default) signals
|
|
|
|
* cause the process to run.
|
|
|
|
*/
|
1994-06-29 10:29:24 +04:00
|
|
|
goto runfast;
|
2003-01-18 13:06:22 +03:00
|
|
|
/*NOTREACHED*/
|
|
|
|
} else if (p->p_stat == SSTOP) {
|
|
|
|
/* Process is stopped */
|
|
|
|
/*
|
|
|
|
* If traced process is already stopped,
|
|
|
|
* then no further action is necessary.
|
|
|
|
*/
|
|
|
|
if (p->p_flag & P_TRACED)
|
|
|
|
goto out;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/*
|
2003-01-18 13:06:22 +03:00
|
|
|
* Kill signal always sets processes running,
|
|
|
|
* if possible.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
if (signum == SIGKILL) {
|
|
|
|
l = proc_unstop(p);
|
|
|
|
if (l)
|
|
|
|
goto runfast;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prop & SA_CONT) {
|
|
|
|
/*
|
|
|
|
* If SIGCONT is default (or ignored),
|
|
|
|
* we continue the process but don't
|
|
|
|
* leave the signal in ps_siglist, as
|
|
|
|
* it has no further action. If
|
|
|
|
* SIGCONT is held, we continue the
|
|
|
|
* process and leave the signal in
|
|
|
|
* ps_siglist. If the process catches
|
|
|
|
* SIGCONT, let it handle the signal
|
|
|
|
* itself. If it isn't waiting on an
|
|
|
|
* event, then it goes back to run
|
|
|
|
* state. Otherwise, process goes
|
|
|
|
* back to sleep state.
|
|
|
|
*/
|
|
|
|
if (action == SIG_DFL)
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist,
|
|
|
|
signum);
|
|
|
|
l = proc_unstop(p);
|
|
|
|
if (l && (action == SIG_CATCH))
|
|
|
|
goto runfast;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (prop & SA_STOP) {
|
|
|
|
/*
|
|
|
|
* Already stopped, don't need to stop again.
|
|
|
|
* (If we did the shell could get confused.)
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
2003-01-18 13:06:22 +03:00
|
|
|
goto out;
|
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/*
|
2003-02-08 00:43:18 +03:00
|
|
|
* If a lwp is sleeping interruptibly, then
|
|
|
|
* wake it up; it will run until the kernel
|
|
|
|
* boundary, where it will stop in issignal(),
|
|
|
|
* since p->p_stat is still SSTOP. When the
|
|
|
|
* process is continued, it will be made
|
|
|
|
* runnable and can look at the signal.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
if (l)
|
2003-02-08 00:43:18 +03:00
|
|
|
goto run;
|
1994-06-29 10:29:24 +04:00
|
|
|
goto out;
|
2003-01-18 13:06:22 +03:00
|
|
|
} else {
|
|
|
|
/* Else what? */
|
2003-02-04 01:56:23 +03:00
|
|
|
panic("psignal: Invalid process state %d.",
|
|
|
|
p->p_stat);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
runfast:
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Raise priority to at least PUSER.
|
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
if (l->l_priority > PUSER)
|
|
|
|
l->l_priority = PUSER;
|
2001-02-27 00:58:30 +03:00
|
|
|
run:
|
2003-01-18 13:06:22 +03:00
|
|
|
setrunnable(l); /* XXXSMP: recurse? */
|
2001-02-27 00:58:30 +03:00
|
|
|
out:
|
2000-08-21 01:50:06 +04:00
|
|
|
/* XXXSMP: works, but icky */
|
|
|
|
if (dolock)
|
|
|
|
SCHED_UNLOCK(s);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
void
|
|
|
|
psendsig(struct lwp *l, int sig, sigset_t *mask, u_long code)
|
|
|
|
{
|
|
|
|
struct proc *p = l->l_proc;
|
|
|
|
struct lwp *le, *li;
|
|
|
|
siginfo_t *si;
|
|
|
|
|
|
|
|
if (p->p_flag & P_SA) {
|
|
|
|
si = pool_get(&siginfo_pool, PR_WAITOK);
|
|
|
|
si->si_signo = sig;
|
|
|
|
si->si_errno = 0;
|
|
|
|
si->si_code = code;
|
|
|
|
le = li = NULL;
|
|
|
|
if (code)
|
|
|
|
le = l;
|
|
|
|
else
|
|
|
|
li = l;
|
|
|
|
|
|
|
|
sa_upcall(l, SA_UPCALL_SIGNAL | SA_UPCALL_DEFER, le, li,
|
|
|
|
sizeof(siginfo_t), si);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
(*p->p_emul->e_sendsig)(sig, mask, code);
|
|
|
|
}
|
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
static __inline int firstsig(const sigset_t *);
|
1998-09-11 16:50:05 +04:00
|
|
|
|
|
|
|
static __inline int
|
2001-02-27 00:58:30 +03:00
|
|
|
firstsig(const sigset_t *ss)
|
1998-09-11 16:50:05 +04:00
|
|
|
{
|
|
|
|
int sig;
|
|
|
|
|
|
|
|
sig = ffs(ss->__bits[0]);
|
|
|
|
if (sig != 0)
|
|
|
|
return (sig);
|
|
|
|
#if NSIG > 33
|
|
|
|
sig = ffs(ss->__bits[1]);
|
|
|
|
if (sig != 0)
|
|
|
|
return (sig + 32);
|
|
|
|
#endif
|
|
|
|
#if NSIG > 65
|
|
|
|
sig = ffs(ss->__bits[2]);
|
|
|
|
if (sig != 0)
|
|
|
|
return (sig + 64);
|
|
|
|
#endif
|
|
|
|
#if NSIG > 97
|
|
|
|
sig = ffs(ss->__bits[3]);
|
|
|
|
if (sig != 0)
|
|
|
|
return (sig + 96);
|
|
|
|
#endif
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* If the current process has received a signal (should be caught or cause
|
|
|
|
* termination, should interrupt current syscall), return the signal number.
|
|
|
|
* Stop signals with default action are processed immediately, then cleared;
|
|
|
|
* they aren't returned. This is checked after each entry to the system for
|
|
|
|
* a syscall or trap (though this can usually be done without calling issignal
|
|
|
|
* by checking the pending signal masks in the CURSIG macro.) The normal call
|
|
|
|
* sequence is
|
|
|
|
*
|
2003-01-18 13:06:22 +03:00
|
|
|
* while (signum = CURSIG(curlwp))
|
1994-06-29 10:29:24 +04:00
|
|
|
* postsig(signum);
|
|
|
|
*/
|
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
issignal(struct lwp *l)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p = l->l_proc;
|
2002-11-24 14:37:54 +03:00
|
|
|
int s = 0, signum, prop;
|
2003-01-18 13:06:22 +03:00
|
|
|
int dolock = (l->l_flag & L_SINTR) == 0, locked = !dolock;
|
2001-02-27 00:58:30 +03:00
|
|
|
sigset_t ss;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
if (p->p_stat == SSTOP) {
|
|
|
|
/*
|
|
|
|
* The process is stopped/stopping. Stop ourselves now that
|
|
|
|
* we're on the kernel/userspace boundary.
|
|
|
|
*/
|
|
|
|
if (dolock)
|
|
|
|
SCHED_LOCK(s);
|
|
|
|
l->l_stat = LSSTOP;
|
|
|
|
p->p_nrlwps--;
|
|
|
|
if (p->p_flag & P_TRACED)
|
|
|
|
goto sigtraceswitch;
|
|
|
|
else
|
|
|
|
goto sigswitch;
|
|
|
|
}
|
1994-06-29 10:29:24 +04:00
|
|
|
for (;;) {
|
1998-09-11 16:50:05 +04:00
|
|
|
sigpending1(p, &ss);
|
1994-06-29 10:29:24 +04:00
|
|
|
if (p->p_flag & P_PPWAIT)
|
1998-09-11 16:50:05 +04:00
|
|
|
sigminusset(&stopsigmask, &ss);
|
|
|
|
signum = firstsig(&ss);
|
|
|
|
if (signum == 0) { /* no signal to send */
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sigcheck = 0;
|
2001-12-18 18:51:52 +03:00
|
|
|
if (locked && dolock)
|
|
|
|
SCHED_LOCK(s);
|
1994-06-29 10:29:24 +04:00
|
|
|
return (0);
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
2001-02-27 00:58:30 +03:00
|
|
|
/* take the signal! */
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
1995-06-09 03:51:01 +04:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* We should see pending but ignored signals
|
|
|
|
* only if P_TRACED was on when they were posted.
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
if (sigismember(&p->p_sigctx.ps_sigignore, signum) &&
|
1998-09-11 16:50:05 +04:00
|
|
|
(p->p_flag & P_TRACED) == 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
continue;
|
1995-06-09 03:51:01 +04:00
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) {
|
|
|
|
/*
|
|
|
|
* If traced, always stop, and stay
|
|
|
|
* stopped until released by the debugger.
|
|
|
|
*/
|
|
|
|
p->p_xstat = signum;
|
1997-04-28 08:49:27 +04:00
|
|
|
if ((p->p_flag & P_FSTRACE) == 0)
|
2001-12-18 18:51:52 +03:00
|
|
|
psignal1(p->p_pptr, SIGCHLD, dolock);
|
|
|
|
if (dolock)
|
|
|
|
SCHED_LOCK(s);
|
2001-06-13 20:06:27 +04:00
|
|
|
proc_stop(p);
|
2003-01-18 13:06:22 +03:00
|
|
|
sigtraceswitch:
|
|
|
|
mi_switch(l, NULL);
|
2001-06-13 20:06:27 +04:00
|
|
|
SCHED_ASSERT_UNLOCKED();
|
2001-12-18 18:51:52 +03:00
|
|
|
if (dolock)
|
|
|
|
splx(s);
|
|
|
|
else
|
|
|
|
dolock = 1;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
|
|
|
/*
|
1995-06-09 03:51:01 +04:00
|
|
|
* If we are no longer being traced, or the parent
|
|
|
|
* didn't give us a signal, look for more signals.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
1995-06-09 03:51:01 +04:00
|
|
|
if ((p->p_flag & P_TRACED) == 0 || p->p_xstat == 0)
|
1994-06-29 10:29:24 +04:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
1995-06-09 03:51:01 +04:00
|
|
|
* If the new signal is being masked, look for other
|
|
|
|
* signals.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
1995-06-09 03:51:01 +04:00
|
|
|
signum = p->p_xstat;
|
2003-01-18 13:06:22 +03:00
|
|
|
p->p_xstat = 0;
|
2001-02-27 00:58:30 +03:00
|
|
|
/*
|
|
|
|
* `p->p_sigctx.ps_siglist |= mask' is done
|
|
|
|
* in setrunnable().
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
if (sigismember(&p->p_sigctx.ps_sigmask, signum))
|
1994-06-29 10:29:24 +04:00
|
|
|
continue;
|
2001-02-27 00:58:30 +03:00
|
|
|
/* take the signal! */
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
1995-06-09 03:51:01 +04:00
|
|
|
prop = sigprop[signum];
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Decide whether the signal should be returned.
|
|
|
|
* Return the signal's number, or fall through
|
|
|
|
* to clear it from the pending mask.
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
switch ((long)SIGACTION(p, signum).sa_handler) {
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1994-10-30 22:15:46 +03:00
|
|
|
case (long)SIG_DFL:
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Don't take default actions on system processes.
|
|
|
|
*/
|
|
|
|
if (p->p_pid <= 1) {
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
/*
|
|
|
|
* Are you sure you want to ignore SIGSEGV
|
|
|
|
* in init? XXX
|
|
|
|
*/
|
1996-10-13 06:32:29 +04:00
|
|
|
printf("Process (pid %d) got signal %d\n",
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_pid, signum);
|
|
|
|
#endif
|
|
|
|
break; /* == ignore */
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If there is a pending stop signal to process
|
|
|
|
* with default action, stop here,
|
|
|
|
* then clear the signal. However,
|
|
|
|
* if process is member of an orphaned
|
|
|
|
* process group, ignore tty stop signals.
|
|
|
|
*/
|
|
|
|
if (prop & SA_STOP) {
|
|
|
|
if (p->p_flag & P_TRACED ||
|
|
|
|
(p->p_pgrp->pg_jobc == 0 &&
|
|
|
|
prop & SA_TTYSTOP))
|
|
|
|
break; /* == ignore */
|
|
|
|
p->p_xstat = signum;
|
|
|
|
if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)
|
2001-12-18 18:51:52 +03:00
|
|
|
psignal1(p->p_pptr, SIGCHLD, dolock);
|
|
|
|
if (dolock)
|
|
|
|
SCHED_LOCK(s);
|
2000-08-21 01:50:06 +04:00
|
|
|
proc_stop(p);
|
2003-01-18 13:06:22 +03:00
|
|
|
sigswitch:
|
|
|
|
mi_switch(l, NULL);
|
2000-08-21 01:50:06 +04:00
|
|
|
SCHED_ASSERT_UNLOCKED();
|
2001-12-18 18:51:52 +03:00
|
|
|
if (dolock)
|
|
|
|
splx(s);
|
|
|
|
else
|
|
|
|
dolock = 1;
|
1994-06-29 10:29:24 +04:00
|
|
|
break;
|
|
|
|
} else if (prop & SA_IGNORE) {
|
|
|
|
/*
|
|
|
|
* Except for SIGCONT, shouldn't get here.
|
|
|
|
* Default action is to ignore; drop it.
|
|
|
|
*/
|
|
|
|
break; /* == ignore */
|
|
|
|
} else
|
1995-06-09 03:51:01 +04:00
|
|
|
goto keep;
|
1994-06-29 10:29:24 +04:00
|
|
|
/*NOTREACHED*/
|
|
|
|
|
1994-10-30 22:15:46 +03:00
|
|
|
case (long)SIG_IGN:
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Masking above should prevent us ever trying
|
|
|
|
* to take action on an ignored signal other
|
|
|
|
* than SIGCONT, unless process is traced.
|
|
|
|
*/
|
2002-11-29 00:00:27 +03:00
|
|
|
#ifdef DEBUG_ISSIGNAL
|
1994-06-29 10:29:24 +04:00
|
|
|
if ((prop & SA_CONT) == 0 &&
|
|
|
|
(p->p_flag & P_TRACED) == 0)
|
1996-10-13 06:32:29 +04:00
|
|
|
printf("issignal\n");
|
2002-11-29 00:00:27 +03:00
|
|
|
#endif
|
1994-06-29 10:29:24 +04:00
|
|
|
break; /* == ignore */
|
|
|
|
|
|
|
|
default:
|
|
|
|
/*
|
|
|
|
* This signal has an action, let
|
|
|
|
* postsig() process it.
|
|
|
|
*/
|
1995-06-09 03:51:01 +04:00
|
|
|
goto keep;
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
1995-06-09 03:51:01 +04:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
keep:
|
|
|
|
/* leave the signal for later */
|
|
|
|
sigaddset(&p->p_sigctx.ps_siglist, signum);
|
2001-01-15 01:31:58 +03:00
|
|
|
CHECKSIGS(p);
|
2001-12-18 18:51:52 +03:00
|
|
|
if (locked && dolock)
|
|
|
|
SCHED_LOCK(s);
|
1995-06-09 03:51:01 +04:00
|
|
|
return (signum);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Put the argument process into the stopped state and notify the parent
|
|
|
|
* via wakeup. Signals are handled elsewhere. The process must not be
|
|
|
|
* on the run queue.
|
|
|
|
*/
|
2000-08-21 01:50:06 +04:00
|
|
|
static void
|
2001-02-27 00:58:30 +03:00
|
|
|
proc_stop(struct proc *p)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2003-01-18 13:06:22 +03:00
|
|
|
struct lwp *l;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2000-08-21 01:50:06 +04:00
|
|
|
SCHED_ASSERT_LOCKED();
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
/* XXX lock process LWP state */
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_stat = SSTOP;
|
|
|
|
p->p_flag &= ~P_WAITED;
|
2003-01-18 13:06:22 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Put as many LWP's as possible in stopped state.
|
|
|
|
* Sleeping ones will notice the stopped state as they try to
|
|
|
|
* return to userspace.
|
|
|
|
*/
|
|
|
|
|
2003-02-07 12:02:14 +03:00
|
|
|
LIST_FOREACH(l, &p->p_lwps, l_sibling) {
|
2003-01-18 13:06:22 +03:00
|
|
|
if (l->l_stat == LSONPROC) {
|
|
|
|
/* XXX SMP this assumes that a LWP that is LSONPROC
|
|
|
|
* is curlwp and hence is about to be mi_switched
|
|
|
|
* away; the only callers of proc_stop() are:
|
|
|
|
* - psignal
|
|
|
|
* - issignal()
|
|
|
|
* For the former, proc_stop() is only called when
|
|
|
|
* no processes are running, so we don't worry.
|
|
|
|
* For the latter, proc_stop() is called right
|
|
|
|
* before mi_switch().
|
|
|
|
*/
|
|
|
|
l->l_stat = LSSTOP;
|
|
|
|
p->p_nrlwps--;
|
|
|
|
} else if (l->l_stat == LSRUN) {
|
|
|
|
/* Remove LWP from the run queue */
|
|
|
|
remrunqueue(l);
|
|
|
|
l->l_stat = LSSTOP;
|
|
|
|
p->p_nrlwps--;
|
|
|
|
} else if ((l->l_stat == LSSLEEP) ||
|
|
|
|
(l->l_stat == LSSUSPENDED) ||
|
|
|
|
(l->l_stat == LSZOMB) ||
|
|
|
|
(l->l_stat == LSDEAD)) {
|
|
|
|
/*
|
|
|
|
* Don't do anything; let sleeping LWPs
|
|
|
|
* discover the stopped state of the process
|
|
|
|
* on their way out of the kernel; otherwise,
|
|
|
|
* things like NFS threads that sleep with
|
|
|
|
* locks will block the rest of the system
|
|
|
|
* from getting any work done.
|
|
|
|
*
|
|
|
|
* Suspended/dead/zombie LWPs aren't going
|
|
|
|
* anywhere, so we don't need to touch them.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
else {
|
|
|
|
panic("proc_stop: process %d lwp %d "
|
|
|
|
"in unstoppable state %d.\n",
|
|
|
|
p->p_pid, l->l_lid, l->l_stat);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* XXX unlock process LWP state */
|
|
|
|
|
2000-08-21 01:50:06 +04:00
|
|
|
sched_wakeup((caddr_t)p->p_pptr);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
2003-02-08 00:43:18 +03:00
|
|
|
/*
|
|
|
|
* Given a process in state SSTOP, set the state back to SACTIVE and
|
|
|
|
* move LSSTOP'd LWPs to LSSLEEP or make them runnable.
|
|
|
|
*
|
|
|
|
* If no LWPs ended up runnable (and therefore able to take a signal),
|
|
|
|
* return a LWP that is sleeping interruptably. The caller can wake
|
|
|
|
* that LWP up to take a signal.
|
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
struct lwp *
|
2003-04-15 16:11:25 +04:00
|
|
|
proc_unstop(struct proc *p)
|
2003-01-18 13:06:22 +03:00
|
|
|
{
|
|
|
|
struct lwp *l, *lr = NULL;
|
2003-02-08 00:43:18 +03:00
|
|
|
int cantake = 0;
|
2003-01-18 13:06:22 +03:00
|
|
|
|
|
|
|
SCHED_ASSERT_LOCKED();
|
|
|
|
|
|
|
|
/*
|
2003-04-24 01:32:10 +04:00
|
|
|
* Our caller wants to be informed if there are only sleeping
|
|
|
|
* and interruptable LWPs left after we have run so that it
|
|
|
|
* can invoke setrunnable() if required - return one of the
|
|
|
|
* interruptable LWPs if this is the case.
|
2003-01-18 13:06:22 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
p->p_stat = SACTIVE;
|
2003-02-08 00:43:18 +03:00
|
|
|
if (p->p_flag & P_SA) {
|
2003-04-24 01:32:10 +04:00
|
|
|
/*
|
|
|
|
* Preferentially select the idle LWP as the interruptable
|
|
|
|
* LWP to return if it exists.
|
|
|
|
*/
|
|
|
|
lr = p->p_sa->sa_idle;
|
|
|
|
if (lr != NULL)
|
|
|
|
cantake = 1;
|
2003-02-08 00:43:18 +03:00
|
|
|
}
|
2003-02-07 12:02:14 +03:00
|
|
|
LIST_FOREACH(l, &p->p_lwps, l_sibling) {
|
2003-04-24 01:32:10 +04:00
|
|
|
if (l->l_stat == LSRUN) {
|
|
|
|
lr = NULL;
|
2003-02-08 00:43:18 +03:00
|
|
|
cantake = 1;
|
2003-04-24 01:32:10 +04:00
|
|
|
}
|
2003-02-07 12:02:14 +03:00
|
|
|
if (l->l_stat != LSSTOP)
|
|
|
|
continue;
|
|
|
|
|
2003-02-08 00:43:18 +03:00
|
|
|
if (l->l_wchan != NULL) {
|
2003-02-07 12:02:14 +03:00
|
|
|
l->l_stat = LSSLEEP;
|
2003-02-08 00:43:18 +03:00
|
|
|
if ((cantake == 0) && (l->l_flag & L_SINTR)) {
|
|
|
|
lr = l;
|
|
|
|
cantake = 1;
|
|
|
|
}
|
|
|
|
} else {
|
2003-04-24 01:32:10 +04:00
|
|
|
setrunnable(l);
|
|
|
|
lr = NULL;
|
2003-02-08 00:43:18 +03:00
|
|
|
cantake = 1;
|
|
|
|
}
|
2003-02-07 12:02:14 +03:00
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
|
|
|
|
return lr;
|
|
|
|
}
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
/*
|
|
|
|
* Take the action for the specified signal
|
|
|
|
* from the current set of pending signals.
|
|
|
|
*/
|
|
|
|
void
|
2001-02-27 00:58:30 +03:00
|
|
|
postsig(int signum)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2003-01-18 13:06:22 +03:00
|
|
|
struct lwp *l;
|
2001-02-27 00:58:30 +03:00
|
|
|
struct proc *p;
|
|
|
|
struct sigacts *ps;
|
|
|
|
sig_t action;
|
|
|
|
u_long code;
|
|
|
|
sigset_t *returnmask;
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
l = curlwp;
|
|
|
|
p = l->l_proc;
|
2001-02-27 00:58:30 +03:00
|
|
|
ps = p->p_sigacts;
|
1994-06-29 10:29:24 +04:00
|
|
|
#ifdef DIAGNOSTIC
|
|
|
|
if (signum == 0)
|
|
|
|
panic("postsig");
|
|
|
|
#endif
|
2000-08-22 21:28:28 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
KERNEL_PROC_LOCK(l);
|
2000-08-22 21:28:28 +04:00
|
|
|
|
2000-12-23 01:58:52 +03:00
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
|
|
|
action = SIGACTION_PS(ps, signum).sa_handler;
|
1994-06-29 10:29:24 +04:00
|
|
|
#ifdef KTRACE
|
|
|
|
if (KTRPOINT(p, KTR_PSIG))
|
2003-06-30 02:28:00 +04:00
|
|
|
ktrpsig(p,
|
2000-12-23 01:58:52 +03:00
|
|
|
signum, action, p->p_sigctx.ps_flags & SAS_OLDMASK ?
|
|
|
|
&p->p_sigctx.ps_oldmask : &p->p_sigctx.ps_sigmask, 0);
|
1994-06-29 10:29:24 +04:00
|
|
|
#endif
|
|
|
|
if (action == SIG_DFL) {
|
|
|
|
/*
|
|
|
|
* Default action, where the default is to kill
|
|
|
|
* the process. (Other cases were ignored above.)
|
|
|
|
*/
|
2003-01-18 13:06:22 +03:00
|
|
|
sigexit(l, signum);
|
1994-06-29 10:29:24 +04:00
|
|
|
/* NOTREACHED */
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* If we get here, the signal must be caught.
|
|
|
|
*/
|
|
|
|
#ifdef DIAGNOSTIC
|
2001-02-27 00:58:30 +03:00
|
|
|
if (action == SIG_IGN ||
|
|
|
|
sigismember(&p->p_sigctx.ps_sigmask, signum))
|
1994-06-29 10:29:24 +04:00
|
|
|
panic("postsig action");
|
|
|
|
#endif
|
|
|
|
/*
|
|
|
|
* Set the new mask value and also defer further
|
2003-03-30 01:48:37 +03:00
|
|
|
* occurrences of this signal.
|
1994-06-29 10:29:24 +04:00
|
|
|
*
|
|
|
|
* Special case: user has done a sigpause. Here the
|
|
|
|
* current mask is not of interest, but rather the
|
|
|
|
* mask from before the sigpause is what we want
|
|
|
|
* restored after the signal processing is completed.
|
|
|
|
*/
|
2000-12-23 01:58:52 +03:00
|
|
|
if (p->p_sigctx.ps_flags & SAS_OLDMASK) {
|
|
|
|
returnmask = &p->p_sigctx.ps_oldmask;
|
|
|
|
p->p_sigctx.ps_flags &= ~SAS_OLDMASK;
|
1994-06-29 10:29:24 +04:00
|
|
|
} else
|
2000-12-23 01:58:52 +03:00
|
|
|
returnmask = &p->p_sigctx.ps_sigmask;
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_stats->p_ru.ru_nsignals++;
|
2000-12-23 01:58:52 +03:00
|
|
|
if (p->p_sigctx.ps_sig != signum) {
|
1994-06-29 10:29:24 +04:00
|
|
|
code = 0;
|
|
|
|
} else {
|
2000-12-23 01:58:52 +03:00
|
|
|
code = p->p_sigctx.ps_code;
|
|
|
|
p->p_sigctx.ps_code = 0;
|
2003-05-20 21:42:51 +04:00
|
|
|
p->p_sigctx.ps_lwp = 0;
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sig = 0;
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
psendsig(l, signum, returnmask, code);
|
2000-08-21 06:09:33 +04:00
|
|
|
(void) splsched(); /* XXXSMP */
|
2001-02-27 00:58:30 +03:00
|
|
|
sigplusset(&SIGACTION_PS(ps, signum).sa_mask,
|
|
|
|
&p->p_sigctx.ps_sigmask);
|
2000-12-23 01:58:52 +03:00
|
|
|
if (SIGACTION_PS(ps, signum).sa_flags & SA_RESETHAND) {
|
|
|
|
sigdelset(&p->p_sigctx.ps_sigcatch, signum);
|
1998-09-11 16:50:05 +04:00
|
|
|
if (signum != SIGCONT && sigprop[signum] & SA_IGNORE)
|
2000-12-23 01:58:52 +03:00
|
|
|
sigaddset(&p->p_sigctx.ps_sigignore, signum);
|
|
|
|
SIGACTION_PS(ps, signum).sa_handler = SIG_DFL;
|
1998-09-11 16:50:05 +04:00
|
|
|
}
|
2000-08-21 01:50:06 +04:00
|
|
|
(void) spl0(); /* XXXSMP */
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
2000-08-22 21:28:28 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
KERNEL_PROC_UNLOCK(l);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Kill the current process for stated reason.
|
|
|
|
*/
|
1996-02-04 05:15:01 +03:00
|
|
|
void
|
2002-07-29 02:18:51 +04:00
|
|
|
killproc(struct proc *p, const char *why)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
|
|
|
|
|
|
|
log(LOG_ERR, "pid %d was killed: %s\n", p->p_pid, why);
|
|
|
|
uprintf("sorry, pid %d was killed: %s\n", p->p_pid, why);
|
|
|
|
psignal(p, SIGKILL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Force the current process to exit with the specified signal, dumping core
|
|
|
|
* if appropriate. We bypass the normal tests for masked and caught signals,
|
|
|
|
* allowing unrecoverable failures to terminate the process without changing
|
|
|
|
* signal state. Mark the accounting record with the signal termination.
|
|
|
|
* If dumping core, save the signal number for the debugger. Calls exit and
|
|
|
|
* does not return.
|
|
|
|
*/
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
|
2000-02-08 07:13:51 +03:00
|
|
|
#if defined(DEBUG)
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
int kern_logsigexit = 1; /* not static to make public for sysctl */
|
|
|
|
#else
|
|
|
|
int kern_logsigexit = 0; /* not static to make public for sysctl */
|
|
|
|
#endif
|
|
|
|
|
2000-07-08 22:10:25 +04:00
|
|
|
static const char logcoredump[] =
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
"pid %d (%s), uid %d: exited on signal %d (core dumped)\n";
|
2000-07-08 22:10:25 +04:00
|
|
|
static const char lognocoredump[] =
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
"pid %d (%s), uid %d: exited on signal %d (core not dumped, err = %d)\n";
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
/* Wrapper function for use in p_userret */
|
|
|
|
static void
|
|
|
|
lwp_coredump_hook(struct lwp *l, void *arg)
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Suspend ourselves, so that the kernel stack and therefore
|
|
|
|
* the userland registers saved in the trapframe are around
|
|
|
|
* for coredump() to write them out.
|
|
|
|
*/
|
|
|
|
KERNEL_PROC_LOCK(l);
|
|
|
|
l->l_flag &= ~L_DETACHED;
|
|
|
|
SCHED_LOCK(s);
|
|
|
|
l->l_stat = LSSUSPENDED;
|
|
|
|
l->l_proc->p_nrlwps--;
|
|
|
|
/* XXX NJWLWP check if this makes sense here: */
|
|
|
|
l->l_proc->p_stats->p_ru.ru_nvcsw++;
|
|
|
|
mi_switch(l, NULL);
|
|
|
|
SCHED_ASSERT_UNLOCKED();
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
lwp_exit(l);
|
|
|
|
}
|
|
|
|
|
1996-02-04 05:15:01 +03:00
|
|
|
void
|
2003-01-18 13:06:22 +03:00
|
|
|
sigexit(struct lwp *l, int signum)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
2003-02-18 02:45:00 +03:00
|
|
|
struct lwp *l2;
|
2003-01-18 13:06:22 +03:00
|
|
|
int error, exitsig;
|
|
|
|
|
|
|
|
p = l->l_proc;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't permit coredump() or exit1() multiple times
|
|
|
|
* in the same process.
|
|
|
|
*/
|
2003-02-18 02:45:00 +03:00
|
|
|
if (p->p_flag & P_WEXIT) {
|
|
|
|
KERNEL_PROC_UNLOCK(l);
|
2003-01-18 13:06:22 +03:00
|
|
|
(*p->p_userret)(l, p->p_userret_arg);
|
2003-02-18 02:45:00 +03:00
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
p->p_flag |= P_WEXIT;
|
|
|
|
/* We don't want to switch away from exiting. */
|
|
|
|
/* XXX multiprocessor: stop LWPs on other processors. */
|
2003-02-18 02:45:00 +03:00
|
|
|
if (p->p_flag & P_SA) {
|
|
|
|
LIST_FOREACH(l2, &p->p_lwps, l_sibling)
|
|
|
|
l2->l_flag &= ~L_SA;
|
2003-01-18 13:06:22 +03:00
|
|
|
p->p_flag &= ~P_SA;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make other LWPs stick around long enough to be dumped */
|
|
|
|
p->p_userret = lwp_coredump_hook;
|
|
|
|
p->p_userret_arg = NULL;
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
|
2001-02-27 00:58:30 +03:00
|
|
|
exitsig = signum;
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_acflag |= AXSIG;
|
|
|
|
if (sigprop[signum] & SA_CORE) {
|
2000-12-23 01:58:52 +03:00
|
|
|
p->p_sigctx.ps_sig = signum;
|
2003-01-18 13:06:22 +03:00
|
|
|
if ((error = coredump(l)) == 0)
|
2000-07-08 22:10:25 +04:00
|
|
|
exitsig |= WCOREFLAG;
|
|
|
|
|
|
|
|
if (kern_logsigexit) {
|
2002-08-26 01:47:50 +04:00
|
|
|
/* XXX What if we ever have really large UIDs? */
|
2000-07-08 22:10:25 +04:00
|
|
|
int uid = p->p_cred && p->p_ucred ?
|
2002-08-26 01:47:50 +04:00
|
|
|
(int) p->p_ucred->cr_uid : -1;
|
2000-07-08 22:10:25 +04:00
|
|
|
|
|
|
|
if (error)
|
|
|
|
log(LOG_INFO, lognocoredump, p->p_pid,
|
|
|
|
p->p_comm, uid, signum, error);
|
|
|
|
else
|
|
|
|
log(LOG_INFO, logcoredump, p->p_pid,
|
|
|
|
p->p_comm, uid, signum);
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
}
|
|
|
|
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
Add kernel logging of processes which exit on signals which can
cause a core to drop, and whether the core dropped, or, if it did
not, why not (i.e. error number). Logs process ID, name, signal that
hit it, and whether the core dump was successful.
logging only happens if kern_logsigexit is non-zero, and it can be
changed by the new sysctl(3) value KERN_LOGSIGEXIT. The name of this
sysctl and its function are taken from FreeBSD, at the suggestion
of Greg Woods in PR 6224. Default behavior is zero for a normal
kernel, and one for a kernel compiled with DIAGNOSTIC.
2000-02-06 10:29:56 +03:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
exit1(l, W_EXITCODE(0, exitsig));
|
1994-06-29 10:29:24 +04:00
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
1998-06-29 01:34:58 +04:00
|
|
|
* Dump core, into a file named "progname.core" or "core" (depending on the
|
|
|
|
* value of shortcorename), unless the process was setuid/setgid.
|
1994-06-29 10:29:24 +04:00
|
|
|
*/
|
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
coredump(struct lwp *l)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
struct vnode *vp;
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
2001-02-27 00:58:30 +03:00
|
|
|
struct vmspace *vm;
|
|
|
|
struct ucred *cred;
|
|
|
|
struct nameidata nd;
|
|
|
|
struct vattr vattr;
|
|
|
|
int error, error1;
|
|
|
|
char name[MAXPATHLEN];
|
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
2001-02-27 00:58:30 +03:00
|
|
|
vm = p->p_vmspace;
|
|
|
|
cred = p->p_cred->pc_ucred;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
1996-10-24 03:13:19 +04:00
|
|
|
/*
|
|
|
|
* Make sure the process has not set-id, to prevent data leaks.
|
|
|
|
*/
|
1996-10-18 12:39:34 +04:00
|
|
|
if (p->p_flag & P_SUGID)
|
1996-10-24 03:13:19 +04:00
|
|
|
return (EPERM);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Refuse to core if the data + stack + user size is larger than
|
|
|
|
* the core dump limit. XXX THIS IS WRONG, because of mapped
|
|
|
|
* data.
|
|
|
|
*/
|
1994-08-24 02:07:42 +04:00
|
|
|
if (USPACE + ctob(vm->vm_dsize + vm->vm_ssize) >=
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_rlimit[RLIMIT_CORE].rlim_cur)
|
1996-10-24 03:13:19 +04:00
|
|
|
return (EFBIG); /* better error code? */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The core dump will go in the current working directory. Make
|
1998-09-11 17:25:20 +04:00
|
|
|
* sure that the directory is still there and that the mount flags
|
|
|
|
* allow us to write core dumps there.
|
1996-10-24 03:13:19 +04:00
|
|
|
*/
|
1999-04-30 22:42:58 +04:00
|
|
|
vp = p->p_cwdi->cwdi_cdir;
|
1998-09-11 17:25:20 +04:00
|
|
|
if (vp->v_mount == NULL ||
|
|
|
|
(vp->v_mount->mnt_flag & MNT_NOCOREDUMP) != 0)
|
1996-10-24 03:13:19 +04:00
|
|
|
return (EPERM);
|
|
|
|
|
2000-05-27 04:40:29 +04:00
|
|
|
error = build_corename(p, name);
|
1999-09-28 18:47:00 +04:00
|
|
|
if (error)
|
|
|
|
return error;
|
|
|
|
|
2003-06-30 02:28:00 +04:00
|
|
|
NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name, p);
|
2002-12-07 01:44:49 +03:00
|
|
|
error = vn_open(&nd, O_CREAT | O_NOFOLLOW | FWRITE, S_IRUSR | S_IWUSR);
|
1996-02-04 05:15:01 +03:00
|
|
|
if (error)
|
1994-06-29 10:29:24 +04:00
|
|
|
return (error);
|
|
|
|
vp = nd.ni_vp;
|
|
|
|
|
|
|
|
/* Don't dump to non-regular files or files with links. */
|
|
|
|
if (vp->v_type != VREG ||
|
2003-06-30 02:28:00 +04:00
|
|
|
VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) {
|
1996-10-24 03:13:19 +04:00
|
|
|
error = EINVAL;
|
1994-06-29 10:29:24 +04:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
VATTR_NULL(&vattr);
|
|
|
|
vattr.va_size = 0;
|
2003-06-30 02:28:00 +04:00
|
|
|
VOP_LEASE(vp, p, cred, LEASE_WRITE);
|
|
|
|
VOP_SETATTR(vp, &vattr, cred, p);
|
1994-06-29 10:29:24 +04:00
|
|
|
p->p_acflag |= ACORE;
|
1999-12-30 19:00:23 +03:00
|
|
|
|
2001-12-08 03:35:25 +03:00
|
|
|
/* Now dump the actual core file. */
|
2003-01-18 13:06:22 +03:00
|
|
|
error = (*p->p_execsw->es_coredump)(l, vp, cred);
|
2001-02-27 00:58:30 +03:00
|
|
|
out:
|
1998-03-01 05:20:01 +03:00
|
|
|
VOP_UNLOCK(vp, 0);
|
2003-06-30 02:28:00 +04:00
|
|
|
error1 = vn_close(vp, FWRITE, cred, p);
|
1994-06-29 10:29:24 +04:00
|
|
|
if (error == 0)
|
|
|
|
error = error1;
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Nonexistent system call-- signal process (may want to handle it).
|
|
|
|
* Flag error in case process won't see signal immediately (blocked or ignored).
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
2003-01-18 13:06:22 +03:00
|
|
|
sys_nosys(struct lwp *l, void *v, register_t *retval)
|
1994-06-29 10:29:24 +04:00
|
|
|
{
|
2003-01-18 13:06:22 +03:00
|
|
|
struct proc *p;
|
1994-06-29 10:29:24 +04:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
p = l->l_proc;
|
1994-06-29 10:29:24 +04:00
|
|
|
psignal(p, SIGSYS);
|
1994-12-08 00:31:11 +03:00
|
|
|
return (ENOSYS);
|
1994-06-29 10:29:24 +04:00
|
|
|
}
|
1999-09-28 18:47:00 +04:00
|
|
|
|
|
|
|
static int
|
2001-02-27 00:58:30 +03:00
|
|
|
build_corename(struct proc *p, char dst[MAXPATHLEN])
|
1999-09-28 18:47:00 +04:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
const char *s;
|
|
|
|
char *d, *end;
|
|
|
|
int i;
|
2000-05-27 04:40:29 +04:00
|
|
|
|
2000-09-23 04:48:29 +04:00
|
|
|
for (s = p->p_limit->pl_corename, d = dst, end = d + MAXPATHLEN;
|
1999-09-28 18:47:00 +04:00
|
|
|
*s != '\0'; s++) {
|
|
|
|
if (*s == '%') {
|
2000-09-23 04:48:29 +04:00
|
|
|
switch (*(s + 1)) {
|
1999-09-28 18:47:00 +04:00
|
|
|
case 'n':
|
2000-09-23 04:48:29 +04:00
|
|
|
i = snprintf(d, end - d, "%s", p->p_comm);
|
1999-09-28 18:47:00 +04:00
|
|
|
break;
|
|
|
|
case 'p':
|
2000-09-23 04:48:29 +04:00
|
|
|
i = snprintf(d, end - d, "%d", p->p_pid);
|
1999-09-28 18:47:00 +04:00
|
|
|
break;
|
|
|
|
case 'u':
|
2003-02-15 21:10:15 +03:00
|
|
|
i = snprintf(d, end - d, "%.*s",
|
|
|
|
(int)sizeof p->p_pgrp->pg_session->s_login,
|
2000-05-27 04:40:29 +04:00
|
|
|
p->p_pgrp->pg_session->s_login);
|
1999-09-28 18:47:00 +04:00
|
|
|
break;
|
|
|
|
case 't':
|
2000-09-23 04:48:29 +04:00
|
|
|
i = snprintf(d, end - d, "%ld",
|
2000-05-27 04:40:29 +04:00
|
|
|
p->p_stats->p_start.tv_sec);
|
1999-09-28 18:47:00 +04:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto copy;
|
|
|
|
}
|
|
|
|
d += i;
|
|
|
|
s++;
|
|
|
|
} else {
|
2001-02-27 00:58:30 +03:00
|
|
|
copy: *d = *s;
|
1999-09-28 18:47:00 +04:00
|
|
|
d++;
|
|
|
|
}
|
2000-09-23 04:48:29 +04:00
|
|
|
if (d >= end)
|
|
|
|
return (ENAMETOOLONG);
|
1999-09-28 18:47:00 +04:00
|
|
|
}
|
|
|
|
*d = '\0';
|
2003-01-18 13:06:22 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
getucontext(struct lwp *l, ucontext_t *ucp)
|
|
|
|
{
|
|
|
|
struct proc *p;
|
|
|
|
|
|
|
|
p = l->l_proc;
|
|
|
|
|
|
|
|
ucp->uc_flags = 0;
|
|
|
|
ucp->uc_link = l->l_ctxlink;
|
|
|
|
|
|
|
|
(void)sigprocmask1(p, 0, NULL, &ucp->uc_sigmask);
|
|
|
|
ucp->uc_flags |= _UC_SIGMASK;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The (unsupplied) definition of the `current execution stack'
|
|
|
|
* in the System V Interface Definition appears to allow returning
|
|
|
|
* the main context stack.
|
|
|
|
*/
|
|
|
|
if ((p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK) == 0) {
|
|
|
|
ucp->uc_stack.ss_sp = (void *)USRSTACK;
|
|
|
|
ucp->uc_stack.ss_size = ctob(p->p_vmspace->vm_ssize);
|
|
|
|
ucp->uc_stack.ss_flags = 0; /* XXX, def. is Very Fishy */
|
|
|
|
} else {
|
|
|
|
/* Simply copy alternate signal execution stack. */
|
|
|
|
ucp->uc_stack = p->p_sigctx.ps_sigstk;
|
|
|
|
}
|
|
|
|
ucp->uc_flags |= _UC_STACK;
|
|
|
|
|
|
|
|
cpu_getmcontext(l, &ucp->uc_mcontext, &ucp->uc_flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
|
|
sys_getcontext(struct lwp *l, void *v, register_t *retval)
|
|
|
|
{
|
|
|
|
struct sys_getcontext_args /* {
|
|
|
|
syscallarg(struct __ucontext *) ucp;
|
|
|
|
} */ *uap = v;
|
|
|
|
ucontext_t uc;
|
|
|
|
|
|
|
|
getucontext(l, &uc);
|
|
|
|
|
|
|
|
return (copyout(&uc, SCARG(uap, ucp), sizeof (*SCARG(uap, ucp))));
|
1999-09-28 18:47:00 +04:00
|
|
|
}
|
2000-11-05 18:37:09 +03:00
|
|
|
|
2003-01-18 13:06:22 +03:00
|
|
|
int
|
|
|
|
setucontext(struct lwp *l, const ucontext_t *ucp)
|
|
|
|
{
|
|
|
|
struct proc *p;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
p = l->l_proc;
|
|
|
|
if ((error = cpu_setmcontext(l, &ucp->uc_mcontext, ucp->uc_flags)) != 0)
|
|
|
|
return (error);
|
|
|
|
l->l_ctxlink = ucp->uc_link;
|
|
|
|
/*
|
|
|
|
* We might want to take care of the stack portion here but currently
|
|
|
|
* don't; see the comment in getucontext().
|
|
|
|
*/
|
|
|
|
if ((ucp->uc_flags & _UC_SIGMASK) != 0)
|
|
|
|
sigprocmask1(p, SIG_SETMASK, &ucp->uc_sigmask, NULL);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
|
|
sys_setcontext(struct lwp *l, void *v, register_t *retval)
|
|
|
|
{
|
|
|
|
struct sys_setcontext_args /* {
|
|
|
|
syscallarg(const ucontext_t *) ucp;
|
|
|
|
} */ *uap = v;
|
|
|
|
ucontext_t uc;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (SCARG(uap, ucp) == NULL) /* i.e. end of uc_link chain */
|
|
|
|
exit1(l, W_EXITCODE(0, 0));
|
|
|
|
else if ((error = copyin(SCARG(uap, ucp), &uc, sizeof (uc))) != 0 ||
|
|
|
|
(error = setucontext(l, &uc)) != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
return (EJUSTRETURN);
|
|
|
|
}
|
|
|
|
|
2003-02-15 23:54:38 +03:00
|
|
|
/*
|
|
|
|
* sigtimedwait(2) system call, used also for implementation
|
|
|
|
* of sigwaitinfo() and sigwait().
|
|
|
|
*
|
|
|
|
* This only handles single LWP in signal wait. libpthread provides
|
|
|
|
* it's own sigtimedwait() wrapper to DTRT WRT individual threads.
|
|
|
|
*
|
|
|
|
* XXX no support for queued signals, si_code is always SI_USER.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
sys___sigtimedwait(struct lwp *l, void *v, register_t *retval)
|
|
|
|
{
|
|
|
|
struct sys___sigtimedwait_args /* {
|
|
|
|
syscallarg(const sigset_t *) set;
|
|
|
|
syscallarg(siginfo_t *) info;
|
|
|
|
syscallarg(struct timespec *) timeout;
|
|
|
|
} */ *uap = v;
|
|
|
|
sigset_t waitset, twaitset;
|
|
|
|
struct proc *p = l->l_proc;
|
|
|
|
int error, signum, s;
|
|
|
|
int timo = 0;
|
|
|
|
struct timeval tvstart;
|
|
|
|
struct timespec ts;
|
|
|
|
|
|
|
|
if ((error = copyin(SCARG(uap, set), &waitset, sizeof(waitset))))
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Silently ignore SA_CANTMASK signals. psignal1() would
|
|
|
|
* ignore SA_CANTMASK signals in waitset, we do this
|
|
|
|
* only for the below siglist check.
|
|
|
|
*/
|
|
|
|
sigminusset(&sigcantmask, &waitset);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* First scan siglist and check if there is signal from
|
|
|
|
* our waitset already pending.
|
|
|
|
*/
|
|
|
|
twaitset = waitset;
|
|
|
|
__sigandset(&p->p_sigctx.ps_siglist, &twaitset);
|
|
|
|
if ((signum = firstsig(&twaitset))) {
|
|
|
|
/* found pending signal */
|
|
|
|
sigdelset(&p->p_sigctx.ps_siglist, signum);
|
|
|
|
goto sig;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate timeout, if it was specified.
|
|
|
|
*/
|
|
|
|
if (SCARG(uap, timeout)) {
|
|
|
|
uint64_t ms;
|
|
|
|
|
|
|
|
if ((error = copyin(SCARG(uap, timeout), &ts, sizeof(ts))))
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
ms = (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000);
|
|
|
|
timo = mstohz(ms);
|
|
|
|
if (timo == 0 && ts.tv_sec == 0 && ts.tv_nsec > 0)
|
|
|
|
timo = 1;
|
|
|
|
if (timo <= 0)
|
|
|
|
return (EAGAIN);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remember current mono_time, it would be used in
|
|
|
|
* ECANCELED/ERESTART case.
|
|
|
|
*/
|
|
|
|
s = splclock();
|
|
|
|
tvstart = mono_time;
|
|
|
|
splx(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup ps_sigwait list.
|
|
|
|
*/
|
|
|
|
p->p_sigctx.ps_sigwaited = -1;
|
|
|
|
p->p_sigctx.ps_sigwait = waitset;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Wait for signal to arrive. We can either be woken up or
|
|
|
|
* time out.
|
|
|
|
*/
|
|
|
|
error = tsleep(&p->p_sigctx.ps_sigwait, PPAUSE|PCATCH, "sigwait", timo);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check if a signal from our wait set has arrived, or if it
|
|
|
|
* was mere wakeup.
|
|
|
|
*/
|
|
|
|
if (!error) {
|
|
|
|
if ((signum = p->p_sigctx.ps_sigwaited) <= 0) {
|
|
|
|
/* wakeup via _lwp_wakeup() */
|
|
|
|
error = ECANCELED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On error, clear sigwait indication. psignal1() sets it
|
|
|
|
* in !error case.
|
|
|
|
*/
|
|
|
|
if (error) {
|
|
|
|
p->p_sigctx.ps_sigwaited = 0;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the sleep was interrupted (either by signal or wakeup),
|
|
|
|
* update the timeout and copyout new value back.
|
|
|
|
* It would be used when the syscall would be restarted
|
|
|
|
* or called again.
|
|
|
|
*/
|
|
|
|
if (timo && (error == ERESTART || error == ECANCELED)) {
|
|
|
|
struct timeval tvnow, tvtimo;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
s = splclock();
|
|
|
|
tvnow = mono_time;
|
|
|
|
splx(s);
|
|
|
|
|
|
|
|
TIMESPEC_TO_TIMEVAL(&tvtimo, &ts);
|
|
|
|
|
|
|
|
/* compute how much time has passed since start */
|
|
|
|
timersub(&tvnow, &tvstart, &tvnow);
|
|
|
|
/* substract passed time from timeout */
|
|
|
|
timersub(&tvtimo, &tvnow, &tvtimo);
|
|
|
|
|
|
|
|
if (tvtimo.tv_sec < 0)
|
|
|
|
return (EAGAIN);
|
|
|
|
|
|
|
|
TIMEVAL_TO_TIMESPEC(&tvtimo, &ts);
|
|
|
|
|
|
|
|
/* copy updated timeout to userland */
|
|
|
|
if ((err = copyout(&ts, SCARG(uap, timeout), sizeof(ts))))
|
|
|
|
return (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If a signal from the wait set arrived, copy it to userland.
|
|
|
|
* XXX no queued signals for now
|
|
|
|
*/
|
|
|
|
if (signum > 0) {
|
|
|
|
siginfo_t si;
|
|
|
|
|
|
|
|
sig:
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
|
|
si.si_signo = signum;
|
|
|
|
si.si_code = SI_USER;
|
|
|
|
|
|
|
|
error = copyout(&si, SCARG(uap, info), sizeof(si));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
2003-01-18 13:06:22 +03:00
|
|
|
|
2000-11-05 18:37:09 +03:00
|
|
|
/*
|
|
|
|
* Returns true if signal is ignored or masked for passed process.
|
|
|
|
*/
|
|
|
|
int
|
2001-02-27 00:58:30 +03:00
|
|
|
sigismasked(struct proc *p, int sig)
|
2000-11-05 18:37:09 +03:00
|
|
|
{
|
2001-02-27 00:58:30 +03:00
|
|
|
|
2001-12-05 10:32:24 +03:00
|
|
|
return (sigismember(&p->p_sigctx.ps_sigignore, sig) ||
|
|
|
|
sigismember(&p->p_sigctx.ps_sigmask, sig));
|
2000-11-05 18:37:09 +03:00
|
|
|
}
|
2002-10-23 13:10:23 +04:00
|
|
|
|
|
|
|
static int
|
|
|
|
filt_sigattach(struct knote *kn)
|
|
|
|
{
|
|
|
|
struct proc *p = curproc;
|
|
|
|
|
|
|
|
kn->kn_ptr.p_proc = p;
|
|
|
|
kn->kn_flags |= EV_CLEAR; /* automatically set */
|
|
|
|
|
|
|
|
SLIST_INSERT_HEAD(&p->p_klist, kn, kn_selnext);
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
filt_sigdetach(struct knote *kn)
|
|
|
|
{
|
|
|
|
struct proc *p = kn->kn_ptr.p_proc;
|
|
|
|
|
|
|
|
SLIST_REMOVE(&p->p_klist, kn, knote, kn_selnext);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* signal knotes are shared with proc knotes, so we apply a mask to
|
|
|
|
* the hint in order to differentiate them from process hints. This
|
|
|
|
* could be avoided by using a signal-specific knote list, but probably
|
|
|
|
* isn't worth the trouble.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
filt_signal(struct knote *kn, long hint)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (hint & NOTE_SIGNAL) {
|
|
|
|
hint &= ~NOTE_SIGNAL;
|
|
|
|
|
|
|
|
if (kn->kn_id == hint)
|
|
|
|
kn->kn_data++;
|
|
|
|
}
|
|
|
|
return (kn->kn_data != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
const struct filterops sig_filtops = {
|
|
|
|
0, filt_sigattach, filt_sigdetach, filt_signal
|
|
|
|
};
|