xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 7439)
1*7439Sroot /*	vfs_syscalls.c	4.28	82/07/15	*/
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"
14*7439Sroot #ifdef EFS
15*7439Sroot #include "../net/in.h"
16*7439Sroot #include "../h/efs.h"
17*7439Sroot #endif
1837Sbill 
196254Sroot chdir()
206254Sroot {
216254Sroot 
226254Sroot 	chdirec(&u.u_cdir);
236254Sroot }
246254Sroot 
256254Sroot chroot()
266254Sroot {
276254Sroot 
286254Sroot 	if (suser())
296254Sroot 		chdirec(&u.u_rdir);
306254Sroot }
316254Sroot 
326254Sroot chdirec(ipp)
336254Sroot register struct inode **ipp;
346254Sroot {
356254Sroot 	register struct inode *ip;
366254Sroot 	struct a {
376254Sroot 		char	*fname;
386254Sroot 	};
396254Sroot 
406254Sroot 	ip = namei(uchar, 0, 1);
416254Sroot 	if(ip == NULL)
426254Sroot 		return;
436254Sroot 	if((ip->i_mode&IFMT) != IFDIR) {
446254Sroot 		u.u_error = ENOTDIR;
456254Sroot 		goto bad;
466254Sroot 	}
476254Sroot 	if(access(ip, IEXEC))
486254Sroot 		goto bad;
497122Smckusick 	iunlock(ip);
507142Smckusick 	if (*ipp)
517142Smckusick 		irele(*ipp);
526254Sroot 	*ipp = ip;
536254Sroot 	return;
546254Sroot 
556254Sroot bad:
566254Sroot 	iput(ip);
576254Sroot }
586254Sroot 
5937Sbill /*
606254Sroot  * Open system call.
616254Sroot  */
626254Sroot open()
636254Sroot {
646254Sroot 	register struct inode *ip;
656254Sroot 	register struct a {
666254Sroot 		char	*fname;
676254Sroot 		int	rwmode;
686254Sroot 	} *uap;
696254Sroot 
706254Sroot 	uap = (struct a *)u.u_ap;
716254Sroot 	ip = namei(uchar, 0, 1);
726254Sroot 	if (ip == NULL)
736254Sroot 		return;
746254Sroot 	open1(ip, ++uap->rwmode, 0);
756254Sroot }
766254Sroot 
776254Sroot /*
786254Sroot  * Creat system call.
796254Sroot  */
806254Sroot creat()
816254Sroot {
826254Sroot 	register struct inode *ip;
836254Sroot 	register struct a {
846254Sroot 		char	*fname;
856254Sroot 		int	fmode;
866254Sroot 	} *uap;
876254Sroot 
886254Sroot 	uap = (struct a *)u.u_ap;
896254Sroot 	ip = namei(uchar, 1, 1);
906254Sroot 	if (ip == NULL) {
916254Sroot 		if (u.u_error)
926254Sroot 			return;
936254Sroot 		ip = maknode(uap->fmode&07777&(~ISVTX));
946254Sroot 		if (ip==NULL)
956254Sroot 			return;
966254Sroot 		open1(ip, FWRITE, 2);
976254Sroot 	} else
986254Sroot 		open1(ip, FWRITE, 1);
996254Sroot }
1006254Sroot 
1016254Sroot /*
1026254Sroot  * Common code for open and creat.
1036254Sroot  * Check permissions, allocate an open file structure,
1046254Sroot  * and call the device open routine if any.
1056254Sroot  */
1066254Sroot open1(ip, mode, trf)
1076254Sroot 	register struct inode *ip;
1086254Sroot 	register mode;
1096254Sroot {
1106254Sroot 	register struct file *fp;
1116254Sroot 	int i;
1126254Sroot 
1136254Sroot 	if (trf != 2) {
1146254Sroot 		if (mode&FREAD)
1156254Sroot 			(void) access(ip, IREAD);
1166254Sroot 		if (mode&FWRITE) {
1176254Sroot 			(void) access(ip, IWRITE);
1186254Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
1196254Sroot 				u.u_error = EISDIR;
1206254Sroot 		}
1216254Sroot 	}
1227142Smckusick 	if (u.u_error) {
1237142Smckusick 		iput(ip);
1247142Smckusick 		return;
1257142Smckusick 	}
1266254Sroot 	if (trf == 1)
1276254Sroot 		itrunc(ip);
1287122Smckusick 	iunlock(ip);
1296254Sroot 	if ((fp = falloc()) == NULL)
1306254Sroot 		goto out;
1316254Sroot 	fp->f_flag = mode&(FREAD|FWRITE);
1326254Sroot 	i = u.u_r.r_val1;
1336254Sroot 	fp->f_inode = ip;
134*7439Sroot #ifdef EFS
135*7439Sroot 	openi(ip, mode&(FREAD|FWRITE), trf);
136*7439Sroot #else
1376254Sroot 	openi(ip, mode&(FREAD|FWRITE));
138*7439Sroot #endif
1396254Sroot 	if (u.u_error == 0)
1406254Sroot 		return;
1416254Sroot 	u.u_ofile[i] = NULL;
1426254Sroot 	fp->f_count--;
1436254Sroot out:
1447142Smckusick 	irele(ip);
1456254Sroot }
1466254Sroot 
1476254Sroot /*
1486254Sroot  * Mknod system call
1496254Sroot  */
1506254Sroot mknod()
1516254Sroot {
1526254Sroot 	register struct inode *ip;
1536254Sroot 	register struct a {
1546254Sroot 		char	*fname;
1556254Sroot 		int	fmode;
1566254Sroot 		int	dev;
1576254Sroot 	} *uap;
1586254Sroot 
1596254Sroot 	uap = (struct a *)u.u_ap;
1606254Sroot 	if (suser()) {
1616254Sroot 		ip = namei(uchar, 1, 0);
1626254Sroot 		if (ip != NULL) {
1636254Sroot 			u.u_error = EEXIST;
1646254Sroot 			goto out;
1656254Sroot 		}
1666254Sroot 	}
1676254Sroot 	if (u.u_error)
1686254Sroot 		return;
1696254Sroot 	ip = maknode(uap->fmode);
1706254Sroot 	if (ip == NULL)
1716254Sroot 		return;
1726254Sroot 	if (uap->dev) {
1736254Sroot 		/*
1746254Sroot 		 * Want to be able to use this to make badblock
1756254Sroot 		 * inodes, so don't truncate the dev number.
1766254Sroot 		 */
1776574Smckusic 		ip->i_rdev = uap->dev;
1786254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
1796254Sroot 	}
1806254Sroot 
1816254Sroot out:
1826254Sroot 	iput(ip);
1836254Sroot }
1846254Sroot 
1856254Sroot /*
1866254Sroot  * link system call
1876254Sroot  */
1886254Sroot link()
1896254Sroot {
1906254Sroot 	register struct inode *ip, *xp;
1916254Sroot 	register struct a {
1926254Sroot 		char	*target;
1936254Sroot 		char	*linkname;
1946254Sroot 	} *uap;
1956254Sroot 
1966254Sroot 	uap = (struct a *)u.u_ap;
1976254Sroot 	ip = namei(uchar, 0, 1);    /* well, this routine is doomed anyhow */
1986254Sroot 	if (ip == NULL)
1996254Sroot 		return;
200*7439Sroot 	if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
201*7439Sroot 		iput(ip);
202*7439Sroot 		return;
203*7439Sroot 	}
2046254Sroot 	ip->i_nlink++;
2056254Sroot 	ip->i_flag |= ICHG;
2066254Sroot 	iupdat(ip, &time, &time, 1);
2077122Smckusick 	iunlock(ip);
2086254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2096254Sroot 	xp = namei(uchar, 1, 0);
2106254Sroot 	if (xp != NULL) {
2116254Sroot 		u.u_error = EEXIST;
2126254Sroot 		iput(xp);
2136254Sroot 		goto out;
2146254Sroot 	}
2156254Sroot 	if (u.u_error)
2166254Sroot 		goto out;
2176254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2186254Sroot 		iput(u.u_pdir);
2196254Sroot 		u.u_error = EXDEV;
2206254Sroot 		goto out;
2216254Sroot 	}
2226254Sroot 	wdir(ip);
2236254Sroot out:
2246254Sroot 	if (u.u_error) {
2256254Sroot 		ip->i_nlink--;
2266254Sroot 		ip->i_flag |= ICHG;
2276254Sroot 	}
2286254Sroot out1:
2297142Smckusick 	irele(ip);
2306254Sroot }
2316254Sroot 
2326254Sroot /*
2336254Sroot  * symlink -- make a symbolic link
2346254Sroot  */
2356254Sroot symlink()
2366254Sroot {
2376254Sroot 	register struct a {
2386254Sroot 		char	*target;
2396254Sroot 		char	*linkname;
2406254Sroot 	} *uap;
2416254Sroot 	register struct inode *ip;
2426254Sroot 	register char *tp;
2436254Sroot 	register c, nc;
2446254Sroot 
2456254Sroot 	uap = (struct a *)u.u_ap;
2466254Sroot 	tp = uap->target;
2476254Sroot 	nc = 0;
2486254Sroot 	while (c = fubyte(tp)) {
2496254Sroot 		if (c < 0) {
2506254Sroot 			u.u_error = EFAULT;
2516254Sroot 			return;
2526254Sroot 		}
2536254Sroot 		tp++;
2546254Sroot 		nc++;
2556254Sroot 	}
2566254Sroot 	u.u_dirp = uap->linkname;
2576254Sroot 	ip = namei(uchar, 1, 0);
2586254Sroot 	if (ip) {
2596254Sroot 		iput(ip);
2606254Sroot 		u.u_error = EEXIST;
2616254Sroot 		return;
2626254Sroot 	}
2636254Sroot 	if (u.u_error)
2646254Sroot 		return;
2656254Sroot 	ip = maknode(IFLNK | 0777);
2666254Sroot 	if (ip == NULL)
2676254Sroot 		return;
2686254Sroot 	u.u_base = uap->target;
2696254Sroot 	u.u_count = nc;
2706254Sroot 	u.u_offset = 0;
2716254Sroot 	u.u_segflg = 0;
2726254Sroot 	writei(ip);
2736254Sroot 	iput(ip);
2746254Sroot }
2756254Sroot 
2766254Sroot /*
2776254Sroot  * Unlink system call.
2786254Sroot  * Hard to avoid races here, especially
2796254Sroot  * in unlinking directories.
2806254Sroot  */
2816254Sroot unlink()
2826254Sroot {
2836254Sroot 	register struct inode *ip, *pp;
2846254Sroot 	struct a {
2856254Sroot 		char	*fname;
2866254Sroot 	};
2876574Smckusic 	struct fs *fs;
2886574Smckusic 	struct buf *bp;
2896574Smckusic 	int lbn, bn, base;
2907142Smckusick 	int unlinkingdot = 0;
2916254Sroot 
2926254Sroot 	pp = namei(uchar, 2, 0);
2936254Sroot 	if(pp == NULL)
2946254Sroot 		return;
295*7439Sroot #ifdef EFS
296*7439Sroot 	/* divert to extended file system if off machine. */
297*7439Sroot 	if (efsinode(pp)) {
298*7439Sroot 		dev_t ndev = pp->i_rdev;
299*7439Sroot 
300*7439Sroot 		iput(pp);	/* avoid recursive hang on inode */
301*7439Sroot 		efsunlink(ndev);
302*7439Sroot 		if (u.u_error != EEXIST)
303*7439Sroot 			return;
304*7439Sroot 
305*7439Sroot 		/*
306*7439Sroot 		 * If a null pathname remainder, then do
307*7439Sroot 		 * the unlink locally after restoring state.
308*7439Sroot 		 */
309*7439Sroot 		u.u_error = 0;
310*7439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
311*7439Sroot 		pp = namei(uchar, 2, 0);
312*7439Sroot 	}
313*7439Sroot #endif
314*7439Sroot 
3156254Sroot 	/*
3166254Sroot 	 * Check for unlink(".")
3176254Sroot 	 * to avoid hanging on the iget
3186254Sroot 	 */
3196254Sroot 	if (pp->i_number == u.u_dent.d_ino) {
3206254Sroot 		ip = pp;
3216254Sroot 		ip->i_count++;
3227142Smckusick 		unlinkingdot++;
3236254Sroot 	} else
3246574Smckusic 		ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
3256254Sroot 	if(ip == NULL)
3266254Sroot 		goto out1;
3276254Sroot 	if((ip->i_mode&IFMT)==IFDIR && !suser())
3286254Sroot 		goto out;
3296254Sroot 	/*
3306254Sroot 	 * Don't unlink a mounted file.
3316254Sroot 	 */
3326254Sroot 	if (ip->i_dev != pp->i_dev) {
3336254Sroot 		u.u_error = EBUSY;
3346254Sroot 		goto out;
3356254Sroot 	}
3366254Sroot 	if (ip->i_flag&ITEXT)
3376254Sroot 		xrele(ip);	/* try once to free text */
3386254Sroot /*
3396254Sroot 	if ((ip->i_flag&ITEXT) && ip->i_nlink==1) {
3406254Sroot  		u.u_error = ETXTBSY;
3416254Sroot 		goto out;
3426254Sroot 	}
3436254Sroot */
3446574Smckusic 	if (u.u_count == 0) {
3456574Smckusic 		/*
3466574Smckusic 		 * first entry in block, so set d_ino to zero.
3476574Smckusic 		 */
3486574Smckusic 		u.u_base = (caddr_t)&u.u_dent;
3496574Smckusic 		u.u_count = DIRSIZ(&u.u_dent);
3506574Smckusic 		u.u_dent.d_ino = 0;
3516574Smckusic 		writei(pp);
3526574Smckusic 	} else {
3536574Smckusic 		/*
3546574Smckusic 		 * updating preceeding entry to skip over current entry.
3556574Smckusic 		 */
3566574Smckusic 		fs = pp->i_fs;
3576574Smckusic 		lbn = lblkno(fs, u.u_offset);
3586574Smckusic 		base = blkoff(fs, u.u_offset);
3596574Smckusic 		bn = fsbtodb(fs, bmap(pp, lbn, B_WRITE, base + u.u_count));
3606574Smckusic 		bp = bread(pp->i_dev, bn, blksize(fs, pp, lbn));
3616574Smckusic 		if (bp->b_flags & B_ERROR) {
3626574Smckusic 			brelse(bp);
3636574Smckusic 			goto out;
3646574Smckusic 		}
3656574Smckusic 		((struct direct *)(bp->b_un.b_addr + base))->d_reclen +=
3666574Smckusic 		    u.u_dent.d_reclen;
3676574Smckusic 		bwrite(bp);
3686574Smckusic 		pp->i_flag |= IUPD|ICHG;
3696574Smckusic 	}
3706254Sroot 	ip->i_nlink--;
3716254Sroot 	ip->i_flag |= ICHG;
3726254Sroot 
3736254Sroot out:
3747142Smckusick 	if (unlinkingdot)
3757142Smckusick 		irele(ip);
3767142Smckusick 	else
3777142Smckusick 		iput(ip);
3786254Sroot out1:
3796254Sroot 	iput(pp);
3806254Sroot }
3816254Sroot 
3826254Sroot /*
3836254Sroot  * Seek system call
3846254Sroot  */
3856254Sroot seek()
3866254Sroot {
3876254Sroot 	register struct file *fp;
3886254Sroot 	register struct a {
3896254Sroot 		int	fdes;
3906254Sroot 		off_t	off;
3916254Sroot 		int	sbase;
3926254Sroot 	} *uap;
3936254Sroot 
3946254Sroot 	uap = (struct a *)u.u_ap;
3956254Sroot 	fp = getf(uap->fdes);
3966254Sroot 	if (fp == NULL)
3976254Sroot 		return;
3986254Sroot 	if (fp->f_flag&FSOCKET) {
3996254Sroot 		u.u_error = ESPIPE;
4006254Sroot 		return;
4016254Sroot 	}
4026254Sroot 	if (uap->sbase == 1)
4036254Sroot 		uap->off += fp->f_offset;
404*7439Sroot 	else if (uap->sbase == 2) {
405*7439Sroot #ifdef EFS
406*7439Sroot 		struct inode *ip = fp->f_inode;
407*7439Sroot 		uap->off += efsinode(ip) ? efsfilesize(fp) : ip->i_size;
408*7439Sroot #else
4096254Sroot 		uap->off += fp->f_inode->i_size;
410*7439Sroot #endif
411*7439Sroot 	}
4126254Sroot 	fp->f_offset = uap->off;
4136254Sroot 	u.u_r.r_off = uap->off;
4146254Sroot }
4156254Sroot 
4166254Sroot /*
4176254Sroot  * Access system call
4186254Sroot  */
4196254Sroot saccess()
4206254Sroot {
4216254Sroot 	register svuid, svgid;
4226254Sroot 	register struct inode *ip;
4236254Sroot 	register struct a {
4246254Sroot 		char	*fname;
4256254Sroot 		int	fmode;
4266254Sroot 	} *uap;
4276254Sroot 
4286254Sroot 	uap = (struct a *)u.u_ap;
4296254Sroot 	svuid = u.u_uid;
4306254Sroot 	svgid = u.u_gid;
4316254Sroot 	u.u_uid = u.u_ruid;
4326254Sroot 	u.u_gid = u.u_rgid;
4336254Sroot 	ip = namei(uchar, 0, 1);
434*7439Sroot #ifdef EFS
435*7439Sroot 	if (efsinode(ip)) {
436*7439Sroot 		dev_t ndev = ip->i_rdev;
437*7439Sroot 
438*7439Sroot 		iput(ip);
439*7439Sroot 		efssaccess(ndev);
440*7439Sroot 		if (u.u_error != EEXIST)
441*7439Sroot 			return;
442*7439Sroot 		u.u_error = 0;
443*7439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
444*7439Sroot 		ip = namei(uchar, 0, 1);
445*7439Sroot 	}
446*7439Sroot #endif
4476254Sroot 	if (ip != NULL) {
4486254Sroot 		if (uap->fmode&(IREAD>>6))
4496254Sroot 			(void) access(ip, IREAD);
4506254Sroot 		if (uap->fmode&(IWRITE>>6))
4516254Sroot 			(void) access(ip, IWRITE);
4526254Sroot 		if (uap->fmode&(IEXEC>>6))
4536254Sroot 			(void) access(ip, IEXEC);
4546254Sroot 		iput(ip);
4556254Sroot 	}
4566254Sroot 	u.u_uid = svuid;
4576254Sroot 	u.u_gid = svgid;
4586254Sroot }
4596254Sroot 
4606254Sroot /*
46137Sbill  * the fstat system call.
46237Sbill  */
46337Sbill fstat()
46437Sbill {
46537Sbill 	register struct file *fp;
46637Sbill 	register struct a {
46737Sbill 		int	fdes;
46837Sbill 		struct stat *sb;
46937Sbill 	} *uap;
47037Sbill 
47137Sbill 	uap = (struct a *)u.u_ap;
47237Sbill 	fp = getf(uap->fdes);
4734828Swnj 	if (fp == NULL)
47437Sbill 		return;
475*7439Sroot #ifdef EFS
476*7439Sroot 	if (efsinode(fp->f_inode)) {
477*7439Sroot 		efsfstat(fp->f_inode->i_rdev, fp);
478*7439Sroot 		return;
479*7439Sroot 	}
480*7439Sroot #endif
4814828Swnj 	if (fp->f_flag & FSOCKET)
4824891Swnj 		u.u_error = sostat(fp->f_socket, uap->sb);
4834828Swnj 	else
4844828Swnj 		stat1(fp->f_inode, uap->sb);
48537Sbill }
48637Sbill 
48737Sbill /*
4886574Smckusic  * Stat system call.  This version follows links.
48937Sbill  */
49037Sbill stat()
49137Sbill {
49237Sbill 	register struct inode *ip;
49337Sbill 	register struct a {
49437Sbill 		char	*fname;
49537Sbill 		struct stat *sb;
49637Sbill 	} *uap;
49737Sbill 
49837Sbill 	uap = (struct a *)u.u_ap;
4996423Sroot 	ip = namei(uchar, 0, 1);
5004828Swnj 	if (ip == NULL)
50137Sbill 		return;
502*7439Sroot #ifdef EFS
503*7439Sroot 	if (efsinode(ip)) {
504*7439Sroot 		dev_t ndev = ip->i_rdev;
505*7439Sroot 
506*7439Sroot 		iput(ip);
507*7439Sroot 		efsstat(ndev);
508*7439Sroot 		if (u.u_error != EEXIST)
509*7439Sroot 			return;
510*7439Sroot 		u.u_error = 0;
511*7439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
512*7439Sroot 		ip = namei(uchar, 0, 1);
513*7439Sroot 	}
514*7439Sroot #endif
5153624Sroot 	stat1(ip, uap->sb);
51637Sbill 	iput(ip);
51737Sbill }
51837Sbill 
51937Sbill /*
5206574Smckusic  * Lstat system call.  This version does not follow links.
5215992Swnj  */
5225992Swnj lstat()
5235992Swnj {
5245992Swnj 	register struct inode *ip;
5255992Swnj 	register struct a {
5265992Swnj 		char	*fname;
5275992Swnj 		struct stat *sb;
5285992Swnj 	} *uap;
5295992Swnj 
5305992Swnj 	uap = (struct a *)u.u_ap;
5316423Sroot 	ip = namei(uchar, 0, 0);
5325992Swnj 	if (ip == NULL)
5335992Swnj 		return;
534*7439Sroot #ifdef EFS
535*7439Sroot 	if (efsinode(ip)) {
536*7439Sroot 		dev_t ndev = ip->i_rdev;
537*7439Sroot 
538*7439Sroot 		iput(ip);
539*7439Sroot 		efslstat(ndev);
540*7439Sroot 		if (u.u_error != EEXIST)
541*7439Sroot 			return;
542*7439Sroot 		u.u_error = 0;
543*7439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
544*7439Sroot 		ip = namei(uchar, 0, 0);
545*7439Sroot 	}
546*7439Sroot #endif
5476153Ssam 	stat1(ip, uap->sb);
5485992Swnj 	iput(ip);
5495992Swnj }
5505992Swnj 
5515992Swnj /*
55237Sbill  * The basic routine for fstat and stat:
55337Sbill  * get the inode and pass appropriate parts back.
55437Sbill  */
5553624Sroot stat1(ip, ub)
5564828Swnj 	register struct inode *ip;
5574828Swnj 	struct stat *ub;
55837Sbill {
55937Sbill 	struct stat ds;
56037Sbill 
5611204Sbill 	IUPDAT(ip, &time, &time, 0);
56237Sbill 	/*
5637023Smckusick 	 * Copy from inode table
56437Sbill 	 */
56537Sbill 	ds.st_dev = ip->i_dev;
56637Sbill 	ds.st_ino = ip->i_number;
56737Sbill 	ds.st_mode = ip->i_mode;
56837Sbill 	ds.st_nlink = ip->i_nlink;
56937Sbill 	ds.st_uid = ip->i_uid;
57037Sbill 	ds.st_gid = ip->i_gid;
5716574Smckusic 	ds.st_rdev = (dev_t)ip->i_rdev;
5723624Sroot 	ds.st_size = ip->i_size;
5736574Smckusic 	ds.st_atime = ip->i_atime;
5746574Smckusic 	ds.st_mtime = ip->i_mtime;
5756574Smckusic 	ds.st_ctime = ip->i_ctime;
5767023Smckusick 	ds.st_blksize = ip->i_fs->fs_bsize;
57737Sbill 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
57837Sbill 		u.u_error = EFAULT;
57937Sbill }
58037Sbill 
58137Sbill /*
5825992Swnj  * Return target name of a symbolic link
58337Sbill  */
5845992Swnj readlink()
5855992Swnj {
5865992Swnj 	register struct inode *ip;
5875992Swnj 	register struct a {
5885992Swnj 		char	*name;
5895992Swnj 		char	*buf;
5905992Swnj 		int	count;
5915992Swnj 	} *uap;
5925992Swnj 
5935992Swnj 	ip = namei(uchar, 0, 0);
5945992Swnj 	if (ip == NULL)
5955992Swnj 		return;
596*7439Sroot #ifdef EFS
597*7439Sroot 	if (efsinode(ip)) {
598*7439Sroot 		dev_t ndev = ip->i_rdev;
599*7439Sroot 
600*7439Sroot 		iput(ip);
601*7439Sroot 		efsreadlink(ndev);
602*7439Sroot 		if (u.u_error != EEXIST)
603*7439Sroot 			return;
604*7439Sroot 		u.u_error = 0;
605*7439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
606*7439Sroot 		ip = namei(uchar, 0, 0);
607*7439Sroot 		return (0);
608*7439Sroot 	}
609*7439Sroot #endif
6105992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
6115992Swnj 		u.u_error = ENXIO;
6125992Swnj 		goto out;
6135992Swnj 	}
6145992Swnj 	uap = (struct a *)u.u_ap;
6155992Swnj 	u.u_offset = 0;
6165992Swnj 	u.u_base = uap->buf;
6175992Swnj 	u.u_count = uap->count;
6185992Swnj 	u.u_segflg = 0;
6195992Swnj 	readi(ip);
6205992Swnj out:
6215992Swnj 	iput(ip);
6225992Swnj 	u.u_r.r_val1 = uap->count - u.u_count;
6235992Swnj }
6245992Swnj 
6256254Sroot chmod()
6265992Swnj {
6276254Sroot 	register struct inode *ip;
6285992Swnj 	register struct a {
6296254Sroot 		char	*fname;
6306254Sroot 		int	fmode;
6315992Swnj 	} *uap;
6325992Swnj 
6335992Swnj 	uap = (struct a *)u.u_ap;
6346254Sroot 	if ((ip = owner(1)) == NULL)
6355992Swnj 		return;
636*7439Sroot #ifdef EFS
637*7439Sroot 	if (efsinode(ip)) {
638*7439Sroot 		dev_t ndev = ip->i_rdev;
639*7439Sroot 
640*7439Sroot 		iput(ip);
641*7439Sroot 		efschmod(ndev);
642*7439Sroot 		if (u.u_error != EEXIST)
643*7439Sroot 			return;
644*7439Sroot 		u.u_error = 0;
645*7439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
646*7439Sroot 		ip = owner(1);
647*7439Sroot 	}
648*7439Sroot #endif
6496254Sroot 	ip->i_mode &= ~07777;
650*7439Sroot 	if (u.u_uid) {
6516254Sroot 		uap->fmode &= ~ISVTX;
652*7439Sroot 		if (ip->i_gid >= NGRPS ||
653*7439Sroot 		    (u.u_grps[ip->i_gid/(sizeof(int)*8)] &
654*7439Sroot 		     (1 << ip->i_gid%(sizeof(int)*8))) == 0)
655*7439Sroot 			uap->fmode &= ~ISGID;
656*7439Sroot 	}
6576254Sroot 	ip->i_mode |= uap->fmode&07777;
6586254Sroot 	ip->i_flag |= ICHG;
6596254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
6606254Sroot 		xrele(ip);
6615992Swnj 	iput(ip);
6625992Swnj }
6635992Swnj 
6646254Sroot chown()
66537Sbill {
6666254Sroot 	register struct inode *ip;
66737Sbill 	register struct a {
6686254Sroot 		char	*fname;
6696254Sroot 		int	uid;
6706254Sroot 		int	gid;
67137Sbill 	} *uap;
67237Sbill 
67337Sbill 	uap = (struct a *)u.u_ap;
6746254Sroot 	if (!suser() || (ip = owner(0)) == NULL)
67537Sbill 		return;
676*7439Sroot #ifdef EFS
677*7439Sroot 	if (efsinode(ip)) {
678*7439Sroot 		dev_t ndev = ip->i_rdev;
679*7439Sroot 
680*7439Sroot 		iput(ip);
681*7439Sroot 		efschown(ndev);
682*7439Sroot 		if (u.u_error != EEXIST)
683*7439Sroot 			return;
684*7439Sroot 		u.u_error = 0;
685*7439Sroot 		u.u_dirp = (caddr_t)u.u_arg[0];
686*7439Sroot 		ip = owner(0);
687*7439Sroot 	}
688*7439Sroot #endif
689*7439Sroot 	/*
690*7439Sroot 	 * keep uid/gid's in sane range - no err, so chown(file, uid, -1)
691*7439Sroot 	 * will do something useful
692*7439Sroot 	 */
693*7439Sroot 	if (uap->uid >= 0 && uap->uid <= 32767)	/* should have a const	*/
694*7439Sroot 		ip->i_uid = uap->uid;
695*7439Sroot 	if (uap->gid >= 0 && uap->gid <= 32767)	/* same here		*/
696*7439Sroot 		ip->i_gid = uap->gid;
6976254Sroot 	ip->i_flag |= ICHG;
6986254Sroot 	if (u.u_ruid != 0)
6996254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
7006254Sroot 	iput(ip);
70137Sbill }
70237Sbill 
70337Sbill /*
7046254Sroot  * Set IUPD and IACC times on file.
7056254Sroot  * Can't set ICHG.
70637Sbill  */
7076254Sroot utime()
7084828Swnj {
70937Sbill 	register struct a {
7106254Sroot 		char	*fname;
7116254Sroot 		time_t	*tptr;
71237Sbill 	} *uap;
7136254Sroot 	register struct inode *ip;
7146254Sroot 	time_t tv[2];
71537Sbill 
71637Sbill 	uap = (struct a *)u.u_ap;
7176254Sroot 	if ((ip = owner(1)) == NULL)
71837Sbill 		return;
7196254Sroot 	if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
7206254Sroot 		u.u_error = EFAULT;
7216254Sroot 	} else {
722*7439Sroot #ifdef EFS
723*7439Sroot 		if (efsinode(ip)) {
724*7439Sroot 			dev_t ndev = ip->i_rdev;
725*7439Sroot 
726*7439Sroot 			iput(ip);
727*7439Sroot 			efsutime(ndev, uap->fname, tv);
728*7439Sroot 			if (u.u_error != EEXIST)
729*7439Sroot 				return;
730*7439Sroot 			u.u_error = 0;
731*7439Sroot 			u.u_dirp = (caddr_t)u.u_arg[0];
732*7439Sroot 			ip = owner(1);
733*7439Sroot 		}
734*7439Sroot #endif
7356254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
7366254Sroot 		iupdat(ip, &tv[0], &tv[1], 0);
73737Sbill 	}
73837Sbill 	iput(ip);
73937Sbill }
74037Sbill 
7416254Sroot sync()
74237Sbill {
74337Sbill 
7445416Swnj 	update(0);
74537Sbill }
746