xref: /csrg-svn/sys/kern/kern_descrip.c (revision 43449)
123367Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423367Smckusick  *
537728Smckusick  * Redistribution and use in source and binary forms are permitted
637728Smckusick  * provided that the above copyright notice and this paragraph are
737728Smckusick  * duplicated in all such forms and that any documentation,
837728Smckusick  * advertising materials, and other materials related to such
937728Smckusick  * distribution and use acknowledge that the software was developed
1037728Smckusick  * by the University of California, Berkeley.  The name of the
1137728Smckusick  * University may not be used to endorse or promote products derived
1237728Smckusick  * from this software without specific prior written permission.
1337728Smckusick  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1437728Smckusick  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1537728Smckusick  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1637728Smckusick  *
17*43449Smckusick  *	@(#)kern_descrip.c	7.14 (Berkeley) 06/22/90
1823367Smckusick  */
197422Sroot 
2017089Sbloom #include "param.h"
2117089Sbloom #include "systm.h"
2237728Smckusick #include "syscontext.h"
2317089Sbloom #include "kernel.h"
2437728Smckusick #include "vnode.h"
2517089Sbloom #include "proc.h"
2617089Sbloom #include "file.h"
2717089Sbloom #include "socket.h"
2817089Sbloom #include "socketvar.h"
2917089Sbloom #include "stat.h"
3017089Sbloom #include "ioctl.h"
317497Sroot 
327422Sroot /*
337497Sroot  * Descriptor management.
347422Sroot  */
357497Sroot 
367497Sroot /*
377497Sroot  * System calls on descriptors.
387497Sroot  */
3942863Smckusick /* ARGSUSED */
4042863Smckusick getdtablesize(p, uap, retval)
4142863Smckusick 	struct proc *p;
4242863Smckusick 	struct args *uap;
4342863Smckusick 	int *retval;
447497Sroot {
457497Sroot 
4642863Smckusick 	*retval = NOFILE;
4742863Smckusick 	RETURN (0);
487497Sroot }
497497Sroot 
5042863Smckusick /*
5142863Smckusick  * Duplicate a file descriptor.
5242863Smckusick  */
5342863Smckusick /* ARGSUSED */
5442863Smckusick dup(p, uap, retval)
5542863Smckusick 	struct proc *p;
5642863Smckusick 	struct args {
5742863Smckusick 		int	i;
5842863Smckusick 	} *uap;
5942863Smckusick 	int *retval;
607422Sroot {
617696Ssam 	struct file *fp;
6242863Smckusick 	int fd, error;
637497Sroot 
6442863Smckusick 	/*
6542863Smckusick 	 * XXX Compatibility
6642863Smckusick 	 */
6742863Smckusick 	if (uap->i &~ 077) { uap->i &= 077; RETURN (dup2(p, uap, retval)); }
687497Sroot 
6937728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
7037728Smckusick 		RETURN (EBADF);
7142863Smckusick 	if (error = ufalloc(0, &fd))
7242863Smckusick 		RETURN (error);
7342863Smckusick 	u.u_ofile[fd] = fp;
7442863Smckusick 	u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
7542863Smckusick 	fp->f_count++;
7642863Smckusick 	if (fd > u.u_lastfile)
7742863Smckusick 		u.u_lastfile = fd;
7842863Smckusick 	*retval = fd;
7942863Smckusick 	RETURN (0);
807497Sroot }
817497Sroot 
8242863Smckusick /*
8342863Smckusick  * Duplicate a file descriptor to a particular value.
8442863Smckusick  */
8542863Smckusick /* ARGSUSED */
8642863Smckusick dup2(p, uap, retval)
8742863Smckusick 	struct proc *p;
8842863Smckusick 	register struct args {
8942863Smckusick 		int	i;
9042863Smckusick 		int	j;
9142863Smckusick 	} *uap;
9242863Smckusick 	int *retval;
937497Sroot {
947497Sroot 	register struct file *fp;
9539354Smckusick 	int error;
967422Sroot 
9737728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
9837728Smckusick 		RETURN (EBADF);
9939354Smckusick 	if (uap->j < 0 || uap->j >= NOFILE)
10039354Smckusick 		RETURN (EBADF);
10142863Smckusick 	*retval = uap->j;
1027497Sroot 	if (uap->i == uap->j)
10339354Smckusick 		RETURN (0);
1047497Sroot 	if (u.u_ofile[uap->j]) {
1058945Sroot 		if (u.u_pofile[uap->j] & UF_MAPPED)
1068945Sroot 			munmapfd(uap->j);
10739354Smckusick 		error = closef(u.u_ofile[uap->j]);
1087422Sroot 	}
10942863Smckusick 	u.u_ofile[uap->j] = fp;
11042863Smckusick 	u.u_pofile[uap->j] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
11142863Smckusick 	fp->f_count++;
11242863Smckusick 	if (uap->j > u.u_lastfile)
11342863Smckusick 		u.u_lastfile = uap->j;
11439354Smckusick 	/*
11539354Smckusick 	 * dup2() must succeed even though the close had an error.
11639354Smckusick 	 */
11739354Smckusick 	error = 0;		/* XXX */
11839354Smckusick 	RETURN (error);
1197696Ssam }
1207696Ssam 
12112748Ssam /*
12212748Ssam  * The file control system call.
12312748Ssam  */
12442863Smckusick /* ARGSUSED */
12542863Smckusick fcntl(p, uap, retval)
12642863Smckusick 	struct proc *p;
12742863Smckusick 	register struct args {
12812748Ssam 		int	fdes;
12912748Ssam 		int	cmd;
13012748Ssam 		int	arg;
13142863Smckusick 	} *uap;
13242863Smckusick 	int *retval;
13342863Smckusick {
13442863Smckusick 	register struct file *fp;
13512748Ssam 	register char *pop;
13642863Smckusick 	int i, error;
1377497Sroot 
13837728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
13937728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
14037728Smckusick 		RETURN (EBADF);
14112748Ssam 	pop = &u.u_pofile[uap->fdes];
14212748Ssam 	switch(uap->cmd) {
14315076Skarels 	case F_DUPFD:
14442863Smckusick 		if (uap->arg < 0 || uap->arg >= NOFILE)
14542863Smckusick 			RETURN (EINVAL);
14642863Smckusick 		if (error = ufalloc(uap->arg, &i))
14742863Smckusick 			RETURN (error);
14842863Smckusick 		u.u_ofile[i] = fp;
14942863Smckusick 		u.u_pofile[i] = *pop &~ UF_EXCLOSE;
15042863Smckusick 		fp->f_count++;
15142863Smckusick 		if (i > u.u_lastfile)
15242863Smckusick 			u.u_lastfile = i;
15342863Smckusick 		*retval = i;
15442863Smckusick 		RETURN (0);
1557497Sroot 
15615076Skarels 	case F_GETFD:
15742863Smckusick 		*retval = *pop & 1;
15842863Smckusick 		RETURN (0);
1597422Sroot 
16015076Skarels 	case F_SETFD:
16112748Ssam 		*pop = (*pop &~ 1) | (uap->arg & 1);
16242863Smckusick 		RETURN (0);
1638145Sroot 
16415076Skarels 	case F_GETFL:
16542863Smckusick 		*retval = fp->f_flag + FOPEN;
16642863Smckusick 		RETURN (0);
1678145Sroot 
16815076Skarels 	case F_SETFL:
16912748Ssam 		fp->f_flag &= FCNTLCANT;
17012748Ssam 		fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
17142863Smckusick 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
17242863Smckusick 			RETURN (error);
17342863Smckusick 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
17412748Ssam 			(void) fset(fp, FNDELAY, 0);
17542863Smckusick 		RETURN (error);
1767422Sroot 
17715076Skarels 	case F_GETOWN:
17842863Smckusick 		RETURN (fgetown(fp, retval));
1797422Sroot 
18015076Skarels 	case F_SETOWN:
18142863Smckusick 		RETURN (fsetown(fp, uap->arg));
1828115Sroot 
18312748Ssam 	default:
18442863Smckusick 		RETURN (EINVAL);
1857422Sroot 	}
18642863Smckusick 	/* NOTREACHED */
1877422Sroot }
1887422Sroot 
18912748Ssam fset(fp, bit, value)
19012748Ssam 	struct file *fp;
19112748Ssam 	int bit, value;
1927422Sroot {
1937422Sroot 
19412748Ssam 	if (value)
19512748Ssam 		fp->f_flag |= bit;
19612748Ssam 	else
19712748Ssam 		fp->f_flag &= ~bit;
19812748Ssam 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
19912748Ssam 	    (caddr_t)&value));
20012748Ssam }
2017422Sroot 
20212748Ssam fgetown(fp, valuep)
20312748Ssam 	struct file *fp;
20412748Ssam 	int *valuep;
20512748Ssam {
20612748Ssam 	int error;
2078115Sroot 
20812748Ssam 	switch (fp->f_type) {
2098115Sroot 
21012748Ssam 	case DTYPE_SOCKET:
21135810Smarc 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
21212748Ssam 		return (0);
2137497Sroot 
21412748Ssam 	default:
21512748Ssam 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
21612748Ssam 		*valuep = -*valuep;
21712748Ssam 		return (error);
2187422Sroot 	}
2197422Sroot }
2207422Sroot 
22112748Ssam fsetown(fp, value)
22212748Ssam 	struct file *fp;
22312748Ssam 	int value;
2247422Sroot {
22537728Smckusick 
22612748Ssam 	if (fp->f_type == DTYPE_SOCKET) {
22735810Smarc 		((struct socket *)fp->f_data)->so_pgid = value;
22812748Ssam 		return (0);
22912748Ssam 	}
23012748Ssam 	if (value > 0) {
23112748Ssam 		struct proc *p = pfind(value);
23212748Ssam 		if (p == 0)
23328201Skarels 			return (ESRCH);
23435810Smarc 		value = p->p_pgrp->pg_id;
23512748Ssam 	} else
23612748Ssam 		value = -value;
23712748Ssam 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
2387422Sroot }
2397422Sroot 
24012748Ssam fioctl(fp, cmd, value)
24112748Ssam 	struct file *fp;
24212748Ssam 	int cmd;
24312748Ssam 	caddr_t value;
2447422Sroot {
2457422Sroot 
24612748Ssam 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
2477422Sroot }
2487422Sroot 
24942863Smckusick /*
25042863Smckusick  * Close a file descriptor.
25142863Smckusick  */
25242863Smckusick /* ARGSUSED */
25342863Smckusick close(p, uap, retval)
25442863Smckusick 	struct proc *p;
25542863Smckusick 	struct args {
25642863Smckusick 		int	fdes;
25742863Smckusick 	} *uap;
25842863Smckusick 	int *retval;
2598029Sroot {
26012748Ssam 	register struct file *fp;
26113044Ssam 	register u_char *pf;
2628029Sroot 
26337728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
26437728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
26537728Smckusick 		RETURN (EBADF);
26637728Smckusick 	pf = (u_char *)&u.u_pofile[uap->fdes];
26713044Ssam 	if (*pf & UF_MAPPED)
26837728Smckusick 		munmapfd(uap->fdes);
26937728Smckusick 	u.u_ofile[uap->fdes] = NULL;
27021101Skarels 	while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
27121101Skarels 		u.u_lastfile--;
27215550Skarels 	*pf = 0;
27339354Smckusick 	RETURN (closef(fp));
2748029Sroot }
2758029Sroot 
27642863Smckusick /*
27742863Smckusick  * Return status information about a file descriptor.
27842863Smckusick  */
27942863Smckusick /* ARGSUSED */
28042863Smckusick fstat(p, uap, retval)
28142863Smckusick 	struct proc *p;
28242863Smckusick 	register struct args {
28342863Smckusick 		int	fdes;
28442863Smckusick 		struct	stat *sb;
28542863Smckusick 	} *uap;
28642863Smckusick 	int *retval;
28713044Ssam {
28813044Ssam 	register struct file *fp;
28913044Ssam 	struct stat ub;
29042863Smckusick 	int error;
29113044Ssam 
29237728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
29337728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
29437728Smckusick 		RETURN (EBADF);
29513044Ssam 	switch (fp->f_type) {
29613044Ssam 
29737728Smckusick 	case DTYPE_VNODE:
29842863Smckusick 		error = vn_stat((struct vnode *)fp->f_data, &ub);
29913044Ssam 		break;
30013044Ssam 
30113044Ssam 	case DTYPE_SOCKET:
30242863Smckusick 		error = soo_stat((struct socket *)fp->f_data, &ub);
30313044Ssam 		break;
30413044Ssam 
30513044Ssam 	default:
30613044Ssam 		panic("fstat");
30713044Ssam 		/*NOTREACHED*/
30813044Ssam 	}
30942863Smckusick 	if (error == 0)
31042863Smckusick 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
31142863Smckusick 	RETURN (error);
31213044Ssam }
31313044Ssam 
3147422Sroot /*
3157497Sroot  * Allocate a user file descriptor.
3167422Sroot  */
31737728Smckusick ufalloc(want, result)
31837728Smckusick 	register int want;
31937728Smckusick 	int *result;
3207422Sroot {
3217497Sroot 
32239733Smckusick 	for (; want < NOFILE; want++) {
32337728Smckusick 		if (u.u_ofile[want] == NULL) {
32437728Smckusick 			u.u_pofile[want] = 0;
32537728Smckusick 			if (want > u.u_lastfile)
32637728Smckusick 				u.u_lastfile = want;
32739733Smckusick 			*result = want;
32837728Smckusick 			return (0);
3297497Sroot 		}
33039733Smckusick 	}
33137728Smckusick 	return (EMFILE);
3327497Sroot }
3337497Sroot 
33442863Smckusick /*
33542863Smckusick  * Check to see if any user file descriptors are available.
33642863Smckusick  */
33712748Ssam ufavail()
33812748Ssam {
33912748Ssam 	register int i, avail = 0;
34012748Ssam 
34112748Ssam 	for (i = 0; i < NOFILE; i++)
34212748Ssam 		if (u.u_ofile[i] == NULL)
34312748Ssam 			avail++;
34412748Ssam 	return (avail);
34512748Ssam }
34612748Ssam 
3477497Sroot struct	file *lastf;
3487497Sroot /*
3497497Sroot  * Allocate a user file descriptor
3507497Sroot  * and a file structure.
3517497Sroot  * Initialize the descriptor
3527497Sroot  * to point at the file structure.
3537497Sroot  */
35437728Smckusick falloc(resultfp, resultfd)
35537728Smckusick 	struct file **resultfp;
35637728Smckusick 	int *resultfd;
3577497Sroot {
3587422Sroot 	register struct file *fp;
35937728Smckusick 	int error, i;
3607422Sroot 
36137728Smckusick 	if (error = ufalloc(0, &i))
36237728Smckusick 		return (error);
3637497Sroot 	if (lastf == 0)
3647497Sroot 		lastf = file;
3657497Sroot 	for (fp = lastf; fp < fileNFILE; fp++)
3667497Sroot 		if (fp->f_count == 0)
3677497Sroot 			goto slot;
3687497Sroot 	for (fp = file; fp < lastf; fp++)
3697497Sroot 		if (fp->f_count == 0)
3707497Sroot 			goto slot;
3717497Sroot 	tablefull("file");
37237728Smckusick 	return (ENFILE);
3737497Sroot slot:
3747497Sroot 	u.u_ofile[i] = fp;
37512748Ssam 	fp->f_count = 1;
37612748Ssam 	fp->f_data = 0;
3777497Sroot 	fp->f_offset = 0;
37837728Smckusick 	fp->f_cred = u.u_cred;
37937728Smckusick 	crhold(fp->f_cred);
3807497Sroot 	lastf = fp + 1;
38137728Smckusick 	if (resultfp)
38237728Smckusick 		*resultfp = fp;
38337728Smckusick 	if (resultfd)
38437728Smckusick 		*resultfd = i;
38537728Smckusick 	return (0);
3867497Sroot }
38712748Ssam 
3887497Sroot /*
3897497Sroot  * Internal form of close.
39012748Ssam  * Decrement reference count on file structure.
3917497Sroot  */
39213044Ssam closef(fp)
3937497Sroot 	register struct file *fp;
3947497Sroot {
39539354Smckusick 	int error;
3967497Sroot 
3977422Sroot 	if (fp == NULL)
39839354Smckusick 		return (0);
3997497Sroot 	if (fp->f_count > 1) {
4007497Sroot 		fp->f_count--;
40139354Smckusick 		return (0);
4027422Sroot 	}
40337728Smckusick 	if (fp->f_count < 1)
40437728Smckusick 		panic("closef: count < 1");
40539354Smckusick 	error = (*fp->f_ops->fo_close)(fp);
40637728Smckusick 	crfree(fp->f_cred);
4077497Sroot 	fp->f_count = 0;
40839354Smckusick 	return (error);
4097422Sroot }
41013044Ssam 
41113044Ssam /*
41213044Ssam  * Apply an advisory lock on a file descriptor.
41313044Ssam  */
41442863Smckusick /* ARGSUSED */
41542863Smckusick flock(p, uap, retval)
41642863Smckusick 	struct proc *p;
41742863Smckusick 	register struct args {
41837728Smckusick 		int	fdes;
41913044Ssam 		int	how;
42042863Smckusick 	} *uap;
42142863Smckusick 	int *retval;
42242863Smckusick {
42313044Ssam 	register struct file *fp;
42413044Ssam 
42537728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
42637728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
42737728Smckusick 		RETURN (EBADF);
42842863Smckusick 	if (fp->f_type != DTYPE_VNODE)
42942863Smckusick 		RETURN (EOPNOTSUPP);
43013101Ssam 	if (uap->how & LOCK_UN) {
43137728Smckusick 		vn_unlock(fp, FSHLOCK|FEXLOCK);
43242863Smckusick 		RETURN (0);
43313044Ssam 	}
43417434Skarels 	if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
43542863Smckusick 		RETURN (0);				/* error? */
43617998Skarels 	if (uap->how & LOCK_EX)
43717998Skarels 		uap->how &= ~LOCK_SH;
43813101Ssam 	/* avoid work... */
43917998Skarels 	if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
44017998Skarels 	    (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
44142863Smckusick 		RETURN (0);
44242863Smckusick 	RETURN (vn_lock(fp, uap->how));
44313044Ssam }
44437586Smarc 
44537586Smarc /*
44637586Smarc  * File Descriptor pseudo-device driver (/dev/fd/).
44737586Smarc  *
44837586Smarc  * Opening minor device N dup()s the file (if any) connected to file
44937586Smarc  * descriptor N belonging to the calling process.  Note that this driver
45037586Smarc  * consists of only the ``open()'' routine, because all subsequent
45137586Smarc  * references to this file will be direct to the other driver.
45237586Smarc  */
45337728Smckusick /* ARGSUSED */
45437728Smckusick fdopen(dev, mode, type)
45537586Smarc 	dev_t dev;
45637728Smckusick 	int mode, type;
45737586Smarc {
45843406Smckusick 	struct proc *p = u.u_procp;		/* XXX */
45937586Smarc 
46037586Smarc 	/*
461*43449Smckusick 	 * XXX Kludge: set p->p_dupfd to contain the value of the
46243406Smckusick 	 * the file descriptor being sought for duplication. The error
46343406Smckusick 	 * return ensures that the vnode for this device will be released
46443406Smckusick 	 * by vn_open. Open will detect this special error and take the
46543406Smckusick 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
46643406Smckusick 	 * will simply report the error.
46737586Smarc 	 */
468*43449Smckusick 	p->p_dupfd = minor(dev);
46943406Smckusick 	return (ENODEV);
47043406Smckusick }
47140873Sbostic 
47243406Smckusick /*
47343406Smckusick  * Duplicate the specified descriptor to a free descriptor.
47443406Smckusick  */
47543406Smckusick dupfdopen(indx, dfd, mode)
47643406Smckusick 	register int indx, dfd;
47743406Smckusick 	int mode;
47843406Smckusick {
47943406Smckusick 	register struct file *wfp;
48043406Smckusick 	struct file *fp;
48143406Smckusick 
48237586Smarc 	/*
48343406Smckusick 	 * If the to-be-dup'd fd number is greater than the allowed number
48443406Smckusick 	 * of file descriptors, or the fd to be dup'd has already been
48543406Smckusick 	 * closed, reject.  Note, check for new == old is necessary as
48643406Smckusick 	 * falloc could allocate an already closed to-be-dup'd descriptor
48743406Smckusick 	 * as the new descriptor.
48837586Smarc 	 */
48943406Smckusick 	fp = u.u_ofile[indx];
49040873Sbostic 	if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL ||
49140873Sbostic 	    fp == wfp)
49237586Smarc 		return (EBADF);
49340873Sbostic 
49437586Smarc 	/*
49540873Sbostic 	 * Check that the mode the file is being opened for is a subset
49640873Sbostic 	 * of the mode of the existing descriptor.
49737586Smarc 	 */
49843406Smckusick 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
49937586Smarc 		return (EACCES);
50042863Smckusick 	u.u_ofile[indx] = wfp;
50142863Smckusick 	u.u_pofile[indx] = u.u_pofile[dfd];
50242863Smckusick 	wfp->f_count++;
50342863Smckusick 	if (indx > u.u_lastfile)
50442863Smckusick 		u.u_lastfile = indx;
50543406Smckusick 	return (0);
50637586Smarc }
507