Bell 32V development
[unix-history] / usr / src / slowsys / sys / sig.c
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/inode.h"
#include "../h/reg.h"
#include "../h/text.h"
#include "../h/seg.h"
#include "../h/mtpr.h"
#include "../h/page.h"
#include "../h/psl.h"
/*
* Priority for tracing
*/
#define IPCPRI PZERO
/*
* Tracing variables.
* Used to pass trace command from
* parent to child being traced.
* This data base cannot be
* shared and is locked
* per user.
*/
struct
{
int ip_lock;
int ip_req;
int *ip_addr;
int ip_data;
} ipc;
/*
* Send the specified signal to
* all processes with 'pgrp' as
* process group.
* Called by tty.c for quits and
* interrupts.
*/
signal(pgrp, sig)
register pgrp;
{
register struct proc *p;
if(pgrp == 0)
return;
for(p = &proc[0]; p < &proc[NPROC]; p++)
if(p->p_pgrp == pgrp)
psignal(p, sig);
}
/*
* Send the specified signal to
* the specified process.
*/
psignal(p, sig)
register struct proc *p;
register unsigned sig;
{
if((unsigned)sig >= NSIG)
return;
if(sig)
p->p_sig |= 1<<(sig-1);
if(p->p_pri > PUSER)
p->p_pri = PUSER;
if(p->p_stat == SSLEEP && p->p_pri > PZERO)
setrun(p);
}
/*
* Returns true if the current
* process has a signal to process.
* This is asked at least once
* each time a process enters the
* system.
* A signal does not do anything
* directly to a process; it sets
* a flag that asks the process to
* do something to itself.
*/
issig()
{
register n;
register struct proc *p;
p = u.u_procp;
while(p->p_sig) {
n = fsig(p);
if((u.u_signal[n]&1) == 0 || (p->p_flag&STRC))
return(n);
p->p_sig &= ~(1<<(n-1));
}
return(0);
}
/*
* Enter the tracing STOP state.
* In this state, the parent is
* informed and the process is able to
* receive commands from the parent.
*/
stop()
{
register struct proc *pp, *cp;
loop:
cp = u.u_procp;
if(cp->p_ppid != 1)
for (pp = &proc[0]; pp < &proc[NPROC]; pp++)
if (pp->p_pid == cp->p_ppid) {
wakeup((caddr_t)pp);
cp->p_stat = SSTOP;
swtch();
if ((cp->p_flag&STRC)==0 || procxmt())
return;
goto loop;
}
exit(fsig(u.u_procp));
}
/*
* Perform the action specified by
* the current signal.
* The usual sequence is:
* if(issig())
* psig();
*/
psig()
{
register n, p;
register struct proc *rp;
rp = u.u_procp;
if (rp->p_flag&STRC)
stop();
n = fsig(rp);
if (n==0)
return;
rp->p_sig &= ~(1<<(n-1));
if((p=u.u_signal[n]) != 0) {
u.u_error = 0;
if(n != SIGINS && n != SIGTRC)
u.u_signal[n] = 0;
sendsig(p, n);
return;
}
switch(n) {
case SIGQUIT:
case SIGINS:
case SIGTRC:
case SIGIOT:
case SIGEMT:
case SIGFPT:
case SIGBUS:
case SIGSEG:
case SIGSYS:
if(core())
n += 0200;
}
exit(n);
}
/*
* find the signal in bit-position
* representation in p_sig.
*/
fsig(p)
struct proc *p;
{
register n, i;
n = p->p_sig;
for(i=1; i<NSIG; i++) {
if(n & 1)
return(i);
n >>= 1;
}
return(0);
}
/*
* Create a core image on the file "core"
* If you are looking for protection glitches,
* there are probably a wealth of them here
* when this occurs to a suid command.
*
* It writes USIZE block of the
* user.h area followed by the entire
* data+stack segments.
*/
core()
{
register struct inode *ip;
register s;
extern schar();
u.u_error = 0;
u.u_dirp = "core";
ip = namei(schar, 1);
if(ip == NULL) {
if(u.u_error)
return(0);
ip = maknode(0666);
if (ip==NULL)
return(0);
}
if(!access(ip, IWRITE) &&
(ip->i_mode&IFMT) == IFREG &&
u.u_uid == u.u_ruid) {
itrunc(ip);
u.u_offset = 0;
u.u_base = (caddr_t)&u;
u.u_count = ctob(USIZE);
u.u_segflg = 1;
writei(ip);
s = u.u_procp->p_size - USIZE;
estabur((unsigned)0, s, (unsigned)0, 0, RO);
u.u_base = 0;
u.u_count = ctob(s);
u.u_segflg = 0;
writei(ip);
}
iput(ip);
return(u.u_error==0);
}
/*
* grow the stack to include the SP
* true return if successful.
*/
grow(sp)
unsigned sp;
{
register si, i;
register struct proc *p;
register a;
if(sp >= USRSTACK-ctob(u.u_ssize))
return(0);
si = btoc((USRSTACK-sp)) - u.u_ssize + SINCR;
if(si <= 0)
return(0);
if(estabur(u.u_tsize, u.u_dsize, u.u_ssize+si, u.u_sep, RO))
return(0);
p = u.u_procp;
expand(p->p_size+si);
a = p->p_addr + p->p_size;
for(i=u.u_ssize; i; i--) {
a--;
copyseg(a-si, a);
}
for(i=si; i; i--)
clearseg(--a);
u.u_ssize += si;
return(1);
}
/*
* sys-trace system call.
*/
ptrace()
{
register struct proc *p;
register struct a {
int req;
int pid;
int *addr;
int data;
} *uap;
uap = (struct a *)u.u_ap;
if (uap->req <= 0) {
u.u_procp->p_flag |= STRC;
return;
}
for (p=proc; p < &proc[NPROC]; p++)
if (p->p_stat==SSTOP
&& p->p_pid==uap->pid
&& p->p_ppid==u.u_procp->p_pid)
goto found;
u.u_error = ESRCH;
return;
found:
while (ipc.ip_lock)
sleep((caddr_t)&ipc, IPCPRI);
ipc.ip_lock = p->p_pid;
ipc.ip_data = uap->data;
ipc.ip_addr = uap->addr;
ipc.ip_req = uap->req;
p->p_flag &= ~SWTED;
setrun(p);
while (ipc.ip_req > 0)
sleep((caddr_t)&ipc, IPCPRI);
u.u_r.r_val1 = ipc.ip_data;
if (ipc.ip_req < 0)
u.u_error = EIO;
ipc.ip_lock = 0;
wakeup((caddr_t)&ipc);
}
int ipcreg[] = {R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, AP, FP, SP, PC};
/*
* Code that the child process
* executes to implement the command
* of the parent process in tracing.
*/
procxmt()
{
register int i;
register *p;
register struct text *xp;
if (ipc.ip_lock != u.u_procp->p_pid)
return(0);
i = ipc.ip_req;
ipc.ip_req = 0;
wakeup((caddr_t)&ipc);
switch (i) {
/* read user I */
case 1:
if ( !useracc((caddr_t)ipc.ip_addr, 4, 1))
goto error;
ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
break;
/* read user D */
case 2:
if ( !useracc((caddr_t)ipc.ip_addr, 4, 1))
goto error;
ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
break;
/* read u */
case 3:
i = (int)ipc.ip_addr;
if (i<0 || i >= ctob(USIZE))
goto error;
ipc.ip_data = ((physadr)&u)->r[i>>2];
break;
/* write user I */
/* Must set up to allow writing */
case 4:
/*
* If text, must assure exclusive use
*/
if (xp = u.u_procp->p_textp) {
if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
goto error;
xp->x_iptr->i_flag &= ~ITEXT;
}
estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RW);
i = suiword((caddr_t)ipc.ip_addr, 0);
suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep, RO);
if (i<0)
goto error;
if (xp)
xp->x_flag |= XWRIT;
break;
/* write user D */
case 5:
if (suword((caddr_t)ipc.ip_addr, 0) < 0)
goto error;
suword((caddr_t)ipc.ip_addr, ipc.ip_data);
break;
/* write u */
case 6:
i = (int)ipc.ip_addr;
p = (int *)&((physadr)&u)->r[i>>2];
for (i=0; i<16; i++)
if (p == &u.u_ar0[ipcreg[i]])
goto ok;
if (p == &u.u_ar0[PS]) {
ipc.ip_data |= 0x3c00000; /* modes == user */
ipc.ip_data &= ~0x3c20ff00; /* IS, FPD, ... */
goto ok;
}
goto error;
ok:
*p = ipc.ip_data;
break;
/* set signal and continue */
/* one version causes a trace-trap */
case 9:
u.u_ar0[PS] |= PSL_T;
case 7:
if ((int)ipc.ip_addr != 1)
u.u_ar0[PC] = (int)ipc.ip_addr;
u.u_procp->p_sig = 0;
if (ipc.ip_data)
psignal(u.u_procp, ipc.ip_data);
return(1);
/* force exit */
case 8:
exit(fsig(u.u_procp));
default:
error:
ipc.ip_req = -1;
}
return(0);
}