xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 8673)
1*8673Sroot /*	vfs_syscalls.c	4.41	82/10/19	*/
237Sbill 
337Sbill #include "../h/param.h"
437Sbill #include "../h/systm.h"
537Sbill #include "../h/dir.h"
637Sbill #include "../h/user.h"
78040Sroot #include "../h/kernel.h"
86254Sroot #include "../h/file.h"
96574Smckusic #include "../h/stat.h"
1037Sbill #include "../h/inode.h"
116574Smckusic #include "../h/fs.h"
126254Sroot #include "../h/buf.h"
136254Sroot #include "../h/proc.h"
147482Skre #include "../h/quota.h"
157505Sroot #include "../h/descrip.h"
167826Sroot #include "../h/uio.h"
177826Sroot #include "../h/socket.h"
188632Sroot #include "../h/socketvar.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)
347701Ssam 	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;
687701Ssam 		int	flags;
697701Ssam 		int	mode;
706254Sroot 	} *uap;
717701Ssam 	int checkpermissions = 1;
726254Sroot 
736254Sroot 	uap = (struct a *)u.u_ap;
747701Ssam 	if (uap->flags&FCREATE) {
757701Ssam 		ip = namei(uchar, 1, 1);
767701Ssam 		if (ip == NULL) {
777701Ssam 			if (u.u_error)
787701Ssam 				return;
797701Ssam 			ip = maknode(uap->mode&07777&(~ISVTX));
807701Ssam 			checkpermissions = 0;
817701Ssam 			uap->flags &= ~FTRUNCATE;
827701Ssam 		}
837701Ssam 	} else
847701Ssam 		ip = namei(uchar, 0, 1);
856254Sroot 	if (ip == NULL)
866254Sroot 		return;
877701Ssam 	open1(ip, ++uap->flags, checkpermissions);
886254Sroot }
896254Sroot 
907701Ssam #ifndef NOCOMPAT
916254Sroot /*
926254Sroot  * Creat system call.
936254Sroot  */
947505Sroot ocreat()
956254Sroot {
966254Sroot 	register struct inode *ip;
976254Sroot 	register struct a {
986254Sroot 		char	*fname;
996254Sroot 		int	fmode;
1006254Sroot 	} *uap;
1016254Sroot 
1026254Sroot 	uap = (struct a *)u.u_ap;
1036254Sroot 	ip = namei(uchar, 1, 1);
1046254Sroot 	if (ip == NULL) {
1056254Sroot 		if (u.u_error)
1066254Sroot 			return;
1076254Sroot 		ip = maknode(uap->fmode&07777&(~ISVTX));
1087701Ssam 		if (ip == NULL)
1096254Sroot 			return;
1107701Ssam 		open1(ip, FWRITE, 0);
1116254Sroot 	} else
1127701Ssam 		open1(ip, FWRITE|FTRUNCATE, 0);
1136254Sroot }
1147701Ssam #endif
1156254Sroot 
1166254Sroot /*
1176254Sroot  * Common code for open and creat.
1187701Ssam  * Check permissions (if we haven't done so already),
1197701Ssam  * allocate an open file structure, and call
1207701Ssam  * the device open routine, if any.
1216254Sroot  */
1227701Ssam open1(ip, mode, checkpermissions)
1236254Sroot 	register struct inode *ip;
1246254Sroot 	register mode;
1256254Sroot {
1266254Sroot 	register struct file *fp;
1277701Ssam 	int i, flags;
1286254Sroot 
1297701Ssam 	if (checkpermissions) {
1306254Sroot 		if (mode&FREAD)
1317701Ssam 			if (access(ip, IREAD))
1327701Ssam 				goto bad;
1336254Sroot 		if (mode&FWRITE) {
1347701Ssam 			if (access(ip, IWRITE))
1357701Ssam 				goto bad;
1367701Ssam 			if ((ip->i_mode&IFMT) == IFDIR) {
1376254Sroot 				u.u_error = EISDIR;
1387701Ssam 				goto bad;
1397701Ssam 			}
1406254Sroot 		}
1416254Sroot 	}
1427701Ssam 
1437701Ssam 	/*
1447701Ssam 	 * Check locking on inode.  Release "inode lock"
1457701Ssam 	 * while doing so in case we block inside flocki.
1467701Ssam 	 */
1477701Ssam 	flags = 0;
1487701Ssam 	if (mode&(FRDLOCK|FWRLOCK)) {
1497701Ssam 		iunlock(ip);
1507701Ssam 		flags = flocki(ip, 0, mode);
1517701Ssam 		ilock(ip);
1527701Ssam 		if (u.u_error)
1537701Ssam 			goto bad;
1547142Smckusick 	}
1557701Ssam 	if (mode&FTRUNCATE)
1567701Ssam 		itrunc(ip, 0);
1577122Smckusick 	iunlock(ip);
1586254Sroot 	if ((fp = falloc()) == NULL)
1596254Sroot 		goto out;
1607701Ssam 	fp->f_flag = mode & FMODES;
1617505Sroot 	fp->f_type = DTYPE_FILE;
1626254Sroot 	i = u.u_r.r_val1;
1636254Sroot 	fp->f_inode = ip;
1648559Sroot 	u.u_error = openi(ip, mode);
1657701Ssam 	if (u.u_error == 0) {
1667701Ssam 		u.u_pofile[i] = flags;
1676254Sroot 		return;
1687701Ssam 	}
1696254Sroot 	u.u_ofile[i] = NULL;
1706254Sroot 	fp->f_count--;
1716254Sroot out:
1727142Smckusick 	irele(ip);
1737701Ssam 	return;
1747701Ssam bad:
1757701Ssam 	iput(ip);
1766254Sroot }
1776254Sroot 
1786254Sroot /*
1796254Sroot  * Mknod system call
1806254Sroot  */
1816254Sroot mknod()
1826254Sroot {
1836254Sroot 	register struct inode *ip;
1846254Sroot 	register struct a {
1856254Sroot 		char	*fname;
1866254Sroot 		int	fmode;
1876254Sroot 		int	dev;
1886254Sroot 	} *uap;
1896254Sroot 
1906254Sroot 	uap = (struct a *)u.u_ap;
1916254Sroot 	if (suser()) {
1926254Sroot 		ip = namei(uchar, 1, 0);
1936254Sroot 		if (ip != NULL) {
1946254Sroot 			u.u_error = EEXIST;
1956254Sroot 			goto out;
1966254Sroot 		}
1976254Sroot 	}
1986254Sroot 	if (u.u_error)
1996254Sroot 		return;
2006254Sroot 	ip = maknode(uap->fmode);
2016254Sroot 	if (ip == NULL)
2026254Sroot 		return;
2036254Sroot 	if (uap->dev) {
2046254Sroot 		/*
2056254Sroot 		 * Want to be able to use this to make badblock
2066254Sroot 		 * inodes, so don't truncate the dev number.
2076254Sroot 		 */
2086574Smckusic 		ip->i_rdev = uap->dev;
2096254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
2106254Sroot 	}
2116254Sroot 
2126254Sroot out:
2136254Sroot 	iput(ip);
2146254Sroot }
2156254Sroot 
2166254Sroot /*
2176254Sroot  * link system call
2186254Sroot  */
2196254Sroot link()
2206254Sroot {
2216254Sroot 	register struct inode *ip, *xp;
2226254Sroot 	register struct a {
2236254Sroot 		char	*target;
2246254Sroot 		char	*linkname;
2256254Sroot 	} *uap;
2266254Sroot 
2276254Sroot 	uap = (struct a *)u.u_ap;
2286254Sroot 	ip = namei(uchar, 0, 1);    /* well, this routine is doomed anyhow */
2296254Sroot 	if (ip == NULL)
2306254Sroot 		return;
2317439Sroot 	if ((ip->i_mode&IFMT)==IFDIR && !suser()) {
2327439Sroot 		iput(ip);
2337439Sroot 		return;
2347439Sroot 	}
2356254Sroot 	ip->i_nlink++;
2366254Sroot 	ip->i_flag |= ICHG;
237*8673Sroot 	iupdat(ip, &time, &time, 1);
2387122Smckusick 	iunlock(ip);
2396254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2406254Sroot 	xp = namei(uchar, 1, 0);
2416254Sroot 	if (xp != NULL) {
2426254Sroot 		u.u_error = EEXIST;
2436254Sroot 		iput(xp);
2446254Sroot 		goto out;
2456254Sroot 	}
2466254Sroot 	if (u.u_error)
2476254Sroot 		goto out;
2486254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2496254Sroot 		iput(u.u_pdir);
2506254Sroot 		u.u_error = EXDEV;
2516254Sroot 		goto out;
2526254Sroot 	}
2537535Sroot 	direnter(ip);
2546254Sroot out:
2556254Sroot 	if (u.u_error) {
2566254Sroot 		ip->i_nlink--;
2576254Sroot 		ip->i_flag |= ICHG;
2586254Sroot 	}
2597142Smckusick 	irele(ip);
2606254Sroot }
2616254Sroot 
2626254Sroot /*
2636254Sroot  * symlink -- make a symbolic link
2646254Sroot  */
2656254Sroot symlink()
2666254Sroot {
2676254Sroot 	register struct a {
2686254Sroot 		char	*target;
2696254Sroot 		char	*linkname;
2706254Sroot 	} *uap;
2716254Sroot 	register struct inode *ip;
2726254Sroot 	register char *tp;
2736254Sroot 	register c, nc;
2746254Sroot 
2756254Sroot 	uap = (struct a *)u.u_ap;
2766254Sroot 	tp = uap->target;
2776254Sroot 	nc = 0;
2786254Sroot 	while (c = fubyte(tp)) {
2796254Sroot 		if (c < 0) {
2806254Sroot 			u.u_error = EFAULT;
2816254Sroot 			return;
2826254Sroot 		}
2836254Sroot 		tp++;
2846254Sroot 		nc++;
2856254Sroot 	}
2866254Sroot 	u.u_dirp = uap->linkname;
2876254Sroot 	ip = namei(uchar, 1, 0);
2886254Sroot 	if (ip) {
2896254Sroot 		iput(ip);
2906254Sroot 		u.u_error = EEXIST;
2916254Sroot 		return;
2926254Sroot 	}
2936254Sroot 	if (u.u_error)
2946254Sroot 		return;
2956254Sroot 	ip = maknode(IFLNK | 0777);
2966254Sroot 	if (ip == NULL)
2976254Sroot 		return;
2987826Sroot 	u.u_error = rdwri(UIO_WRITE, ip, uap->target, nc, 0, 0, (int *)0);
2996254Sroot 	iput(ip);
3006254Sroot }
3016254Sroot 
3026254Sroot /*
3036254Sroot  * Unlink system call.
3046254Sroot  * Hard to avoid races here, especially
3056254Sroot  * in unlinking directories.
3066254Sroot  */
3076254Sroot unlink()
3086254Sroot {
3096254Sroot 	register struct inode *ip, *pp;
3106254Sroot 	struct a {
3116254Sroot 		char	*fname;
3126254Sroot 	};
3137142Smckusick 	int unlinkingdot = 0;
3146254Sroot 
3156254Sroot 	pp = namei(uchar, 2, 0);
3167535Sroot 	if (pp == NULL)
3176254Sroot 		return;
3187439Sroot 
3196254Sroot 	/*
3206254Sroot 	 * Check for unlink(".")
3216254Sroot 	 * to avoid hanging on the iget
3226254Sroot 	 */
3236254Sroot 	if (pp->i_number == u.u_dent.d_ino) {
3246254Sroot 		ip = pp;
3256254Sroot 		ip->i_count++;
3267142Smckusick 		unlinkingdot++;
3276254Sroot 	} else
3286574Smckusic 		ip = iget(pp->i_dev, pp->i_fs, u.u_dent.d_ino);
3296254Sroot 	if(ip == NULL)
3306254Sroot 		goto out1;
3316254Sroot 	if((ip->i_mode&IFMT)==IFDIR && !suser())
3326254Sroot 		goto out;
3336254Sroot 	/*
3346254Sroot 	 * Don't unlink a mounted file.
3356254Sroot 	 */
3366254Sroot 	if (ip->i_dev != pp->i_dev) {
3376254Sroot 		u.u_error = EBUSY;
3386254Sroot 		goto out;
3396254Sroot 	}
3406254Sroot 	if (ip->i_flag&ITEXT)
3416254Sroot 		xrele(ip);	/* try once to free text */
3427535Sroot 	if (dirremove()) {
3437535Sroot 		ip->i_nlink--;
3447535Sroot 		ip->i_flag |= ICHG;
3456254Sroot 	}
3466254Sroot out:
3477142Smckusick 	if (unlinkingdot)
3487142Smckusick 		irele(ip);
3497142Smckusick 	else
3507142Smckusick 		iput(ip);
3516254Sroot out1:
3526254Sroot 	iput(pp);
3536254Sroot }
3546254Sroot 
3556254Sroot /*
3566254Sroot  * Seek system call
3576254Sroot  */
3588040Sroot lseek()
3596254Sroot {
3606254Sroot 	register struct file *fp;
3616254Sroot 	register struct a {
3627701Ssam 		int	fd;
3636254Sroot 		off_t	off;
3646254Sroot 		int	sbase;
3656254Sroot 	} *uap;
3666254Sroot 
3676254Sroot 	uap = (struct a *)u.u_ap;
3687701Ssam 	fp = getf(uap->fd);
3696254Sroot 	if (fp == NULL)
3706254Sroot 		return;
3717505Sroot 	if (fp->f_type == DTYPE_SOCKET) {
3726254Sroot 		u.u_error = ESPIPE;
3736254Sroot 		return;
3746254Sroot 	}
3757701Ssam 	if (uap->sbase == FSEEK_RELATIVE)
3766254Sroot 		uap->off += fp->f_offset;
3777701Ssam 	else if (uap->sbase == FSEEK_EOF)
3786254Sroot 		uap->off += fp->f_inode->i_size;
3796254Sroot 	fp->f_offset = uap->off;
3806254Sroot 	u.u_r.r_off = uap->off;
3816254Sroot }
3826254Sroot 
3836254Sroot /*
3846254Sroot  * Access system call
3856254Sroot  */
3866254Sroot saccess()
3876254Sroot {
3886254Sroot 	register svuid, svgid;
3896254Sroot 	register struct inode *ip;
3906254Sroot 	register struct a {
3916254Sroot 		char	*fname;
3926254Sroot 		int	fmode;
3936254Sroot 	} *uap;
3946254Sroot 
3956254Sroot 	uap = (struct a *)u.u_ap;
3966254Sroot 	svuid = u.u_uid;
3976254Sroot 	svgid = u.u_gid;
3986254Sroot 	u.u_uid = u.u_ruid;
3996254Sroot 	u.u_gid = u.u_rgid;
4006254Sroot 	ip = namei(uchar, 0, 1);
4016254Sroot 	if (ip != NULL) {
4027701Ssam 		if (uap->fmode&FACCESS_READ && access(ip, IREAD))
4037701Ssam 			goto done;
4047701Ssam 		if (uap->fmode&FACCESS_WRITE && access(ip, IWRITE))
4057701Ssam 			goto done;
4067701Ssam 		if (uap->fmode&FACCESS_EXECUTE && access(ip, IEXEC))
4077701Ssam 			goto done;
4087701Ssam done:
4096254Sroot 		iput(ip);
4106254Sroot 	}
4116254Sroot 	u.u_uid = svuid;
4126254Sroot 	u.u_gid = svgid;
4136254Sroot }
4146254Sroot 
4156254Sroot /*
41637Sbill  * the fstat system call.
41737Sbill  */
41837Sbill fstat()
41937Sbill {
42037Sbill 	register struct file *fp;
42137Sbill 	register struct a {
4227701Ssam 		int	fd;
42337Sbill 		struct stat *sb;
42437Sbill 	} *uap;
42537Sbill 
42637Sbill 	uap = (struct a *)u.u_ap;
4277701Ssam 	fp = getf(uap->fd);
4284828Swnj 	if (fp == NULL)
42937Sbill 		return;
4307505Sroot 	if (fp->f_type == DTYPE_SOCKET)
4314891Swnj 		u.u_error = sostat(fp->f_socket, uap->sb);
4324828Swnj 	else
4334828Swnj 		stat1(fp->f_inode, uap->sb);
43437Sbill }
43537Sbill 
43637Sbill /*
4376574Smckusic  * Stat system call.  This version follows links.
43837Sbill  */
43937Sbill stat()
44037Sbill {
44137Sbill 	register struct inode *ip;
44237Sbill 	register struct a {
44337Sbill 		char	*fname;
44437Sbill 		struct stat *sb;
44537Sbill 	} *uap;
44637Sbill 
44737Sbill 	uap = (struct a *)u.u_ap;
4486423Sroot 	ip = namei(uchar, 0, 1);
4494828Swnj 	if (ip == NULL)
45037Sbill 		return;
4513624Sroot 	stat1(ip, uap->sb);
45237Sbill 	iput(ip);
45337Sbill }
45437Sbill 
45537Sbill /*
4566574Smckusic  * Lstat system call.  This version does not follow links.
4575992Swnj  */
4585992Swnj lstat()
4595992Swnj {
4605992Swnj 	register struct inode *ip;
4615992Swnj 	register struct a {
4625992Swnj 		char	*fname;
4635992Swnj 		struct stat *sb;
4645992Swnj 	} *uap;
4655992Swnj 
4665992Swnj 	uap = (struct a *)u.u_ap;
4676423Sroot 	ip = namei(uchar, 0, 0);
4685992Swnj 	if (ip == NULL)
4695992Swnj 		return;
4706153Ssam 	stat1(ip, uap->sb);
4715992Swnj 	iput(ip);
4725992Swnj }
4735992Swnj 
4745992Swnj /*
47537Sbill  * The basic routine for fstat and stat:
47637Sbill  * get the inode and pass appropriate parts back.
47737Sbill  */
4783624Sroot stat1(ip, ub)
4794828Swnj 	register struct inode *ip;
4804828Swnj 	struct stat *ub;
48137Sbill {
48237Sbill 	struct stat ds;
48337Sbill 
484*8673Sroot 	IUPDAT(ip, &time, &time, 0);
48537Sbill 	/*
4867023Smckusick 	 * Copy from inode table
48737Sbill 	 */
48837Sbill 	ds.st_dev = ip->i_dev;
48937Sbill 	ds.st_ino = ip->i_number;
49037Sbill 	ds.st_mode = ip->i_mode;
49137Sbill 	ds.st_nlink = ip->i_nlink;
49237Sbill 	ds.st_uid = ip->i_uid;
49337Sbill 	ds.st_gid = ip->i_gid;
4946574Smckusic 	ds.st_rdev = (dev_t)ip->i_rdev;
4953624Sroot 	ds.st_size = ip->i_size;
4966574Smckusic 	ds.st_atime = ip->i_atime;
4976574Smckusic 	ds.st_mtime = ip->i_mtime;
4986574Smckusic 	ds.st_ctime = ip->i_ctime;
4997701Ssam 	/* this doesn't belong here */
5007701Ssam 	if ((ip->i_mode&IFMT) == IFBLK)
5017701Ssam 		ds.st_blksize = BLKDEV_IOSIZE;
5027701Ssam 	else if ((ip->i_mode&IFMT) == IFCHR)
5037701Ssam 		ds.st_blksize = MAXBSIZE;
5047701Ssam 	else
5057701Ssam 		ds.st_blksize = ip->i_fs->fs_bsize;
50637Sbill 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
50737Sbill 		u.u_error = EFAULT;
50837Sbill }
50937Sbill 
51037Sbill /*
5115992Swnj  * Return target name of a symbolic link
51237Sbill  */
5135992Swnj readlink()
5145992Swnj {
5155992Swnj 	register struct inode *ip;
5165992Swnj 	register struct a {
5175992Swnj 		char	*name;
5185992Swnj 		char	*buf;
5195992Swnj 		int	count;
5207826Sroot 	} *uap = (struct a *)u.u_ap;
5217826Sroot 	int resid;
5225992Swnj 
5235992Swnj 	ip = namei(uchar, 0, 0);
5245992Swnj 	if (ip == NULL)
5255992Swnj 		return;
5265992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
5275992Swnj 		u.u_error = ENXIO;
5285992Swnj 		goto out;
5295992Swnj 	}
5307826Sroot 	u.u_error = rdwri(UIO_READ, ip, uap->buf, uap->count, 0, 0, &resid);
5315992Swnj out:
5325992Swnj 	iput(ip);
5337826Sroot 	u.u_r.r_val1 = uap->count - resid;
5345992Swnj }
5355992Swnj 
5366254Sroot chmod()
5375992Swnj {
5387701Ssam 	struct inode *ip;
5397701Ssam 	struct a {
5406254Sroot 		char	*fname;
5416254Sroot 		int	fmode;
5425992Swnj 	} *uap;
5435992Swnj 
5445992Swnj 	uap = (struct a *)u.u_ap;
5456254Sroot 	if ((ip = owner(1)) == NULL)
5465992Swnj 		return;
5477701Ssam 	chmod1(ip, uap->fmode);
5487701Ssam }
5497439Sroot 
5507701Ssam fchmod()
5517701Ssam {
5527701Ssam 	struct a {
5537701Ssam 		int	fd;
5547701Ssam 		int	fmode;
5557701Ssam 	} *uap;
5567701Ssam 	register struct inode *ip;
5577701Ssam 	register struct file *fp;
5587701Ssam 
5597701Ssam 	uap = (struct a *)u.u_ap;
5607701Ssam 	fp = getf(uap->fd);
5617701Ssam 	if (fp == NULL)
5627701Ssam 		return;
5637701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
5647701Ssam 		u.u_error = EINVAL;
5657701Ssam 		return;
5667439Sroot 	}
5677701Ssam 	ip = fp->f_inode;
5687701Ssam 	ilock(ip);
5697701Ssam 	if (u.u_uid != ip->i_uid && !suser()) {
5707701Ssam 		iunlock(ip);
5717701Ssam 		return;
5727701Ssam 	}
5737701Ssam 	chmod1(ip, uap->fmode);
5747701Ssam }
5757701Ssam 
5767701Ssam chmod1(ip, mode)
5777701Ssam 	register struct inode *ip;
5787701Ssam 	register int mode;
5797701Ssam {
5807868Sroot 	register int *gp;
5817868Sroot 
5826254Sroot 	ip->i_mode &= ~07777;
5837439Sroot 	if (u.u_uid) {
5847701Ssam 		mode &= ~ISVTX;
5857868Sroot 		for (gp = u.u_groups; gp < &u.u_groups[NGROUPS]; gp++)
5867868Sroot 			if (*gp == ip->i_gid)
5877868Sroot 				goto ok;
5887868Sroot 		mode &= ~ISGID;
5897868Sroot ok:
5907868Sroot 		;
5917701Ssam #ifdef MUSH
5927482Skre 		if (u.u_quota->q_syflags & QF_UMASK && u.u_uid != 0 &&
5937482Skre 		    (ip->i_mode & IFMT) != IFCHR)
5947701Ssam 			mode &= ~u.u_cmask;
5957482Skre #endif
5967439Sroot 	}
5977701Ssam 	ip->i_mode |= mode&07777;
5986254Sroot 	ip->i_flag |= ICHG;
5996254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
6006254Sroot 		xrele(ip);
6015992Swnj 	iput(ip);
6025992Swnj }
6035992Swnj 
6046254Sroot chown()
60537Sbill {
6067701Ssam 	struct inode *ip;
6077701Ssam 	struct a {
6086254Sroot 		char	*fname;
6096254Sroot 		int	uid;
6106254Sroot 		int	gid;
61137Sbill 	} *uap;
61237Sbill 
61337Sbill 	uap = (struct a *)u.u_ap;
6146254Sroot 	if (!suser() || (ip = owner(0)) == NULL)
61537Sbill 		return;
6167701Ssam 	chown1(ip, uap->uid, uap->gid);
6177701Ssam }
6187439Sroot 
6197701Ssam fchown()
6207701Ssam {
6217701Ssam 	struct a {
6227701Ssam 		int	fd;
6237701Ssam 		int	uid;
6247701Ssam 		int	gid;
6257701Ssam 	} *uap;
6267701Ssam 	register struct inode *ip;
6277701Ssam 	register struct file *fp;
6287701Ssam 
6297701Ssam 	uap = (struct a *)u.u_ap;
6307701Ssam 	fp = getf(uap->fd);
6317701Ssam 	if (fp == NULL)
6327701Ssam 		return;
6337701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
6347701Ssam 		u.u_error = EINVAL;
6357701Ssam 		return;
6367439Sroot 	}
6377701Ssam 	ip = fp->f_inode;
6387701Ssam 	ilock(ip);
6397701Ssam 	if (!suser()) {
6407701Ssam 		iunlock(ip);
6417701Ssam 		return;
6427701Ssam 	}
6437701Ssam 	chown1(ip, uap->uid, uap->gid);
6447701Ssam }
6457701Ssam 
6467701Ssam /*
6477701Ssam  * Perform chown operation on inode ip;
6487701Ssam  * inode must be locked prior to call.
6497701Ssam  */
6507701Ssam chown1(ip, uid, gid)
6517701Ssam 	register struct inode *ip;
6527701Ssam 	int uid, gid;
6537701Ssam {
6547701Ssam #ifdef QUOTA
6557701Ssam 	register long change;
6567701Ssam 
6577439Sroot 	/*
6587482Skre 	 * This doesn't allow for holes in files (which hopefully don't
6597482Skre 	 * happen often in files that we chown), and is not accurate anyway
6607482Skre 	 * (eg: it totally ignores 3 level indir blk files - but hopefully
6617482Skre 	 * noone who can make a file that big will have a quota)
6627482Skre 	 */
6637701Ssam 	if (ip->i_uid == uid)
6647482Skre 		change = 0;
6657482Skre 	else {
6667482Skre 		register struct fs *fs = ip->i_fs;
6677482Skre 
6687482Skre 		if (ip->i_size > (change = NDADDR * fs->fs_bsize)) {
6697482Skre 			register off_t size;
6707482Skre 
6717482Skre 			size = blkroundup(fs, ip->i_size) - change;
6727482Skre 			change += size;
6737482Skre 			change += fs->fs_bsize;
6747701Ssam 			/* this assumes NIADDR <= 2 */
6757482Skre 			if (size > NINDIR(fs) * fs->fs_bsize)
6767482Skre 				change += fs->fs_bsize;
6777482Skre 		} else
6787482Skre 			change = fragroundup(fs, ip->i_size);
6797482Skre 		change /= DEV_BSIZE;
6807482Skre 	}
6817482Skre 	chkdq(ip, -change, 1);
6827482Skre 	chkiq(ip->i_dev, ip, ip->i_uid, 1);
6837482Skre 	dqrele(ip->i_dquot);
6847482Skre #endif
6857482Skre 	/*
6867701Ssam 	 * keep uid/gid's in sane range -- no err,
6877701Ssam 	 * so chown(file, uid, -1) will do something useful
6887439Sroot 	 */
6897701Ssam 	if (uid >= 0 && uid <= 32767)	/* should have a constant */
6907701Ssam 		ip->i_uid = uid;
6917701Ssam 	if (gid >= 0 && gid <= 32767)	/* same here */
6927701Ssam 		ip->i_gid = gid;
6936254Sroot 	ip->i_flag |= ICHG;
6946254Sroot 	if (u.u_ruid != 0)
6956254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
6967701Ssam #ifdef QUOTA
6977482Skre 	ip->i_dquot = inoquota(ip);
6987482Skre 	chkdq(ip, change, 1);
6997701Ssam 	chkiq(ip->i_dev, NULL, uid, 1);
7007482Skre #endif
7016254Sroot 	iput(ip);
70237Sbill }
70337Sbill 
70437Sbill /*
7056254Sroot  * Set IUPD and IACC times on file.
7066254Sroot  * Can't set ICHG.
70737Sbill  */
7088107Sroot outime()
7094828Swnj {
71037Sbill 	register struct a {
7116254Sroot 		char	*fname;
7126254Sroot 		time_t	*tptr;
71337Sbill 	} *uap;
7146254Sroot 	register struct inode *ip;
7156254Sroot 	time_t tv[2];
7168632Sroot 	struct timeval tv0, tv1;
71737Sbill 
71837Sbill 	uap = (struct a *)u.u_ap;
7196254Sroot 	if ((ip = owner(1)) == NULL)
72037Sbill 		return;
7216254Sroot 	if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
7226254Sroot 		u.u_error = EFAULT;
7236254Sroot 	} else {
7246254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
7258632Sroot 		tv0.tv_sec = tv[0]; tv0.tv_usec = 0;
7268632Sroot 		tv1.tv_sec = tv[1]; tv1.tv_usec = 0;
7278632Sroot 		iupdat(ip, &tv0, &tv1, 0);
72837Sbill 	}
72937Sbill 	iput(ip);
73037Sbill }
73137Sbill 
7326254Sroot sync()
73337Sbill {
73437Sbill 
735*8673Sroot 	update();
73637Sbill }
7377535Sroot 
7387701Ssam flock()
7397701Ssam {
7407701Ssam 	struct a {
7417701Ssam 		int	fd;
7427701Ssam 		int	how;
7437701Ssam 	} *uap;
7447701Ssam 	register struct file *fp;
7457701Ssam 	register int cmd, flags;
7467701Ssam 
7477701Ssam 	uap = (struct a *)u.u_ap;
7487701Ssam 	fp = getf(uap->fd);
7497701Ssam 	if (fp == NULL)
7507701Ssam 		return;
7517701Ssam 	if (fp->f_type == DTYPE_SOCKET) {		/* XXX */
7527701Ssam 		u.u_error = EINVAL;
7537701Ssam 		return;
7547701Ssam 	}
7557701Ssam 	cmd = uap->how;
7567701Ssam 	flags = u.u_pofile[uap->fd] & (RDLOCK|WRLOCK);
7577701Ssam 	if (cmd&FUNLOCK) {
7587701Ssam 		if (flags == 0) {
7597701Ssam 			u.u_error = EINVAL;
7607701Ssam 			return;
7617701Ssam 		}
7627701Ssam 		funlocki(fp->f_inode, flags);
7637701Ssam 		u.u_pofile[uap->fd] &= ~(RDLOCK|WRLOCK);
7647701Ssam 		return;
7657701Ssam 	}
7667701Ssam 	/*
7677701Ssam 	 * No reason to write lock a file we've already
7687701Ssam 	 * write locked, similarly with a read lock.
7697701Ssam 	 */
7707701Ssam 	if ((flags&WRLOCK) && (cmd&FWRLOCK) ||
7717701Ssam 	    (flags&RDLOCK) && (cmd&FRDLOCK))
7727701Ssam 		return;
7737701Ssam 	u.u_pofile[uap->fd] = flocki(fp->f_inode, u.u_pofile[uap->fd], cmd);
7747701Ssam }
7757701Ssam 
7767701Ssam truncate()
7777701Ssam {
7787701Ssam 	struct a {
7797701Ssam 		char	*fname;
7807701Ssam 		int	length;
7817826Sroot 	} *uap = (struct a *)u.u_ap;
7827701Ssam 	struct inode *ip;
7837701Ssam 
7847701Ssam 	ip = namei(uchar, 0, 1);
7857701Ssam 	if (ip == NULL)
7867701Ssam 		return;
7877701Ssam 	if (access(ip, IWRITE))
7887701Ssam 		goto bad;
7897701Ssam 	if ((ip->i_mode&IFMT) == IFDIR) {
7907701Ssam 		u.u_error = EISDIR;
7917701Ssam 		goto bad;
7927701Ssam 	}
7937701Ssam 	itrunc(ip, uap->length);
7947701Ssam 	return;
7957701Ssam bad:
7967701Ssam 	iput(ip);
7977701Ssam }
7987701Ssam 
7997701Ssam ftruncate()
8007701Ssam {
8017701Ssam 	struct a {
8027701Ssam 		int	fd;
8037701Ssam 		int	length;
8047826Sroot 	} *uap = (struct a *)u.u_ap;
8057701Ssam 	struct inode *ip;
8067701Ssam 	struct file *fp;
8077701Ssam 
8087701Ssam 	fp = getf(uap->fd);
8097701Ssam 	if (fp == NULL)
8107701Ssam 		return;
8117701Ssam 	if (fp->f_type == DTYPE_SOCKET) {
8127701Ssam 		u.u_error = EINVAL;
8137701Ssam 		return;
8147701Ssam 	}
8157701Ssam 	if ((fp->f_flag&FWRITE) == 0) {
8167701Ssam 		u.u_error = EINVAL;
8177701Ssam 		return;
8187701Ssam 	}
8197701Ssam 	ip = fp->f_inode;
8207701Ssam 	ilock(ip);
8217701Ssam 	itrunc(ip, uap->length);
8227701Ssam }
8237701Ssam 
8247701Ssam rename()
8257701Ssam {
8267826Sroot #ifdef notdef
8277701Ssam 	struct a {
8287701Ssam 		char	*from;
8297701Ssam 		char	*to;
8307701Ssam 	} *uap;
8317826Sroot #endif
8327701Ssam 
8337701Ssam }
8347701Ssam 
8357535Sroot /*
8367535Sroot  * Make a new file.
8377535Sroot  */
8387535Sroot struct inode *
8397535Sroot maknode(mode)
8407535Sroot 	int mode;
8417535Sroot {
8427535Sroot 	register struct inode *ip;
8437535Sroot 	ino_t ipref;
8447535Sroot 
8457535Sroot 	if ((mode & IFMT) == IFDIR)
8467535Sroot 		ipref = dirpref(u.u_pdir->i_fs);
8477535Sroot 	else
8487535Sroot 		ipref = u.u_pdir->i_number;
8497535Sroot 	ip = ialloc(u.u_pdir, ipref, mode);
8507535Sroot 	if (ip == NULL) {
8517535Sroot 		iput(u.u_pdir);
8527701Ssam 		return (NULL);
8537535Sroot 	}
8547701Ssam #ifdef QUOTA
8557535Sroot 	if (ip->i_dquot != NODQUOT)
8567535Sroot 		panic("maknode: dquot");
8577535Sroot #endif
8587535Sroot 	ip->i_flag |= IACC|IUPD|ICHG;
8597535Sroot 	if ((mode & IFMT) == 0)
8607535Sroot 		mode |= IFREG;
8617535Sroot 	ip->i_mode = mode & ~u.u_cmask;
8627535Sroot 	ip->i_nlink = 1;
8637535Sroot 	ip->i_uid = u.u_uid;
8647535Sroot 	ip->i_gid = u.u_pdir->i_gid;
8657701Ssam #ifdef QUOTA
8667535Sroot 	ip->i_dquot = inoquota(ip);
8677535Sroot #endif
8687535Sroot 
8697535Sroot 	/*
8707535Sroot 	 * Make sure inode goes to disk before directory entry.
8717535Sroot 	 */
872*8673Sroot 	iupdat(ip, &time, &time, 1);
8737535Sroot 	direnter(ip);
8747535Sroot 	if (u.u_error) {
8757535Sroot 		/*
8767535Sroot 		 * write error occurred trying to update directory
8777535Sroot 		 * so must deallocate the inode
8787535Sroot 		 */
8797535Sroot 		ip->i_nlink = 0;
8807535Sroot 		ip->i_flag |= ICHG;
8817535Sroot 		iput(ip);
8827701Ssam 		return (NULL);
8837535Sroot 	}
8847701Ssam 	return (ip);
8857535Sroot }
886