xref: /csrg-svn/sys/kern/kern_descrip.c (revision 43406)
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*43406Smckusick  *	@(#)kern_descrip.c	7.13 (Berkeley) 06/21/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 
32*43406Smckusick #define	p_devtmp	p_logname[11]
33*43406Smckusick 
347422Sroot /*
357497Sroot  * Descriptor management.
367422Sroot  */
377497Sroot 
387497Sroot /*
397497Sroot  * System calls on descriptors.
407497Sroot  */
4142863Smckusick /* ARGSUSED */
4242863Smckusick getdtablesize(p, uap, retval)
4342863Smckusick 	struct proc *p;
4442863Smckusick 	struct args *uap;
4542863Smckusick 	int *retval;
467497Sroot {
477497Sroot 
4842863Smckusick 	*retval = NOFILE;
4942863Smckusick 	RETURN (0);
507497Sroot }
517497Sroot 
5242863Smckusick /*
5342863Smckusick  * Duplicate a file descriptor.
5442863Smckusick  */
5542863Smckusick /* ARGSUSED */
5642863Smckusick dup(p, uap, retval)
5742863Smckusick 	struct proc *p;
5842863Smckusick 	struct args {
5942863Smckusick 		int	i;
6042863Smckusick 	} *uap;
6142863Smckusick 	int *retval;
627422Sroot {
637696Ssam 	struct file *fp;
6442863Smckusick 	int fd, error;
657497Sroot 
6642863Smckusick 	/*
6742863Smckusick 	 * XXX Compatibility
6842863Smckusick 	 */
6942863Smckusick 	if (uap->i &~ 077) { uap->i &= 077; RETURN (dup2(p, uap, retval)); }
707497Sroot 
7137728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
7237728Smckusick 		RETURN (EBADF);
7342863Smckusick 	if (error = ufalloc(0, &fd))
7442863Smckusick 		RETURN (error);
7542863Smckusick 	u.u_ofile[fd] = fp;
7642863Smckusick 	u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
7742863Smckusick 	fp->f_count++;
7842863Smckusick 	if (fd > u.u_lastfile)
7942863Smckusick 		u.u_lastfile = fd;
8042863Smckusick 	*retval = fd;
8142863Smckusick 	RETURN (0);
827497Sroot }
837497Sroot 
8442863Smckusick /*
8542863Smckusick  * Duplicate a file descriptor to a particular value.
8642863Smckusick  */
8742863Smckusick /* ARGSUSED */
8842863Smckusick dup2(p, uap, retval)
8942863Smckusick 	struct proc *p;
9042863Smckusick 	register struct args {
9142863Smckusick 		int	i;
9242863Smckusick 		int	j;
9342863Smckusick 	} *uap;
9442863Smckusick 	int *retval;
957497Sroot {
967497Sroot 	register struct file *fp;
9739354Smckusick 	int error;
987422Sroot 
9937728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
10037728Smckusick 		RETURN (EBADF);
10139354Smckusick 	if (uap->j < 0 || uap->j >= NOFILE)
10239354Smckusick 		RETURN (EBADF);
10342863Smckusick 	*retval = uap->j;
1047497Sroot 	if (uap->i == uap->j)
10539354Smckusick 		RETURN (0);
1067497Sroot 	if (u.u_ofile[uap->j]) {
1078945Sroot 		if (u.u_pofile[uap->j] & UF_MAPPED)
1088945Sroot 			munmapfd(uap->j);
10939354Smckusick 		error = closef(u.u_ofile[uap->j]);
1107422Sroot 	}
11142863Smckusick 	u.u_ofile[uap->j] = fp;
11242863Smckusick 	u.u_pofile[uap->j] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
11342863Smckusick 	fp->f_count++;
11442863Smckusick 	if (uap->j > u.u_lastfile)
11542863Smckusick 		u.u_lastfile = uap->j;
11639354Smckusick 	/*
11739354Smckusick 	 * dup2() must succeed even though the close had an error.
11839354Smckusick 	 */
11939354Smckusick 	error = 0;		/* XXX */
12039354Smckusick 	RETURN (error);
1217696Ssam }
1227696Ssam 
12312748Ssam /*
12412748Ssam  * The file control system call.
12512748Ssam  */
12642863Smckusick /* ARGSUSED */
12742863Smckusick fcntl(p, uap, retval)
12842863Smckusick 	struct proc *p;
12942863Smckusick 	register struct args {
13012748Ssam 		int	fdes;
13112748Ssam 		int	cmd;
13212748Ssam 		int	arg;
13342863Smckusick 	} *uap;
13442863Smckusick 	int *retval;
13542863Smckusick {
13642863Smckusick 	register struct file *fp;
13712748Ssam 	register char *pop;
13842863Smckusick 	int i, error;
1397497Sroot 
14037728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
14137728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
14237728Smckusick 		RETURN (EBADF);
14312748Ssam 	pop = &u.u_pofile[uap->fdes];
14412748Ssam 	switch(uap->cmd) {
14515076Skarels 	case F_DUPFD:
14642863Smckusick 		if (uap->arg < 0 || uap->arg >= NOFILE)
14742863Smckusick 			RETURN (EINVAL);
14842863Smckusick 		if (error = ufalloc(uap->arg, &i))
14942863Smckusick 			RETURN (error);
15042863Smckusick 		u.u_ofile[i] = fp;
15142863Smckusick 		u.u_pofile[i] = *pop &~ UF_EXCLOSE;
15242863Smckusick 		fp->f_count++;
15342863Smckusick 		if (i > u.u_lastfile)
15442863Smckusick 			u.u_lastfile = i;
15542863Smckusick 		*retval = i;
15642863Smckusick 		RETURN (0);
1577497Sroot 
15815076Skarels 	case F_GETFD:
15942863Smckusick 		*retval = *pop & 1;
16042863Smckusick 		RETURN (0);
1617422Sroot 
16215076Skarels 	case F_SETFD:
16312748Ssam 		*pop = (*pop &~ 1) | (uap->arg & 1);
16442863Smckusick 		RETURN (0);
1658145Sroot 
16615076Skarels 	case F_GETFL:
16742863Smckusick 		*retval = fp->f_flag + FOPEN;
16842863Smckusick 		RETURN (0);
1698145Sroot 
17015076Skarels 	case F_SETFL:
17112748Ssam 		fp->f_flag &= FCNTLCANT;
17212748Ssam 		fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
17342863Smckusick 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
17442863Smckusick 			RETURN (error);
17542863Smckusick 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
17612748Ssam 			(void) fset(fp, FNDELAY, 0);
17742863Smckusick 		RETURN (error);
1787422Sroot 
17915076Skarels 	case F_GETOWN:
18042863Smckusick 		RETURN (fgetown(fp, retval));
1817422Sroot 
18215076Skarels 	case F_SETOWN:
18342863Smckusick 		RETURN (fsetown(fp, uap->arg));
1848115Sroot 
18512748Ssam 	default:
18642863Smckusick 		RETURN (EINVAL);
1877422Sroot 	}
18842863Smckusick 	/* NOTREACHED */
1897422Sroot }
1907422Sroot 
19112748Ssam fset(fp, bit, value)
19212748Ssam 	struct file *fp;
19312748Ssam 	int bit, value;
1947422Sroot {
1957422Sroot 
19612748Ssam 	if (value)
19712748Ssam 		fp->f_flag |= bit;
19812748Ssam 	else
19912748Ssam 		fp->f_flag &= ~bit;
20012748Ssam 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
20112748Ssam 	    (caddr_t)&value));
20212748Ssam }
2037422Sroot 
20412748Ssam fgetown(fp, valuep)
20512748Ssam 	struct file *fp;
20612748Ssam 	int *valuep;
20712748Ssam {
20812748Ssam 	int error;
2098115Sroot 
21012748Ssam 	switch (fp->f_type) {
2118115Sroot 
21212748Ssam 	case DTYPE_SOCKET:
21335810Smarc 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
21412748Ssam 		return (0);
2157497Sroot 
21612748Ssam 	default:
21712748Ssam 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
21812748Ssam 		*valuep = -*valuep;
21912748Ssam 		return (error);
2207422Sroot 	}
2217422Sroot }
2227422Sroot 
22312748Ssam fsetown(fp, value)
22412748Ssam 	struct file *fp;
22512748Ssam 	int value;
2267422Sroot {
22737728Smckusick 
22812748Ssam 	if (fp->f_type == DTYPE_SOCKET) {
22935810Smarc 		((struct socket *)fp->f_data)->so_pgid = value;
23012748Ssam 		return (0);
23112748Ssam 	}
23212748Ssam 	if (value > 0) {
23312748Ssam 		struct proc *p = pfind(value);
23412748Ssam 		if (p == 0)
23528201Skarels 			return (ESRCH);
23635810Smarc 		value = p->p_pgrp->pg_id;
23712748Ssam 	} else
23812748Ssam 		value = -value;
23912748Ssam 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
2407422Sroot }
2417422Sroot 
24212748Ssam fioctl(fp, cmd, value)
24312748Ssam 	struct file *fp;
24412748Ssam 	int cmd;
24512748Ssam 	caddr_t value;
2467422Sroot {
2477422Sroot 
24812748Ssam 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
2497422Sroot }
2507422Sroot 
25142863Smckusick /*
25242863Smckusick  * Close a file descriptor.
25342863Smckusick  */
25442863Smckusick /* ARGSUSED */
25542863Smckusick close(p, uap, retval)
25642863Smckusick 	struct proc *p;
25742863Smckusick 	struct args {
25842863Smckusick 		int	fdes;
25942863Smckusick 	} *uap;
26042863Smckusick 	int *retval;
2618029Sroot {
26212748Ssam 	register struct file *fp;
26313044Ssam 	register u_char *pf;
2648029Sroot 
26537728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
26637728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
26737728Smckusick 		RETURN (EBADF);
26837728Smckusick 	pf = (u_char *)&u.u_pofile[uap->fdes];
26913044Ssam 	if (*pf & UF_MAPPED)
27037728Smckusick 		munmapfd(uap->fdes);
27137728Smckusick 	u.u_ofile[uap->fdes] = NULL;
27221101Skarels 	while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
27321101Skarels 		u.u_lastfile--;
27415550Skarels 	*pf = 0;
27539354Smckusick 	RETURN (closef(fp));
2768029Sroot }
2778029Sroot 
27842863Smckusick /*
27942863Smckusick  * Return status information about a file descriptor.
28042863Smckusick  */
28142863Smckusick /* ARGSUSED */
28242863Smckusick fstat(p, uap, retval)
28342863Smckusick 	struct proc *p;
28442863Smckusick 	register struct args {
28542863Smckusick 		int	fdes;
28642863Smckusick 		struct	stat *sb;
28742863Smckusick 	} *uap;
28842863Smckusick 	int *retval;
28913044Ssam {
29013044Ssam 	register struct file *fp;
29113044Ssam 	struct stat ub;
29242863Smckusick 	int error;
29313044Ssam 
29437728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
29537728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
29637728Smckusick 		RETURN (EBADF);
29713044Ssam 	switch (fp->f_type) {
29813044Ssam 
29937728Smckusick 	case DTYPE_VNODE:
30042863Smckusick 		error = vn_stat((struct vnode *)fp->f_data, &ub);
30113044Ssam 		break;
30213044Ssam 
30313044Ssam 	case DTYPE_SOCKET:
30442863Smckusick 		error = soo_stat((struct socket *)fp->f_data, &ub);
30513044Ssam 		break;
30613044Ssam 
30713044Ssam 	default:
30813044Ssam 		panic("fstat");
30913044Ssam 		/*NOTREACHED*/
31013044Ssam 	}
31142863Smckusick 	if (error == 0)
31242863Smckusick 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
31342863Smckusick 	RETURN (error);
31413044Ssam }
31513044Ssam 
3167422Sroot /*
3177497Sroot  * Allocate a user file descriptor.
3187422Sroot  */
31937728Smckusick ufalloc(want, result)
32037728Smckusick 	register int want;
32137728Smckusick 	int *result;
3227422Sroot {
3237497Sroot 
32439733Smckusick 	for (; want < NOFILE; want++) {
32537728Smckusick 		if (u.u_ofile[want] == NULL) {
32637728Smckusick 			u.u_pofile[want] = 0;
32737728Smckusick 			if (want > u.u_lastfile)
32837728Smckusick 				u.u_lastfile = want;
32939733Smckusick 			*result = want;
33037728Smckusick 			return (0);
3317497Sroot 		}
33239733Smckusick 	}
33337728Smckusick 	return (EMFILE);
3347497Sroot }
3357497Sroot 
33642863Smckusick /*
33742863Smckusick  * Check to see if any user file descriptors are available.
33842863Smckusick  */
33912748Ssam ufavail()
34012748Ssam {
34112748Ssam 	register int i, avail = 0;
34212748Ssam 
34312748Ssam 	for (i = 0; i < NOFILE; i++)
34412748Ssam 		if (u.u_ofile[i] == NULL)
34512748Ssam 			avail++;
34612748Ssam 	return (avail);
34712748Ssam }
34812748Ssam 
3497497Sroot struct	file *lastf;
3507497Sroot /*
3517497Sroot  * Allocate a user file descriptor
3527497Sroot  * and a file structure.
3537497Sroot  * Initialize the descriptor
3547497Sroot  * to point at the file structure.
3557497Sroot  */
35637728Smckusick falloc(resultfp, resultfd)
35737728Smckusick 	struct file **resultfp;
35837728Smckusick 	int *resultfd;
3597497Sroot {
3607422Sroot 	register struct file *fp;
36137728Smckusick 	int error, i;
3627422Sroot 
36337728Smckusick 	if (error = ufalloc(0, &i))
36437728Smckusick 		return (error);
3657497Sroot 	if (lastf == 0)
3667497Sroot 		lastf = file;
3677497Sroot 	for (fp = lastf; fp < fileNFILE; fp++)
3687497Sroot 		if (fp->f_count == 0)
3697497Sroot 			goto slot;
3707497Sroot 	for (fp = file; fp < lastf; fp++)
3717497Sroot 		if (fp->f_count == 0)
3727497Sroot 			goto slot;
3737497Sroot 	tablefull("file");
37437728Smckusick 	return (ENFILE);
3757497Sroot slot:
3767497Sroot 	u.u_ofile[i] = fp;
37712748Ssam 	fp->f_count = 1;
37812748Ssam 	fp->f_data = 0;
3797497Sroot 	fp->f_offset = 0;
38037728Smckusick 	fp->f_cred = u.u_cred;
38137728Smckusick 	crhold(fp->f_cred);
3827497Sroot 	lastf = fp + 1;
38337728Smckusick 	if (resultfp)
38437728Smckusick 		*resultfp = fp;
38537728Smckusick 	if (resultfd)
38637728Smckusick 		*resultfd = i;
38737728Smckusick 	return (0);
3887497Sroot }
38912748Ssam 
3907497Sroot /*
3917497Sroot  * Internal form of close.
39212748Ssam  * Decrement reference count on file structure.
3937497Sroot  */
39413044Ssam closef(fp)
3957497Sroot 	register struct file *fp;
3967497Sroot {
39739354Smckusick 	int error;
3987497Sroot 
3997422Sroot 	if (fp == NULL)
40039354Smckusick 		return (0);
4017497Sroot 	if (fp->f_count > 1) {
4027497Sroot 		fp->f_count--;
40339354Smckusick 		return (0);
4047422Sroot 	}
40537728Smckusick 	if (fp->f_count < 1)
40637728Smckusick 		panic("closef: count < 1");
40739354Smckusick 	error = (*fp->f_ops->fo_close)(fp);
40837728Smckusick 	crfree(fp->f_cred);
4097497Sroot 	fp->f_count = 0;
41039354Smckusick 	return (error);
4117422Sroot }
41213044Ssam 
41313044Ssam /*
41413044Ssam  * Apply an advisory lock on a file descriptor.
41513044Ssam  */
41642863Smckusick /* ARGSUSED */
41742863Smckusick flock(p, uap, retval)
41842863Smckusick 	struct proc *p;
41942863Smckusick 	register struct args {
42037728Smckusick 		int	fdes;
42113044Ssam 		int	how;
42242863Smckusick 	} *uap;
42342863Smckusick 	int *retval;
42442863Smckusick {
42513044Ssam 	register struct file *fp;
42613044Ssam 
42737728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
42837728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
42937728Smckusick 		RETURN (EBADF);
43042863Smckusick 	if (fp->f_type != DTYPE_VNODE)
43142863Smckusick 		RETURN (EOPNOTSUPP);
43213101Ssam 	if (uap->how & LOCK_UN) {
43337728Smckusick 		vn_unlock(fp, FSHLOCK|FEXLOCK);
43442863Smckusick 		RETURN (0);
43513044Ssam 	}
43617434Skarels 	if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
43742863Smckusick 		RETURN (0);				/* error? */
43817998Skarels 	if (uap->how & LOCK_EX)
43917998Skarels 		uap->how &= ~LOCK_SH;
44013101Ssam 	/* avoid work... */
44117998Skarels 	if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
44217998Skarels 	    (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
44342863Smckusick 		RETURN (0);
44442863Smckusick 	RETURN (vn_lock(fp, uap->how));
44513044Ssam }
44637586Smarc 
44737586Smarc /*
44837586Smarc  * File Descriptor pseudo-device driver (/dev/fd/).
44937586Smarc  *
45037586Smarc  * Opening minor device N dup()s the file (if any) connected to file
45137586Smarc  * descriptor N belonging to the calling process.  Note that this driver
45237586Smarc  * consists of only the ``open()'' routine, because all subsequent
45337586Smarc  * references to this file will be direct to the other driver.
45437586Smarc  */
45537728Smckusick /* ARGSUSED */
45637728Smckusick fdopen(dev, mode, type)
45737586Smarc 	dev_t dev;
45837728Smckusick 	int mode, type;
45937586Smarc {
460*43406Smckusick 	struct proc *p = u.u_procp;		/* XXX */
46137586Smarc 
46237586Smarc 	/*
463*43406Smckusick 	 * XXX Kludge: set p->p_devtmp to contain the value of the
464*43406Smckusick 	 * the file descriptor being sought for duplication. The error
465*43406Smckusick 	 * return ensures that the vnode for this device will be released
466*43406Smckusick 	 * by vn_open. Open will detect this special error and take the
467*43406Smckusick 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
468*43406Smckusick 	 * will simply report the error.
46937586Smarc 	 */
470*43406Smckusick 	p->p_devtmp = minor(dev);
471*43406Smckusick 	return (ENODEV);
472*43406Smckusick }
47340873Sbostic 
474*43406Smckusick /*
475*43406Smckusick  * Duplicate the specified descriptor to a free descriptor.
476*43406Smckusick  */
477*43406Smckusick dupfdopen(indx, dfd, mode)
478*43406Smckusick 	register int indx, dfd;
479*43406Smckusick 	int mode;
480*43406Smckusick {
481*43406Smckusick 	register struct file *wfp;
482*43406Smckusick 	struct file *fp;
483*43406Smckusick 
48437586Smarc 	/*
485*43406Smckusick 	 * If the to-be-dup'd fd number is greater than the allowed number
486*43406Smckusick 	 * of file descriptors, or the fd to be dup'd has already been
487*43406Smckusick 	 * closed, reject.  Note, check for new == old is necessary as
488*43406Smckusick 	 * falloc could allocate an already closed to-be-dup'd descriptor
489*43406Smckusick 	 * as the new descriptor.
49037586Smarc 	 */
491*43406Smckusick 	fp = u.u_ofile[indx];
49240873Sbostic 	if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL ||
49340873Sbostic 	    fp == wfp)
49437586Smarc 		return (EBADF);
49540873Sbostic 
49637586Smarc 	/*
49740873Sbostic 	 * Check that the mode the file is being opened for is a subset
49840873Sbostic 	 * of the mode of the existing descriptor.
49937586Smarc 	 */
500*43406Smckusick 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
50137586Smarc 		return (EACCES);
50242863Smckusick 	u.u_ofile[indx] = wfp;
50342863Smckusick 	u.u_pofile[indx] = u.u_pofile[dfd];
50442863Smckusick 	wfp->f_count++;
50542863Smckusick 	if (indx > u.u_lastfile)
50642863Smckusick 		u.u_lastfile = indx;
507*43406Smckusick 	return (0);
50837586Smarc }
509