xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 7482)
1*7482Skre /*	vfs_syscalls.c	4.29	82/07/22	*/
237Sbill 
337Sbill #include "../h/param.h"
437Sbill #include "../h/systm.h"
537Sbill #include "../h/dir.h"
637Sbill #include "../h/user.h"
76254Sroot #include "../h/file.h"
86574Smckusic #include "../h/stat.h"
937Sbill #include "../h/inode.h"
106574Smckusic #include "../h/fs.h"
116254Sroot #include "../h/buf.h"
126254Sroot #include "../h/proc.h"
136254Sroot #include "../h/inline.h"
147439Sroot #ifdef EFS
157439Sroot #include "../net/in.h"
167439Sroot #include "../h/efs.h"
177439Sroot #endif
18*7482Skre #include "../h/quota.h"
1937Sbill 
206254Sroot chdir()
216254Sroot {
226254Sroot 
236254Sroot 	chdirec(&u.u_cdir);
246254Sroot }
256254Sroot 
266254Sroot chroot()
276254Sroot {
286254Sroot 
296254Sroot 	if (suser())
306254Sroot 		chdirec(&u.u_rdir);
316254Sroot }
326254Sroot 
336254Sroot chdirec(ipp)
346254Sroot register struct inode **ipp;
356254Sroot {
366254Sroot 	register struct inode *ip;
376254Sroot 	struct a {
386254Sroot 		char	*fname;
396254Sroot 	};
406254Sroot 
416254Sroot 	ip = namei(uchar, 0, 1);
426254Sroot 	if(ip == NULL)
436254Sroot 		return;
446254Sroot 	if((ip->i_mode&IFMT) != IFDIR) {
456254Sroot 		u.u_error = ENOTDIR;
466254Sroot 		goto bad;
476254Sroot 	}
486254Sroot 	if(access(ip, IEXEC))
496254Sroot 		goto bad;
507122Smckusick 	iunlock(ip);
517142Smckusick 	if (*ipp)
527142Smckusick 		irele(*ipp);
536254Sroot 	*ipp = ip;
546254Sroot 	return;
556254Sroot 
566254Sroot bad:
576254Sroot 	iput(ip);
586254Sroot }
596254Sroot 
6037Sbill /*
616254Sroot  * Open system call.
626254Sroot  */
636254Sroot open()
646254Sroot {
656254Sroot 	register struct inode *ip;
666254Sroot 	register struct a {
676254Sroot 		char	*fname;
686254Sroot 		int	rwmode;
696254Sroot 	} *uap;
706254Sroot 
716254Sroot 	uap = (struct a *)u.u_ap;
726254Sroot 	ip = namei(uchar, 0, 1);
736254Sroot 	if (ip == NULL)
746254Sroot 		return;
756254Sroot 	open1(ip, ++uap->rwmode, 0);
766254Sroot }
776254Sroot 
786254Sroot /*
796254Sroot  * Creat system call.
806254Sroot  */
816254Sroot creat()
826254Sroot {
836254Sroot 	register struct inode *ip;
846254Sroot 	register struct a {
856254Sroot 		char	*fname;
866254Sroot 		int	fmode;
876254Sroot 	} *uap;
886254Sroot 
896254Sroot 	uap = (struct a *)u.u_ap;
906254Sroot 	ip = namei(uchar, 1, 1);
916254Sroot 	if (ip == NULL) {
926254Sroot 		if (u.u_error)
936254Sroot 			return;
946254Sroot 		ip = maknode(uap->fmode&07777&(~ISVTX));
956254Sroot 		if (ip==NULL)
966254Sroot 			return;
976254Sroot 		open1(ip, FWRITE, 2);
986254Sroot 	} else
996254Sroot 		open1(ip, FWRITE, 1);
1006254Sroot }
1016254Sroot 
1026254Sroot /*
1036254Sroot  * Common code for open and creat.
1046254Sroot  * Check permissions, allocate an open file structure,
1056254Sroot  * and call the device open routine if any.
1066254Sroot  */
1076254Sroot open1(ip, mode, trf)
1086254Sroot 	register struct inode *ip;
1096254Sroot 	register mode;
1106254Sroot {
1116254Sroot 	register struct file *fp;
1126254Sroot 	int i;
1136254Sroot 
1146254Sroot 	if (trf != 2) {
1156254Sroot 		if (mode&FREAD)
1166254Sroot 			(void) access(ip, IREAD);
1176254Sroot 		if (mode&FWRITE) {
1186254Sroot 			(void) access(ip, IWRITE);
1196254Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
1206254Sroot 				u.u_error = EISDIR;
1216254Sroot 		}
1226254Sroot 	}
1237142Smckusick 	if (u.u_error) {
1247142Smckusick 		iput(ip);
1257142Smckusick 		return;
1267142Smckusick 	}
1276254Sroot 	if (trf == 1)
1286254Sroot 		itrunc(ip);
1297122Smckusick 	iunlock(ip);
1306254Sroot 	if ((fp = falloc()) == NULL)
1316254Sroot 		goto out;
1326254Sroot 	fp->f_flag = mode&(FREAD|FWRITE);
1336254Sroot 	i = u.u_r.r_val1;
1346254Sroot 	fp->f_inode = ip;
1357439Sroot #ifdef EFS
1367439Sroot 	openi(ip, mode&(FREAD|FWRITE), trf);
1377439Sroot #else
1386254Sroot 	openi(ip, mode&(FREAD|FWRITE));
1397439Sroot #endif
1406254Sroot 	if (u.u_error == 0)
1416254Sroot 		return;
1426254Sroot 	u.u_ofile[i] = NULL;
1436254Sroot 	fp->f_count--;
1446254Sroot out:
1457142Smckusick 	irele(ip);
1466254Sroot }
1476254Sroot 
1486254Sroot /*
1496254Sroot  * Mknod system call
1506254Sroot  */
1516254Sroot mknod()
1526254Sroot {
1536254Sroot 	register struct inode *ip;
1546254Sroot 	register struct a {
1556254Sroot 		char	*fname;
1566254Sroot 		int	fmode;
1576254Sroot 		int	dev;
1586254Sroot 	} *uap;
1596254Sroot 
1606254Sroot 	uap = (struct a *)u.u_ap;
1616254Sroot 	if (suser()) {
1626254Sroot 		ip = namei(uchar, 1, 0);
1636254Sroot 		if (ip != NULL) {
1646254Sroot 			u.u_error = EEXIST;
1656254Sroot 			goto out;
1666254Sroot 		}
1676254Sroot 	}
1686254Sroot 	if (u.u_error)
1696254Sroot 		return;
1706254Sroot 	ip = maknode(uap->fmode);
1716254Sroot 	if (ip == NULL)
1726254Sroot 		return;
1736254Sroot 	if (uap->dev) {
1746254Sroot 		/*
1756254Sroot 		 * Want to be able to use this to make badblock
1766254Sroot 		 * inodes, so don't truncate the dev number.
1776254Sroot 		 */
1786574Smckusic 		ip->i_rdev = uap->dev;
1796254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
1806254Sroot 	}
1816254Sroot 
1826254Sroot out:
1836254Sroot 	iput(ip);
1846254Sroot }
1856254Sroot 
1866254Sroot /*
1876254Sroot  * link system call
1886254Sroot  */
1896254Sroot link()
1906254Sroot {
1916254Sroot 	register struct inode *ip, *xp;
1926254Sroot 	register struct a {
1936254Sroot 		char	*target;
1946254Sroot 		char	*linkname;
1956254Sroot 	} *uap;
1966254Sroot 
1976254Sroot 	uap = (struct a *)u.u_ap;
1986254Sroot 	ip = namei(uchar, 0, 1);    /* well, this routine is doomed anyhow */
1996254Sroot 	if (ip == NULL)
2006254Sroot 		return;
2017439Sroot 	if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
2027439Sroot 		iput(ip);
2037439Sroot 		return;
2047439Sroot 	}
2056254Sroot 	ip->i_nlink++;
2066254Sroot 	ip->i_flag |= ICHG;
2076254Sroot 	iupdat(ip, &time, &time, 1);
2087122Smckusick 	iunlock(ip);
2096254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2106254Sroot 	xp = namei(uchar, 1, 0);
2116254Sroot 	if (xp != NULL) {
2126254Sroot 		u.u_error = EEXIST;
2136254Sroot 		iput(xp);
2146254Sroot 		goto out;
2156254Sroot 	}
2166254Sroot 	if (u.u_error)
2176254Sroot 		goto out;
2186254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2196254Sroot 		iput(u.u_pdir);
2206254Sroot 		u.u_error = EXDEV;
2216254Sroot 		goto out;
2226254Sroot 	}
2236254Sroot 	wdir(ip);
2246254Sroot out:
2256254Sroot 	if (u.u_error) {
2266254Sroot 		ip->i_nlink--;
2276254Sroot 		ip->i_flag |= ICHG;
2286254Sroot 	}
2296254Sroot out1:
2307142Smckusick 	irele(ip);
2316254Sroot }
2326254Sroot 
2336254Sroot /*
2346254Sroot  * symlink -- make a symbolic link
2356254Sroot  */
2366254Sroot symlink()
2376254Sroot {
2386254Sroot 	register struct a {
2396254Sroot 		char	*target;
2406254Sroot 		char	*linkname;
2416254Sroot 	} *uap;
2426254Sroot 	register struct inode *ip;
2436254Sroot 	register char *tp;
2446254Sroot 	register c, nc;
2456254Sroot 
2466254Sroot 	uap = (struct a *)u.u_ap;
2476254Sroot 	tp = uap->target;
2486254Sroot 	nc = 0;
2496254Sroot 	while (c = fubyte(tp)) {
2506254Sroot 		if (c < 0) {
2516254Sroot 			u.u_error = EFAULT;
2526254Sroot 			return;
2536254Sroot 		}
2546254Sroot 		tp++;
2556254Sroot 		nc++;
2566254Sroot 	}
2576254Sroot 	u.u_dirp = uap->linkname;
2586254Sroot 	ip = namei(uchar, 1, 0);
2596254Sroot 	if (ip) {
2606254Sroot 		iput(ip);
2616254Sroot 		u.u_error = EEXIST;
2626254Sroot 		return;
2636254Sroot 	}
2646254Sroot 	if (u.u_error)
2656254Sroot 		return;
2666254Sroot 	ip = maknode(IFLNK | 0777);
2676254Sroot 	if (ip == NULL)
2686254Sroot 		return;
2696254Sroot 	u.u_base = uap->target;
2706254Sroot 	u.u_count = nc;
2716254Sroot 	u.u_offset = 0;
2726254Sroot 	u.u_segflg = 0;
2736254Sroot 	writei(ip);
2746254Sroot 	iput(ip);
2756254Sroot }
2766254Sroot 
2776254Sroot /*
2786254Sroot  * Unlink system call.
2796254Sroot  * Hard to avoid races here, especially
2806254Sroot  * in unlinking directories.
2816254Sroot  */
2826254Sroot unlink()
2836254Sroot {
2846254Sroot 	register struct inode *ip, *pp;
2856254Sroot 	struct a {
2866254Sroot 		char	*fname;
2876254Sroot 	};
2886574Smckusic 	struct fs *fs;
2896574Smckusic 	struct buf *bp;
2906574Smckusic 	int lbn, bn, base;
2917142Smckusick 	int unlinkingdot = 0;
2926254Sroot 
2936254Sroot 	pp = namei(uchar, 2, 0);
2946254Sroot 	if(pp == NULL)
2956254Sroot 		return;
2967439Sroot #ifdef EFS
2977439Sroot 	/* divert to extended file system if off machine. */
2987439Sroot 	if (efsinode(pp)) {
2997439Sroot 		dev_t ndev = pp->i_rdev;
3007439Sroot 
3017439Sroot 		iput(pp);	/* avoid recursive hang on inode */
3027439Sroot 		efsunlink(ndev);
3037439Sroot 		if (u.u_error != EEXIST)
3047439Sroot 			return;
3057439Sroot 
3067439Sroot 		/*
3077439Sroot 		 * If a null pathname remainder, then do
3087439Sroot 		 * the unlink locally after restoring state.
3097439Sroot 		 */
3107439Sroot 		u.u_error = 0;
3117439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
3127439Sroot 		pp = namei(uchar, 2, 0);
3137439Sroot 	}
3147439Sroot #endif
3157439Sroot 
3166254Sroot 	/*
3176254Sroot 	 * Check for unlink(".")
3186254Sroot 	 * to avoid hanging on the iget
3196254Sroot 	 */
3206254Sroot 	if (pp->i_number == u.u_dent.d_ino) {
3216254Sroot 		ip = pp;
3226254Sroot 		ip->i_count++;
3237142Smckusick 		unlinkingdot++;
3246254Sroot 	} else
3256574Smckusic 		ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
3266254Sroot 	if(ip == NULL)
3276254Sroot 		goto out1;
3286254Sroot 	if((ip->i_mode&IFMT)==IFDIR && !suser())
3296254Sroot 		goto out;
3306254Sroot 	/*
3316254Sroot 	 * Don't unlink a mounted file.
3326254Sroot 	 */
3336254Sroot 	if (ip->i_dev != pp->i_dev) {
3346254Sroot 		u.u_error = EBUSY;
3356254Sroot 		goto out;
3366254Sroot 	}
3376254Sroot 	if (ip->i_flag&ITEXT)
3386254Sroot 		xrele(ip);	/* try once to free text */
3396254Sroot /*
3406254Sroot 	if ((ip->i_flag&ITEXT) && ip->i_nlink==1) {
3416254Sroot  		u.u_error = ETXTBSY;
3426254Sroot 		goto out;
3436254Sroot 	}
3446254Sroot */
3456574Smckusic 	if (u.u_count == 0) {
3466574Smckusic 		/*
3476574Smckusic 		 * first entry in block, so set d_ino to zero.
3486574Smckusic 		 */
3496574Smckusic 		u.u_base = (caddr_t)&u.u_dent;
3506574Smckusic 		u.u_count = DIRSIZ(&u.u_dent);
3516574Smckusic 		u.u_dent.d_ino = 0;
3526574Smckusic 		writei(pp);
3536574Smckusic 	} else {
3546574Smckusic 		/*
3556574Smckusic 		 * updating preceeding entry to skip over current entry.
3566574Smckusic 		 */
3576574Smckusic 		fs = pp->i_fs;
3586574Smckusic 		lbn = lblkno(fs, u.u_offset);
3596574Smckusic 		base = blkoff(fs, u.u_offset);
3606574Smckusic 		bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count));
3616574Smckusic 		bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn));
3626574Smckusic 		if (bp->b_flags & B_ERROR) {
3636574Smckusic 			brelse(bp);
3646574Smckusic 			goto out;
3656574Smckusic 		}
3666574Smckusic 		((struct direct *)(bp->b_un.b_addr + base))->d_reclen +=
3676574Smckusic 		    u.u_dent.d_reclen;
3686574Smckusic 		bwrite(bp);
3696574Smckusic 		pp->i_flag |= IUPD|ICHG;
3706574Smckusic 	}
3716254Sroot 	ip->i_nlink--;
3726254Sroot 	ip->i_flag |= ICHG;
3736254Sroot 
3746254Sroot out:
3757142Smckusick 	if (unlinkingdot)
3767142Smckusick 		irele(ip);
3777142Smckusick 	else
3787142Smckusick 		iput(ip);
3796254Sroot out1:
3806254Sroot 	iput(pp);
3816254Sroot }
3826254Sroot 
3836254Sroot /*
3846254Sroot  * Seek system call
3856254Sroot  */
3866254Sroot seek()
3876254Sroot {
3886254Sroot 	register struct file *fp;
3896254Sroot 	register struct a {
3906254Sroot 		int	fdes;
3916254Sroot 		off_t	off;
3926254Sroot 		int	sbase;
3936254Sroot 	} *uap;
3946254Sroot 
3956254Sroot 	uap = (struct a *)u.u_ap;
3966254Sroot 	fp = getf(uap->fdes);
3976254Sroot 	if (fp == NULL)
3986254Sroot 		return;
3996254Sroot 	if (fp->f_flag&FSOCKET) {
4006254Sroot 		u.u_error = ESPIPE;
4016254Sroot 		return;
4026254Sroot 	}
4036254Sroot 	if (uap->sbase == 1)
4046254Sroot 		uap->off += fp->f_offset;
4057439Sroot 	else if (uap->sbase == 2) {
4067439Sroot #ifdef EFS
4077439Sroot 		struct inode *ip = fp->f_inode;
4087439Sroot 		uap->off += efsinode(ip) ? efsfilesize(fp) : ip->i_size;
4097439Sroot #else
4106254Sroot 		uap->off += fp->f_inode->i_size;
4117439Sroot #endif
4127439Sroot 	}
4136254Sroot 	fp->f_offset = uap->off;
4146254Sroot 	u.u_r.r_off = uap->off;
4156254Sroot }
4166254Sroot 
4176254Sroot /*
4186254Sroot  * Access system call
4196254Sroot  */
4206254Sroot saccess()
4216254Sroot {
4226254Sroot 	register svuid, svgid;
4236254Sroot 	register struct inode *ip;
4246254Sroot 	register struct a {
4256254Sroot 		char	*fname;
4266254Sroot 		int	fmode;
4276254Sroot 	} *uap;
4286254Sroot 
4296254Sroot 	uap = (struct a *)u.u_ap;
4306254Sroot 	svuid = u.u_uid;
4316254Sroot 	svgid = u.u_gid;
4326254Sroot 	u.u_uid = u.u_ruid;
4336254Sroot 	u.u_gid = u.u_rgid;
4346254Sroot 	ip = namei(uchar, 0, 1);
4357439Sroot #ifdef EFS
4367439Sroot 	if (efsinode(ip)) {
4377439Sroot 		dev_t ndev = ip->i_rdev;
4387439Sroot 
4397439Sroot 		iput(ip);
4407439Sroot 		efssaccess(ndev);
4417439Sroot 		if (u.u_error != EEXIST)
4427439Sroot 			return;
4437439Sroot 		u.u_error = 0;
4447439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
4457439Sroot 		ip = namei(uchar, 0, 1);
4467439Sroot 	}
4477439Sroot #endif
4486254Sroot 	if (ip != NULL) {
4496254Sroot 		if (uap->fmode&(IREAD>>6))
4506254Sroot 			(void) access(ip, IREAD);
4516254Sroot 		if (uap->fmode&(IWRITE>>6))
4526254Sroot 			(void) access(ip, IWRITE);
4536254Sroot 		if (uap->fmode&(IEXEC>>6))
4546254Sroot 			(void) access(ip, IEXEC);
4556254Sroot 		iput(ip);
4566254Sroot 	}
4576254Sroot 	u.u_uid = svuid;
4586254Sroot 	u.u_gid = svgid;
4596254Sroot }
4606254Sroot 
4616254Sroot /*
46237Sbill  * the fstat system call.
46337Sbill  */
46437Sbill fstat()
46537Sbill {
46637Sbill 	register struct file *fp;
46737Sbill 	register struct a {
46837Sbill 		int	fdes;
46937Sbill 		struct stat *sb;
47037Sbill 	} *uap;
47137Sbill 
47237Sbill 	uap = (struct a *)u.u_ap;
47337Sbill 	fp = getf(uap->fdes);
4744828Swnj 	if (fp == NULL)
47537Sbill 		return;
4767439Sroot #ifdef EFS
4777439Sroot 	if (efsinode(fp->f_inode)) {
4787439Sroot 		efsfstat(fp->f_inode->i_rdev, fp);
4797439Sroot 		return;
4807439Sroot 	}
4817439Sroot #endif
4824828Swnj 	if (fp->f_flag & FSOCKET)
4834891Swnj 		u.u_error = sostat(fp->f_socket, uap->sb);
4844828Swnj 	else
4854828Swnj 		stat1(fp->f_inode, uap->sb);
48637Sbill }
48737Sbill 
48837Sbill /*
4896574Smckusic  * Stat system call.  This version follows links.
49037Sbill  */
49137Sbill stat()
49237Sbill {
49337Sbill 	register struct inode *ip;
49437Sbill 	register struct a {
49537Sbill 		char	*fname;
49637Sbill 		struct stat *sb;
49737Sbill 	} *uap;
49837Sbill 
49937Sbill 	uap = (struct a *)u.u_ap;
5006423Sroot 	ip = namei(uchar, 0, 1);
5014828Swnj 	if (ip == NULL)
50237Sbill 		return;
5037439Sroot #ifdef EFS
5047439Sroot 	if (efsinode(ip)) {
5057439Sroot 		dev_t ndev = ip->i_rdev;
5067439Sroot 
5077439Sroot 		iput(ip);
5087439Sroot 		efsstat(ndev);
5097439Sroot 		if (u.u_error != EEXIST)
5107439Sroot 			return;
5117439Sroot 		u.u_error = 0;
5127439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
5137439Sroot 		ip = namei(uchar, 0, 1);
5147439Sroot 	}
5157439Sroot #endif
5163624Sroot 	stat1(ip, uap->sb);
51737Sbill 	iput(ip);
51837Sbill }
51937Sbill 
52037Sbill /*
5216574Smckusic  * Lstat system call.  This version does not follow links.
5225992Swnj  */
5235992Swnj lstat()
5245992Swnj {
5255992Swnj 	register struct inode *ip;
5265992Swnj 	register struct a {
5275992Swnj 		char	*fname;
5285992Swnj 		struct stat *sb;
5295992Swnj 	} *uap;
5305992Swnj 
5315992Swnj 	uap = (struct a *)u.u_ap;
5326423Sroot 	ip = namei(uchar, 0, 0);
5335992Swnj 	if (ip == NULL)
5345992Swnj 		return;
5357439Sroot #ifdef EFS
5367439Sroot 	if (efsinode(ip)) {
5377439Sroot 		dev_t ndev = ip->i_rdev;
5387439Sroot 
5397439Sroot 		iput(ip);
5407439Sroot 		efslstat(ndev);
5417439Sroot 		if (u.u_error != EEXIST)
5427439Sroot 			return;
5437439Sroot 		u.u_error = 0;
5447439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
5457439Sroot 		ip = namei(uchar, 0, 0);
5467439Sroot 	}
5477439Sroot #endif
5486153Ssam 	stat1(ip, uap->sb);
5495992Swnj 	iput(ip);
5505992Swnj }
5515992Swnj 
5525992Swnj /*
55337Sbill  * The basic routine for fstat and stat:
55437Sbill  * get the inode and pass appropriate parts back.
55537Sbill  */
5563624Sroot stat1(ip, ub)
5574828Swnj 	register struct inode *ip;
5584828Swnj 	struct stat *ub;
55937Sbill {
56037Sbill 	struct stat ds;
56137Sbill 
5621204Sbill 	IUPDAT(ip, &time, &time, 0);
56337Sbill 	/*
5647023Smckusick 	 * Copy from inode table
56537Sbill 	 */
56637Sbill 	ds.st_dev = ip->i_dev;
56737Sbill 	ds.st_ino = ip->i_number;
56837Sbill 	ds.st_mode = ip->i_mode;
56937Sbill 	ds.st_nlink = ip->i_nlink;
57037Sbill 	ds.st_uid = ip->i_uid;
57137Sbill 	ds.st_gid = ip->i_gid;
5726574Smckusic 	ds.st_rdev = (dev_t)ip->i_rdev;
5733624Sroot 	ds.st_size = ip->i_size;
5746574Smckusic 	ds.st_atime = ip->i_atime;
5756574Smckusic 	ds.st_mtime = ip->i_mtime;
5766574Smckusic 	ds.st_ctime = ip->i_ctime;
5777023Smckusick 	ds.st_blksize = ip->i_fs->fs_bsize;
57837Sbill 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
57937Sbill 		u.u_error = EFAULT;
58037Sbill }
58137Sbill 
58237Sbill /*
5835992Swnj  * Return target name of a symbolic link
58437Sbill  */
5855992Swnj readlink()
5865992Swnj {
5875992Swnj 	register struct inode *ip;
5885992Swnj 	register struct a {
5895992Swnj 		char	*name;
5905992Swnj 		char	*buf;
5915992Swnj 		int	count;
5925992Swnj 	} *uap;
5935992Swnj 
5945992Swnj 	ip = namei(uchar, 0, 0);
5955992Swnj 	if (ip == NULL)
5965992Swnj 		return;
5977439Sroot #ifdef EFS
5987439Sroot 	if (efsinode(ip)) {
5997439Sroot 		dev_t ndev = ip->i_rdev;
6007439Sroot 
6017439Sroot 		iput(ip);
6027439Sroot 		efsreadlink(ndev);
6037439Sroot 		if (u.u_error != EEXIST)
6047439Sroot 			return;
6057439Sroot 		u.u_error = 0;
6067439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
6077439Sroot 		ip = namei(uchar, 0, 0);
6087439Sroot 		return (0);
6097439Sroot 	}
6107439Sroot #endif
6115992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
6125992Swnj 		u.u_error = ENXIO;
6135992Swnj 		goto out;
6145992Swnj 	}
6155992Swnj 	uap = (struct a *)u.u_ap;
6165992Swnj 	u.u_offset = 0;
6175992Swnj 	u.u_base = uap->buf;
6185992Swnj 	u.u_count = uap->count;
6195992Swnj 	u.u_segflg = 0;
6205992Swnj 	readi(ip);
6215992Swnj out:
6225992Swnj 	iput(ip);
6235992Swnj 	u.u_r.r_val1 = uap->count - u.u_count;
6245992Swnj }
6255992Swnj 
6266254Sroot chmod()
6275992Swnj {
6286254Sroot 	register struct inode *ip;
6295992Swnj 	register struct a {
6306254Sroot 		char	*fname;
6316254Sroot 		int	fmode;
6325992Swnj 	} *uap;
6335992Swnj 
6345992Swnj 	uap = (struct a *)u.u_ap;
6356254Sroot 	if ((ip = owner(1)) == NULL)
6365992Swnj 		return;
6377439Sroot #ifdef EFS
6387439Sroot 	if (efsinode(ip)) {
6397439Sroot 		dev_t ndev = ip->i_rdev;
6407439Sroot 
6417439Sroot 		iput(ip);
6427439Sroot 		efschmod(ndev);
6437439Sroot 		if (u.u_error != EEXIST)
6447439Sroot 			return;
6457439Sroot 		u.u_error = 0;
6467439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
6477439Sroot 		ip = owner(1);
6487439Sroot 	}
6497439Sroot #endif
6506254Sroot 	ip->i_mode &= ~07777;
6517439Sroot 	if (u.u_uid) {
6526254Sroot 		uap->fmode &= ~ISVTX;
6537439Sroot 		if (ip->i_gid >= NGRPS ||
6547439Sroot 		    (u.u_grps[ip->i_gid/(sizeof(int)*8)] &
6557439Sroot 		     (1 << ip->i_gid%(sizeof(int)*8))) == 0)
6567439Sroot 			uap->fmode &= ~ISGID;
657*7482Skre #if	MUSH
658*7482Skre 		if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
659*7482Skre 		    (ip->i_mode & IFMT) != IFCHR)
660*7482Skre 			uap->fmode &= ~u.u_cmask;
661*7482Skre #endif
6627439Sroot 	}
6636254Sroot 	ip->i_mode |= uap->fmode&07777;
6646254Sroot 	ip->i_flag |= ICHG;
6656254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
6666254Sroot 		xrele(ip);
667*7482Skre #ifdef MELB
668*7482Skre 	if ((ip->i_mode & ISUID) && ip->i_uid == 0)
669*7482Skre 		printf("%s: ino %d (%s) setuid root\n"
670*7482Skre 		    , getfs(ip->i_dev)->s_fsmnt
671*7482Skre 		    , ip->i_number
672*7482Skre 		    , u.u_dent.d_name
673*7482Skre 		);
674*7482Skre #endif
6755992Swnj 	iput(ip);
6765992Swnj }
6775992Swnj 
6786254Sroot chown()
67937Sbill {
6806254Sroot 	register struct inode *ip;
68137Sbill 	register struct a {
6826254Sroot 		char	*fname;
6836254Sroot 		int	uid;
6846254Sroot 		int	gid;
68537Sbill 	} *uap;
686*7482Skre #if	QUOTA
687*7482Skre 	register long change;
688*7482Skre #endif
68937Sbill 
69037Sbill 	uap = (struct a *)u.u_ap;
6916254Sroot 	if (!suser() || (ip = owner(0)) == NULL)
69237Sbill 		return;
6937439Sroot #ifdef EFS
6947439Sroot 	if (efsinode(ip)) {
6957439Sroot 		dev_t ndev = ip->i_rdev;
6967439Sroot 
6977439Sroot 		iput(ip);
6987439Sroot 		efschown(ndev);
6997439Sroot 		if (u.u_error != EEXIST)
7007439Sroot 			return;
7017439Sroot 		u.u_error = 0;
7027439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
7037439Sroot 		ip = owner(0);
7047439Sroot 	}
7057439Sroot #endif
706*7482Skre #if	QUOTA
7077439Sroot 	/*
708*7482Skre 	 * This doesn't allow for holes in files (which hopefully don't
709*7482Skre 	 * happen often in files that we chown), and is not accurate anyway
710*7482Skre 	 * (eg: it totally ignores 3 level indir blk files - but hopefully
711*7482Skre 	 * noone who can make a file that big will have a quota)
712*7482Skre 	 */
713*7482Skre 	if (ip->i_uid == uap->uid)
714*7482Skre 		change = 0;
715*7482Skre 	else {
716*7482Skre 		register struct fs *fs = ip->i_fs;
717*7482Skre 
718*7482Skre 		if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
719*7482Skre 			register off_t size;
720*7482Skre 
721*7482Skre 			size = blkroundup(fs, ip->i_size) - change;
722*7482Skre 			change += size;
723*7482Skre 			change += fs->fs_bsize;
724*7482Skre 			/* This assumes NIADDR <= 2 */
725*7482Skre 			if (size > NINDIR(fs) * fs->fs_bsize)
726*7482Skre 				change += fs->fs_bsize;
727*7482Skre 		} else
728*7482Skre 			change = fragroundup(fs, ip->i_size);
729*7482Skre 		change /= DEV_BSIZE;
730*7482Skre 	}
731*7482Skre 	chkdq(ip, -change, 1);
732*7482Skre 	chkiq(ip->i_dev, ip, ip->i_uid, 1);
733*7482Skre 	dqrele(ip->i_dquot);
734*7482Skre #endif
735*7482Skre 	/*
7367439Sroot 	 * keep uid/gid's in sane range - no err, so chown(file, uid, -1)
7377439Sroot 	 * will do something useful
7387439Sroot 	 */
7397439Sroot 	if (uap->uid >= 0 && uap->uid <= 32767)	/* should have a const	*/
7407439Sroot 		ip->i_uid = uap->uid;
7417439Sroot 	if (uap->gid >= 0 && uap->gid <= 32767)	/* same here		*/
7427439Sroot 		ip->i_gid = uap->gid;
7436254Sroot 	ip->i_flag |= ICHG;
7446254Sroot 	if (u.u_ruid != 0)
7456254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
746*7482Skre #if	QUOTA
747*7482Skre 	ip->i_dquot = inoquota(ip);
748*7482Skre 	chkdq(ip, change, 1);
749*7482Skre 	chkiq(ip->i_dev, NULL, uap->uid, 1);
750*7482Skre #endif
7516254Sroot 	iput(ip);
75237Sbill }
75337Sbill 
75437Sbill /*
7556254Sroot  * Set IUPD and IACC times on file.
7566254Sroot  * Can't set ICHG.
75737Sbill  */
7586254Sroot utime()
7594828Swnj {
76037Sbill 	register struct a {
7616254Sroot 		char	*fname;
7626254Sroot 		time_t	*tptr;
76337Sbill 	} *uap;
7646254Sroot 	register struct inode *ip;
7656254Sroot 	time_t tv[2];
76637Sbill 
76737Sbill 	uap = (struct a *)u.u_ap;
7686254Sroot 	if ((ip = owner(1)) == NULL)
76937Sbill 		return;
7706254Sroot 	if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
7716254Sroot 		u.u_error = EFAULT;
7726254Sroot 	} else {
7737439Sroot #ifdef EFS
7747439Sroot 		if (efsinode(ip)) {
7757439Sroot 			dev_t ndev = ip->i_rdev;
7767439Sroot 
7777439Sroot 			iput(ip);
7787439Sroot 			efsutime(ndev, uap->fname, tv);
7797439Sroot 			if (u.u_error != EEXIST)
7807439Sroot 				return;
7817439Sroot 			u.u_error = 0;
7827439Sroot 			u.u_dirp = (caddr_t)u.u_arg[0];
7837439Sroot 			ip = owner(1);
7847439Sroot 		}
7857439Sroot #endif
7866254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
7876254Sroot 		iupdat(ip, &tv[0], &tv[1], 0);
78837Sbill 	}
78937Sbill 	iput(ip);
79037Sbill }
79137Sbill 
7926254Sroot sync()
79337Sbill {
79437Sbill 
7955416Swnj 	update(0);
79637Sbill }
797