xref: /csrg-svn/sys/kern/kern_descrip.c (revision 42863)
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*42863Smckusick  *	@(#)kern_descrip.c	7.12 (Berkeley) 06/04/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"
307422Sroot 
3117089Sbloom #include "ioctl.h"
327497Sroot 
337422Sroot /*
347497Sroot  * Descriptor management.
357422Sroot  */
367497Sroot 
377497Sroot /*
387497Sroot  * System calls on descriptors.
397497Sroot  */
40*42863Smckusick /* ARGSUSED */
41*42863Smckusick getdtablesize(p, uap, retval)
42*42863Smckusick 	struct proc *p;
43*42863Smckusick 	struct args *uap;
44*42863Smckusick 	int *retval;
457497Sroot {
467497Sroot 
47*42863Smckusick 	*retval = NOFILE;
48*42863Smckusick 	RETURN (0);
497497Sroot }
507497Sroot 
51*42863Smckusick /*
52*42863Smckusick  * Duplicate a file descriptor.
53*42863Smckusick  */
54*42863Smckusick /* ARGSUSED */
55*42863Smckusick dup(p, uap, retval)
56*42863Smckusick 	struct proc *p;
57*42863Smckusick 	struct args {
58*42863Smckusick 		int	i;
59*42863Smckusick 	} *uap;
60*42863Smckusick 	int *retval;
617422Sroot {
627696Ssam 	struct file *fp;
63*42863Smckusick 	int fd, error;
647497Sroot 
65*42863Smckusick 	/*
66*42863Smckusick 	 * XXX Compatibility
67*42863Smckusick 	 */
68*42863Smckusick 	if (uap->i &~ 077) { uap->i &= 077; RETURN (dup2(p, uap, retval)); }
697497Sroot 
7037728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
7137728Smckusick 		RETURN (EBADF);
72*42863Smckusick 	if (error = ufalloc(0, &fd))
73*42863Smckusick 		RETURN (error);
74*42863Smckusick 	u.u_ofile[fd] = fp;
75*42863Smckusick 	u.u_pofile[fd] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
76*42863Smckusick 	fp->f_count++;
77*42863Smckusick 	if (fd > u.u_lastfile)
78*42863Smckusick 		u.u_lastfile = fd;
79*42863Smckusick 	*retval = fd;
80*42863Smckusick 	RETURN (0);
817497Sroot }
827497Sroot 
83*42863Smckusick /*
84*42863Smckusick  * Duplicate a file descriptor to a particular value.
85*42863Smckusick  */
86*42863Smckusick /* ARGSUSED */
87*42863Smckusick dup2(p, uap, retval)
88*42863Smckusick 	struct proc *p;
89*42863Smckusick 	register struct args {
90*42863Smckusick 		int	i;
91*42863Smckusick 		int	j;
92*42863Smckusick 	} *uap;
93*42863Smckusick 	int *retval;
947497Sroot {
957497Sroot 	register struct file *fp;
9639354Smckusick 	int error;
977422Sroot 
9837728Smckusick 	if ((unsigned)uap->i >= NOFILE || (fp = u.u_ofile[uap->i]) == NULL)
9937728Smckusick 		RETURN (EBADF);
10039354Smckusick 	if (uap->j < 0 || uap->j >= NOFILE)
10139354Smckusick 		RETURN (EBADF);
102*42863Smckusick 	*retval = uap->j;
1037497Sroot 	if (uap->i == uap->j)
10439354Smckusick 		RETURN (0);
1057497Sroot 	if (u.u_ofile[uap->j]) {
1068945Sroot 		if (u.u_pofile[uap->j] & UF_MAPPED)
1078945Sroot 			munmapfd(uap->j);
10839354Smckusick 		error = closef(u.u_ofile[uap->j]);
1097422Sroot 	}
110*42863Smckusick 	u.u_ofile[uap->j] = fp;
111*42863Smckusick 	u.u_pofile[uap->j] = u.u_pofile[uap->i] &~ UF_EXCLOSE;
112*42863Smckusick 	fp->f_count++;
113*42863Smckusick 	if (uap->j > u.u_lastfile)
114*42863Smckusick 		u.u_lastfile = uap->j;
11539354Smckusick 	/*
11639354Smckusick 	 * dup2() must succeed even though the close had an error.
11739354Smckusick 	 */
11839354Smckusick 	error = 0;		/* XXX */
11939354Smckusick 	RETURN (error);
1207696Ssam }
1217696Ssam 
12212748Ssam /*
12312748Ssam  * The file control system call.
12412748Ssam  */
125*42863Smckusick /* ARGSUSED */
126*42863Smckusick fcntl(p, uap, retval)
127*42863Smckusick 	struct proc *p;
128*42863Smckusick 	register struct args {
12912748Ssam 		int	fdes;
13012748Ssam 		int	cmd;
13112748Ssam 		int	arg;
132*42863Smckusick 	} *uap;
133*42863Smckusick 	int *retval;
134*42863Smckusick {
135*42863Smckusick 	register struct file *fp;
13612748Ssam 	register char *pop;
137*42863Smckusick 	int i, error;
1387497Sroot 
13937728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
14037728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
14137728Smckusick 		RETURN (EBADF);
14212748Ssam 	pop = &u.u_pofile[uap->fdes];
14312748Ssam 	switch(uap->cmd) {
14415076Skarels 	case F_DUPFD:
145*42863Smckusick 		if (uap->arg < 0 || uap->arg >= NOFILE)
146*42863Smckusick 			RETURN (EINVAL);
147*42863Smckusick 		if (error = ufalloc(uap->arg, &i))
148*42863Smckusick 			RETURN (error);
149*42863Smckusick 		u.u_ofile[i] = fp;
150*42863Smckusick 		u.u_pofile[i] = *pop &~ UF_EXCLOSE;
151*42863Smckusick 		fp->f_count++;
152*42863Smckusick 		if (i > u.u_lastfile)
153*42863Smckusick 			u.u_lastfile = i;
154*42863Smckusick 		*retval = i;
155*42863Smckusick 		RETURN (0);
1567497Sroot 
15715076Skarels 	case F_GETFD:
158*42863Smckusick 		*retval = *pop & 1;
159*42863Smckusick 		RETURN (0);
1607422Sroot 
16115076Skarels 	case F_SETFD:
16212748Ssam 		*pop = (*pop &~ 1) | (uap->arg & 1);
163*42863Smckusick 		RETURN (0);
1648145Sroot 
16515076Skarels 	case F_GETFL:
166*42863Smckusick 		*retval = fp->f_flag + FOPEN;
167*42863Smckusick 		RETURN (0);
1688145Sroot 
16915076Skarels 	case F_SETFL:
17012748Ssam 		fp->f_flag &= FCNTLCANT;
17112748Ssam 		fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
172*42863Smckusick 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
173*42863Smckusick 			RETURN (error);
174*42863Smckusick 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
17512748Ssam 			(void) fset(fp, FNDELAY, 0);
176*42863Smckusick 		RETURN (error);
1777422Sroot 
17815076Skarels 	case F_GETOWN:
179*42863Smckusick 		RETURN (fgetown(fp, retval));
1807422Sroot 
18115076Skarels 	case F_SETOWN:
182*42863Smckusick 		RETURN (fsetown(fp, uap->arg));
1838115Sroot 
18412748Ssam 	default:
185*42863Smckusick 		RETURN (EINVAL);
1867422Sroot 	}
187*42863Smckusick 	/* NOTREACHED */
1887422Sroot }
1897422Sroot 
19012748Ssam fset(fp, bit, value)
19112748Ssam 	struct file *fp;
19212748Ssam 	int bit, value;
1937422Sroot {
1947422Sroot 
19512748Ssam 	if (value)
19612748Ssam 		fp->f_flag |= bit;
19712748Ssam 	else
19812748Ssam 		fp->f_flag &= ~bit;
19912748Ssam 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
20012748Ssam 	    (caddr_t)&value));
20112748Ssam }
2027422Sroot 
20312748Ssam fgetown(fp, valuep)
20412748Ssam 	struct file *fp;
20512748Ssam 	int *valuep;
20612748Ssam {
20712748Ssam 	int error;
2088115Sroot 
20912748Ssam 	switch (fp->f_type) {
2108115Sroot 
21112748Ssam 	case DTYPE_SOCKET:
21235810Smarc 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
21312748Ssam 		return (0);
2147497Sroot 
21512748Ssam 	default:
21612748Ssam 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
21712748Ssam 		*valuep = -*valuep;
21812748Ssam 		return (error);
2197422Sroot 	}
2207422Sroot }
2217422Sroot 
22212748Ssam fsetown(fp, value)
22312748Ssam 	struct file *fp;
22412748Ssam 	int value;
2257422Sroot {
22637728Smckusick 
22712748Ssam 	if (fp->f_type == DTYPE_SOCKET) {
22835810Smarc 		((struct socket *)fp->f_data)->so_pgid = value;
22912748Ssam 		return (0);
23012748Ssam 	}
23112748Ssam 	if (value > 0) {
23212748Ssam 		struct proc *p = pfind(value);
23312748Ssam 		if (p == 0)
23428201Skarels 			return (ESRCH);
23535810Smarc 		value = p->p_pgrp->pg_id;
23612748Ssam 	} else
23712748Ssam 		value = -value;
23812748Ssam 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
2397422Sroot }
2407422Sroot 
24112748Ssam fioctl(fp, cmd, value)
24212748Ssam 	struct file *fp;
24312748Ssam 	int cmd;
24412748Ssam 	caddr_t value;
2457422Sroot {
2467422Sroot 
24712748Ssam 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
2487422Sroot }
2497422Sroot 
250*42863Smckusick /*
251*42863Smckusick  * Close a file descriptor.
252*42863Smckusick  */
253*42863Smckusick /* ARGSUSED */
254*42863Smckusick close(p, uap, retval)
255*42863Smckusick 	struct proc *p;
256*42863Smckusick 	struct args {
257*42863Smckusick 		int	fdes;
258*42863Smckusick 	} *uap;
259*42863Smckusick 	int *retval;
2608029Sroot {
26112748Ssam 	register struct file *fp;
26213044Ssam 	register u_char *pf;
2638029Sroot 
26437728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
26537728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
26637728Smckusick 		RETURN (EBADF);
26737728Smckusick 	pf = (u_char *)&u.u_pofile[uap->fdes];
26813044Ssam 	if (*pf & UF_MAPPED)
26937728Smckusick 		munmapfd(uap->fdes);
27037728Smckusick 	u.u_ofile[uap->fdes] = NULL;
27121101Skarels 	while (u.u_lastfile >= 0 && u.u_ofile[u.u_lastfile] == NULL)
27221101Skarels 		u.u_lastfile--;
27315550Skarels 	*pf = 0;
27439354Smckusick 	RETURN (closef(fp));
2758029Sroot }
2768029Sroot 
277*42863Smckusick /*
278*42863Smckusick  * Return status information about a file descriptor.
279*42863Smckusick  */
280*42863Smckusick /* ARGSUSED */
281*42863Smckusick fstat(p, uap, retval)
282*42863Smckusick 	struct proc *p;
283*42863Smckusick 	register struct args {
284*42863Smckusick 		int	fdes;
285*42863Smckusick 		struct	stat *sb;
286*42863Smckusick 	} *uap;
287*42863Smckusick 	int *retval;
28813044Ssam {
28913044Ssam 	register struct file *fp;
29013044Ssam 	struct stat ub;
291*42863Smckusick 	int error;
29213044Ssam 
29337728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
29437728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
29537728Smckusick 		RETURN (EBADF);
29613044Ssam 	switch (fp->f_type) {
29713044Ssam 
29837728Smckusick 	case DTYPE_VNODE:
299*42863Smckusick 		error = vn_stat((struct vnode *)fp->f_data, &ub);
30013044Ssam 		break;
30113044Ssam 
30213044Ssam 	case DTYPE_SOCKET:
303*42863Smckusick 		error = soo_stat((struct socket *)fp->f_data, &ub);
30413044Ssam 		break;
30513044Ssam 
30613044Ssam 	default:
30713044Ssam 		panic("fstat");
30813044Ssam 		/*NOTREACHED*/
30913044Ssam 	}
310*42863Smckusick 	if (error == 0)
311*42863Smckusick 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
312*42863Smckusick 	RETURN (error);
31313044Ssam }
31413044Ssam 
3157422Sroot /*
3167497Sroot  * Allocate a user file descriptor.
3177422Sroot  */
31837728Smckusick ufalloc(want, result)
31937728Smckusick 	register int want;
32037728Smckusick 	int *result;
3217422Sroot {
3227497Sroot 
32339733Smckusick 	for (; want < NOFILE; want++) {
32437728Smckusick 		if (u.u_ofile[want] == NULL) {
32537728Smckusick 			u.u_pofile[want] = 0;
32637728Smckusick 			if (want > u.u_lastfile)
32737728Smckusick 				u.u_lastfile = want;
32839733Smckusick 			*result = want;
32937728Smckusick 			return (0);
3307497Sroot 		}
33139733Smckusick 	}
33237728Smckusick 	return (EMFILE);
3337497Sroot }
3347497Sroot 
335*42863Smckusick /*
336*42863Smckusick  * Check to see if any user file descriptors are available.
337*42863Smckusick  */
33812748Ssam ufavail()
33912748Ssam {
34012748Ssam 	register int i, avail = 0;
34112748Ssam 
34212748Ssam 	for (i = 0; i < NOFILE; i++)
34312748Ssam 		if (u.u_ofile[i] == NULL)
34412748Ssam 			avail++;
34512748Ssam 	return (avail);
34612748Ssam }
34712748Ssam 
3487497Sroot struct	file *lastf;
3497497Sroot /*
3507497Sroot  * Allocate a user file descriptor
3517497Sroot  * and a file structure.
3527497Sroot  * Initialize the descriptor
3537497Sroot  * to point at the file structure.
3547497Sroot  */
35537728Smckusick falloc(resultfp, resultfd)
35637728Smckusick 	struct file **resultfp;
35737728Smckusick 	int *resultfd;
3587497Sroot {
3597422Sroot 	register struct file *fp;
36037728Smckusick 	int error, i;
3617422Sroot 
36237728Smckusick 	if (error = ufalloc(0, &i))
36337728Smckusick 		return (error);
3647497Sroot 	if (lastf == 0)
3657497Sroot 		lastf = file;
3667497Sroot 	for (fp = lastf; fp < fileNFILE; fp++)
3677497Sroot 		if (fp->f_count == 0)
3687497Sroot 			goto slot;
3697497Sroot 	for (fp = file; fp < lastf; fp++)
3707497Sroot 		if (fp->f_count == 0)
3717497Sroot 			goto slot;
3727497Sroot 	tablefull("file");
37337728Smckusick 	return (ENFILE);
3747497Sroot slot:
3757497Sroot 	u.u_ofile[i] = fp;
37612748Ssam 	fp->f_count = 1;
37712748Ssam 	fp->f_data = 0;
3787497Sroot 	fp->f_offset = 0;
37937728Smckusick 	fp->f_cred = u.u_cred;
38037728Smckusick 	crhold(fp->f_cred);
3817497Sroot 	lastf = fp + 1;
38237728Smckusick 	if (resultfp)
38337728Smckusick 		*resultfp = fp;
38437728Smckusick 	if (resultfd)
38537728Smckusick 		*resultfd = i;
38637728Smckusick 	return (0);
3877497Sroot }
38812748Ssam 
3897497Sroot /*
3907497Sroot  * Internal form of close.
39112748Ssam  * Decrement reference count on file structure.
3927497Sroot  */
39313044Ssam closef(fp)
3947497Sroot 	register struct file *fp;
3957497Sroot {
39639354Smckusick 	int error;
3977497Sroot 
3987422Sroot 	if (fp == NULL)
39939354Smckusick 		return (0);
4007497Sroot 	if (fp->f_count > 1) {
4017497Sroot 		fp->f_count--;
40239354Smckusick 		return (0);
4037422Sroot 	}
40437728Smckusick 	if (fp->f_count < 1)
40537728Smckusick 		panic("closef: count < 1");
40639354Smckusick 	error = (*fp->f_ops->fo_close)(fp);
40737728Smckusick 	crfree(fp->f_cred);
4087497Sroot 	fp->f_count = 0;
40939354Smckusick 	return (error);
4107422Sroot }
41113044Ssam 
41213044Ssam /*
41313044Ssam  * Apply an advisory lock on a file descriptor.
41413044Ssam  */
415*42863Smckusick /* ARGSUSED */
416*42863Smckusick flock(p, uap, retval)
417*42863Smckusick 	struct proc *p;
418*42863Smckusick 	register struct args {
41937728Smckusick 		int	fdes;
42013044Ssam 		int	how;
421*42863Smckusick 	} *uap;
422*42863Smckusick 	int *retval;
423*42863Smckusick {
42413044Ssam 	register struct file *fp;
42513044Ssam 
42637728Smckusick 	if ((unsigned)uap->fdes >= NOFILE ||
42737728Smckusick 	    (fp = u.u_ofile[uap->fdes]) == NULL)
42837728Smckusick 		RETURN (EBADF);
429*42863Smckusick 	if (fp->f_type != DTYPE_VNODE)
430*42863Smckusick 		RETURN (EOPNOTSUPP);
43113101Ssam 	if (uap->how & LOCK_UN) {
43237728Smckusick 		vn_unlock(fp, FSHLOCK|FEXLOCK);
433*42863Smckusick 		RETURN (0);
43413044Ssam 	}
43517434Skarels 	if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
436*42863Smckusick 		RETURN (0);				/* error? */
43717998Skarels 	if (uap->how & LOCK_EX)
43817998Skarels 		uap->how &= ~LOCK_SH;
43913101Ssam 	/* avoid work... */
44017998Skarels 	if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
44117998Skarels 	    (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
442*42863Smckusick 		RETURN (0);
443*42863Smckusick 	RETURN (vn_lock(fp, uap->how));
44413044Ssam }
44537586Smarc 
44637586Smarc /*
44737586Smarc  * File Descriptor pseudo-device driver (/dev/fd/).
44837586Smarc  *
44937586Smarc  * Fred Blonder - U of Maryland	11-Sep-1984
45037586Smarc  *
45137586Smarc  * Opening minor device N dup()s the file (if any) connected to file
45237586Smarc  * descriptor N belonging to the calling process.  Note that this driver
45337586Smarc  * consists of only the ``open()'' routine, because all subsequent
45437586Smarc  * references to this file will be direct to the other driver.
45537586Smarc  */
45637728Smckusick /* ARGSUSED */
45737728Smckusick fdopen(dev, mode, type)
45837586Smarc 	dev_t dev;
45937728Smckusick 	int mode, type;
46037586Smarc {
46137586Smarc 	struct file *fp, *wfp;
46240873Sbostic 	int indx, dfd;
46337586Smarc 
46437586Smarc 	/*
46540873Sbostic 	 * XXX
46640873Sbostic 	 * Horrid kludge: u.u_r.r_val1 contains the value of the new file
46740873Sbostic 	 * descriptor, which was set before the call to vn_open() by copen()
46840873Sbostic 	 * in vfs_syscalls.c.
46937586Smarc 	 */
47040873Sbostic 	indx = u.u_r.r_val1;
47140873Sbostic 	fp = u.u_ofile[indx];
47240873Sbostic 
47337586Smarc 	/*
47440873Sbostic 	 * File system device minor number is the to-be-dup'd fd number.
47540873Sbostic 	 * If it is greater than the allowed number of file descriptors,
47640873Sbostic 	 * or the fd to be dup'd has already been closed, reject.  Note,
47740873Sbostic  	 * check for new == old is necessary as u_falloc could allocate
47840873Sbostic 	 * an already closed to-be-dup'd descriptor as the new descriptor.
47937586Smarc 	 */
48040873Sbostic 	dfd = minor(dev);
48140873Sbostic 	if ((u_int)dfd >= NOFILE || (wfp = u.u_ofile[dfd]) == NULL ||
48240873Sbostic 	    fp == wfp)
48337586Smarc 		return (EBADF);
48440873Sbostic 
48537586Smarc 	/*
48640873Sbostic 	 * Check that the mode the file is being opened for is a subset
48740873Sbostic 	 * of the mode of the existing descriptor.
48837586Smarc 	 */
48940873Sbostic 	if ((mode & (FREAD|FWRITE) | wfp->f_flag) != wfp->f_flag)
49037586Smarc 		return (EACCES);
491*42863Smckusick 	u.u_ofile[indx] = wfp;
492*42863Smckusick 	u.u_pofile[indx] = u.u_pofile[dfd];
493*42863Smckusick 	wfp->f_count++;
494*42863Smckusick 	if (indx > u.u_lastfile)
495*42863Smckusick 		u.u_lastfile = indx;
49640873Sbostic 
49739498Smckusick 	/*
49840873Sbostic 	 * Delete references to this pseudo-device by returning a special
49940873Sbostic 	 * error (EJUSTRETURN) that will cause all resources to be freed,
50040873Sbostic 	 * then detected and cleared by copen().
50139498Smckusick 	 */
50240704Skarels 	return (EJUSTRETURN);			/* XXX */
50337586Smarc }
504