xref: /csrg-svn/sys/kern/vfs_syscalls.c (revision 6423)
1*6423Sroot /*	vfs_syscalls.c	4.22	82/04/01	*/
237Sbill 
337Sbill #include "../h/param.h"
437Sbill #include "../h/systm.h"
537Sbill #include "../h/dir.h"
637Sbill #include "../h/user.h"
76254Sroot #include "../h/reg.h"
86254Sroot #include "../h/file.h"
937Sbill #include "../h/inode.h"
106254Sroot #include "../h/ino.h"
116254Sroot #include "../h/pte.h"
126254Sroot #include "../h/vm.h"
136254Sroot #include "../h/buf.h"
146254Sroot #include "../h/mtpr.h"
156254Sroot #include "../h/proc.h"
166254Sroot #include "../h/inline.h"
1737Sbill #include "../h/conf.h"
184918Swnj #include "../h/socket.h"
194918Swnj #include "../h/socketvar.h"
206254Sroot #include "../h/stat.h"
2137Sbill 
226254Sroot chdir()
236254Sroot {
246254Sroot 
256254Sroot 	chdirec(&u.u_cdir);
266254Sroot }
276254Sroot 
286254Sroot chroot()
296254Sroot {
306254Sroot 
316254Sroot 	if (suser())
326254Sroot 		chdirec(&u.u_rdir);
336254Sroot }
346254Sroot 
356254Sroot chdirec(ipp)
366254Sroot register struct inode **ipp;
376254Sroot {
386254Sroot 	register struct inode *ip;
396254Sroot 	struct a {
406254Sroot 		char	*fname;
416254Sroot 	};
426254Sroot 
436254Sroot 	ip = namei(uchar, 0, 1);
446254Sroot 	if(ip == NULL)
456254Sroot 		return;
466254Sroot 	if((ip->i_mode&IFMT) != IFDIR) {
476254Sroot 		u.u_error = ENOTDIR;
486254Sroot 		goto bad;
496254Sroot 	}
506254Sroot 	if(access(ip, IEXEC))
516254Sroot 		goto bad;
526254Sroot 	irele(ip);
536254Sroot 	if (*ipp) {
546254Sroot 		ilock(*ipp);
556254Sroot 		iput(*ipp);
566254Sroot 	}
576254Sroot 	*ipp = ip;
586254Sroot 	return;
596254Sroot 
606254Sroot bad:
616254Sroot 	iput(ip);
626254Sroot }
636254Sroot 
6437Sbill /*
656254Sroot  * Open system call.
666254Sroot  */
676254Sroot open()
686254Sroot {
696254Sroot 	register struct inode *ip;
706254Sroot 	register struct a {
716254Sroot 		char	*fname;
726254Sroot 		int	rwmode;
736254Sroot 	} *uap;
746254Sroot 
756254Sroot 	uap = (struct a *)u.u_ap;
766254Sroot 	ip = namei(uchar, 0, 1);
776254Sroot 	if (ip == NULL)
786254Sroot 		return;
796254Sroot 	open1(ip, ++uap->rwmode, 0);
806254Sroot }
816254Sroot 
826254Sroot /*
836254Sroot  * Creat system call.
846254Sroot  */
856254Sroot creat()
866254Sroot {
876254Sroot 	register struct inode *ip;
886254Sroot 	register struct a {
896254Sroot 		char	*fname;
906254Sroot 		int	fmode;
916254Sroot 	} *uap;
926254Sroot 
936254Sroot 	uap = (struct a *)u.u_ap;
946254Sroot 	ip = namei(uchar, 1, 1);
956254Sroot 	if (ip == NULL) {
966254Sroot 		if (u.u_error)
976254Sroot 			return;
986254Sroot 		ip = maknode(uap->fmode&07777&(~ISVTX));
996254Sroot 		if (ip==NULL)
1006254Sroot 			return;
1016254Sroot 		open1(ip, FWRITE, 2);
1026254Sroot 	} else
1036254Sroot 		open1(ip, FWRITE, 1);
1046254Sroot }
1056254Sroot 
1066254Sroot /*
1076254Sroot  * Common code for open and creat.
1086254Sroot  * Check permissions, allocate an open file structure,
1096254Sroot  * and call the device open routine if any.
1106254Sroot  */
1116254Sroot open1(ip, mode, trf)
1126254Sroot 	register struct inode *ip;
1136254Sroot 	register mode;
1146254Sroot {
1156254Sroot 	register struct file *fp;
1166254Sroot 	int i;
1176254Sroot 
1186254Sroot 	if (trf != 2) {
1196254Sroot 		if (mode&FREAD)
1206254Sroot 			(void) access(ip, IREAD);
1216254Sroot 		if (mode&FWRITE) {
1226254Sroot 			(void) access(ip, IWRITE);
1236254Sroot 			if ((ip->i_mode&IFMT) == IFDIR)
1246254Sroot 				u.u_error = EISDIR;
1256254Sroot 		}
1266254Sroot 	}
1276254Sroot 	if (u.u_error)
1286254Sroot 		goto out;
1296254Sroot 	if (trf == 1)
1306254Sroot 		itrunc(ip);
1316254Sroot 	irele(ip);
1326254Sroot 	if ((fp = falloc()) == NULL)
1336254Sroot 		goto out;
1346254Sroot 	fp->f_flag = mode&(FREAD|FWRITE);
1356254Sroot 	i = u.u_r.r_val1;
1366254Sroot 	fp->f_inode = ip;
1376254Sroot 	openi(ip, mode&(FREAD|FWRITE));
1386254Sroot 	if (u.u_error == 0)
1396254Sroot 		return;
1406254Sroot 	u.u_ofile[i] = NULL;
1416254Sroot 	fp->f_count--;
1426254Sroot out:
1436254Sroot 	if (ip != NULL)
1446254Sroot 		iput(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 		 */
1776254Sroot 		ip->i_un.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;
2006254Sroot 	if ((ip->i_mode&IFMT)==IFDIR && !suser())
2016254Sroot 		goto out1;
2026254Sroot 	ip->i_nlink++;
2036254Sroot 	ip->i_flag |= ICHG;
2046254Sroot 	iupdat(ip, &time, &time, 1);
2056254Sroot 	irele(ip);
2066254Sroot 	u.u_dirp = (caddr_t)uap->linkname;
2076254Sroot 	xp = namei(uchar, 1, 0);
2086254Sroot 	if (xp != NULL) {
2096254Sroot 		u.u_error = EEXIST;
2106254Sroot 		iput(xp);
2116254Sroot 		goto out;
2126254Sroot 	}
2136254Sroot 	if (u.u_error)
2146254Sroot 		goto out;
2156254Sroot 	if (u.u_pdir->i_dev != ip->i_dev) {
2166254Sroot 		iput(u.u_pdir);
2176254Sroot 		u.u_error = EXDEV;
2186254Sroot 		goto out;
2196254Sroot 	}
2206254Sroot 	wdir(ip);
2216254Sroot out:
2226254Sroot 	if (u.u_error) {
2236254Sroot 		ip->i_nlink--;
2246254Sroot 		ip->i_flag |= ICHG;
2256254Sroot 	}
2266254Sroot out1:
2276254Sroot 	iput(ip);
2286254Sroot }
2296254Sroot 
2306254Sroot /*
2316254Sroot  * symlink -- make a symbolic link
2326254Sroot  */
2336254Sroot symlink()
2346254Sroot {
2356254Sroot 	register struct a {
2366254Sroot 		char	*target;
2376254Sroot 		char	*linkname;
2386254Sroot 	} *uap;
2396254Sroot 	register struct inode *ip;
2406254Sroot 	register char *tp;
2416254Sroot 	register c, nc;
2426254Sroot 
2436254Sroot 	uap = (struct a *)u.u_ap;
2446254Sroot 	tp = uap->target;
2456254Sroot 	nc = 0;
2466254Sroot 	while (c = fubyte(tp)) {
2476254Sroot 		if (c < 0) {
2486254Sroot 			u.u_error = EFAULT;
2496254Sroot 			return;
2506254Sroot 		}
2516254Sroot 		tp++;
2526254Sroot 		nc++;
2536254Sroot 	}
2546254Sroot 	u.u_dirp = uap->linkname;
2556254Sroot 	ip = namei(uchar, 1, 0);
2566254Sroot 	if (ip) {
2576254Sroot 		iput(ip);
2586254Sroot 		u.u_error = EEXIST;
2596254Sroot 		return;
2606254Sroot 	}
2616254Sroot 	if (u.u_error)
2626254Sroot 		return;
2636254Sroot 	ip = maknode(IFLNK | 0777);
2646254Sroot 	if (ip == NULL)
2656254Sroot 		return;
2666254Sroot 	u.u_base = uap->target;
2676254Sroot 	u.u_count = nc;
2686254Sroot 	u.u_offset = 0;
2696254Sroot 	u.u_segflg = 0;
2706254Sroot 	writei(ip);
2716254Sroot 	iput(ip);
2726254Sroot }
2736254Sroot 
2746254Sroot /*
2756254Sroot  * Unlink system call.
2766254Sroot  * Hard to avoid races here, especially
2776254Sroot  * in unlinking directories.
2786254Sroot  */
2796254Sroot unlink()
2806254Sroot {
2816254Sroot 	register struct inode *ip, *pp;
2826254Sroot 	struct a {
2836254Sroot 		char	*fname;
2846254Sroot 	};
2856254Sroot 
2866254Sroot 	pp = namei(uchar, 2, 0);
2876254Sroot 	if(pp == NULL)
2886254Sroot 		return;
2896254Sroot 	/*
2906254Sroot 	 * Check for unlink(".")
2916254Sroot 	 * to avoid hanging on the iget
2926254Sroot 	 */
2936254Sroot 	if (pp->i_number == u.u_dent.d_ino) {
2946254Sroot 		ip = pp;
2956254Sroot 		ip->i_count++;
2966254Sroot 	} else
2976254Sroot 		ip = iget(pp->i_dev, u.u_dent.d_ino);
2986254Sroot 	if(ip == NULL)
2996254Sroot 		goto out1;
3006254Sroot 	if((ip->i_mode&IFMT)==IFDIR && !suser())
3016254Sroot 		goto out;
3026254Sroot 	/*
3036254Sroot 	 * Don't unlink a mounted file.
3046254Sroot 	 */
3056254Sroot 	if (ip->i_dev != pp->i_dev) {
3066254Sroot 		u.u_error = EBUSY;
3076254Sroot 		goto out;
3086254Sroot 	}
3096254Sroot 	if (ip->i_flag&ITEXT)
3106254Sroot 		xrele(ip);	/* try once to free text */
3116254Sroot /*
3126254Sroot 	if ((ip->i_flag&ITEXT) && ip->i_nlink==1) {
3136254Sroot  		u.u_error = ETXTBSY;
3146254Sroot 		goto out;
3156254Sroot 	}
3166254Sroot */
3176254Sroot 	u.u_offset -= sizeof(struct direct);
3186254Sroot 	u.u_base = (caddr_t)&u.u_dent;
3196254Sroot 	u.u_count = sizeof(struct direct);
3206254Sroot 	u.u_dent.d_ino = 0;
3216254Sroot 	writei(pp);
3226254Sroot 	ip->i_nlink--;
3236254Sroot 	ip->i_flag |= ICHG;
3246254Sroot 
3256254Sroot out:
3266254Sroot 	iput(ip);
3276254Sroot out1:
3286254Sroot 	iput(pp);
3296254Sroot }
3306254Sroot 
3316254Sroot /*
3326254Sroot  * Seek system call
3336254Sroot  */
3346254Sroot seek()
3356254Sroot {
3366254Sroot 	register struct file *fp;
3376254Sroot 	register struct a {
3386254Sroot 		int	fdes;
3396254Sroot 		off_t	off;
3406254Sroot 		int	sbase;
3416254Sroot 	} *uap;
3426254Sroot 
3436254Sroot 	uap = (struct a *)u.u_ap;
3446254Sroot 	fp = getf(uap->fdes);
3456254Sroot 	if (fp == NULL)
3466254Sroot 		return;
3476254Sroot 	if (fp->f_flag&FSOCKET) {
3486254Sroot 		u.u_error = ESPIPE;
3496254Sroot 		return;
3506254Sroot 	}
3516254Sroot 	if (uap->sbase == 1)
3526254Sroot 		uap->off += fp->f_offset;
3536254Sroot 	else if (uap->sbase == 2)
3546254Sroot 		uap->off += fp->f_inode->i_size;
3556254Sroot 	fp->f_offset = uap->off;
3566254Sroot 	u.u_r.r_off = uap->off;
3576254Sroot }
3586254Sroot 
3596254Sroot /*
3606254Sroot  * Access system call
3616254Sroot  */
3626254Sroot saccess()
3636254Sroot {
3646254Sroot 	register svuid, svgid;
3656254Sroot 	register struct inode *ip;
3666254Sroot 	register struct a {
3676254Sroot 		char	*fname;
3686254Sroot 		int	fmode;
3696254Sroot 	} *uap;
3706254Sroot 
3716254Sroot 	uap = (struct a *)u.u_ap;
3726254Sroot 	svuid = u.u_uid;
3736254Sroot 	svgid = u.u_gid;
3746254Sroot 	u.u_uid = u.u_ruid;
3756254Sroot 	u.u_gid = u.u_rgid;
3766254Sroot 	ip = namei(uchar, 0, 1);
3776254Sroot 	if (ip != NULL) {
3786254Sroot 		if (uap->fmode&(IREAD>>6))
3796254Sroot 			(void) access(ip, IREAD);
3806254Sroot 		if (uap->fmode&(IWRITE>>6))
3816254Sroot 			(void) access(ip, IWRITE);
3826254Sroot 		if (uap->fmode&(IEXEC>>6))
3836254Sroot 			(void) access(ip, IEXEC);
3846254Sroot 		iput(ip);
3856254Sroot 	}
3866254Sroot 	u.u_uid = svuid;
3876254Sroot 	u.u_gid = svgid;
3886254Sroot }
3896254Sroot 
3906254Sroot /*
39137Sbill  * the fstat system call.
39237Sbill  */
39337Sbill fstat()
39437Sbill {
39537Sbill 	register struct file *fp;
39637Sbill 	register struct a {
39737Sbill 		int	fdes;
39837Sbill 		struct stat *sb;
39937Sbill 	} *uap;
40037Sbill 
40137Sbill 	uap = (struct a *)u.u_ap;
40237Sbill 	fp = getf(uap->fdes);
4034828Swnj 	if (fp == NULL)
40437Sbill 		return;
4054828Swnj 	if (fp->f_flag & FSOCKET)
4064891Swnj 		u.u_error = sostat(fp->f_socket, uap->sb);
4074828Swnj 	else
4084828Swnj 		stat1(fp->f_inode, uap->sb);
40937Sbill }
41037Sbill 
41137Sbill /*
412*6423Sroot  * Stat system call; this follows links.
41337Sbill  */
41437Sbill stat()
41537Sbill {
41637Sbill 	register struct inode *ip;
41737Sbill 	register struct a {
41837Sbill 		char	*fname;
41937Sbill 		struct stat *sb;
42037Sbill 	} *uap;
42137Sbill 
42237Sbill 	uap = (struct a *)u.u_ap;
423*6423Sroot 	ip = namei(uchar, 0, 1);
4244828Swnj 	if (ip == NULL)
42537Sbill 		return;
4263624Sroot 	stat1(ip, uap->sb);
42737Sbill 	iput(ip);
42837Sbill }
42937Sbill 
43037Sbill /*
431*6423Sroot  * Lstat system call; like stat but doesn't follow links.
4325992Swnj  */
4335992Swnj lstat()
4345992Swnj {
4355992Swnj 	register struct inode *ip;
4365992Swnj 	register struct a {
4375992Swnj 		char	*fname;
4385992Swnj 		struct stat *sb;
4395992Swnj 	} *uap;
4405992Swnj 
4415992Swnj 	uap = (struct a *)u.u_ap;
442*6423Sroot 	ip = namei(uchar, 0, 0);
4435992Swnj 	if (ip == NULL)
4445992Swnj 		return;
4456153Ssam 	stat1(ip, uap->sb);
4465992Swnj 	iput(ip);
4475992Swnj }
4485992Swnj 
4495992Swnj /*
45037Sbill  * The basic routine for fstat and stat:
45137Sbill  * get the inode and pass appropriate parts back.
45237Sbill  */
4533624Sroot stat1(ip, ub)
4544828Swnj 	register struct inode *ip;
4554828Swnj 	struct stat *ub;
45637Sbill {
45737Sbill 	register struct dinode *dp;
45837Sbill 	register struct buf *bp;
45937Sbill 	struct stat ds;
46037Sbill 
4611204Sbill 	IUPDAT(ip, &time, &time, 0);
46237Sbill 	/*
4634828Swnj 	 * First copy from inode table
46437Sbill 	 */
46537Sbill 	ds.st_dev = ip->i_dev;
46637Sbill 	ds.st_ino = ip->i_number;
46737Sbill 	ds.st_mode = ip->i_mode;
46837Sbill 	ds.st_nlink = ip->i_nlink;
46937Sbill 	ds.st_uid = ip->i_uid;
47037Sbill 	ds.st_gid = ip->i_gid;
47137Sbill 	ds.st_rdev = (dev_t)ip->i_un.i_rdev;
4723624Sroot 	ds.st_size = ip->i_size;
47337Sbill 	/*
4745992Swnj 	 * next the dates in the disk
47537Sbill 	 */
47637Sbill 	bp = bread(ip->i_dev, itod(ip->i_number));
47737Sbill 	dp = bp->b_un.b_dino;
47837Sbill 	dp += itoo(ip->i_number);
47937Sbill 	ds.st_atime = dp->di_atime;
48037Sbill 	ds.st_mtime = dp->di_mtime;
48137Sbill 	ds.st_ctime = dp->di_ctime;
48237Sbill 	brelse(bp);
48337Sbill 	if (copyout((caddr_t)&ds, (caddr_t)ub, sizeof(ds)) < 0)
48437Sbill 		u.u_error = EFAULT;
48537Sbill }
48637Sbill 
48737Sbill /*
4885992Swnj  * Return target name of a symbolic link
48937Sbill  */
4905992Swnj readlink()
4915992Swnj {
4925992Swnj 	register struct inode *ip;
4935992Swnj 	register struct a {
4945992Swnj 		char	*name;
4955992Swnj 		char	*buf;
4965992Swnj 		int	count;
4975992Swnj 	} *uap;
4985992Swnj 
4995992Swnj 	ip = namei(uchar, 0, 0);
5005992Swnj 	if (ip == NULL)
5015992Swnj 		return;
5025992Swnj 	if ((ip->i_mode&IFMT) != IFLNK) {
5035992Swnj 		u.u_error = ENXIO;
5045992Swnj 		goto out;
5055992Swnj 	}
5065992Swnj 	uap = (struct a *)u.u_ap;
5075992Swnj 	u.u_offset = 0;
5085992Swnj 	u.u_base = uap->buf;
5095992Swnj 	u.u_count = uap->count;
5105992Swnj 	u.u_segflg = 0;
5115992Swnj 	readi(ip);
5125992Swnj out:
5135992Swnj 	iput(ip);
5145992Swnj 	u.u_r.r_val1 = uap->count - u.u_count;
5155992Swnj }
5165992Swnj 
5176254Sroot chmod()
5185992Swnj {
5196254Sroot 	register struct inode *ip;
5205992Swnj 	register struct a {
5216254Sroot 		char	*fname;
5226254Sroot 		int	fmode;
5235992Swnj 	} *uap;
5245992Swnj 
5255992Swnj 	uap = (struct a *)u.u_ap;
5266254Sroot 	if ((ip = owner(1)) == NULL)
5275992Swnj 		return;
5286254Sroot 	ip->i_mode &= ~07777;
5296254Sroot 	if (u.u_uid)
5306254Sroot 		uap->fmode &= ~ISVTX;
5316254Sroot 	ip->i_mode |= uap->fmode&07777;
5326254Sroot 	ip->i_flag |= ICHG;
5336254Sroot 	if (ip->i_flag&ITEXT && (ip->i_mode&ISVTX)==0)
5346254Sroot 		xrele(ip);
5355992Swnj 	iput(ip);
5365992Swnj }
5375992Swnj 
5386254Sroot chown()
53937Sbill {
5406254Sroot 	register struct inode *ip;
54137Sbill 	register struct a {
5426254Sroot 		char	*fname;
5436254Sroot 		int	uid;
5446254Sroot 		int	gid;
54537Sbill 	} *uap;
54637Sbill 
54737Sbill 	uap = (struct a *)u.u_ap;
5486254Sroot 	if (!suser() || (ip = owner(0)) == NULL)
54937Sbill 		return;
5506254Sroot 	ip->i_uid = uap->uid;
5516254Sroot 	ip->i_gid = uap->gid;
5526254Sroot 	ip->i_flag |= ICHG;
5536254Sroot 	if (u.u_ruid != 0)
5546254Sroot 		ip->i_mode &= ~(ISUID|ISGID);
5556254Sroot 	iput(ip);
55637Sbill }
55737Sbill 
55837Sbill /*
5596254Sroot  * Set IUPD and IACC times on file.
5606254Sroot  * Can't set ICHG.
56137Sbill  */
5626254Sroot utime()
5634828Swnj {
56437Sbill 	register struct a {
5656254Sroot 		char	*fname;
5666254Sroot 		time_t	*tptr;
56737Sbill 	} *uap;
5686254Sroot 	register struct inode *ip;
5696254Sroot 	time_t tv[2];
57037Sbill 
57137Sbill 	uap = (struct a *)u.u_ap;
5726254Sroot 	if ((ip = owner(1)) == NULL)
57337Sbill 		return;
5746254Sroot 	if (copyin((caddr_t)uap->tptr, (caddr_t)tv, sizeof(tv))) {
5756254Sroot 		u.u_error = EFAULT;
5766254Sroot 	} else {
5776254Sroot 		ip->i_flag |= IACC|IUPD|ICHG;
5786254Sroot 		iupdat(ip, &tv[0], &tv[1], 0);
57937Sbill 	}
58037Sbill 	iput(ip);
58137Sbill }
58237Sbill 
5836254Sroot sync()
58437Sbill {
58537Sbill 
5865416Swnj 	update(0);
58737Sbill }
588