Ultrix-3.1/sys/sys/sys3.c

Compare this file to the similar file:
Show the results in this format:


/**********************************************************************
 *   Copyright (c) Digital Equipment Corporation 1984, 1985, 1986.    *
 *   All Rights Reserved. 					      *
 *   Reference "/usr/src/COPYRIGHT" for applicable restrictions.      *
 **********************************************************************/

/*
 * SCCSID: @(#)sys3.c	3.0	4/21/86
 */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/ino.h>
#include <sys/reg.h>
#include <sys/buf.h>
#include <sys/filsys.h>
#include <sys/mount.h>
#include <sys/dir.h>
#include <sys/user.h>
#include <sys/inode.h>
#include <sys/file.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <sys/inline.h>
#include <sys/flock.h>
#include <sys/ioctl.h>

/*
 * the fstat system call.
 */
fstat()
{
	register struct file *fp;
	register struct a {
		int	fdes;
		struct stat *sb;
	} *uap;

	uap = (struct a *)u.u_ap;
	fp = getf(uap->fdes);
	if(fp == NULL)
		return;
#ifdef	UCB_NET
	if (fp->f_flag & FSOCKET)
		u.u_error = soo_stat(fp->f_socket, uap->sb);
	else
#endif	UCB_NET
	stat1(fp->f_inode, uap->sb, 
		((fp->f_inode->i_flag&IFMT) == IFIFO)? fp->f_un.f_offset: 0);
}

/*
 * the stat system call.
 */
stat()
{
	register struct inode *ip;
	register struct a {
		char	*fname;
		struct stat *sb;
	} *uap;

	uap = (struct a *)u.u_ap;
#ifdef	UCB_SYMLINKS
	ip = namei(uchar, LOOKUP, 1);
#else	UCB_SYMLINKS
	ip = namei(uchar, LOOKUP);
#endif	UCB_SYMLINKS
	if(ip == NULL)
		return;
	stat1(ip, uap->sb, (off_t)0);
	iput(ip);
}

#ifdef	UCB_SYMLINKS
/*
 * Lstat system call; like stat but doesn't follow links.
 */
lstat()
{
	register struct inode *ip;
	register struct a {
		char	*fname;
		struct stat *sb;
	} *uap;

	uap = (struct a *)u.u_ap;
	ip = namei(uchar, 0, 0);
	if (ip == NULL)
		return;
	stat1(ip, uap->sb, (off_t)0);
	iput(ip);
}
#endif

/*
 * The basic routine for fstat and stat:
 * get the inode and pass appropriate parts back.
 */
static
stat1(ip, ub, pipeadj)
register struct inode *ip;
struct stat *ub;
off_t pipeadj;
{
	register struct dinode *dp;
	register struct buf *bp;
	struct stat ds;

	IUPDAT(ip, &time, &time, 0);
	/*
	 * first copy from inode table
	 */
	ds.st_dev = ip->i_dev;
	ds.st_ino = ip->i_number;
	ds.st_mode = ip->i_mode;
	ds.st_nlink = ip->i_nlink;
	ds.st_uid = ip->i_uid;
	ds.st_gid = ip->i_gid;
	ds.st_rdev = (dev_t)ip->i_rdev;
	ds.st_size = ip->i_size - pipeadj;
	/*
	 * next the dates in the disk
	 */
	bp = bread(ip->i_dev, itod(ip->i_number));
	dp = (struct dinode *) mapin(bp);
	dp += itoo(ip->i_number);
	ds.st_atime = dp->di_atime;
	ds.st_mtime = dp->di_mtime;
	ds.st_ctime = dp->di_ctime;
	mapout(bp);
	brelse(bp);
	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
		u.u_error = EFAULT;
}

/*
 * the dup system call.
 */
dup()
{
	register struct file *fp;
	register struct a {
		int	fdes;
		int	fdes2;
	} *uap;
	register i, m;

	uap = (struct a *)u.u_ap;
	m = uap->fdes & ~077;
	uap->fdes &= 077;
	fp = getf(uap->fdes);
	if(fp == NULL)
		return;
	if ((m&0100) == 0) {
		if ((i = ufalloc(0)) < 0)
			return;
	} else {
		i = uap->fdes2;
		if (i<0 || i>=NOFILE) {
			u.u_error = EBADF;
			return;
		}
		u.u_rval1 = i;
	}
	if (i!=uap->fdes) {
		if (u.u_ofile[i]!=NULL)
#ifndef	UCB_NET
			closef(u.u_ofile[i]);
#else	UCB_NET
			closef(u.u_ofile[i], 0);
#endif	UCB_NET
		u.u_ofile[i] = fp;
		fp->f_count++;
	}
}

/*
 * the file control system call.
 */
fcntl()
{
	register struct file *fp;
	register struct a {
		int	fdes;
		int	cmd;
		int	arg;
	} *uap;
	register i;
 	struct flock bf;

	uap = (struct a *)u.u_ap;
	fp = getf(uap->fdes);
	if (fp == NULL)
		return;
	switch(uap->cmd) {
	case 0:			/* F_DUPFD */
		i = uap->arg;
		if (i < 0 || i > NOFILE) {
			u.u_error = EINVAL;
			return;
		}
		if ((i = ufalloc(i)) < 0)
			return;
		u.u_ofile[i] = fp;
		fp->f_count++;
		break;

	case 1:			/* F_GETFD */
		u.u_rval1 = u.u_pofile[uap->fdes];
		break;

	case 2:			/* F_SETFD */
		u.u_pofile[uap->fdes] = uap->arg;
		break;

	case 3:			/* F_GETFL */
		u.u_rval1 = fp->f_flag+FOPEN;
		break;

	case 4:			/* F_SETFL */
		fp->f_flag &= (FREAD|FWRITE);
		fp->f_flag |= (uap->arg-FOPEN) & ~(FREAD|FWRITE);
		if ((uap->arg-FOPEN) & FNDELAY) {
			uap->arg = 1;
		}
		else
			uap->arg = 0;
		uap->cmd = FKRNBIO;
		ioctl();
		u.u_error = 0;   /* ioctl may fail for some valid reasons
				  * like FNDELAY for a pipe */
		break;

 	case 5:			/* F_GETLK */
 		/* get record lock */
 		if (copyin(uap->arg, &bf, sizeof bf))
 			u.u_error = EFAULT;
 		else if ((i=getflck(fp, &bf)) != 0)
 			u.u_error = i;
 		else if (copyout(&bf, uap->arg, sizeof bf))
 			u.u_error = EFAULT;
 		break;
 
 	case 6:			/* F_SETLK */
 		/* set record lock and return if blocked */
 		if (copyin(uap->arg, &bf, sizeof bf))
 			u.u_error = EFAULT;
 		else if ((i=setflck(fp, &bf, 0)) != 0)
 			u.u_error = i;
 		break;
 
 	case 7:			/* F_SETLKW */
 		/* set record lock and wait if blocked */
 		if (copyin(uap->arg, &bf, sizeof bf))
 			u.u_error = EFAULT;
 		else if ((i=setflck(fp, &bf, 1)) != 0)
 			u.u_error = i;
 		break;
 
	default:
		u.u_error = EINVAL;
	}
}

/*
 * the mount system call.
 */
smount()
{
	dev_t dev;
	register struct inode *ip;
	register struct mount *mp;
	struct mount *smp;
	register struct filsys *fp;
	struct buf *bp;
	register struct a {
		char	*fspec;
		char	*freg;
		int	ronly;
	} *uap;

	uap = (struct a *)u.u_ap;
	dev = getmdev();
	if(u.u_error || !suser())
		return;
	u.u_dirp = (caddr_t)uap->freg;
#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_count!=1 || (ip->i_mode&(IFBLK&IFCHR))!=0)
		goto out;
	smp = NULL;
	for(mp = &mount[0]; mp < &mount[nmount]; mp++) {
		if(mp->m_inodp != NULL)
		{
			if(dev == mp->m_dev)
				goto out;
		} else
		if(smp == NULL)
			smp = mp;
	}
	mp = smp;
	if(mp == NULL)
		goto out;
	(*bdevsw[major(dev)].d_open)(dev, !uap->ronly);
	if(u.u_error)
		goto out;
	bp = bread(dev, SUPERB);
	if(u.u_error) {
		brelse(bp);
		goto out1;
	}
	if (!uap->ronly) {
		/*
		 * Write it back out.  We don't call bwrite() because
		 * it will release the buffer, and we don't want to
		 * do that. We've just taken the code that we need.
		 * If there are any errors, we assume that it is
		 * because the disk is write-locked, so bomb out.
		 */
		bp->b_flags &= ~(B_READ|B_DONE|B_ERROR|B_DELWRI);
		(*bdevsw[major(dev)].d_strategy)(bp);
		iowait(bp);
		if (bp->b_flags & B_ERROR) {
			brelse(bp);
			u.u_error = EROFS;
			goto out1;
		}
	}
	/*
	 * Sanity check some superblock values,
	 * so we don't mount corrupted or non UNIX file systems.
	 * The checks could be more stringent, but we don't
	 * want to risk limiting file system sizes.
	 * Max file system size assumed to be 2^24 blocks.
	 */
	fp = mapin(bp);
	if((fp->s_isize <= (SUPERB+1)) ||
	   (fp->s_fsize <= 0L) ||
	   (fp->s_fsize > 16777216L) ||
	   (fp->s_isize >= fp->s_fsize)) {
		mapout(bp);
		brelse(bp);
		u.u_error = EBADFS;
		goto out1;
	}
	mp->m_inodp = ip;
	mp->m_dev = dev;
	bp->b_flags |= B_MOUNT;
	mp->m_bufp = bp;
	fp->s_ilock = 0;
	fp->s_flock = 0;
	fp->s_ronly = uap->ronly & 1;
	fp->s_nbehind = 0;
	fp->s_lasti = 1;
	mapout(bp);
	brelse(bp);
	ip->i_flag |= IMOUNT;
	prele(ip);
	return;

out:
	u.u_error = EBUSY;
out1:
	iput(ip);
}

/*
 * the umount system call.
 */
sumount()
{
	dev_t dev;
	register struct inode *ip;
	register struct mount *mp;
	struct buf *bp;
	struct buf *dp;
	register struct a {
		char	*fspec;
	};

	dev = getmdev();
	if(u.u_error || !suser())
		return;
	xumount(dev);	/* remove unused sticky files from text table */
	update();
	for(mp = &mount[0]; mp < &mount[nmount]; mp++)
		if(mp->m_inodp != NULL && dev == mp->m_dev)
			goto found;
	u.u_error = EINVAL;
	return;

found:
	for(ip = &inode[0]; ip < &inode[ninode]; ip++)
		if(ip->i_number != 0 && dev == ip->i_dev) {
			u.u_error = EBUSY;
			return;
		}
	(*bdevsw[major(dev)].d_close)(dev, 0);
	/*
	 * the call to update might have just returned, so at this
	 * point we don't know if the flushing is done yet.  So we
	 * call bflush ourselves, and we then know that everything
	 * is flushed.
	 */
	bflush(BF_FLUSH, dev);
	dp = bdevsw[major(dev)].d_tab;
	dp += dp_adj(dev);
	spl6();
backthere:
	for (bp = dp->b_forw; bp != dp; bp = bp->b_forw) {
		if (bp->b_dev == dev) {
			if (bp->b_flags&(B_BUSY|B_ASYNC)) {
				/* It's active, wait for it to finish */
				bp->b_flags |= B_WANTED;
				sleep((caddr_t)bp, PRIBIO+1);
				goto backthere;
			} else {
				/* not active, disassociate it from the drive */
				bunhash(bp);
				bp->b_dev = NODEV;
			}
		}
	}
	spl0();
	ip = mp->m_inodp;
	ip->i_flag &= ~IMOUNT;
	plock(ip);
	iput(ip);
	mp->m_inodp = NULL;
	bp = mp->m_bufp;
	mp->m_bufp = NULL;
	bp->b_flags &= ~B_MOUNT;
	brelse(bp);
}

/*
 * Common code for mount and umount.
 * Check that the user's argument is a reasonable
 * thing on which to mount, and return the device number if so.
 */
static dev_t
getmdev()
{
	dev_t dev;
	register struct inode *ip;

#ifdef	UCB_SYMLINKS
	ip = namei(uchar, LOOKUP, 1);
#else	UCB_SYMLINKS
	ip = namei(uchar, LOOKUP);
#endif	UCB_SYMLINKS
	if(ip == NULL)
		return(NODEV);
	if((ip->i_mode&IFMT) != IFBLK)
		u.u_error = ENOTBLK;
	dev = (dev_t)ip->i_rdev;
	if(major(dev) >= nblkdev)
		u.u_error = ENXIO;
	iput(ip);
	return(dev);
}


#include <sys/utsname.h>

utssys()
{

	register i;
	register struct a {
		char	*cbuf;
		int	mv;
		int	type;
	} *uap;
	register struct mount *mp;

	uap = (struct a *)u.u_ap;
	switch(uap->type) {

case 0:		/* uname */
	if (copyout(&utsname, uap->cbuf, sizeof(struct utsname)))
		u.u_error = EFAULT;
	return;

case 2:		/* ustat */
	for(mp = &mount[i]; mp < &mount[nmount]; mp++) {
		if(mp->m_inodp != NULL && mp->m_dev==uap->mv) {
			register struct filsys *fp;

			fp = (struct filsys *)(mapin(mp->m_bufp));

/* Orig system III code. Our super block is different. OHMS		
			if(copyout(&fp->s_tfree, uap->cbuf, 18))
				u.u_error = EFAULT;
*/

			if(copyout(&fp->s_tfree, uap->cbuf, 6))
				u.u_error = EFAULT;
			if(copyout(&fp->s_fname, (uap->cbuf+6), 12))
				u.u_error = EFAULT;
			mapout(mp->m_bufp);
			return;
		}
	}
	u.u_error = EINVAL;
	return;

default:
	u.u_error = EFAULT;
	}
}

#ifdef	UCB_SYMLINKS
/*
 * Return target name of a symbolic link
 */
readlink()
{
	register struct inode *ip;
	register struct a {
		char	*name;
		char	*buf;
		int	count;
	} *uap;

	ip = namei(uchar, 0, 0);
	if (ip == NULL)
		return;
	if ((ip->i_mode&IFMT) != IFLNK) {
		u.u_error = ENXIO;
		goto out;
	}
	uap = (struct a *)u.u_ap;
	u.u_offset = 0;
	u.u_base = uap->buf;
	u.u_count = uap->count;
	u.u_segflg = 0;
	readi(ip);
out:
	iput(ip);
	u.u_r.r_val1 = uap->count - u.u_count;
}

/*
 * symlink -- make a symbolic link
 */
symlink()
{
	register struct a {
		char	*target;
		char	*linkname;
	} *uap;
	register struct inode *ip;
	register char *tp;
	register c, nc;

	uap = (struct a *)u.u_ap;
	tp = uap->target;
	nc = 0;
	while (c = fubyte(tp)) {
		if (c < 0) {
			u.u_error = EFAULT;
			return;
		}
		tp++;
		nc++;
	}
	u.u_dirp = uap->linkname;
	ip = namei(uchar, 1, 0);
	if (ip) {
		iput(ip);
		u.u_error = EEXIST;
		return;
	}
	if (u.u_error)
		return;
	ip = maknode(IFLNK | 0777);
	if (ip == NULL)
		return;
	u.u_base = uap->target;
	u.u_count = nc;
	u.u_offset = 0;
	u.u_segflg = 0;
	writei(ip);
	iput(ip);
}
#endif	UCB_SYMLINKS