xref: /csrg-svn/sys/kern/kern_descrip.c (revision 44431)
123367Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423367Smckusick  *
5*44431Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*44431Sbostic  *	@(#)kern_descrip.c	7.16 (Berkeley) 06/28/90
823367Smckusick  */
97422Sroot 
1017089Sbloom #include "param.h"
1117089Sbloom #include "systm.h"
1244404Skarels #include "user.h"
1317089Sbloom #include "kernel.h"
1437728Smckusick #include "vnode.h"
1517089Sbloom #include "proc.h"
1617089Sbloom #include "file.h"
1717089Sbloom #include "socket.h"
1817089Sbloom #include "socketvar.h"
1917089Sbloom #include "stat.h"
2017089Sbloom #include "ioctl.h"
217497Sroot 
227422Sroot /*
237497Sroot  * Descriptor management.
247422Sroot  */
257497Sroot 
267497Sroot /*
277497Sroot  * System calls on descriptors.
287497Sroot  */
2942863Smckusick /* ARGSUSED */
3042863Smckusick getdtablesize(p, uap, retval)
3142863Smckusick 	struct proc *p;
3242863Smckusick 	struct args *uap;
3342863Smckusick 	int *retval;
347497Sroot {
357497Sroot 
3642863Smckusick 	*retval = NOFILE;
3744404Skarels 	return (0);
387497Sroot }
397497Sroot 
4042863Smckusick /*
4142863Smckusick  * Duplicate a file descriptor.
4242863Smckusick  */
4342863Smckusick /* ARGSUSED */
4442863Smckusick dup(p, uap, retval)
4542863Smckusick 	struct proc *p;
4642863Smckusick 	struct args {
4742863Smckusick 		int	i;
4842863Smckusick 	} *uap;
4942863Smckusick 	int *retval;
507422Sroot {
517696Ssam 	struct file *fp;
5242863Smckusick 	int fd, error;
537497Sroot 
5442863Smckusick 	/*
5542863Smckusick 	 * XXX Compatibility
5642863Smckusick 	 */
5744404Skarels 	if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
587497Sroot 
5937728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
6044404Skarels 		return (EBADF);
6142863Smckusick 	if (error = ufalloc(0, &fd))
6244404Skarels 		return (error);
6342863Smckusick 	u.u_ofile[fd] = fp;
6442863Smckusick 	u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
6542863Smckusick 	fp->f_count++;
6642863Smckusick 	if (fd > u.u_lastfile)
6742863Smckusick 		u.u_lastfile = fd;
6842863Smckusick 	*retval = fd;
6944404Skarels 	return (0);
707497Sroot }
717497Sroot 
7242863Smckusick /*
7342863Smckusick  * Duplicate a file descriptor to a particular value.
7442863Smckusick  */
7542863Smckusick /* ARGSUSED */
7642863Smckusick dup2(p, uap, retval)
7742863Smckusick 	struct proc *p;
7842863Smckusick 	register struct args {
7942863Smckusick 		int	i;
8042863Smckusick 		int	j;
8142863Smckusick 	} *uap;
8242863Smckusick 	int *retval;
837497Sroot {
847497Sroot 	register struct file *fp;
8539354Smckusick 	int error;
867422Sroot 
8737728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
8844404Skarels 		return (EBADF);
8939354Smckusick 	if (uap->j < 0 || uap->j >= NOFILE)
9044404Skarels 		return (EBADF);
9142863Smckusick 	*retval = uap->j;
927497Sroot 	if (uap->i == uap->j)
9344404Skarels 		return (0);
947497Sroot 	if (u.u_ofile[uap->j]) {
958945Sroot 		if (u.u_pofile[uap->j] & UF_MAPPED)
968945Sroot 			munmapfd(uap->j);
9739354Smckusick 		error = closef(u.u_ofile[uap->j]);
987422Sroot 	}
9942863Smckusick 	u.u_ofile[uap->j] = fp;
10042863Smckusick 	u.u_pofile[uap->j] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
10142863Smckusick 	fp->f_count++;
10242863Smckusick 	if (uap->j > u.u_lastfile)
10342863Smckusick 		u.u_lastfile = uap->j;
10439354Smckusick 	/*
10539354Smckusick 	 * dup2() must succeed even though the close had an error.
10639354Smckusick 	 */
10739354Smckusick 	error = 0;		/* XXX */
10844404Skarels 	return (error);
1097696Ssam }
1107696Ssam 
11112748Ssam /*
11212748Ssam  * The file control system call.
11312748Ssam  */
11442863Smckusick /* ARGSUSED */
11542863Smckusick fcntl(p, uap, retval)
11642863Smckusick 	struct proc *p;
11742863Smckusick 	register struct args {
11812748Ssam 		int	fdes;
11912748Ssam 		int	cmd;
12012748Ssam 		int	arg;
12142863Smckusick 	} *uap;
12242863Smckusick 	int *retval;
12342863Smckusick {
12442863Smckusick 	register struct file *fp;
12512748Ssam 	register char *pop;
12642863Smckusick 	int i, error;
1277497Sroot 
12837728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
12937728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
13044404Skarels 		return (EBADF);
13112748Ssam 	pop = &u.u_pofile[uap->fdes];
13212748Ssam 	switch(uap->cmd) {
13315076Skarels 	case F_DUPFD:
13442863Smckusick 		if (uap->arg < 0 || uap->arg >= NOFILE)
13544404Skarels 			return (EINVAL);
13642863Smckusick 		if (error = ufalloc(uap->arg, &i))
13744404Skarels 			return (error);
13842863Smckusick 		u.u_ofile[i] = fp;
13942863Smckusick 		u.u_pofile[i] = *pop &~ UF_EXCLOSE;
14042863Smckusick 		fp->f_count++;
14142863Smckusick 		if (i > u.u_lastfile)
14242863Smckusick 			u.u_lastfile = i;
14342863Smckusick 		*retval = i;
14444404Skarels 		return (0);
1457497Sroot 
14615076Skarels 	case F_GETFD:
14742863Smckusick 		*retval = *pop & 1;
14844404Skarels 		return (0);
1497422Sroot 
15015076Skarels 	case F_SETFD:
15112748Ssam 		*pop = (*pop &~ 1) | (uap->arg & 1);
15244404Skarels 		return (0);
1538145Sroot 
15415076Skarels 	case F_GETFL:
15542863Smckusick 		*retval = fp->f_flag + FOPEN;
15644404Skarels 		return (0);
1578145Sroot 
15815076Skarels 	case F_SETFL:
15912748Ssam 		fp->f_flag &= FCNTLCANT;
16012748Ssam 		fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
16142863Smckusick 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
16244404Skarels 			return (error);
16342863Smckusick 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
16412748Ssam 			(void) fset(fp, FNDELAY, 0);
16544404Skarels 		return (error);
1667422Sroot 
16715076Skarels 	case F_GETOWN:
16844404Skarels 		return (fgetown(fp, retval));
1697422Sroot 
17015076Skarels 	case F_SETOWN:
17144404Skarels 		return (fsetown(fp, uap->arg));
1728115Sroot 
17312748Ssam 	default:
17444404Skarels 		return (EINVAL);
1757422Sroot 	}
17642863Smckusick 	/* NOTREACHED */
1777422Sroot }
1787422Sroot 
17912748Ssam fset(fp, bit, value)
18012748Ssam 	struct file *fp;
18112748Ssam 	int bit, value;
1827422Sroot {
1837422Sroot 
18412748Ssam 	if (value)
18512748Ssam 		fp->f_flag |= bit;
18612748Ssam 	else
18712748Ssam 		fp->f_flag &= ~bit;
18812748Ssam 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
18912748Ssam 	    (caddr_t)&value));
19012748Ssam }
1917422Sroot 
19212748Ssam fgetown(fp, valuep)
19312748Ssam 	struct file *fp;
19412748Ssam 	int *valuep;
19512748Ssam {
19612748Ssam 	int error;
1978115Sroot 
19812748Ssam 	switch (fp->f_type) {
1998115Sroot 
20012748Ssam 	case DTYPE_SOCKET:
20135810Smarc 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
20212748Ssam 		return (0);
2037497Sroot 
20412748Ssam 	default:
20512748Ssam 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
20612748Ssam 		*valuep = -*valuep;
20712748Ssam 		return (error);
2087422Sroot 	}
2097422Sroot }
2107422Sroot 
21112748Ssam fsetown(fp, value)
21212748Ssam 	struct file *fp;
21312748Ssam 	int value;
2147422Sroot {
21537728Smckusick 
21612748Ssam 	if (fp->f_type == DTYPE_SOCKET) {
21735810Smarc 		((struct socket *)fp->f_data)->so_pgid = value;
21812748Ssam 		return (0);
21912748Ssam 	}
22012748Ssam 	if (value > 0) {
22112748Ssam 		struct proc *p = pfind(value);
22212748Ssam 		if (p == 0)
22328201Skarels 			return (ESRCH);
22435810Smarc 		value = p->p_pgrp->pg_id;
22512748Ssam 	} else
22612748Ssam 		value = -value;
22712748Ssam 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
2287422Sroot }
2297422Sroot 
23012748Ssam fioctl(fp, cmd, value)
23112748Ssam 	struct file *fp;
23212748Ssam 	int cmd;
23312748Ssam 	caddr_t value;
2347422Sroot {
2357422Sroot 
23612748Ssam 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
2377422Sroot }
2387422Sroot 
23942863Smckusick /*
24042863Smckusick  * Close a file descriptor.
24142863Smckusick  */
24242863Smckusick /* ARGSUSED */
24342863Smckusick close(p, uap, retval)
24442863Smckusick 	struct proc *p;
24542863Smckusick 	struct args {
24642863Smckusick 		int	fdes;
24742863Smckusick 	} *uap;
24842863Smckusick 	int *retval;
2498029Sroot {
25012748Ssam 	register struct file *fp;
25113044Ssam 	register u_char *pf;
2528029Sroot 
25337728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
25437728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
25544404Skarels 		return (EBADF);
25637728Smckusick 	pf = (u_char *)&u.u_pofile[uap->fdes];
25713044Ssam 	if (*pf & UF_MAPPED)
25837728Smckusick 		munmapfd(uap->fdes);
25937728Smckusick 	u.u_ofile[uap->fdes] = NULL;
26021101Skarels 	while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
26121101Skarels 		u.u_lastfile--;
26215550Skarels 	*pf = 0;
26344404Skarels 	return (closef(fp));
2648029Sroot }
2658029Sroot 
26642863Smckusick /*
26742863Smckusick  * Return status information about a file descriptor.
26842863Smckusick  */
26942863Smckusick /* ARGSUSED */
27042863Smckusick fstat(p, uap, retval)
27142863Smckusick 	struct proc *p;
27242863Smckusick 	register struct args {
27342863Smckusick 		int	fdes;
27442863Smckusick 		struct	stat *sb;
27542863Smckusick 	} *uap;
27642863Smckusick 	int *retval;
27713044Ssam {
27813044Ssam 	register struct file *fp;
27913044Ssam 	struct stat ub;
28042863Smckusick 	int error;
28113044Ssam 
28237728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
28337728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
28444404Skarels 		return (EBADF);
28513044Ssam 	switch (fp->f_type) {
28613044Ssam 
28737728Smckusick 	case DTYPE_VNODE:
28842863Smckusick 		error = vn_stat((struct vnode *)fp->f_data, &ub);
28913044Ssam 		break;
29013044Ssam 
29113044Ssam 	case DTYPE_SOCKET:
29242863Smckusick 		error = soo_stat((struct socket *)fp->f_data, &ub);
29313044Ssam 		break;
29413044Ssam 
29513044Ssam 	default:
29613044Ssam 		panic("fstat");
29713044Ssam 		/*NOTREACHED*/
29813044Ssam 	}
29942863Smckusick 	if (error == 0)
30042863Smckusick 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
30144404Skarels 	return (error);
30213044Ssam }
30313044Ssam 
3047422Sroot /*
3057497Sroot  * Allocate a user file descriptor.
3067422Sroot  */
30737728Smckusick ufalloc(want, result)
30837728Smckusick 	register int want;
30937728Smckusick 	int *result;
3107422Sroot {
3117497Sroot 
31239733Smckusick 	for (; want < NOFILE; want++) {
31337728Smckusick 		if (u.u_ofile[want] == NULL) {
31437728Smckusick 			u.u_pofile[want] = 0;
31537728Smckusick 			if (want > u.u_lastfile)
31637728Smckusick 				u.u_lastfile = want;
31739733Smckusick 			*result = want;
31837728Smckusick 			return (0);
3197497Sroot 		}
32039733Smckusick 	}
32137728Smckusick 	return (EMFILE);
3227497Sroot }
3237497Sroot 
32442863Smckusick /*
32542863Smckusick  * Check to see if any user file descriptors are available.
32642863Smckusick  */
32712748Ssam ufavail()
32812748Ssam {
32912748Ssam 	register int i, avail = 0;
33012748Ssam 
33112748Ssam 	for (i = 0; i < NOFILE; i++)
33212748Ssam 		if (u.u_ofile[i] == NULL)
33312748Ssam 			avail++;
33412748Ssam 	return (avail);
33512748Ssam }
33612748Ssam 
3377497Sroot struct	file *lastf;
3387497Sroot /*
3397497Sroot  * Allocate a user file descriptor
3407497Sroot  * and a file structure.
3417497Sroot  * Initialize the descriptor
3427497Sroot  * to point at the file structure.
3437497Sroot  */
34437728Smckusick falloc(resultfp, resultfd)
34537728Smckusick 	struct file **resultfp;
34637728Smckusick 	int *resultfd;
3477497Sroot {
3487422Sroot 	register struct file *fp;
34937728Smckusick 	int error, i;
3507422Sroot 
35137728Smckusick 	if (error = ufalloc(0, &i))
35237728Smckusick 		return (error);
3537497Sroot 	if (lastf == 0)
3547497Sroot 		lastf = file;
3557497Sroot 	for (fp = lastf; fp < fileNFILE; fp++)
3567497Sroot 		if (fp->f_count == 0)
3577497Sroot 			goto slot;
3587497Sroot 	for (fp = file; fp < lastf; fp++)
3597497Sroot 		if (fp->f_count == 0)
3607497Sroot 			goto slot;
3617497Sroot 	tablefull("file");
36237728Smckusick 	return (ENFILE);
3637497Sroot slot:
3647497Sroot 	u.u_ofile[i] = fp;
36512748Ssam 	fp->f_count = 1;
36612748Ssam 	fp->f_data = 0;
3677497Sroot 	fp->f_offset = 0;
36837728Smckusick 	fp->f_cred = u.u_cred;
36937728Smckusick 	crhold(fp->f_cred);
3707497Sroot 	lastf = fp + 1;
37137728Smckusick 	if (resultfp)
37237728Smckusick 		*resultfp = fp;
37337728Smckusick 	if (resultfd)
37437728Smckusick 		*resultfd = i;
37537728Smckusick 	return (0);
3767497Sroot }
37712748Ssam 
3787497Sroot /*
3797497Sroot  * Internal form of close.
38012748Ssam  * Decrement reference count on file structure.
3817497Sroot  */
38213044Ssam closef(fp)
3837497Sroot 	register struct file *fp;
3847497Sroot {
38539354Smckusick 	int error;
3867497Sroot 
3877422Sroot 	if (fp == NULL)
38839354Smckusick 		return (0);
3897497Sroot 	if (fp->f_count > 1) {
3907497Sroot 		fp->f_count--;
39139354Smckusick 		return (0);
3927422Sroot 	}
39337728Smckusick 	if (fp->f_count < 1)
39437728Smckusick 		panic("closef: count < 1");
39539354Smckusick 	error = (*fp->f_ops->fo_close)(fp);
39637728Smckusick 	crfree(fp->f_cred);
3977497Sroot 	fp->f_count = 0;
39839354Smckusick 	return (error);
3997422Sroot }
40013044Ssam 
40113044Ssam /*
40213044Ssam  * Apply an advisory lock on a file descriptor.
40313044Ssam  */
40442863Smckusick /* ARGSUSED */
40542863Smckusick flock(p, uap, retval)
40642863Smckusick 	struct proc *p;
40742863Smckusick 	register struct args {
40837728Smckusick 		int	fdes;
40913044Ssam 		int	how;
41042863Smckusick 	} *uap;
41142863Smckusick 	int *retval;
41242863Smckusick {
41313044Ssam 	register struct file *fp;
41413044Ssam 
41537728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
41637728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
41744404Skarels 		return (EBADF);
41842863Smckusick 	if (fp->f_type != DTYPE_VNODE)
41944404Skarels 		return (EOPNOTSUPP);
42013101Ssam 	if (uap->how & LOCK_UN) {
42137728Smckusick 		vn_unlock(fp, FSHLOCK|FEXLOCK);
42244404Skarels 		return (0);
42313044Ssam 	}
42417434Skarels 	if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
42544404Skarels 		return (0);				/* error? */
42617998Skarels 	if (uap->how & LOCK_EX)
42717998Skarels 		uap->how &= ~LOCK_SH;
42813101Ssam 	/* avoid work... */
42917998Skarels 	if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
43017998Skarels 	    (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
43144404Skarels 		return (0);
43244404Skarels 	return (vn_lock(fp, uap->how));
43313044Ssam }
43437586Smarc 
43537586Smarc /*
43637586Smarc  * File Descriptor pseudo-device driver (/dev/fd/).
43737586Smarc  *
43837586Smarc  * Opening minor device N dup()s the file (if any) connected to file
43937586Smarc  * descriptor N belonging to the calling process.  Note that this driver
44037586Smarc  * consists of only the ``open()'' routine, because all subsequent
44137586Smarc  * references to this file will be direct to the other driver.
44237586Smarc  */
44337728Smckusick /* ARGSUSED */
44437728Smckusick fdopen(dev, mode, type)
44537586Smarc 	dev_t dev;
44637728Smckusick 	int mode, type;
44737586Smarc {
44843406Smckusick 	struct proc *p = u.u_procp;		/* XXX */
44937586Smarc 
45037586Smarc 	/*
45143449Smckusick 	 * XXX Kludge: set p->p_dupfd to contain the value of the
45243406Smckusick 	 * the file descriptor being sought for duplication. The error
45343406Smckusick 	 * return ensures that the vnode for this device will be released
45443406Smckusick 	 * by vn_open. Open will detect this special error and take the
45543406Smckusick 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
45643406Smckusick 	 * will simply report the error.
45737586Smarc 	 */
45843449Smckusick 	p->p_dupfd = minor(dev);
45943406Smckusick 	return (ENODEV);
46043406Smckusick }
46140873Sbostic 
46243406Smckusick /*
46343406Smckusick  * Duplicate the specified descriptor to a free descriptor.
46443406Smckusick  */
46543406Smckusick dupfdopen(indx, dfd, mode)
46643406Smckusick 	register int indx, dfd;
46743406Smckusick 	int mode;
46843406Smckusick {
46943406Smckusick 	register struct file *wfp;
47043406Smckusick 	struct file *fp;
47143406Smckusick 
47237586Smarc 	/*
47343406Smckusick 	 * If the to-be-dup'd fd number is greater than the allowed number
47443406Smckusick 	 * of file descriptors, or the fd to be dup'd has already been
47543406Smckusick 	 * closed, reject.  Note, check for new == old is necessary as
47643406Smckusick 	 * falloc could allocate an already closed to-be-dup'd descriptor
47743406Smckusick 	 * as the new descriptor.
47837586Smarc 	 */
47943406Smckusick 	fp = u.u_ofile[indx];
48040873Sbostic 	if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL ||
48140873Sbostic 	    fp == wfp)
48237586Smarc 		return (EBADF);
48340873Sbostic 
48437586Smarc 	/*
48540873Sbostic 	 * Check that the mode the file is being opened for is a subset
48640873Sbostic 	 * of the mode of the existing descriptor.
48737586Smarc 	 */
48843406Smckusick 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
48937586Smarc 		return (EACCES);
49042863Smckusick 	u.u_ofile[indx] = wfp;
49142863Smckusick 	u.u_pofile[indx] = u.u_pofile[dfd];
49242863Smckusick 	wfp->f_count++;
49342863Smckusick 	if (indx > u.u_lastfile)
49442863Smckusick 		u.u_lastfile = indx;
49543406Smckusick 	return (0);
49637586Smarc }
497