xref: /csrg-svn/sys/kern/vfs_vnops.c (revision 4914)
1*4914Swnj /*	vfs_vnops.c	4.16	81/11/16	*/
218Sbill 
318Sbill #include "../h/param.h"
418Sbill #include "../h/systm.h"
518Sbill #include "../h/dir.h"
618Sbill #include "../h/user.h"
718Sbill #include "../h/filsys.h"
818Sbill #include "../h/file.h"
918Sbill #include "../h/conf.h"
1018Sbill #include "../h/inode.h"
1118Sbill #include "../h/reg.h"
1218Sbill #include "../h/acct.h"
132302Skre #include "../h/mount.h"
14*4914Swnj #include "../h/socket.h"
15*4914Swnj #include "../h/socketvar.h"
1618Sbill 
1718Sbill /*
184817Swnj  * Convert a user supplied file descriptor into a pointer
194817Swnj  * to a file structure.  Only task is to check range of the descriptor.
204817Swnj  * Critical paths should use the GETF macro, defined in inline.h.
2118Sbill  */
2218Sbill struct file *
2318Sbill getf(f)
244817Swnj 	register int f;
2518Sbill {
2618Sbill 	register struct file *fp;
2718Sbill 
282329Swnj 	if ((unsigned)f >= NOFILE || (fp = u.u_ofile[f]) == NULL) {
292329Swnj 		u.u_error = EBADF;
302329Swnj 		return (NULL);
3118Sbill 	}
322329Swnj 	return (fp);
3318Sbill }
3418Sbill 
3518Sbill /*
3618Sbill  * Internal form of close.
3718Sbill  * Decrement reference count on
3818Sbill  * file structure.
3918Sbill  * Also make sure the pipe protocol
4018Sbill  * does not constipate.
4118Sbill  *
4218Sbill  * Decrement reference count on the inode following
4318Sbill  * removal to the referencing file structure.
4418Sbill  * Call device handler on last close.
4518Sbill  */
4618Sbill closef(fp)
474817Swnj 	register struct file *fp;
4818Sbill {
4918Sbill 	register struct inode *ip;
502302Skre 	register struct mount *mp;
5118Sbill 	int flag, mode;
5218Sbill 	dev_t dev;
5318Sbill 	register int (*cfunc)();
5418Sbill 
554817Swnj 	if (fp == NULL)
5618Sbill 		return;
5718Sbill 	if (fp->f_count > 1) {
5818Sbill 		fp->f_count--;
5918Sbill 		return;
6018Sbill 	}
613616Sroot 	flag = fp->f_flag;
624817Swnj 	if (flag & FSOCKET) {
634888Swnj 		soclose(fp->f_socket);
644817Swnj 		fp->f_socket = 0;
653616Sroot 		fp->f_count = 0;
663616Sroot 		return;
673616Sroot 	}
6818Sbill 	ip = fp->f_inode;
6918Sbill 	dev = (dev_t)ip->i_un.i_rdev;
702302Skre 	mode = ip->i_mode & IFMT;
714817Swnj 	ilock(ip);
723616Sroot 	iput(ip);
7318Sbill 	fp->f_count = 0;
7418Sbill 
753616Sroot 	switch (mode) {
7618Sbill 
7718Sbill 	case IFCHR:
7818Sbill 		cfunc = cdevsw[major(dev)].d_close;
7918Sbill 		break;
8018Sbill 
8118Sbill 	case IFBLK:
822302Skre 		/*
832302Skre 		 * We don't want to really close the device if it is mounted
842302Skre 		 */
852302Skre 		for (mp = mount; mp < &mount[NMOUNT]; mp++)
862302Skre 			if (mp->m_bufp != NULL && mp->m_dev == dev)
872302Skre 				return;
8818Sbill 		cfunc = bdevsw[major(dev)].d_close;
8918Sbill 		break;
904817Swnj 
9118Sbill 	default:
9218Sbill 		return;
9318Sbill 	}
944817Swnj 	for (fp = file; fp < fileNFILE; fp++) {
954817Swnj 		if (fp->f_flag & FSOCKET)
964817Swnj 			continue;
974485Swnj 		if (fp->f_count && (ip = fp->f_inode) &&
984817Swnj 		    ip->i_un.i_rdev == dev && (ip->i_mode&IFMT) == mode)
994485Swnj 			return;
1002302Skre 	}
1014485Swnj 	if (mode == IFBLK) {
1024485Swnj 		/*
1034817Swnj 		 * On last close of a block device (that isn't mounted)
1044485Swnj 		 * we must invalidate any in core blocks
1054485Swnj 		 */
1064485Swnj 		bflush(dev);
1074485Swnj 		binval(dev);
1084485Swnj 	}
1092274Swnj 	(*cfunc)(dev, flag, fp);
11018Sbill }
11118Sbill 
11218Sbill /*
1134817Swnj  * Openi called to allow handler
11418Sbill  * of special files to initialize and
11518Sbill  * validate before actual IO.
11618Sbill  */
11718Sbill openi(ip, rw)
1184817Swnj 	register struct inode *ip;
11918Sbill {
12018Sbill 	dev_t dev;
12118Sbill 	register unsigned int maj;
12218Sbill 
12318Sbill 	dev = (dev_t)ip->i_un.i_rdev;
12418Sbill 	maj = major(dev);
1254817Swnj 	switch (ip->i_mode&IFMT) {
12618Sbill 
12718Sbill 	case IFCHR:
1284817Swnj 		if (maj >= nchrdev)
12918Sbill 			goto bad;
13018Sbill 		(*cdevsw[maj].d_open)(dev, rw);
13118Sbill 		break;
13218Sbill 
13318Sbill 	case IFBLK:
1344817Swnj 		if (maj >= nblkdev)
13518Sbill 			goto bad;
13618Sbill 		(*bdevsw[maj].d_open)(dev, rw);
13718Sbill 	}
13818Sbill 	return;
13918Sbill 
14018Sbill bad:
14118Sbill 	u.u_error = ENXIO;
14218Sbill }
14318Sbill 
14418Sbill /*
14518Sbill  * Check mode permission on inode pointer.
14618Sbill  * Mode is READ, WRITE or EXEC.
14718Sbill  * In the case of WRITE, the
14818Sbill  * read-only status of the file
14918Sbill  * system is checked.
15018Sbill  * Also in WRITE, prototype text
15118Sbill  * segments cannot be written.
15218Sbill  * The mode is shifted to select
15318Sbill  * the owner/group/other fields.
15418Sbill  * The super user is granted all
15518Sbill  * permissions.
15618Sbill  */
15718Sbill access(ip, mode)
1584817Swnj 	register struct inode *ip;
1594817Swnj 	int mode;
16018Sbill {
16118Sbill 	register m;
16218Sbill 
16318Sbill 	m = mode;
1644817Swnj 	if (m == IWRITE) {
1654817Swnj 		if (getfs(ip->i_dev)->s_ronly != 0) {
16618Sbill 			u.u_error = EROFS;
1674817Swnj 			return (1);
16818Sbill 		}
16918Sbill 		if (ip->i_flag&ITEXT)		/* try to free text */
17018Sbill 			xrele(ip);
1714817Swnj 		if (ip->i_flag & ITEXT) {
17218Sbill 			u.u_error = ETXTBSY;
1734817Swnj 			return (1);
17418Sbill 		}
17518Sbill 	}
1764817Swnj 	if (u.u_uid == 0)
1774817Swnj 		return (0);
1784817Swnj 	if (u.u_uid != ip->i_uid) {
17918Sbill 		m >>= 3;
1804817Swnj 		if (u.u_gid != ip->i_gid)
18118Sbill 			m >>= 3;
18218Sbill 	}
1834817Swnj 	if ((ip->i_mode&m) != 0)
1844817Swnj 		return (0);
18518Sbill 	u.u_error = EACCES;
1864817Swnj 	return (1);
18718Sbill }
18818Sbill 
18918Sbill /*
19018Sbill  * Look up a pathname and test if
19118Sbill  * the resultant inode is owned by the
19218Sbill  * current user.
19318Sbill  * If not, try for super-user.
19418Sbill  * If permission is granted,
19518Sbill  * return inode pointer.
19618Sbill  */
19718Sbill struct inode *
19818Sbill owner()
19918Sbill {
20018Sbill 	register struct inode *ip;
20118Sbill 
20218Sbill 	ip = namei(uchar, 0);
2034817Swnj 	if (ip == NULL)
2044817Swnj 		return (NULL);
2054817Swnj 	if (u.u_uid == ip->i_uid)
2064817Swnj 		return (ip);
2074817Swnj 	if (suser())
2084817Swnj 		return (ip);
20918Sbill 	iput(ip);
2104817Swnj 	return (NULL);
21118Sbill }
21218Sbill 
21318Sbill /*
21418Sbill  * Test if the current user is the
21518Sbill  * super user.
21618Sbill  */
21718Sbill suser()
21818Sbill {
21918Sbill 
2204817Swnj 	if (u.u_uid == 0) {
22118Sbill 		u.u_acflag |= ASU;
2224817Swnj 		return (1);
22318Sbill 	}
22418Sbill 	u.u_error = EPERM;
2254817Swnj 	return (0);
22618Sbill }
22718Sbill 
22818Sbill /*
22918Sbill  * Allocate a user file descriptor.
23018Sbill  */
23118Sbill ufalloc()
23218Sbill {
23318Sbill 	register i;
23418Sbill 
2354817Swnj 	for (i=0; i<NOFILE; i++)
2364817Swnj 		if (u.u_ofile[i] == NULL) {
23718Sbill 			u.u_r.r_val1 = i;
23818Sbill 			u.u_pofile[i] = 0;
2394817Swnj 			return (i);
24018Sbill 		}
24118Sbill 	u.u_error = EMFILE;
2424817Swnj 	return (-1);
24318Sbill }
24418Sbill 
2452768Swnj struct	file *lastf;
24618Sbill /*
24718Sbill  * Allocate a user file descriptor
24818Sbill  * and a file structure.
24918Sbill  * Initialize the descriptor
25018Sbill  * to point at the file structure.
25118Sbill  */
25218Sbill struct file *
25318Sbill falloc()
25418Sbill {
25518Sbill 	register struct file *fp;
25618Sbill 	register i;
25718Sbill 
25818Sbill 	i = ufalloc();
2592768Swnj 	if (i < 0)
2604817Swnj 		return (NULL);
2612768Swnj 	if (lastf == 0)
2622768Swnj 		lastf = file;
2632768Swnj 	for (fp = lastf; fp < fileNFILE; fp++)
2642768Swnj 		if (fp->f_count == 0)
265387Sbill 			goto slot;
2662768Swnj 	for (fp = file; fp < lastf; fp++)
2672768Swnj 		if (fp->f_count == 0)
268387Sbill 			goto slot;
2692932Swnj 	tablefull("file");
27018Sbill 	u.u_error = ENFILE;
2712768Swnj 	return (NULL);
272387Sbill slot:
273387Sbill 	u.u_ofile[i] = fp;
274387Sbill 	fp->f_count++;
2754817Swnj 	fp->f_offset = 0;
2763782Sroot 	fp->f_inode = 0;
277387Sbill 	lastf = fp + 1;
2782768Swnj 	return (fp);
27918Sbill }
280