BBN-V6/ken/sys1.c
#
/*
*/
#include "../h/param.h"
#include "../h/systm.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/buf.h"
#include "../h/reg.h"
#include "../h/inode.h"
#include "../h/file.h" /* rand:bobg for eofp call */
/*
* exec system call.
* Because of the fact that an I/O buffer is used
* to store the caller's arguments during exec,
* and more buffers are needed to read in the text file,
* deadly embraces waiting for free buffers are possible.
* Therefore the number of processes simultaneously
* running in exec has to be limited to NEXEC.
*/
#define EXPRI -1
exec()
{
int ap, na, nc, *bp;
int ts, ds, sep, ss;
int overlay, entloc;
int a; /* temporary address for malloc */
struct proc *pptr;
register c, *ip;
register char *cp;
extern uchar;
/*
* pick up file names
* and check various modes
* for execute permission
*/
ip = namei(&uchar, 0);
if(ip == NULL)
return;
while(execnt >= NEXEC)
sleep(&execnt, EXPRI);
execnt++;
bp = getblk(NODEV);
if(access(ip, IEXEC))
goto bad;
if((ip->i_mode & IFMT) != 0 ||
(ip->i_mode & (IEXEC|(IEXEC>>3)|(IEXEC>>6))) == 0) {
u.u_error = EACCES;
goto bad;
}
/*
* pack up arguments into
* allocated disk buffer
*/
cp = bp->b_addr;
na = 0;
nc = 0;
if (u.u_arg[1]) { /* BBN:cdh from Bell diff list */
while(ap = fuword(u.u_arg[1])) {
na++;
if(ap == -1)
goto bad;
u.u_arg[1] =+ 2;
for(;;) {
c = fubyte(ap++);
if(c == -1)
goto bad;
*cp++ = c;
nc++;
if(nc > 510) {
u.u_error = E2BIG;
goto bad;
}
if(c == 0)
break;
}
}
}
if((nc&1) != 0) {
*cp++ = 0;
nc++;
}
/*
* read in first 8 bytes
* of file for segment
* sizes:
* w0 = 407/410/411 (410 implies RO text) (411 implies sep ID)
* (405 implies overlay).
* w1 = text size
* w2 = data size
* w3 = bss size
*/
/*
* Read in entry location for later use.
* BBN: cdh
*/
u.u_base = &u.u_arg[0];
u.u_count = 2;
u.u_offset[1] = 10;
u.u_offset[0] = 0;
u.u_segflg = 1;
readi(ip);
u.u_segflg = 0;
if (u.u_error)
goto bad;
entloc = u.u_arg[0];
u.u_base = &u.u_arg[0];
u.u_count = 8;
u.u_offset[1] = 0;
u.u_offset[0] = 0;
u.u_segflg = 1;
readi(ip);
u.u_segflg = 0;
if(u.u_error)
goto bad;
sep = 0;
overlay = 0;
if(u.u_arg[0] == 0407) {
u.u_arg[2] =+ u.u_arg[1];
u.u_arg[1] = 0;
} else
if(u.u_arg[0] == 0411)
sep++; else
if(u.u_arg[0] == 0405)
overlay++; else
if(u.u_arg[0] != 0410) {
u.u_error = ENOEXEC;
goto bad;
}
if(u.u_arg[1]!=0 && (ip->i_flag&ITEXT)==0 && ip->i_count!=1) {
u.u_error = ETXTBSY;
goto bad;
}
/*
* find text and data sizes
* try them out for possible
* exceed of max sizes
*/
ts = ((u.u_arg[1]+63)>>6) & 01777;
ds = ((u.u_arg[2]+u.u_arg[3]+63)>>6) & 01777;
ss = SSIZE;
if (overlay) { /* BBN:cdh implementation of 405 overlays */
if (u.u_sep==0 && ((ts+127)>>7) != ((u.u_tsize+127)>>7)) {
u.u_error = ENOMEM;
goto bad;
}
pptr = u.u_procp;
c = pptr->p_size; /* save swappable size in clicks */
ds = u.u_dsize;
ss = u.u_ssize;
sep = u.u_sep;
/*
* The strategy here is the following:
* 1) Allocate swap space.
* 2) Swap data space out.
* 3) Get new text segment.
* 4) Reallocate data space.
* 5) Read in data space from swap.
* 6) Free swap space.
*/
a = malloc(swapmap, (c-USIZE+7)/8); /* allocate swap area */
if (a==NULL) {
printf("No room for overlay swap; killed proc\n");
psignal(pptr, SIGKIL);
return;
}
/*
* swap data space out.
*/
pptr->p_flag =| SLOCK;
if (swap(a,pptr->p_addr+USIZE,c-USIZE,0)) {
pptr->p_flag =& ~SLOCK;
printf("Swap write error on overlay, killed proc\n");
mfree(swapmap,(c-USIZE+7)/8,a);
psignal(pptr,SIGKIL);
return;
}
pptr->p_flag =& ~SLOCK;
/*
* get new text segment.
*/
expand(USIZE);
xfree();
xalloc(ip);
expand(c);
/*
* read data space back from swap.
*/
pptr->p_flag =| SLOCK;
if (swap(a,pptr->p_addr+USIZE,c-USIZE,1)) {
pptr->p_flag =& ~SLOCK;
printf("Swap read error on overlay, killed proc\n");
mfree(swapmap,(c-USIZE+7)/8,a);
psignal(pptr,SIGKIL);
return;
}
pptr->p_flag =& ~SLOCK;
/*
* free swap space allocated.
*/
mfree(swapmap,(c-USIZE+7)/8,a);
u.u_ar0[R7] = entloc & ~01; /* make sure even */
}
else {
if(estabur(ts, ds, SSIZE, sep))
goto bad;
/*
* allocate and clear core
* at this point, committed
* to the new image
*/
u.u_prof[3] = 0;
xfree();
expand(USIZE);
xalloc(ip);
c = USIZE+ds+SSIZE;
expand(c);
while(--c >= USIZE)
clearseg(u.u_procp->p_addr+c);
/*
* read in data segment
*/
estabur(0, ds, 0, 0);
u.u_base = 0;
u.u_offset[1] = 020+u.u_arg[1];
u.u_count = u.u_arg[2];
readi(ip);
}
/*
* initialize stack segment
*/
u.u_tsize = ts;
u.u_dsize = ds;
u.u_ssize = ss;
u.u_sep = sep;
estabur(u.u_tsize, u.u_dsize, u.u_ssize, u.u_sep);
if (overlay) goto bad; /* don't want to do any of this stuff */
cp = bp->b_addr;
ap = -nc - na*2 - 4;
u.u_ar0[R6] = ap;
suword(ap, na);
c = -nc;
while(na--) {
suword(ap=+2, c);
do
subyte(c++, *cp);
while(*cp++);
}
suword(ap+2, -1);
/*
* set SUID/SGID protections, if no tracing
*/
if ((u.u_procp->p_flag&STRC)==0) {
if(ip->i_mode&ISUID)
if(u.u_uid != 0) {
u.u_uid = ip->i_uid;
u.u_procp->p_uid = ip->i_uid;
}
if(ip->i_mode&ISGID)
u.u_gid = ip->i_gid;
}
/*
* clear sigs, regs and return
*/
c = ip;
for(ip = &u.u_signal[0]; ip < &u.u_signal[NSIG]; ip++)
if((*ip & 1) == 0)
*ip = 0;
for(cp = ®loc[0]; cp < ®loc[6];)
u.u_ar0[*cp++] = 0;
u.u_ar0[R7] = entloc & ~01; /* make sure even BBN:cdh */
for(ip = &u.u_fsav[0]; ip < &u.u_fsav[25];)
*ip++ = 0;
ip = c;
bad:
iput(ip);
#ifdef BUFMOD
brelse(bp,&bfreelist);
#endif BUFMOD
#ifndef BUFMOD
brelse(bp);
#endif BUFMOD
if(execnt >= NEXEC)
wakeup(&execnt);
execnt--;
}
/*
* exit system call:
* pass back caller's r0
*/
rexit()
{
u.u_arg[0] = u.u_ar0[R0] << 8;
exit();
}
/*
* Release resources.
* Save u. area for parent to look at.
* Enter zombie state.
* Wake up parent and init processes,
* and dispose of children.
*
* Modified 1/78 (BBN:jfh) to call awtdis to clear process' entries
*
*/
exit()
{
register int *q, a;
register struct proc *p;
#ifdef LCBA
rel_lcba();
#endif
p = u.u_procp;
p->p_flag =& ~STRC;
p->p_clktim = 0;
for(q = &u.u_signal[0]; q < &u.u_signal[NSIG];)
*q++ = 1;
awtdis(-1); /* clear any enabled file descriptors */
for(q = &u.u_ofile[0]; q < &u.u_ofile[NOFILE]; q++)
if(a = *q) {
*q = NULL;
closef(a);
}
plock(u.u_cdir); /* BBN:cdh improved locking */
iput(u.u_cdir);
xfree();
a = malloc(swapmap, 1);
if(a == NULL)
panic("out of swap");
p = getblk(swapdev, a);
bcopy(&u, p->b_addr, 256);
bwrite(p);
q = u.u_procp;
mfree(coremap, q->p_size, q->p_addr);
q->p_addr = a;
q->p_stat = SZOMB;
loop:
for(p = &proc[0]; p <= MAXPROC; p++)
if(q->p_ppid == p->p_pid) {
wakeup(&proc[1]);
wakeup(p);
for(p = &proc[0]; p <= MAXPROC; p++)
if(q->p_pid == p->p_ppid) {
p->p_ppid = 1;
if (p->p_stat == SSTOP)
setrun(p);
}
swtch();
/* no return */
}
q->p_ppid = 1;
goto loop;
}
/*
* Wait system call.
* Search for a terminated (zombie) child,
* finally lay it to rest, and collect its status.
* Look also for stopped (traced) children,
* and pass back status from them.
*/
wait()
{ wait1(0);
}
/*
* Waitr system call.
* Same as wait but returns accounting information.
*/
waitr()
{ wait1(1);
}
wait1(flag)
int flag;
{
register f, *bp;
register struct proc *p;
struct proc *mproc;
int *pp;
f = 0;
loop:
for(p = &proc[0]; p <= MAXPROC; p++)
if(p->p_ppid == u.u_procp->p_pid) {
f++;
if(p->p_stat == SZOMB) {
u.u_ar0[R0] = p->p_pid;
bp = bread(swapdev, f=p->p_addr);
mfree(swapmap, 1, f);
p->p_stat = NULL;
p->p_ppid = 0;
p->p_sig = 0;
p->p_pgrp = 0;
p->p_flag = 0;
/* enter process back into the free list */
cqenter( &Free_proc,p );
for( mproc = &proc[NPROC-1]; mproc >= &proc[0]; mproc-- )
if( mproc->p_stat )
{
MAXPROC = mproc;
break;
}
p = bp->b_addr;
u.u_cstime[0] =+ p->u_cstime[0];
dpadd(u.u_cstime, p->u_cstime[1]);
u.u_cstime[0] =+ p->u_stime[0];
dpadd(u.u_cstime, p->u_stime[1]);
u.u_cutime[0] =+ p->u_cutime[0];
dpadd(u.u_cutime, p->u_cutime[1]);
u.u_cutime[0] =+ p->u_utime[0];
dpadd(u.u_cutime, p->u_utime[1]);
u.u_tio[0] =+ p->u_tio[0];
dpadd(u.u_tio, p->u_tio[1]);
u.u_mem1[0] =+ p->u_mem1[0];
dpadd(u.u_mem1, p->u_mem1[1]);
u.u_mem2[0] =+ p->u_mem2[0];
dpadd(u.u_mem2, p->u_mem2[1]);
u.u_io[0] =+ p->u_io[0];
dpadd(u.u_io, p->u_io[1]);
u.u_ar0[R1] = p->u_arg[0];
if (flag) /* if waitr, return statistics */
{ suword(u.u_arg[0],p->u_ruid);
u.u_arg[0] =+ 2;
for(pp = &p->u_utime[0]; pp <= &p->u_io[1];)
{ suword(u.u_arg[0], *pp++);
u.u_arg[0] =+ 2;
}
}
#ifdef BUFMOD
brelse(bp,&bfreelist);
#endif BUFMOD
#ifndef BUFMOD
brelse(bp);
#endif BUFMOD
return;
}
if(p->p_stat == SSTOP) {
if((p->p_flag&SWTED) == 0) {
p->p_flag =| SWTED;
u.u_ar0[R0] = p->p_pid;
u.u_ar0[R1] = (p->p_sig<<8) | 0177;
return;
}
/*
* This change is to avoid finding
* ptrace'd procs that are already
* stopped when doing the wait.
* BBN:cdh 1 May 79
*/
f--; /* Seen stopped proc's don't count */
}
}
if(f) {
sleep(u.u_procp, PWAIT);
goto loop;
}
u.u_error = ECHILD;
}
/*
* The following was added by rand:bobg. Sfork is identical to fork
* except that it sets the SNOSIG flag in the child inhibiting signals
* from the teletype.
*/
sfork()
{
fork1(1);
}
fork()
{
fork1(0);
}
/*
* fork system call. (Changed to fork1 by rand:bobg.)
*/
fork1(sflag)
{
register struct proc *p1, *p2;
register int *pp;
p1 = u.u_procp;
/* is queue empty */
if( Free_proc.qhead )
{
p2 = (Free_proc.qhead)->qlink; /* get first in queue */
goto found;
}
u.u_error = EAGAIN;
goto out;
found:
if(newproc()) {
u.u_ar0[R0] = p1->p_pid;
for(pp = &u.u_utime[0]; pp <= &u.u_io[1];) *pp++ = 0;
u.u_tim1[0] = time[0]; /* set beginning time of process */
u.u_tim1[1] = time[1];
if (sflag) u.u_procp->p_flag =| SNOSIG;
/* rand:bobg--set NOSIG flag in child if an sfork */
return;
}
u.u_ar0[R0] = p2->p_pid;
out:
u.u_ar0[R7] =+ 2;
}
/*
* ztime system call.
* kludge stuck in for accounting -
* zeroes accounting information fields and reset process beginning time;
* used by login program
*/
ztime()
{
register int *pp;
if(suser()) {
for(pp = &u.u_utime[0]; pp <= &u.u_io[1];) *pp++ = 0;
u.u_tim1[0] = time[0];
u.u_tim1[1] = time[1];
}
}
/*
* break system call.
* -- bad planning: "break" is a dirty word in C.
*/
sbreak()
{
register a, n, d;
int i;
/*
* set n to new data size
* set d to new-old
* set n to new total size
*/
n = (((u.u_arg[0]+63)>>6) & 01777);
if(!u.u_sep)
n =- nseg(u.u_tsize) * 128;
if(n < 0)
n = 0;
d = n - u.u_dsize;
n =+ USIZE+u.u_ssize;
if(estabur(u.u_tsize, u.u_dsize+d, u.u_ssize, u.u_sep))
return;
u.u_dsize =+ d;
if(d > 0)
goto bigger;
a = u.u_procp->p_addr + n - u.u_ssize;
i = n;
n = u.u_ssize;
while(n--) {
copyseg(a-d, a);
a++;
}
expand(i);
return;
bigger:
expand(n);
a = u.u_procp->p_addr + n;
n = u.u_ssize;
while(n--) {
a--;
copyseg(a-d, a);
}
while(d--)
clearseg(--a);
}
/*
* gprocs system call (rand:bobg)
* copies proc table into buffer supplied by user
* returns size of proc table
*/
gprocs()
{
register int p;
if ((p = u.u_ar0[R0]) & 1) /* get addr of buffer from R0 */
{ /* won't allow odd address */
u.u_error = EINVAL;
return;
}
if (p) copyout(&proc[0],p,sizeof(proc));
/* if adr not 0, copyout proc tbl to user */
u.u_ar0[R0] = NPROC; /* return NPROC as value in any case */
}
/*
* eofp system call (rand:bobg)
* write an end-of-file on a pipe
*/
eofpipe()
{
register int *p;
p = getf(u.u_ar0[R0]); /* get file desc from r0 */
if (p == NULL) return; /* couldn't */
if (!(p->f_flag & FPIPE) || !(p->f_flag & FWRITE))
return(u.u_error = EBADF); /* must be the write end of a pipe */
eofp(p->f_inode); /* call eof code on the inode */
}