xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 7505)
1*7505Sroot /*	vfs_syscalls.c	4.30	82/07/24	*/
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
187482Skre #include "../h/quota.h"
19*7505Sroot #include "../h/descrip.h"
2037Sbill 
216254Sroot chdir()
226254Sroot {
236254Sroot 
246254Sroot 	chdirec(&u.u_cdir);
256254Sroot }
266254Sroot 
276254Sroot chroot()
286254Sroot {
296254Sroot 
306254Sroot 	if (suser())
316254Sroot 		chdirec(&u.u_rdir);
326254Sroot }
336254Sroot 
346254Sroot chdirec(ipp)
356254Sroot register struct inode **ipp;
366254Sroot {
376254Sroot 	register struct inode *ip;
386254Sroot 	struct a {
396254Sroot 		char	*fname;
406254Sroot 	};
416254Sroot 
426254Sroot 	ip = namei(uchar, 0, 1);
436254Sroot 	if(ip == NULL)
446254Sroot 		return;
456254Sroot 	if((ip->i_mode&IFMT) != IFDIR) {
466254Sroot 		u.u_error = ENOTDIR;
476254Sroot 		goto bad;
486254Sroot 	}
496254Sroot 	if(access(ip, IEXEC))
506254Sroot 		goto bad;
517122Smckusick 	iunlock(ip);
527142Smckusick 	if (*ipp)
537142Smckusick 		irele(*ipp);
546254Sroot 	*ipp = ip;
556254Sroot 	return;
566254Sroot 
576254Sroot bad:
586254Sroot 	iput(ip);
596254Sroot }
606254Sroot 
6137Sbill /*
626254Sroot  * Open system call.
636254Sroot  */
646254Sroot open()
656254Sroot {
666254Sroot 	register struct inode *ip;
676254Sroot 	register struct a {
686254Sroot 		char	*fname;
696254Sroot 		int	rwmode;
706254Sroot 	} *uap;
716254Sroot 
726254Sroot 	uap = (struct a *)u.u_ap;
736254Sroot 	ip = namei(uchar, 0, 1);
746254Sroot 	if (ip == NULL)
756254Sroot 		return;
766254Sroot 	open1(ip, ++uap->rwmode, 0);
776254Sroot }
786254Sroot 
796254Sroot /*
806254Sroot  * Creat system call.
816254Sroot  */
82*7505Sroot ocreat()
836254Sroot {
846254Sroot 	register struct inode *ip;
856254Sroot 	register struct a {
866254Sroot 		char	*fname;
876254Sroot 		int	fmode;
886254Sroot 	} *uap;
896254Sroot 
906254Sroot 	uap = (struct a *)u.u_ap;
916254Sroot 	ip = namei(uchar, 1, 1);
926254Sroot 	if (ip == NULL) {
936254Sroot 		if (u.u_error)
946254Sroot 			return;
956254Sroot 		ip = maknode(uap->fmode&07777&(~ISVTX));
966254Sroot 		if (ip==NULL)
976254Sroot 			return;
986254Sroot 		open1(ip, FWRITE, 2);
996254Sroot 	} else
1006254Sroot 		open1(ip, FWRITE, 1);
1016254Sroot }
1026254Sroot 
1036254Sroot /*
1046254Sroot  * Common code for open and creat.
1056254Sroot  * Check permissions, allocate an open file structure,
1066254Sroot  * and call the device open routine if any.
1076254Sroot  */
1086254Sroot open1(ip, mode, trf)
1096254Sroot 	register struct inode *ip;
1106254Sroot 	register mode;
1116254Sroot {
1126254Sroot 	register struct file *fp;
1136254Sroot 	int i;
1146254Sroot 
1156254Sroot 	if (trf != 2) {
1166254Sroot 		if (mode&FREAD)
1176254Sroot 			(void) access(ip, IREAD);
1186254Sroot 		if (mode&FWRITE) {
1196254Sroot 			(void) access(ip, IWRITE);
1206254Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
1216254Sroot 				u.u_error = EISDIR;
1226254Sroot 		}
1236254Sroot 	}
1247142Smckusick 	if (u.u_error) {
1257142Smckusick 		iput(ip);
1267142Smckusick 		return;
1277142Smckusick 	}
1286254Sroot 	if (trf == 1)
1296254Sroot 		itrunc(ip);
1307122Smckusick 	iunlock(ip);
1316254Sroot 	if ((fp = falloc()) == NULL)
1326254Sroot 		goto out;
1336254Sroot 	fp->f_flag = mode&(FREAD|FWRITE);
134*7505Sroot 	fp->f_type = DTYPE_FILE;
1356254Sroot 	i = u.u_r.r_val1;
1366254Sroot 	fp->f_inode = ip;
1377439Sroot #ifdef EFS
1387439Sroot 	openi(ip, mode&(FREAD|FWRITE), trf);
1397439Sroot #else
1406254Sroot 	openi(ip, mode&(FREAD|FWRITE));
1417439Sroot #endif
1426254Sroot 	if (u.u_error == 0)
1436254Sroot 		return;
1446254Sroot 	u.u_ofile[i] = NULL;
1456254Sroot 	fp->f_count--;
1466254Sroot out:
1477142Smckusick 	irele(ip);
1486254Sroot }
1496254Sroot 
1506254Sroot /*
1516254Sroot  * Mknod system call
1526254Sroot  */
1536254Sroot mknod()
1546254Sroot {
1556254Sroot 	register struct inode *ip;
1566254Sroot 	register struct a {
1576254Sroot 		char	*fname;
1586254Sroot 		int	fmode;
1596254Sroot 		int	dev;
1606254Sroot 	} *uap;
1616254Sroot 
1626254Sroot 	uap = (struct a *)u.u_ap;
1636254Sroot 	if (suser()) {
1646254Sroot 		ip = namei(uchar, 1, 0);
1656254Sroot 		if (ip != NULL) {
1666254Sroot 			u.u_error = EEXIST;
1676254Sroot 			goto out;
1686254Sroot 		}
1696254Sroot 	}
1706254Sroot 	if (u.u_error)
1716254Sroot 		return;
1726254Sroot 	ip = maknode(uap->fmode);
1736254Sroot 	if (ip == NULL)
1746254Sroot 		return;
1756254Sroot 	if (uap->dev) {
1766254Sroot 		/*
1776254Sroot 		 * Want to be able to use this to make badblock
1786254Sroot 		 * inodes, so don't truncate the dev number.
1796254Sroot 		 */
1806574Smckusic 		ip->i_rdev = uap->dev;
1816254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
1826254Sroot 	}
1836254Sroot 
1846254Sroot out:
1856254Sroot 	iput(ip);
1866254Sroot }
1876254Sroot 
1886254Sroot /*
1896254Sroot  * link system call
1906254Sroot  */
1916254Sroot link()
1926254Sroot {
1936254Sroot 	register struct inode *ip, *xp;
1946254Sroot 	register struct a {
1956254Sroot 		char	*target;
1966254Sroot 		char	*linkname;
1976254Sroot 	} *uap;
1986254Sroot 
1996254Sroot 	uap = (struct a *)u.u_ap;
2006254Sroot 	ip = namei(uchar, 0, 1);    /* well, this routine is doomed anyhow */
2016254Sroot 	if (ip == NULL)
2026254Sroot 		return;
2037439Sroot 	if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
2047439Sroot 		iput(ip);
2057439Sroot 		return;
2067439Sroot 	}
2076254Sroot 	ip->i_nlink++;
2086254Sroot 	ip->i_flag |= ICHG;
2096254Sroot 	iupdat(ip, &time, &time, 1);
2107122Smckusick 	iunlock(ip);
2116254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2126254Sroot 	xp = namei(uchar, 1, 0);
2136254Sroot 	if (xp != NULL) {
2146254Sroot 		u.u_error = EEXIST;
2156254Sroot 		iput(xp);
2166254Sroot 		goto out;
2176254Sroot 	}
2186254Sroot 	if (u.u_error)
2196254Sroot 		goto out;
2206254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2216254Sroot 		iput(u.u_pdir);
2226254Sroot 		u.u_error = EXDEV;
2236254Sroot 		goto out;
2246254Sroot 	}
2256254Sroot 	wdir(ip);
2266254Sroot out:
2276254Sroot 	if (u.u_error) {
2286254Sroot 		ip->i_nlink--;
2296254Sroot 		ip->i_flag |= ICHG;
2306254Sroot 	}
2316254Sroot out1:
2327142Smckusick 	irele(ip);
2336254Sroot }
2346254Sroot 
2356254Sroot /*
2366254Sroot  * symlink -- make a symbolic link
2376254Sroot  */
2386254Sroot symlink()
2396254Sroot {
2406254Sroot 	register struct a {
2416254Sroot 		char	*target;
2426254Sroot 		char	*linkname;
2436254Sroot 	} *uap;
2446254Sroot 	register struct inode *ip;
2456254Sroot 	register char *tp;
2466254Sroot 	register c, nc;
2476254Sroot 
2486254Sroot 	uap = (struct a *)u.u_ap;
2496254Sroot 	tp = uap->target;
2506254Sroot 	nc = 0;
2516254Sroot 	while (c = fubyte(tp)) {
2526254Sroot 		if (c < 0) {
2536254Sroot 			u.u_error = EFAULT;
2546254Sroot 			return;
2556254Sroot 		}
2566254Sroot 		tp++;
2576254Sroot 		nc++;
2586254Sroot 	}
2596254Sroot 	u.u_dirp = uap->linkname;
2606254Sroot 	ip = namei(uchar, 1, 0);
2616254Sroot 	if (ip) {
2626254Sroot 		iput(ip);
2636254Sroot 		u.u_error = EEXIST;
2646254Sroot 		return;
2656254Sroot 	}
2666254Sroot 	if (u.u_error)
2676254Sroot 		return;
2686254Sroot 	ip = maknode(IFLNK | 0777);
2696254Sroot 	if (ip == NULL)
2706254Sroot 		return;
2716254Sroot 	u.u_base = uap->target;
2726254Sroot 	u.u_count = nc;
2736254Sroot 	u.u_offset = 0;
2746254Sroot 	u.u_segflg = 0;
2756254Sroot 	writei(ip);
2766254Sroot 	iput(ip);
2776254Sroot }
2786254Sroot 
2796254Sroot /*
2806254Sroot  * Unlink system call.
2816254Sroot  * Hard to avoid races here, especially
2826254Sroot  * in unlinking directories.
2836254Sroot  */
2846254Sroot unlink()
2856254Sroot {
2866254Sroot 	register struct inode *ip, *pp;
2876254Sroot 	struct a {
2886254Sroot 		char	*fname;
2896254Sroot 	};
2906574Smckusic 	struct fs *fs;
2916574Smckusic 	struct buf *bp;
2926574Smckusic 	int lbn, bn, base;
2937142Smckusick 	int unlinkingdot = 0;
2946254Sroot 
2956254Sroot 	pp = namei(uchar, 2, 0);
2966254Sroot 	if(pp == NULL)
2976254Sroot 		return;
2987439Sroot #ifdef EFS
2997439Sroot 	/* divert to extended file system if off machine. */
3007439Sroot 	if (efsinode(pp)) {
3017439Sroot 		dev_t ndev = pp->i_rdev;
3027439Sroot 
3037439Sroot 		iput(pp);	/* avoid recursive hang on inode */
3047439Sroot 		efsunlink(ndev);
3057439Sroot 		if (u.u_error != EEXIST)
3067439Sroot 			return;
3077439Sroot 
3087439Sroot 		/*
3097439Sroot 		 * If a null pathname remainder, then do
3107439Sroot 		 * the unlink locally after restoring state.
3117439Sroot 		 */
3127439Sroot 		u.u_error = 0;
3137439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
3147439Sroot 		pp = namei(uchar, 2, 0);
3157439Sroot 	}
3167439Sroot #endif
3177439Sroot 
3186254Sroot 	/*
3196254Sroot 	 * Check for unlink(".")
3206254Sroot 	 * to avoid hanging on the iget
3216254Sroot 	 */
3226254Sroot 	if (pp->i_number == u.u_dent.d_ino) {
3236254Sroot 		ip = pp;
3246254Sroot 		ip->i_count++;
3257142Smckusick 		unlinkingdot++;
3266254Sroot 	} else
3276574Smckusic 		ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
3286254Sroot 	if(ip == NULL)
3296254Sroot 		goto out1;
3306254Sroot 	if((ip->i_mode&IFMT)==IFDIR && !suser())
3316254Sroot 		goto out;
3326254Sroot 	/*
3336254Sroot 	 * Don't unlink a mounted file.
3346254Sroot 	 */
3356254Sroot 	if (ip->i_dev != pp->i_dev) {
3366254Sroot 		u.u_error = EBUSY;
3376254Sroot 		goto out;
3386254Sroot 	}
3396254Sroot 	if (ip->i_flag&ITEXT)
3406254Sroot 		xrele(ip);	/* try once to free text */
3416254Sroot /*
3426254Sroot 	if ((ip->i_flag&ITEXT) && ip->i_nlink==1) {
3436254Sroot  		u.u_error = ETXTBSY;
3446254Sroot 		goto out;
3456254Sroot 	}
3466254Sroot */
3476574Smckusic 	if (u.u_count == 0) {
3486574Smckusic 		/*
3496574Smckusic 		 * first entry in block, so set d_ino to zero.
3506574Smckusic 		 */
351*7505Sroot /*ZZ*/if(u.u_offset&0x1ff)printf("missed dir compact dir %s/%d off %d file %s\n"
352*7505Sroot /*ZZ*/,pp->i_fs->fs_fsmnt,pp->i_number,u.u_offset,u.u_dent.d_name);
3536574Smckusic 		u.u_base = (caddr_t)&u.u_dent;
3546574Smckusic 		u.u_count = DIRSIZ(&u.u_dent);
3556574Smckusic 		u.u_dent.d_ino = 0;
3566574Smckusic 		writei(pp);
3576574Smckusic 	} else {
3586574Smckusic 		/*
3596574Smckusic 		 * updating preceeding entry to skip over current entry.
3606574Smckusic 		 */
3616574Smckusic 		fs = pp->i_fs;
3626574Smckusic 		lbn = lblkno(fs, u.u_offset);
3636574Smckusic 		base = blkoff(fs, u.u_offset);
3646574Smckusic 		bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count));
3656574Smckusic 		bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn));
3666574Smckusic 		if (bp->b_flags & B_ERROR) {
3676574Smckusic 			brelse(bp);
3686574Smckusic 			goto out;
3696574Smckusic 		}
3706574Smckusic 		((struct direct *)(bp->b_un.b_addr + base))->d_reclen +=
3716574Smckusic 		    u.u_dent.d_reclen;
372*7505Sroot /*ZZ*/if(((int)(bp->b_un.b_addr + base)&0x1ff)+u.u_dent.d_reclen>512)
373*7505Sroot /*ZZ*/	panic("unlink: reclen");
3746574Smckusic 		bwrite(bp);
3756574Smckusic 		pp->i_flag |= IUPD|ICHG;
3766574Smckusic 	}
3776254Sroot 	ip->i_nlink--;
3786254Sroot 	ip->i_flag |= ICHG;
3796254Sroot 
3806254Sroot out:
3817142Smckusick 	if (unlinkingdot)
3827142Smckusick 		irele(ip);
3837142Smckusick 	else
3847142Smckusick 		iput(ip);
3856254Sroot out1:
3866254Sroot 	iput(pp);
3876254Sroot }
3886254Sroot 
3896254Sroot /*
3906254Sroot  * Seek system call
3916254Sroot  */
3926254Sroot seek()
3936254Sroot {
3946254Sroot 	register struct file *fp;
3956254Sroot 	register struct a {
3966254Sroot 		int	fdes;
3976254Sroot 		off_t	off;
3986254Sroot 		int	sbase;
3996254Sroot 	} *uap;
4006254Sroot 
4016254Sroot 	uap = (struct a *)u.u_ap;
4026254Sroot 	fp = getf(uap->fdes);
4036254Sroot 	if (fp == NULL)
4046254Sroot 		return;
405*7505Sroot 	if (fp->f_type == DTYPE_SOCKET) {
4066254Sroot 		u.u_error = ESPIPE;
4076254Sroot 		return;
4086254Sroot 	}
4096254Sroot 	if (uap->sbase == 1)
4106254Sroot 		uap->off += fp->f_offset;
4117439Sroot 	else if (uap->sbase == 2) {
4127439Sroot #ifdef EFS
4137439Sroot 		struct inode *ip = fp->f_inode;
4147439Sroot 		uap->off += efsinode(ip) ? efsfilesize(fp) : ip->i_size;
4157439Sroot #else
4166254Sroot 		uap->off += fp->f_inode->i_size;
4177439Sroot #endif
4187439Sroot 	}
4196254Sroot 	fp->f_offset = uap->off;
4206254Sroot 	u.u_r.r_off = uap->off;
4216254Sroot }
4226254Sroot 
4236254Sroot /*
4246254Sroot  * Access system call
4256254Sroot  */
4266254Sroot saccess()
4276254Sroot {
4286254Sroot 	register svuid, svgid;
4296254Sroot 	register struct inode *ip;
4306254Sroot 	register struct a {
4316254Sroot 		char	*fname;
4326254Sroot 		int	fmode;
4336254Sroot 	} *uap;
4346254Sroot 
4356254Sroot 	uap = (struct a *)u.u_ap;
4366254Sroot 	svuid = u.u_uid;
4376254Sroot 	svgid = u.u_gid;
4386254Sroot 	u.u_uid = u.u_ruid;
4396254Sroot 	u.u_gid = u.u_rgid;
4406254Sroot 	ip = namei(uchar, 0, 1);
4417439Sroot #ifdef EFS
4427439Sroot 	if (efsinode(ip)) {
4437439Sroot 		dev_t ndev = ip->i_rdev;
4447439Sroot 
4457439Sroot 		iput(ip);
4467439Sroot 		efssaccess(ndev);
4477439Sroot 		if (u.u_error != EEXIST)
4487439Sroot 			return;
4497439Sroot 		u.u_error = 0;
4507439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
4517439Sroot 		ip = namei(uchar, 0, 1);
4527439Sroot 	}
4537439Sroot #endif
4546254Sroot 	if (ip != NULL) {
4556254Sroot 		if (uap->fmode&(IREAD>>6))
4566254Sroot 			(void) access(ip, IREAD);
4576254Sroot 		if (uap->fmode&(IWRITE>>6))
4586254Sroot 			(void) access(ip, IWRITE);
4596254Sroot 		if (uap->fmode&(IEXEC>>6))
4606254Sroot 			(void) access(ip, IEXEC);
4616254Sroot 		iput(ip);
4626254Sroot 	}
4636254Sroot 	u.u_uid = svuid;
4646254Sroot 	u.u_gid = svgid;
4656254Sroot }
4666254Sroot 
4676254Sroot /*
46837Sbill  * the fstat system call.
46937Sbill  */
47037Sbill fstat()
47137Sbill {
47237Sbill 	register struct file *fp;
47337Sbill 	register struct a {
47437Sbill 		int	fdes;
47537Sbill 		struct stat *sb;
47637Sbill 	} *uap;
47737Sbill 
47837Sbill 	uap = (struct a *)u.u_ap;
47937Sbill 	fp = getf(uap->fdes);
4804828Swnj 	if (fp == NULL)
48137Sbill 		return;
4827439Sroot #ifdef EFS
4837439Sroot 	if (efsinode(fp->f_inode)) {
4847439Sroot 		efsfstat(fp->f_inode->i_rdev, fp);
4857439Sroot 		return;
4867439Sroot 	}
4877439Sroot #endif
488*7505Sroot 	if (fp->f_type == DTYPE_SOCKET)
4894891Swnj 		u.u_error = sostat(fp->f_socket, uap->sb);
4904828Swnj 	else
4914828Swnj 		stat1(fp->f_inode, uap->sb);
49237Sbill }
49337Sbill 
49437Sbill /*
4956574Smckusic  * Stat system call.  This version follows links.
49637Sbill  */
49737Sbill stat()
49837Sbill {
49937Sbill 	register struct inode *ip;
50037Sbill 	register struct a {
50137Sbill 		char	*fname;
50237Sbill 		struct stat *sb;
50337Sbill 	} *uap;
50437Sbill 
50537Sbill 	uap = (struct a *)u.u_ap;
5066423Sroot 	ip = namei(uchar, 0, 1);
5074828Swnj 	if (ip == NULL)
50837Sbill 		return;
5097439Sroot #ifdef EFS
5107439Sroot 	if (efsinode(ip)) {
5117439Sroot 		dev_t ndev = ip->i_rdev;
5127439Sroot 
5137439Sroot 		iput(ip);
5147439Sroot 		efsstat(ndev);
5157439Sroot 		if (u.u_error != EEXIST)
5167439Sroot 			return;
5177439Sroot 		u.u_error = 0;
5187439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
5197439Sroot 		ip = namei(uchar, 0, 1);
5207439Sroot 	}
5217439Sroot #endif
5223624Sroot 	stat1(ip, uap->sb);
52337Sbill 	iput(ip);
52437Sbill }
52537Sbill 
52637Sbill /*
5276574Smckusic  * Lstat system call.  This version does not follow links.
5285992Swnj  */
5295992Swnj lstat()
5305992Swnj {
5315992Swnj 	register struct inode *ip;
5325992Swnj 	register struct a {
5335992Swnj 		char	*fname;
5345992Swnj 		struct stat *sb;
5355992Swnj 	} *uap;
5365992Swnj 
5375992Swnj 	uap = (struct a *)u.u_ap;
5386423Sroot 	ip = namei(uchar, 0, 0);
5395992Swnj 	if (ip == NULL)
5405992Swnj 		return;
5417439Sroot #ifdef EFS
5427439Sroot 	if (efsinode(ip)) {
5437439Sroot 		dev_t ndev = ip->i_rdev;
5447439Sroot 
5457439Sroot 		iput(ip);
5467439Sroot 		efslstat(ndev);
5477439Sroot 		if (u.u_error != EEXIST)
5487439Sroot 			return;
5497439Sroot 		u.u_error = 0;
5507439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
5517439Sroot 		ip = namei(uchar, 0, 0);
5527439Sroot 	}
5537439Sroot #endif
5546153Ssam 	stat1(ip, uap->sb);
5555992Swnj 	iput(ip);
5565992Swnj }
5575992Swnj 
5585992Swnj /*
55937Sbill  * The basic routine for fstat and stat:
56037Sbill  * get the inode and pass appropriate parts back.
56137Sbill  */
5623624Sroot stat1(ip, ub)
5634828Swnj 	register struct inode *ip;
5644828Swnj 	struct stat *ub;
56537Sbill {
56637Sbill 	struct stat ds;
56737Sbill 
5681204Sbill 	IUPDAT(ip, &time, &time, 0);
56937Sbill 	/*
5707023Smckusick 	 * Copy from inode table
57137Sbill 	 */
57237Sbill 	ds.st_dev = ip->i_dev;
57337Sbill 	ds.st_ino = ip->i_number;
57437Sbill 	ds.st_mode = ip->i_mode;
57537Sbill 	ds.st_nlink = ip->i_nlink;
57637Sbill 	ds.st_uid = ip->i_uid;
57737Sbill 	ds.st_gid = ip->i_gid;
5786574Smckusic 	ds.st_rdev = (dev_t)ip->i_rdev;
5793624Sroot 	ds.st_size = ip->i_size;
5806574Smckusic 	ds.st_atime = ip->i_atime;
5816574Smckusic 	ds.st_mtime = ip->i_mtime;
5826574Smckusic 	ds.st_ctime = ip->i_ctime;
5837023Smckusick 	ds.st_blksize = ip->i_fs->fs_bsize;
58437Sbill 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
58537Sbill 		u.u_error = EFAULT;
58637Sbill }
58737Sbill 
58837Sbill /*
5895992Swnj  * Return target name of a symbolic link
59037Sbill  */
5915992Swnj readlink()
5925992Swnj {
5935992Swnj 	register struct inode *ip;
5945992Swnj 	register struct a {
5955992Swnj 		char	*name;
5965992Swnj 		char	*buf;
5975992Swnj 		int	count;
5985992Swnj 	} *uap;
5995992Swnj 
6005992Swnj 	ip = namei(uchar, 0, 0);
6015992Swnj 	if (ip == NULL)
6025992Swnj 		return;
6037439Sroot #ifdef EFS
6047439Sroot 	if (efsinode(ip)) {
6057439Sroot 		dev_t ndev = ip->i_rdev;
6067439Sroot 
6077439Sroot 		iput(ip);
6087439Sroot 		efsreadlink(ndev);
6097439Sroot 		if (u.u_error != EEXIST)
6107439Sroot 			return;
6117439Sroot 		u.u_error = 0;
6127439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
6137439Sroot 		ip = namei(uchar, 0, 0);
6147439Sroot 		return (0);
6157439Sroot 	}
6167439Sroot #endif
6175992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
6185992Swnj 		u.u_error = ENXIO;
6195992Swnj 		goto out;
6205992Swnj 	}
6215992Swnj 	uap = (struct a *)u.u_ap;
6225992Swnj 	u.u_offset = 0;
6235992Swnj 	u.u_base = uap->buf;
6245992Swnj 	u.u_count = uap->count;
6255992Swnj 	u.u_segflg = 0;
6265992Swnj 	readi(ip);
6275992Swnj out:
6285992Swnj 	iput(ip);
6295992Swnj 	u.u_r.r_val1 = uap->count - u.u_count;
6305992Swnj }
6315992Swnj 
6326254Sroot chmod()
6335992Swnj {
6346254Sroot 	register struct inode *ip;
6355992Swnj 	register struct a {
6366254Sroot 		char	*fname;
6376254Sroot 		int	fmode;
6385992Swnj 	} *uap;
6395992Swnj 
6405992Swnj 	uap = (struct a *)u.u_ap;
6416254Sroot 	if ((ip = owner(1)) == NULL)
6425992Swnj 		return;
6437439Sroot #ifdef EFS
6447439Sroot 	if (efsinode(ip)) {
6457439Sroot 		dev_t ndev = ip->i_rdev;
6467439Sroot 
6477439Sroot 		iput(ip);
6487439Sroot 		efschmod(ndev);
6497439Sroot 		if (u.u_error != EEXIST)
6507439Sroot 			return;
6517439Sroot 		u.u_error = 0;
6527439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
6537439Sroot 		ip = owner(1);
6547439Sroot 	}
6557439Sroot #endif
6566254Sroot 	ip->i_mode &= ~07777;
6577439Sroot 	if (u.u_uid) {
6586254Sroot 		uap->fmode &= ~ISVTX;
6597439Sroot 		if (ip->i_gid >= NGRPS ||
6607439Sroot 		    (u.u_grps[ip->i_gid/(sizeof(int)*8)] &
6617439Sroot 		     (1 << ip->i_gid%(sizeof(int)*8))) == 0)
6627439Sroot 			uap->fmode &= ~ISGID;
6637482Skre #if	MUSH
6647482Skre 		if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
6657482Skre 		    (ip->i_mode & IFMT) != IFCHR)
6667482Skre 			uap->fmode &= ~u.u_cmask;
6677482Skre #endif
6687439Sroot 	}
6696254Sroot 	ip->i_mode |= uap->fmode&07777;
6706254Sroot 	ip->i_flag |= ICHG;
6716254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
6726254Sroot 		xrele(ip);
6737482Skre #ifdef MELB
6747482Skre 	if ((ip->i_mode & ISUID) && ip->i_uid == 0)
6757482Skre 		printf("%s: ino %d (%s) setuid root\n"
6767482Skre 		    , getfs(ip->i_dev)->s_fsmnt
6777482Skre 		    , ip->i_number
6787482Skre 		    , u.u_dent.d_name
6797482Skre 		);
6807482Skre #endif
6815992Swnj 	iput(ip);
6825992Swnj }
6835992Swnj 
6846254Sroot chown()
68537Sbill {
6866254Sroot 	register struct inode *ip;
68737Sbill 	register struct a {
6886254Sroot 		char	*fname;
6896254Sroot 		int	uid;
6906254Sroot 		int	gid;
69137Sbill 	} *uap;
6927482Skre #if	QUOTA
6937482Skre 	register long change;
6947482Skre #endif
69537Sbill 
69637Sbill 	uap = (struct a *)u.u_ap;
6976254Sroot 	if (!suser() || (ip = owner(0)) == NULL)
69837Sbill 		return;
6997439Sroot #ifdef EFS
7007439Sroot 	if (efsinode(ip)) {
7017439Sroot 		dev_t ndev = ip->i_rdev;
7027439Sroot 
7037439Sroot 		iput(ip);
7047439Sroot 		efschown(ndev);
7057439Sroot 		if (u.u_error != EEXIST)
7067439Sroot 			return;
7077439Sroot 		u.u_error = 0;
7087439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
7097439Sroot 		ip = owner(0);
7107439Sroot 	}
7117439Sroot #endif
7127482Skre #if	QUOTA
7137439Sroot 	/*
7147482Skre 	 * This doesn't allow for holes in files (which hopefully don't
7157482Skre 	 * happen often in files that we chown), and is not accurate anyway
7167482Skre 	 * (eg: it totally ignores 3 level indir blk files - but hopefully
7177482Skre 	 * noone who can make a file that big will have a quota)
7187482Skre 	 */
7197482Skre 	if (ip->i_uid == uap->uid)
7207482Skre 		change = 0;
7217482Skre 	else {
7227482Skre 		register struct fs *fs = ip->i_fs;
7237482Skre 
7247482Skre 		if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
7257482Skre 			register off_t size;
7267482Skre 
7277482Skre 			size = blkroundup(fs, ip->i_size) - change;
7287482Skre 			change += size;
7297482Skre 			change += fs->fs_bsize;
7307482Skre 			/* This assumes NIADDR <= 2 */
7317482Skre 			if (size > NINDIR(fs) * fs->fs_bsize)
7327482Skre 				change += fs->fs_bsize;
7337482Skre 		} else
7347482Skre 			change = fragroundup(fs, ip->i_size);
7357482Skre 		change /= DEV_BSIZE;
7367482Skre 	}
7377482Skre 	chkdq(ip, -change, 1);
7387482Skre 	chkiq(ip->i_dev, ip, ip->i_uid, 1);
7397482Skre 	dqrele(ip->i_dquot);
7407482Skre #endif
7417482Skre 	/*
7427439Sroot 	 * keep uid/gid's in sane range - no err, so chown(file, uid, -1)
7437439Sroot 	 * will do something useful
7447439Sroot 	 */
7457439Sroot 	if (uap->uid >= 0 && uap->uid <= 32767)	/* should have a const	*/
7467439Sroot 		ip->i_uid = uap->uid;
7477439Sroot 	if (uap->gid >= 0 && uap->gid <= 32767)	/* same here		*/
7487439Sroot 		ip->i_gid = uap->gid;
7496254Sroot 	ip->i_flag |= ICHG;
7506254Sroot 	if (u.u_ruid != 0)
7516254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
7527482Skre #if	QUOTA
7537482Skre 	ip->i_dquot = inoquota(ip);
7547482Skre 	chkdq(ip, change, 1);
7557482Skre 	chkiq(ip->i_dev, NULL, uap->uid, 1);
7567482Skre #endif
7576254Sroot 	iput(ip);
75837Sbill }
75937Sbill 
76037Sbill /*
7616254Sroot  * Set IUPD and IACC times on file.
7626254Sroot  * Can't set ICHG.
76337Sbill  */
7646254Sroot utime()
7654828Swnj {
76637Sbill 	register struct a {
7676254Sroot 		char	*fname;
7686254Sroot 		time_t	*tptr;
76937Sbill 	} *uap;
7706254Sroot 	register struct inode *ip;
7716254Sroot 	time_t tv[2];
77237Sbill 
77337Sbill 	uap = (struct a *)u.u_ap;
7746254Sroot 	if ((ip = owner(1)) == NULL)
77537Sbill 		return;
7766254Sroot 	if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
7776254Sroot 		u.u_error = EFAULT;
7786254Sroot 	} else {
7797439Sroot #ifdef EFS
7807439Sroot 		if (efsinode(ip)) {
7817439Sroot 			dev_t ndev = ip->i_rdev;
7827439Sroot 
7837439Sroot 			iput(ip);
7847439Sroot 			efsutime(ndev, uap->fname, tv);
7857439Sroot 			if (u.u_error != EEXIST)
7867439Sroot 				return;
7877439Sroot 			u.u_error = 0;
7887439Sroot 			u.u_dirp = (caddr_t)u.u_arg[0];
7897439Sroot 			ip = owner(1);
7907439Sroot 		}
7917439Sroot #endif
7926254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
7936254Sroot 		iupdat(ip, &tv[0], &tv[1], 0);
79437Sbill 	}
79537Sbill 	iput(ip);
79637Sbill }
79737Sbill 
7986254Sroot sync()
79937Sbill {
80037Sbill 
8015416Swnj 	update(0);
80237Sbill }
803