* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)kern_sig.c 7.11 (Berkeley) %G%
#include "syscontext.h" /* XXX */
#include "machine/mtpr.h"
#define stopsigmask (sigmask(SIGSTOP)|sigmask(SIGTSTP)| \
sigmask(SIGTTIN)|sigmask(SIGTTOU))
#define defaultignmask (sigmask(SIGCONT)|sigmask(SIGIO)|sigmask(SIGURG)| \
sigmask(SIGCHLD)|sigmask(SIGWINCH)|sigmask(SIGINFO))
* Can the current process (u.u_procp) send the specified signal
* to the specified process?
#define CANSIGNAL(p, signo) \
u.u_uid == (p)->p_uid || u.u_uid == (p)->p_ruid || \
u.u_procp->p_ruid == (p)->p_uid || \
u.u_procp->p_ruid == (p)->p_ruid || \
((signo) == SIGCONT && (p)->p_session == u.u_procp->p_session))
} *uap
= (struct a
*)u
.u_ap
;
register struct sigaction
*sa
;
if (sig
<= 0 || sig
>= NSIG
|| sig
== SIGKILL
|| sig
== SIGSTOP
)
sa
->sa_handler
= u
.u_signal
[sig
];
sa
->sa_mask
= u
.u_sigmask
[sig
];
if ((u
.u_sigonstack
& bit
) != 0)
sa
->sa_flags
|= SA_ONSTACK
;
if ((u
.u_sigintr
& bit
) == 0)
sa
->sa_flags
|= SA_RESTART
;
if (u
.u_procp
->p_flag
& SNOCLDSTOP
)
sa
->sa_flags
|= SA_NOCLDSTOP
;
if (error
= copyout((caddr_t
)sa
, (caddr_t
)uap
->osa
,
if (error
= copyin((caddr_t
)uap
->nsa
, (caddr_t
)sa
,
register struct sigaction
*sa
;
* Change setting atomically.
u
.u_signal
[sig
] = sa
->sa_handler
;
u
.u_sigmask
[sig
] = sa
->sa_mask
&~ sigcantmask
;
if ((sa
->sa_flags
& SA_RESTART
) == 0)
if (sa
->sa_flags
& SA_ONSTACK
)
if (sa
->sa_flags
& SA_NOCLDSTOP
)
p
->p_flag
&= ~SNOCLDSTOP
;
* 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
||
(bit
& defaultignmask
&& sa
->sa_handler
== SIG_DFL
)) {
p
->p_sig
&= ~bit
; /* never to be seen again */
p
->p_sigignore
|= bit
; /* easier in psignal */
if (sa
->sa_handler
== SIG_DFL
)
* Initialize signal state for process 0;
* set to ignore signals that are ignored by default.
p
->p_sigignore
= defaultignmask
&~ sigmask(SIGCONT
);
* Reset signals for an exec of the specified process.
* Reset caught signals. Held signals remain held
* through p_sigmask (unless they were caught,
* and are now ignored by default).
nc
= ffs((long)p
->p_sigcatch
);
if (mask
& defaultignmask
) {
u
.u_signal
[nc
] = SIG_DFL
;
* Reset stack state to the user stack.
* Clear set of signals caught on the signal stack.
* Manipulate signal mask.
* Note that we receive new mask, not pointer,
* and return old mask as return value;
* the library stub does the rest.
} *uap
= (struct a
*)u
.u_ap
;
register struct proc
*p
= u
.u_procp
;
u
.u_r
.r_val1
= p
->p_sigmask
;
p
->p_sigmask
|= uap
->mask
&~ sigcantmask
;
p
->p_sigmask
&= ~uap
->mask
;
p
->p_sigmask
= uap
->mask
&~ sigcantmask
;
u
.u_r
.r_val1
= u
.u_procp
->p_sig
;
* Generalized interface signal handler, 4.3-compatible.
} *uap
= (struct a
*)u
.u_ap
;
register struct sigvec
*sv
;
if (sig
<= 0 || sig
>= NSIG
|| sig
== SIGKILL
|| sig
== SIGSTOP
)
*(sig_t
*)&sv
->sv_handler
= u
.u_signal
[sig
];
sv
->sv_mask
= u
.u_sigmask
[sig
];
if ((u
.u_sigonstack
& bit
) != 0)
sv
->sv_flags
|= SV_ONSTACK
;
if ((u
.u_sigintr
& bit
) != 0)
sv
->sv_flags
|= SV_INTERRUPT
;
if (u
.u_procp
->p_flag
& SNOCLDSTOP
)
sv
->sv_flags
|= SA_NOCLDSTOP
;
if (error
= copyout((caddr_t
)sv
, (caddr_t
)uap
->osv
,
if (error
= copyin((caddr_t
)uap
->nsv
, (caddr_t
)sv
,
sv
->sv_flags
^= SA_RESTART
; /* opposite of SV_INTERRUPT */
} *uap
= (struct a
*)u
.u_ap
;
register struct proc
*p
= u
.u_procp
;
u
.u_r
.r_val1
= p
->p_sigmask
;
p
->p_sigmask
|= uap
->mask
&~ sigcantmask
;
} *uap
= (struct a
*)u
.u_ap
;
register struct proc
*p
= u
.u_procp
;
u
.u_r
.r_val1
= p
->p_sigmask
;
p
->p_sigmask
= uap
->mask
&~ sigcantmask
;
* 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.
} *uap
= (struct a
*)u
.u_ap
;
register struct proc
*p
= u
.u_procp
;
* 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 proc structure
* to indicate this (should be in u.).
u
.u_oldmask
= p
->p_sigmask
;
p
->p_sigmask
= uap
->mask
&~ sigcantmask
;
sleep((caddr_t
)&u
, PSLEP
);
} *uap
= (struct a
*)u
.u_ap
;
if (uap
->oss
&& (error
= copyout((caddr_t
)&u
.u_sigstack
,
(caddr_t
)uap
->oss
, sizeof (struct sigstack
))))
if (uap
->nss
&& (error
= copyin((caddr_t
)uap
->nss
, (caddr_t
)&ss
,
} *uap
= (struct a
*)u
.u_ap
;
if ((unsigned) uap
->signo
>= NSIG
)
/* kill single process */
if (!CANSIGNAL(p
, uap
->signo
))
case -1: /* broadcast signal */
RETURN (killpg1(uap
->signo
, 0, 1));
case 0: /* signal own process group */
RETURN (killpg1(uap
->signo
, 0, 0));
default: /* negative explicit process group */
RETURN (killpg1(uap
->signo
, -uap
->pid
, 0));
} *uap
= (struct a
*)u
.u_ap
;
if ((unsigned) uap
->signo
>= NSIG
)
RETURN (killpg1(uap
->signo
, uap
->pgid
, 0));
killpg1(signo
, pgid
, all
)
int f
= 0, error
= ESRCH
;
for (p
= allproc
; p
!= NULL
; p
= p
->p_nxt
) {
if (p
->p_ppid
== 0 || p
->p_flag
&SSYS
||
p
== u
.u_procp
|| !CANSIGNAL(p
, signo
))
* zero pgid means send to my process group.
pgrp
= u
.u_procp
->p_pgrp
;
for (p
= pgrp
->pg_mem
; p
!= NULL
; p
= p
->p_pgrpnxt
) {
if (p
->p_ppid
== 0 || p
->p_flag
&SSYS
||
* Send the specified signal to
* all processes with 'pgid' as
if (pgid
&& (pgrp
= pgfind(pgid
)))
for (p
= pgrp
->pg_mem
; p
; p
= p
->p_pgrpnxt
)
* 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.
register struct proc
*p
= u
.u_procp
;
if ((p
->p_flag
& STRC
) == 0 && (p
->p_sigcatch
& mask
) != 0 &&
(p
->p_sigmask
& mask
) == 0) {
sendsig(u
.u_signal
[sig
], sig
, p
->p_sigmask
, code
);
p
->p_sigmask
|= u
.u_sigmask
[sig
] | mask
;
u
.u_arg
[1] = code
; /* XXX for core dump/debugger */
* Send the specified signal to
if ((unsigned)sig
>= NSIG
|| sig
== 0)
if (p
->p_pgrp
->pg_jobc
== 0 &&
(sig
== SIGTTIN
|| sig
== SIGTTOU
|| sig
== SIGTSTP
))
* If proc is traced, always give parent a chance.
* If the signal is being ignored,
* then we forget about it immediately.
* (Note: we don't set SIGCONT in p_sigignore,
* and if it is set to SIG_IGN,
* action will be SIG_DFL here.)
if (p
->p_sigignore
& mask
)
else if (p
->p_sigcatch
& mask
)
if ((p
->p_flag
&STRC
) || action
!= SIG_DFL
)
p
->p_sig
&= ~stopsigmask
;
p
->p_sig
&= ~sigmask(SIGCONT
);
* Defer further processing for signals which are held,
* except that stopped processes must be continued by SIGCONT.
if (action
== SIG_HOLD
&& (sig
!= SIGCONT
|| p
->p_stat
!= SSTOP
))
* If process is sleeping at negative priority
* we can't interrupt the sleep... the signal will
* be noticed when the process returns through
* Process is sleeping and traced... make it runnable
* so it can discover the signal in issig() and stop
* When a sleeping process receives a stop
* signal, process immediately if possible.
* All other (caught or default) signals
* cause the process to run.
if (mask
& stopsigmask
) {
* If a child in vfork(), stopping could
if ((p
->p_pptr
->p_flag
& SNOCLDSTOP
) == 0)
psignal(p
->p_pptr
, SIGCHLD
);
* If traced process is already stopped,
* then no further action is necessary.
* Kill signal always sets processes running.
* If SIGCONT is default (or ignored), we continue
* the process but don't leave the signal in p_sig,
* as it has no further action. If SIGCONT is held,
* continue the process and leave the signal in p_sig.
* 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.
p
->p_cursig
= 0; /* ??? XXX */
* Already stopped, don't need to stop again.
* (If we did the shell could get confused.)
p
->p_sig
&= ~mask
; /* take it away */
* If process is sleeping interruptibly, then
* unstick it so that when it is continued
* it can look at the signal.
* But don't setrun the process as its not to
* be unstopped by the signal alone.
if (p
->p_wchan
&& p
->p_pri
> PZERO
)
* SRUN, SIDL, SZOMB do nothing with the signal,
* other than kicking ourselves if we are running.
* It will either never be noticed, or noticed very soon.
if (p
== u
.u_procp
&& !noproc
)
* Raise priority to at least PUSER.
* Returns true if the current
* process has a signal to process.
* The signal to process is put in p_cursig.
* This is asked at least once each time a process enters the
* system (though this can usually be done without actually
* calling issig by checking the pending signal masks.)
* Most signals do not do anything
* directly to a process; they set
* a flag that asks the process to
* do something to itself.
mask
= p
->p_sig
&~ p
->p_sigmask
;
p
->p_sig
&= ~mask
; /* take the signal! */
if (mask
& p
->p_sigignore
&& (p
->p_flag
&STRC
) == 0)
continue; /* only if STRC was on when posted */
if (p
->p_flag
&STRC
&& (p
->p_flag
&SVFORK
) == 0) {
* If traced, always stop, and stay
* stopped until released by the parent.
psignal(p
->p_pptr
, SIGCHLD
);
} while (!procxmt() && p
->p_flag
&STRC
);
* If the traced bit got turned off,
* then put the signal taken above back into p_sig
* and go back up to the top to rescan signals.
* This ensures that p_sig* and u_signal are consistent.
if ((p
->p_flag
&STRC
) == 0) {
* If parent wants us to take the signal,
* then it will leave it in p->p_cursig;
* otherwise we just look for signals again.
* If signal is being masked put it back
* into p_sig and look for other signals.
if (p
->p_sigmask
& mask
) {
switch ((int)u
.u_signal
[sig
]) {
* Don't take default actions on system processes.
if (mask
& stopsigmask
) {
if ((p
->p_pptr
->p_flag
& SNOCLDSTOP
) == 0)
psignal(p
->p_pptr
, SIGCHLD
);
} else if (mask
& defaultignmask
) {
* Except for SIGCONT, shouldn't get here.
* Default action is to ignore; drop it.
continue; /* == ignore */
* Masking above should prevent us ever trying
* to take action on an ignored signal other
* than SIGCONT, unless process is traced.
if (sig
!= SIGCONT
&& (p
->p_flag
&STRC
) == 0)
* This signal has an action, let
* Didn't find a signal to send.
* Let psig process the signal.
* Put the argument process into the stopped
* state and notify the parent via wakeup.
* Signals are handled elsewhere.
wakeup((caddr_t
)p
->p_pptr
);
* Perform the action specified by
* if (p->p_cursig || ISSIG(p))
* The signal bit has already been cleared by issig,
* and the current signal number stored in p->p_cursig.
register struct proc
*p
= u
.u_procp
;
action
= u
.u_signal
[sig
];
if (action
== SIG_IGN
|| (p
->p_sigmask
& mask
))
* Set the new mask value and also defer further
* occurences of this signal.
* 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.
if (p
->p_flag
& SOMASK
) {
returnmask
= u
.u_oldmask
;
returnmask
= p
->p_sigmask
;
p
->p_sigmask
|= u
.u_sigmask
[sig
] | mask
;
sendsig(action
, sig
, returnmask
, 0);
exit(W_EXITCODE(0, sig
));
* Create a core image on the file "core".
* It writes UPAGES block of the
* user.h area followed by the entire
register struct vnode
*vp
;
register struct proc
*p
= u
.u_procp
;
register struct nameidata
*ndp
= &u
.u_nd
;
if (p
->p_svuid
!= p
->p_ruid
|| p
->p_svgid
!= p
->p_rgid
)
if (ctob(UPAGES
+ u
.u_dsize
+ u
.u_ssize
) >=
u
.u_rlimit
[RLIMIT_CORE
].rlim_cur
)
VOP_LOCK(p
->p_textp
->x_vptr
);
error
= VOP_ACCESS(p
->p_textp
->x_vptr
, VREAD
, u
.u_cred
);
VOP_UNLOCK(p
->p_textp
->x_vptr
);
ndp
->ni_segflg
= UIO_SYSSPACE
;
if (error
= vn_open(ndp
, FCREAT
|FWRITE
, 0644))
if (vp
->v_type
!= VREG
||
VOP_GETATTR(vp
, &vattr
, u
.u_cred
) ||
/* unmap funky devices in the user's address space */
for (fd
= 0; fd
< u
.u_lastfile
; fd
++)
if (u
.u_ofile
[fd
] && (u
.u_pofile
[fd
] & UF_MAPPED
))
VOP_SETATTR(vp
, &vattr
, u
.u_cred
);
error
= vn_rdwr(UIO_WRITE
, vp
, (caddr_t
)&u
, ctob(UPAGES
), (off_t
)0,
UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, ndp
->ni_cred
, (int *)0);
error
= vn_rdwr(UIO_WRITE
, vp
,
(caddr_t
)ctob(dptov(p
, 0)),
(int)ctob(u
.u_dsize
), (off_t
)ctob(UPAGES
), UIO_USERSPACE
,
IO_NODELOCKED
|IO_UNIT
, ndp
->ni_cred
, (int *)0);
error
= vn_rdwr(UIO_WRITE
, vp
,
(caddr_t
)ctob(sptov(p
, u
.u_ssize
- 1)),
(off_t
)ctob(UPAGES
) + ctob(u
.u_dsize
), UIO_USERSPACE
,
IO_NODELOCKED
|IO_UNIT
, ndp
->ni_cred
, (int *)0);
* Nonexistent system call-- signal process (may want to handle it).
* Flag error in case process won't see signal immediately (blocked or ignored).
psignal(u
.u_procp
, SIGSYS
);