Ultrix-3.1/sys/sys/sys4.c
/**********************************************************************
* Copyright (c) Digital Equipment Corporation 1984, 1985, 1986. *
* All Rights Reserved. *
* Reference "/usr/src/COPYRIGHT" for applicable restrictions. *
**********************************************************************/
/*
* SCCSID: @(#)sys4.c 3.3 12/16/87
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/reg.h>
#include <sys/inode.h>
#include <sys/proc.h>
#include <sys/timeb.h>
#include <sys/errlog.h>
int hz; /* line frequency, see c.c */
/*
* Everything in this file is a routine implementing a system call.
*/
/*
* return the current time (old-style entry)
*/
gtime()
{
u.u_r.r_time = time;
}
/*
* New time entry-- return TOD with milliseconds, timezone,
* DST flag
*/
ftime()
{
register struct a {
struct timeb *tp;
} *uap;
struct timeb t;
register unsigned ms;
extern int timezone;
extern int dstflag;
uap = (struct a *)u.u_ap;
spl7();
t.time = time;
ms = lbolt;
spl0();
if (ms > hz) {
ms -= hz;
t.time++;
}
t.millitm = (1000*ms)/hz;
t.timezone = timezone;
t.dstflag = dstflag;
if (copyout((caddr_t)&t, (caddr_t)uap->tp, sizeof(t)) < 0)
u.u_error = EFAULT;
}
/*
* Set the time
*/
stime()
{
register struct a {
time_t time;
} *uap;
time_t ntime;
extern time_t boottime;
uap = (struct a *)u.u_ap;
if(suser()) {
/*
* Enter the time change
* in the error log.
*/
ntime = uap->time;
logerr(E_TC, &ntime, sizeof(ntime));
boottime += uap->time - time;
time = uap->time;
}
}
setuid()
{
register struct a {
int ruid;
int euid;
} *uap = (struct a *)u.u_ap;
uap->euid = uap->ruid;
csetuid();
}
setreuid()
{
register struct a {
int ruid;
int euid;
} *uap = (struct a *)u.u_ap;
if (uap->ruid == -1)
uap->ruid = u.u_ruid;
if (uap->euid == -1)
uap->euid = u.u_uid;
csetuid();
}
/*
* Common code for setuid() and setreuid(). The will have
* already set up uap->ruid & uap->euid as appropriate.
*/
static csetuid()
{
register struct a {
int ruid;
int euid;
} *uap = (struct a *)u.u_ap;
register int ruid, euid;
ruid = uap->ruid;
euid = uap->euid;
if (( (u.u_ruid != ruid && u.u_uid != ruid) ||
(u.u_ruid != euid && u.u_uid != euid) ) && !suser())
return;
u.u_procp->p_uid = ruid;
u.u_ruid = ruid;
u.u_uid = euid;
}
getuid()
{
u.u_rval1 = u.u_ruid;
u.u_rval2 = u.u_uid;
}
setgid()
{
register struct a {
int rgid;
int egid;
} *uap = (struct a *)u.u_ap;
uap->egid = uap->rgid;
csetgid();
}
setregid()
{
register struct a {
int rgid;
int egid;
} *uap = (struct a *)u.u_ap;
if (uap->rgid == -1)
uap->rgid = u.u_rgid;
if (uap->egid == -1)
uap->egid = u.u_gid;
csetgid();
}
/*
* Common code for setgid() and setregid(). The will have
* already set up uap->rgid & uap->egid as appropriate.
*/
static csetgid()
{
register struct a {
int rgid;
int egid;
} *uap = (struct a *)u.u_ap;
register int rgid, egid;
rgid = uap->rgid;
egid = uap->egid;
if (( (u.u_rgid != rgid && u.u_gid != rgid) ||
(u.u_rgid != egid && u.u_gid != egid) ) && !suser())
return;
u.u_gid = egid;
u.u_rgid = rgid;
}
getgid()
{
u.u_rval1 = u.u_rgid;
u.u_rval2 = u.u_gid;
}
getpid()
{
u.u_rval1 = u.u_procp->p_pid;
u.u_rval2 = u.u_procp->p_ppid;
}
sync()
{
update();
}
nice()
{
register n;
register struct a {
int niceness;
} *uap;
uap = (struct a *)u.u_ap;
n = uap->niceness;
if(n < 0 && !suser())
n = 0;
n += u.u_procp->p_nice;
if(n >= 2*NZERO)
n = 2*NZERO -1;
if(n < 0)
n = 0;
u.u_procp->p_nice = n;
}
/*
* Unlink system call.
* Hard to avoid races here, especially
* in unlinking directories.
*/
unlink()
{
register struct inode *ip, *pp;
struct a {
char *fname;
};
#ifdef UCB_SYMLINKS
pp = namei(uchar, DELETE, 0);
#else UCB_SYMLINKS
pp = namei(uchar, DELETE);
#endif UCB_SYMLINKS
if(pp == NULL)
return;
/*
* Check for unlink(".")
* to avoid hanging on the iget
*/
if (pp->i_number == u.u_dent.d_ino) {
ip = pp;
ip->i_count++;
} else
ip = iget(pp->i_dev, u.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) {
u.u_error = EBUSY;
goto out;
}
/*
* If the sticky bit is turned on the parent directory, then to
* remove the file you have meet one of the following conditions:
* 1) Be superuser
* 2) Own the file
* 3) Own the parent directory
*/
if ((pp->i_mode & ISVTX) && u.u_uid &&
u.u_uid != pp->i_uid && ip->i_uid != u.u_uid) {
u.u_error = EPERM;
goto out;
}
if (ip->i_flag&ITEXT)
xrele(ip); /* try once to free text */
if (ip->i_flag&ITEXT && ip->i_nlink==1) {
u.u_error = ETXTBSY;
goto out;
}
u.u_offset -= sizeof(struct direct);
u.u_base = (caddr_t)&u.u_dent;
u.u_count = sizeof(struct direct);
u.u_dent.d_ino = 0;
writei(pp);
ip->i_nlink--;
ip->i_flag |= ICHG;
out:
iput(ip);
out1:
iput(pp);
}
chdir()
{
chdirec(&u.u_cdir);
}
chroot()
{
if (suser())
chdirec(&u.u_rdir);
}
static
chdirec(ipp)
register struct inode **ipp;
{
register struct inode *ip;
struct a {
char *fname;
};
#ifdef UCB_SYMLINKS
ip = namei(uchar, LOOKUP, 1);
#else UCB_SYMLINKS
ip = namei(uchar, LOOKUP);
#endif UCB_SYMLINKS
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;
#ifdef UCB_SYMLINKS
if ((ip = owner(1)) == NULL)
#else UCB_SYMLINKS
if ((ip = owner()) == NULL)
#endif UCB_SYMLINKS
return;
ip->i_mode &= ~07777;
if (u.u_uid) {
uap->fmode &= ~ISVTX;
/* clear set group ID bit if file group id != effective group id
* sysV compatible: George Mathew 6/14/85 */
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;
/* now non super users can invoke this call.
* sysV compatible. George Mathew 6/14/85 */
#ifdef UCB_SYMLINKS
if ((ip = owner(0)) == NULL)
#else UCB_SYMLINKS
if ((ip = owner()) == NULL)
#endif UCB_SYMLINKS
return;
ip->i_uid = uap->uid;
ip->i_gid = uap->gid;
/* if not super user clear set-user-id and set-group-id bits
* SysV compatible: George Mathew 6/14/85 */
if(u.u_uid != 0)
ip->i_mode &= ~(ISUID|ISGID);
ip->i_flag |= ICHG;
iput(ip);
}
ssig()
{
register int (*f)();
register struct a {
int signo;
int (*fun)();
} *uap;
register struct proc *p = u.u_procp;
register a;
long sigmask;
uap = (struct a *)u.u_ap;
a = uap->signo & SIGNUMMASK;
f = uap->fun;
if (a<=0 || a>=NSIG || a==SIGKILL || a==SIGSTOP ||
a==SIGCONT && (f == SIG_IGN || f == SIG_HOLD)) {
u.u_error = EINVAL;
return;
}
if ((uap->signo &~ SIGNUMMASK) || (f != SIG_DFL && f != SIG_IGN &&
SIGISDEFER(f)))
u.u_procp->p_flag |= SNUSIG;
/*
* Don't clobber registers if we are to simulate
* a ret+rti.
*/
if ((uap->signo&SIGDORTI) == 0)
u.u_rval1 = (int)u.u_signal[a];
/*
* Change setting atomically.
*/
spl6();
sigmask = 1L << (a-1);
if (f == SIG_IGN)
p->p_sig &= ~sigmask; /* never to be seen again */
u.u_signal[a] = f;
if (f != SIG_DFL && f != SIG_IGN && f != SIG_HOLD)
f = SIG_CATCH;
if ((int)f & 1)
p->p_siga0 |= sigmask;
else
p->p_siga0 &= ~sigmask;
if ((int)f & 2)
p->p_siga1 |= sigmask;
else
p->p_siga1 &= ~sigmask;
spl0();
/*
* Now handle options.
*/
if (uap->signo & SIGDOPAUSE) {
/*
* Simulate a PDP11 style wait instruction which
* atomically lowers priority, enables interrupts
* and hangs.
*/
pause();
/*NOTREACHED*/
}
if (uap->signo & SIGDORTI)
u.u_eosys = SIMULATERTI;
}
/* changes made to make kill() sysV compatible. GMM */
kill()
{
register struct proc *p;
register a, sig;
register struct a {
int pid;
int signo;
} *uap;
int f, priv;
uap = (struct a *)u.u_ap;
f = 0;
a = uap->pid;
priv = 0;
sig = uap->signo;
if (sig < 0)
/*
* A negative signal means send to process group.
*/
uap->signo = -uap->signo;
if (uap->signo > NSIG) {
u.u_error = EINVAL;
return;
}
if (a > 0) {
if (sig > 0) {
for(p = &proc[0]; p <= maxproc; p++)
if (p->p_pid == a) goto found;
p = 0;
found:
if (p == 0 || u.u_uid && u.u_uid != p->p_uid) {
u.u_error = ESRCH;
return;
}
psignal(p, uap->signo);
return;
}
} else if (a==-1 ) {
priv++;
a = 0;
sig = -1; /* like sending to pgrp */
} else if (a==0) {
/*
* Zero process id means send to my process group.
*/
sig = -1;
a = u.u_procp->p_pgrp;
if (a == 0) {
u.u_error = EINVAL;
return;
}
} else if ( a < -1) { /* send to all processes whose process group ID
* is equal to the absolute value of pid */
sig = -1;
a = -a;
}
for(p = &proc[0]; p <= maxproc; p++) {
if (p->p_stat == NULL)
continue;
/*
* sig = 0, just checking for valid pid
*/
if (uap->signo == 0 && p->p_pid == uap->pid) {
f++;
break;
}
if ( sig > 0 ){
if (p->p_pid != a)
continue;
/*
* Always skip pid 0 (swapper), 1 (init), and 2 (elc).
*/
} else if (p->p_pgrp!=a && priv==0 || p<=&proc[2] ||
(priv && p==u.u_procp))
continue;
if (u.u_uid != 0 && u.u_uid != p->p_uid &&
(uap->signo != SIGCONT || priv || !inferior(p)))
continue;
f++;
if(uap->signo)
psignal(p, uap->signo);
}
if(f == 0)
u.u_error = ESRCH;
}
times()
{
register struct a {
time_t (*times)[4];
} *uap;
uap = (struct a *)u.u_ap;
if (copyout((caddr_t)&u.u_utime, (caddr_t)uap->times, sizeof(*uap->times)) < 0)
u.u_error = EFAULT;
}
profil()
{
register struct a {
short *bufbase;
unsigned bufsize;
unsigned pcoffset;
unsigned pcscale;
} *uap;
uap = (struct a *)u.u_ap;
u.u_prof.pr_base = uap->bufbase;
u.u_prof.pr_size = uap->bufsize;
u.u_prof.pr_off = uap->pcoffset;
u.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(;;)
sleep((caddr_t)&u, PSLEP);
}
/*
* mode mask for creation of files
*/
umask()
{
register struct a {
int mask;
} *uap;
register t;
uap = (struct a *)u.u_ap;
t = u.u_cmask;
u.u_cmask = uap->mask & 0777;
u.u_rval1 = t;
}
/*
* Set IUPD and IACC times on file.
* Can't set ICHG.
*/
utime()
{
register struct a {
char *fname;
time_t *tptr;
} *uap;
register struct inode *ip;
time_t tv[2];
uap = (struct a *)u.u_ap;
#ifdef UCB_SYMLINKS
if ((ip = owner(1)) == NULL)
#else UCB_SYMLINKS
if ((ip = owner()) == NULL)
#endif UCB_SYMLINKS
return;
if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
u.u_error = EFAULT;
} else {
ip->i_flag |= IACC|IUPD|ICHG;
iupdat(ip, &tv[0], &tv[1], 0);
}
iput(ip);
}
ulimit()
{
register struct a {
int cmd;
long arg;
} *uap;
int j, k;
register brk, stk;
uap = (struct a *)u.u_ap;
switch(uap->cmd) {
case 2: /* set file size limit */
if (uap->arg > u.u_limit && !suser())
return;
u.u_limit = uap->arg;
case 1: /* get file size limit */
u.u_r.r_off = u.u_limit;
break;
case 3: /* get maximum break value */
brk = 1024 - u.u_dsize
- ((u.u_ssize + btoct(8*1024) - 1)/btoct(8*1024))
* btoct(8*1024);
/*** below is the SYSTEM V brk value calculation
brk = 1024 - ((u.u_ssize + btoct(8*1024) - 1)/btoct(8*1024))
* btoct(8*1024);
***/
u.u_r.r_off = ctob((long)brk);
if (u.u_mbitm) {
for(j=k=7; j>=0; j--)
if ((u.u_mbitm) & (1 << j))
k = j;
u.u_r.r_off = (unsigned int)(k << 13);
}
break;
}
}