V10/lsys/os/sys4.c
/* sys4.c 4.10 81/07/04 */
#include "sys/param.h"
#include "sys/systm.h"
#include "sys/user.h"
#include "sys/inode.h"
#include "sys/proc.h"
#include "sys/clock.h"
#include "sys/timeb.h"
#include "sys/times.h"
#include "sys/file.h"
/*
* 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;
clkcheck();
}
/*
* 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, dstflag;
uap = (struct a *)u.u_ap;
(void) spl7();
t.time = time;
ms = lbolt;
(void) 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)))
u.u_error = EFAULT;
clkcheck();
}
/*
* Set the time
*/
stime()
{
register struct a {
time_t time;
} *uap;
extern time_t bootime;
uap = (struct a *)u.u_ap;
if(suser()) {
bootime += uap->time - time; /* silly */
time = uap->time;
clkset();
}
}
setuid()
{
register uid;
register struct a {
int uid;
} *uap;
uap = (struct a *)u.u_ap;
uid = uap->uid;
if(u.u_ruid == uid || u.u_uid == uid || suser()) {
u.u_uid = uid;
u.u_procp->p_uid = uid;
u.u_ruid = uid;
}
}
getuid()
{
u.u_r.r_val1 = u.u_ruid;
u.u_r.r_val2 = u.u_uid;
}
setruid()
{
register uid;
register struct a {
int uid;
} *uap;
uap = (struct a *)u.u_ap;
uid = uap->uid;
if(suser())
u.u_ruid = uid;
}
setgid()
{
register gid;
register struct a {
int gid;
} *uap;
uap = (struct a *)u.u_ap;
gid = uap->gid;
if(u.u_rgid == gid || u.u_gid == gid || suser()) {
u.u_gid = gid;
u.u_rgid = gid;
}
}
getgid()
{
u.u_r.r_val1 = u.u_rgid;
u.u_r.r_val2 = u.u_gid;
}
setgroups()
{
register struct a {
u_int gidsetsize;
short *gidset;
} *uap = (struct a *)u.u_ap;
register short *gp;
if (!suser())
return;
if (uap->gidsetsize > sizeof u.u_groups / sizeof u.u_groups[0]) {
u.u_error = EINVAL;
return;
}
if (copyin((caddr_t)uap->gidset, (caddr_t)u.u_groups,
uap->gidsetsize * sizeof u.u_groups[0]) < 0) {
u.u_error = EFAULT;
return;
}
for (gp = &u.u_groups[uap->gidsetsize] ; gp < &u.u_groups[NGROUPS]; gp++)
*gp = NOGROUP;
}
/*
* Check if gid is a member of the group set.
*/
groupmember(gid)
short gid;
{
register short *gp;
if (u.u_gid == gid)
return (1);
for (gp = u.u_groups; gp < &u.u_groups[NGROUPS] && *gp != NOGROUP; gp++)
if (*gp == gid)
return (1);
return (0);
}
getgroups()
{
register struct a {
u_int gidsetsize;
short *gidset;
} *uap = (struct a *)u.u_ap;
register short *gp;
for (gp = &u.u_groups[NGROUPS]; gp > u.u_groups; gp--)
if (gp[-1] != NOGROUP)
break;
if (uap->gidsetsize < gp - u.u_groups) {
u.u_error = EINVAL;
return;
}
uap->gidsetsize = gp - u.u_groups;
if (copyout((caddr_t)u.u_groups, (caddr_t)uap->gidset,
uap->gidsetsize * sizeof u.u_groups[0]) < 0) {
u.u_error = EFAULT;
return;
}
u.u_r.r_val1 = uap->gidsetsize;
}
getpid()
{
u.u_r.r_val1 = u.u_procp->p_pid;
u.u_r.r_val2 = 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 + u.u_procp->p_nice;
if(n >= 2*NZERO)
n = 2*NZERO -1;
if(n < 0)
n = 0;
if (n < u.u_procp->p_nice && !suser())
return;
u.u_procp->p_nice = n;
}
/*
* Unlink system call.
* Hard to avoid races here, especially
* in unlinking directories.
*/
unlink()
{
struct a {
char *fname;
};
struct argnamei nmarg;
nmarg = nilargnamei;
nmarg.flag = NI_DEL;
(void) namei(((struct a *)u.u_ap)->fname, SEGUDATA, &nmarg, 0);
}
chdir()
{
chdirec(&u.u_cdir);
}
chroot()
{
if (suser())
chdirec(&u.u_rdir);
}
chdirec(ipp)
register struct inode **ipp;
{
register struct inode *ip;
struct a {
char *fname;
};
ip = namei(((struct a *)u.u_ap)->fname, SEGUDATA, &nilargnamei, 1);
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);
}
fchmod()
{ register struct file *fp;
register struct a {
int fd;
int fmode;
} *uap;
uap = (struct a *)u.u_ap;
if((fp = getf(uap->fd)) == NULL) {
u.u_error = EBADF;
return;
}
chmod1(fp->f_inode, uap->fmode);
}
chmod()
{
register struct inode *ip;
register struct a {
char *fname;
int fmode;
} *uap;
uap = (struct a *)u.u_ap;
if ((ip = namei(uap->fname, SEGUDATA, &nilargnamei, 1)) == NULL)
return;
chmod1(ip, uap->fmode);
iput(ip);
}
chmod1(ip, mode)
register struct inode *ip;
{
if (accowner(ip) == 0)
return;
ip->i_mode &= ~07777;
if (!(mode&ICONC) && u.u_uid!=0 && !groupmember(ip->i_gid))
mode &= ~ISGID;
ip->i_mode |= mode&07777;
ip->i_flag |= ICHG;
}
/* chown with file descriptor*/
fchown()
{ register struct file *fp;
register struct a {
int fd;
int uid;
int gid;
} *uap;
uap = (struct a *)u.u_ap;
if((fp = getf(uap->fd)) == NULL) {
u.u_error = EBADF;
return;
}
chown1(fp->f_inode, uap->uid, uap->gid);
}
chown()
{
register struct inode *ip;
register struct a {
char *fname;
int uid;
int gid;
} *uap;
uap = (struct a *)u.u_ap;
if ((ip = namei(uap->fname, SEGUDATA, &nilargnamei, 1)) == NULL)
return;
chown1(ip, uap->uid, uap->gid);
iput(ip);
}
chown1(ip, uid, gid)
register struct inode *ip;
{
if (accowner(ip) == 0)
return;
if(u.u_uid){
if((ip->i_uid != uid) || !groupmember(gid)){
u.u_error = EPERM;
return;
}
if((ip->i_mode&ICONC)==0 && gid != ip->i_gid)
ip->i_mode &=~ ISGID;
}
ip->i_uid = uid;
ip->i_gid = gid;
ip->i_flag |= ICHG;
}
ssig()
{
register int (*f)();
struct a {
int signo;
int (*fun)();
} *uap;
register struct proc *p = u.u_procp;
register a;
register long sigmask;
uap = (struct a *)u.u_ap;
a = uap->signo & SIGNUMMASK;
f = uap->fun;
if(a<=0 || a>=NSIG || a==SIGKILL || a==SIGSTOP) {
u.u_error = EINVAL;
return;
}
u.u_r.r_val1 = (int)u.u_signal[a];
sigmask = SIGMASK(a);
(void) spl6();
if (u.u_signal[a] == SIG_IGN)
p->p_sig &= ~sigmask; /* never to be seen again */
u.u_signal[a] = f;
if (f == SIG_DFL)
P_SETDFL(p, sigmask);
else if (f == SIG_IGN)
P_SETIGN(p, sigmask);
else if (f == SIG_HOLD)
P_SETHOLD(p, sigmask);
else
P_SETCATCH(p, sigmask);
(void) spl0();
if (uap->signo & SIGDOPAUSE)
pause();
}
kill()
{
register struct a {
int pid;
int signo;
} *uap;
u.u_error = ESRCH; /* default error */
uap = (struct a *)u.u_ap;
if (uap->signo > NSIG || uap->signo < 0) {
u.u_error = EINVAL;
return;
}
if (uap->pid == -1)
killall(uap->signo);
else if(uap->pid > 0)
killproc(uap->pid, uap->signo);
else if (uap->pid < 0)
killpgrp(-uap->pid, uap->signo);
else
killpgrp(u.u_procp->p_pgrp, uap->signo);
}
/*
* kill a single process
*/
killproc(pid, sig)
register int pid, sig;
{
register struct proc *p;
for (p = proc; p < procNPROC; p++)
if (p->p_stat && p->p_pid == pid)
break;
if (p == procNPROC)
return;
if (u.u_uid && u.u_uid != p->p_uid) { /* no permission */
u.u_error = EPERM;
return;
}
if (sig != 0) /* real signal? */
psignal(p, sig); /* yes, send it */
u.u_error = 0;
}
/*
* Kill all processes within a process group but not system processes.
* SIGCONT may be sent to any descendants (can you say hack?).
*/
killpgrp(pgrp, sig)
register int pgrp, sig;
{
register struct proc *p;
for(p = proc; p < procNPROC; p++) {
if(p->p_stat == 0)
continue; /* non-existent */
if (p->p_pgrp!=pgrp || p->p_flag&SSYS)
continue;
if(u.u_uid != 0 && u.u_uid != p->p_uid &&
(sig != SIGCONT || !inferior(p)))
continue;
u.u_error = 0;
if (sig != 0) /* real signal? */
psignal(p, sig); /* yes, send it */
}
}
/*
* Kill all processes except the system processes and the current process
*/
killall(sig)
register int sig;
{
register struct proc *p;
if (!suser())
return;
for(p = proc; p < procNPROC; p++) {
if(p->p_stat == 0)
continue;
if (p->p_flag&SSYS || p==u.u_procp)
continue;
u.u_error = 0;
psignal(p, sig);
}
}
times()
{
register struct a {
time_t (*times)[4];
} *uap;
struct tms tms;
tms.tms_utime = u.u_vm.vm_utime;
tms.tms_stime = u.u_vm.vm_stime;
tms.tms_cutime = u.u_cvm.vm_utime;
tms.tms_cstime = u.u_cvm.vm_stime;
uap = (struct a *)u.u_ap;
if (copyout((caddr_t)&tms, (caddr_t)uap->times, sizeof(struct tms)) < 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;
if (uap->deltat > 65535L)
uap->deltat = 65535;
p->p_clktim = uap->deltat;
u.u_r.r_val1 = 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_r.r_val1 = 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;
if ((ip = namei(uap->fname, SEGUDATA, &nilargnamei, 1)) == NULL)
return;
if (accowner(ip) == 0) {
iput(ip);
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);
}
/*
* Setpgrp on specified process and its descendants.
* Pid of zero implies current process.
* Pgrp -1 is getpgrp system call returning
* current process group.
*/
setpgrp()
{
register struct proc *top;
register struct a {
int pid;
int pgrp;
} *uap;
uap = (struct a *)u.u_ap;
uap->pid = (short)uap->pid; /* else 0x10000 would make pgrp 0 */
uap->pgrp = (short)uap->pgrp;
if (uap->pid == 0)
top = u.u_procp;
else {
top = pfind(uap->pid);
if (top == 0) {
u.u_error = ESRCH;
return;
}
}
if (uap->pgrp == 0 && !suser())
return;
if (uap->pgrp < 0) {
u.u_r.r_val1 = top->p_pgrp;
return;
}
if (top->p_uid != u.u_uid && u.u_uid && !inferior(top))
u.u_error = EPERM;
else
top->p_pgrp = uap->pgrp;
}
spgrp(top, npgrp)
register struct proc *top;
{
register struct proc *pp, *p;
int f = 0;
for (p = top; npgrp == -1 || u.u_uid == p->p_uid ||
!u.u_uid || inferior(p); p = pp) {
if (npgrp == -1) {
#define bit(a) (1<<(a-1))
p->p_sig &= ~(bit(SIGTSTP)|bit(SIGTTIN)|bit(SIGTTOU));
} else
p->p_pgrp = npgrp;
f++;
/*
* Search for children.
*/
for (pp = proc; pp < procNPROC; pp++)
if (pp->p_stat != 0 && pp->p_pptr == p)
goto cont;
/*
* Search for siblings.
*/
for (; p != top; p = p->p_pptr)
for (pp = p + 1; pp < procNPROC; pp++)
if (pp->p_stat != 0 && pp->p_pptr == p->p_pptr)
goto cont;
break;
cont:
;
}
return (f);
}
/*
* Is p an inferior of the current process?
*/
inferior(p)
register struct proc *p;
{
for (; p != u.u_procp; p = p->p_pptr)
if (p < &proc[SYSPIDS])
return (0);
return (1);
}
sysboot()
{
register struct a {
int opt;
};
if (suser())
boot(((struct a *)u.u_ap)->opt);
}
/*
* lock user into core as much
* as possible. swapping may still
* occur if core grows.
*/
syslock()
{
register struct proc *p;
register struct a {
int flag;
} *uap;
uap = (struct a *)u.u_ap;
if(suser()) {
p = u.u_procp;
p->p_flag &= ~SULOCK;
if(uap->flag)
p->p_flag |= SULOCK;
}
}
/*
* nap for n clock ticks
*/
#define MAXNAP 120
nap()
{
register struct a {
int nticks;
} *uap;
register int n;
uap = (struct a *)u.u_ap;
n = uap->nticks;
if (n < 0)
n = 0;
if (n > MAXNAP)
n = MAXNAP;
delay (n);
}
/*
* get/set user's login name
*/
getlogname()
{
register struct a {
char *name;
int flag;
} *uap;
uap = (struct a *)u.u_ap;
if (uap->flag == 0) {
if (copyout((caddr_t)u.u_logname, (caddr_t)uap->name, sizeof(u.u_logname)) < 0)
u.u_error = EFAULT;
return;
}
if (suser() == 0)
return;
if (copyin((caddr_t)uap->name, (caddr_t)u.u_logname, sizeof(u.u_logname)))
u.u_error = EFAULT;
}