/* @(#)sys4.c	1.5 */#include "sys/param.h"#include "sys/config.h"#include "sys/mmu.h"#include "sys/types.h"#include "sys/sysmacros.h"#include "sys/systm.h"#include "sys/dir.h"#include "sys/signal.h"#include "sys/user.h"#include "sys/errno.h"#include "sys/inode.h"#include "sys/file.h"#include "sys/filsys.h"#include "sys/proc.h"#include "sys/var.h"/* * Everything in this file is a routine implementing a system call. */gtime(){	u.u_rtime = time;}stime(){	register struct a {		time_t	time;	} *uap;	struct filsys *fp;	uap = (struct a *)u.u_ap;	if (suser()) {		logtchg(uap->time);		time = uap->time;		if (fp = getfs(rootdev))			fp->s_fmod = 1;	}}setuid(){	register unsigned uid;	register struct a {		int	uid;	} *uap;	register struct user *up;	up = &u;	uap = (struct a *)up->u_ap;	uid = uap->uid;	if (uid >= MAXUID) {		up->u_error = EINVAL;		return;	}	if (uid && (uid == up->u_ruid || uid == up->u_procp->p_suid))		up->u_uid = uid;	else if (suser()) {		up->u_uid = uid;		up->u_procp->p_uid = uid;		up->u_procp->p_suid = uid;		up->u_ruid = uid;	}}getuid(){	register struct user *up;	up = &u;	up->u_rval1 = up->u_ruid;	up->u_rval2 = up->u_uid;}setgid(){	register unsigned gid;	register struct a {		int	gid;	} *uap;	register struct user *up;	up = &u;	uap = (struct a *)up->u_ap;	gid = uap->gid;	if (gid >= MAXUID) {		up->u_error = EINVAL;		return;	}	if (up->u_rgid == gid || suser()) {		up->u_gid = gid;		up->u_rgid = gid;	}}getgid(){	register struct user *up;	up = &u;	up->u_rval1 = up->u_rgid;	up->u_rval2 = up->u_gid;}getpid(){	register struct user *up;	up = &u;	up->u_rval1 = up->u_procp->p_pid;	up->u_rval2 = up->u_procp->p_ppid;}setpgrp(){	register struct proc *p = u.u_procp;	register struct a {		int	flag;	} *uap;	uap = (struct a *)u.u_ap;	if (uap->flag) {		if (p->p_pgrp != p->p_pid)			u.u_ttyp = NULL;		p->p_pgrp = p->p_pid;	}	u.u_rval1 = p->p_pgrp;}sync(){	update();}nice(){	register n;	register struct a {		int	niceness;	} *uap;	register struct user *up;	up = &u;	uap = (struct a *)up->u_ap;	n = uap->niceness;	if ((n < 0 || n > 2*NZERO) && !suser())		n = 0;	n += up->u_procp->p_nice;	if (n >= 2*NZERO)		n = 2*NZERO -1;	if (n < 0)		n = 0;	up->u_procp->p_nice = n;	up->u_rval1 = n - NZERO;}/* * Unlink system call. * Hard to avoid races here, especially * in unlinking directories. */unlink(){	register struct inode *ip, *pp;	struct a {		char	*fname;	};	register struct user *up;	up = &u;	pp = namei(uchar, 2);	if (pp == NULL)		return;	/*	 * Check for unlink(".")	 * to avoid hanging on the iget	 */	if (pp->i_number == up->u_dent.d_ino) {		ip = pp;		ip->i_count++;	} else		ip = iget(pp->i_dev, up->u_dent.d_ino);	if (ip == NULL)		goto out1;	if ((ip->i_mode&IFMT) == IFDIR && !suser())		goto out;	/*	 * Don't unlink a mounted file.	 */	if (ip->i_dev != pp->i_dev) {		up->u_error = EBUSY;		goto out;	}	if (ip->i_flag&ITEXT)		xrele(ip);	/* try once to free text */	if (ip->i_flag&ITEXT && ip->i_nlink == 1) {		up->u_error = ETXTBSY;		goto out;	}	up->u_offset -= sizeof(struct direct);	up->u_base = (caddr_t)&up->u_dent;	up->u_count = sizeof(struct direct);	up->u_dent.d_ino = 0;	up->u_segflg = 1;	up->u_fmode = FWRITE|FSYNC;	writei(pp);	if (up->u_error)		goto out;	ip->i_nlink--;	ip->i_flag |= ICHG;out:	iput(ip);out1:	iput(pp);}chdir(){	chdirec(&u.u_cdir);}chroot(){	if (!suser())		return;	chdirec(&u.u_rdir);}chdirec(ipp)register struct inode **ipp;{	register struct inode *ip;	struct a {		char	*fname;	};	ip = namei(uchar, 0);	if (ip == NULL)		return;	if ((ip->i_mode&IFMT) != IFDIR) {		u.u_error = ENOTDIR;		goto bad;	}	if (access(ip, IEXEC))		goto bad;	prele(ip);	if (*ipp) {		plock(*ipp);		iput(*ipp);	}	*ipp = ip;	return;bad:	iput(ip);}chmod(){	register struct inode *ip;	register struct a {		char	*fname;		int	fmode;	} *uap;	uap = (struct a *)u.u_ap;	if ((ip = owner()) == NULL)		return;	ip->i_mode &= ~07777;	if (u.u_uid) {		uap->fmode &= ~ISVTX;		if (u.u_gid != ip->i_gid)			uap->fmode &= ~ISGID;	}	ip->i_mode |= uap->fmode&07777;	ip->i_flag |= ICHG;	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)		xrele(ip);	iput(ip);}chown(){	register struct inode *ip;	register struct a {		char	*fname;		int	uid;		int	gid;	} *uap;	uap = (struct a *)u.u_ap;	if ((ip = owner()) == NULL)		return;	ip->i_uid = uap->uid;	ip->i_gid = uap->gid;	if (u.u_uid != 0)		ip->i_mode &= ~(ISUID|ISGID);	ip->i_flag |= ICHG;	iput(ip);}ssig(){	register a;	register struct proc *p;	struct a {		int	signo;		int	fun;	} *uap;	register struct user *up;	up = &u;	uap = (struct a *)up->u_ap;	a = uap->signo;	if (a <= 0 || a > NSIG || a == SIGKILL) {		up->u_error = EINVAL;		return;	}	up->u_rval1 = up->u_signal[a-1];	up->u_signal[a-1] = uap->fun;	up->u_procp->p_sig &= ~(1L<<(a-1));	if (a == SIGCLD) {		a = up->u_procp->p_pid;		for (p = &proc[1]; p < (struct proc *)v.ve_proc; p++) {			if (a == p->p_ppid && p->p_stat == SZOMB)				psignal(up->u_procp, SIGCLD);		}	}	if (uap->fun&1)		up->u_procp->p_sigign |= (1<<(uap->signo-1));	else		up->u_procp->p_sigign &= ~(1<<(uap->signo-1));}kill(){	register struct proc *p, *q;	register arg;	register struct a {		int	pid;		int	signo;	} *uap;	int f;	register struct user *up;	up = &u;	uap = (struct a *)up->u_ap;	if (uap->signo < 0 || uap->signo > NSIG) {		up->u_error = EINVAL;		return;	}	/* Prevent proc 1 (init) from being SIGKILLed */	if (uap->signo == SIGKILL && uap->pid == 1) {		up->u_error = EINVAL;		return;	}	f = 0;	arg = uap->pid;	if (arg > 0)		p = &proc[1];	else		p = &proc[2];	q = up->u_procp;	if (arg == 0 && q->p_pgrp == 0) {		up->u_error = ESRCH;		return;	}	for(; p < (struct proc *)v.ve_proc; p++) {		if (p->p_stat == NULL)			continue;		if (arg > 0 && p->p_pid != arg)			continue;		if (arg == 0 && p->p_pgrp != q->p_pgrp)			continue;		if (arg < -1 && p->p_pgrp != -arg)			continue;		if (! (up->u_uid == 0 ||			up->u_uid == p->p_uid ||			up->u_ruid == p->p_uid ||			up->u_uid == p->p_suid ||			up->u_ruid == p->p_suid ))			if (arg > 0) {				up->u_error = EPERM;				return;			} else				continue;		f++;		if (uap->signo)			psignal(p, uap->signo);		if (arg > 0)			break;	}	if (f == 0)		up->u_error = ESRCH;}times(){	register struct a {		time_t	(*times)[4];	} *uap;	register struct user *up;	time_t loctime[4];	up = &u;	uap = (struct a *)up->u_ap;	if (v.v_hz==60) {		if (copyout((caddr_t)&up->u_utime, (caddr_t)uap->times,		    sizeof(*uap->times)))			up->u_error = EFAULT;		SPL7();		up->u_rtime = lbolt;		SPL0();	} else {		loctime[0] = up->u_utime * 60 / v.v_hz;		loctime[1] = up->u_stime * 60 / v.v_hz;		loctime[2] = up->u_cutime * 60 / v.v_hz;		loctime[3] = up->u_cstime * 60 / v.v_hz;		if (copyout((caddr_t)&loctime[0], (caddr_t)uap->times,		    sizeof(loctime)) < 0)			up->u_error = EFAULT;		SPL7();		up->u_rtime = lbolt*60/v.v_hz;		SPL0();	}}profil(){	register struct a {		short	*bufbase;		unsigned bufsize;		unsigned pcoffset;		unsigned pcscale;	} *uap;	register struct user *up;	up = &u;	uap = (struct a *)up->u_ap;	up->u_prof.pr_base = uap->bufbase;	up->u_prof.pr_size = uap->bufsize;	up->u_prof.pr_off = uap->pcoffset;	up->u_prof.pr_scale = uap->pcscale;}/* * alarm clock signal */alarm(){	register struct proc *p;	register c;	register struct a {		int	deltat;	} *uap;	uap = (struct a *)u.u_ap;	p = u.u_procp;	c = p->p_clktim;	p->p_clktim = uap->deltat;	u.u_rval1 = c;}/* * indefinite wait. * no one should wakeup(&u) */pause(){	for(;;)		(void) sleep((caddr_t)&u, PSLEP);}/* * mode mask for creation of files */umask(){	register struct a {		int	mask;	} *uap;	register t;	register struct user *up;	up = &u;	uap = (struct a *)up->u_ap;	t = up->u_cmask;	up->u_cmask = uap->mask & 0777;	up->u_rval1 = t;}/* * Set IUPD and IACC times on file. */utime(){	register struct a {		char	*fname;		time_t	*tptr;	} *uap;	register struct inode *ip;	time_t tv[2];	uap = (struct a *)u.u_ap;	if (uap->tptr != NULL) {		if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {			u.u_error = EFAULT;			return;		}	} else {		tv[0] = time;		tv[1] = time;	}	ip = namei(uchar, 0);	if (ip == NULL)		return;	if (u.u_uid != ip->i_uid && u.u_uid != 0) {		if (uap->tptr != NULL)			u.u_error = EPERM;		else			(void) access(ip, IWRITE);	}	if (!u.u_error) {		ip->i_flag |= IACC|IUPD|ICHG;		iupdat(ip, &tv[0], &tv[1]);	}	iput(ip);}ulimit(){	register struct a {		int	cmd;		long	arg;	} *uap;	register struct user *up;	register n, ts;	up = &u;	uap = (struct a *)up->u_ap;	switch(uap->cmd) {	case 2:		if (uap->arg > up->u_limit && !suser())			return;		up->u_limit = uap->arg;	case 1:		up->u_roff = up->u_limit;		break;	case 3:		ts = up->u_tsize;		n = maxmem - up->u_ssize - v.v_usize;		if (ts > minmem)			n = MAX((int)n-ts, (int)minmem-up->u_ssize-v.v_usize);		n = MIN(n, MAXMEM-stoc(ctos(ts))-stoc(ctos(up->u_ssize)));		up->u_roff = v.v_ustart + ctob(stoc(ctos(ts)) + n);		break;	default:		up->u_error = EINVAL;	}}/* * phys - Set up a physical address in user's address space. */phys(){	register struct a {		unsigned phnum;		/* phys segment number */		unsigned laddr;		/* logical address */		unsigned bcount;	/* byte count */		unsigned phaddr;	/* physical address */	} *uap;	if (!suser()) return;	uap = (struct a *)u.u_ap;	dophys(uap->phnum, uap->laddr, uap->bcount, uap->phaddr);}/* * reboot the system */reboot(){	register i;	update();	for (i = 0; i < 1000000; i++)		;	doboot();}