xref: /csrg-svn/sys/kern/kern_descrip.c (revision 45914)
123367Smckusick /*
237728Smckusick  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
337728Smckusick  * All rights reserved.
423367Smckusick  *
544431Sbostic  * %sccs.include.redist.c%
637728Smckusick  *
7*45914Smckusick  *	@(#)kern_descrip.c	7.17 (Berkeley) 01/10/91
823367Smckusick  */
97422Sroot 
1017089Sbloom #include "param.h"
1117089Sbloom #include "systm.h"
1244404Skarels #include "user.h"
13*45914Smckusick #include "filedesc.h"
1417089Sbloom #include "kernel.h"
1537728Smckusick #include "vnode.h"
1617089Sbloom #include "proc.h"
1717089Sbloom #include "file.h"
1817089Sbloom #include "socket.h"
1917089Sbloom #include "socketvar.h"
2017089Sbloom #include "stat.h"
2117089Sbloom #include "ioctl.h"
22*45914Smckusick #include "malloc.h"
23*45914Smckusick #include "syslog.h"
247497Sroot 
257422Sroot /*
267497Sroot  * Descriptor management.
277422Sroot  */
28*45914Smckusick int nofile = NOFILE;		/* per-process maximum open files */
297497Sroot 
307497Sroot /*
317497Sroot  * System calls on descriptors.
327497Sroot  */
3342863Smckusick /* ARGSUSED */
3442863Smckusick getdtablesize(p, uap, retval)
3542863Smckusick 	struct proc *p;
3642863Smckusick 	struct args *uap;
3742863Smckusick 	int *retval;
387497Sroot {
397497Sroot 
40*45914Smckusick 	*retval = nofile;
4144404Skarels 	return (0);
427497Sroot }
437497Sroot 
4442863Smckusick /*
4542863Smckusick  * Duplicate a file descriptor.
4642863Smckusick  */
4742863Smckusick /* ARGSUSED */
4842863Smckusick dup(p, uap, retval)
4942863Smckusick 	struct proc *p;
5042863Smckusick 	struct args {
5142863Smckusick 		int	i;
5242863Smckusick 	} *uap;
5342863Smckusick 	int *retval;
547422Sroot {
55*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
567696Ssam 	struct file *fp;
5742863Smckusick 	int fd, error;
587497Sroot 
5942863Smckusick 	/*
6042863Smckusick 	 * XXX Compatibility
6142863Smckusick 	 */
6244404Skarels 	if (uap->i &~ 077) { uap->i &= 077; return (dup2(p, uap, retval)); }
637497Sroot 
64*45914Smckusick 	if ((unsigned)uap->i >= fdp->fd_maxfiles ||
65*45914Smckusick 	    (fp = OFILE(fdp, uap->i)) == NULL)
6644404Skarels 		return (EBADF);
67*45914Smckusick 	if (error = ufalloc(fdp, 0, &fd))
6844404Skarels 		return (error);
69*45914Smckusick 	OFILE(fdp, fd) = fp;
70*45914Smckusick 	OFILEFLAGS(fdp, fd) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE;
7142863Smckusick 	fp->f_count++;
72*45914Smckusick 	if (fd > fdp->fd_lastfile)
73*45914Smckusick 		fdp->fd_lastfile = fd;
7442863Smckusick 	*retval = fd;
7544404Skarels 	return (0);
767497Sroot }
777497Sroot 
7842863Smckusick /*
7942863Smckusick  * Duplicate a file descriptor to a particular value.
8042863Smckusick  */
8142863Smckusick /* ARGSUSED */
8242863Smckusick dup2(p, uap, retval)
8342863Smckusick 	struct proc *p;
8442863Smckusick 	register struct args {
8542863Smckusick 		int	i;
8642863Smckusick 		int	j;
8742863Smckusick 	} *uap;
8842863Smckusick 	int *retval;
897497Sroot {
90*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
917497Sroot 	register struct file *fp;
92*45914Smckusick 	int i, error;
937422Sroot 
94*45914Smckusick 	if ((unsigned)uap->i >= fdp->fd_maxfiles ||
95*45914Smckusick 	    (fp = OFILE(fdp, uap->i)) == NULL ||
96*45914Smckusick 	    (unsigned)uap->j >= nofile)
9744404Skarels 		return (EBADF);
9842863Smckusick 	*retval = uap->j;
997497Sroot 	if (uap->i == uap->j)
10044404Skarels 		return (0);
101*45914Smckusick 	if ((unsigned)uap->j >= fdp->fd_maxfiles) {
102*45914Smckusick 		if (error = ufalloc(fdp, uap->j, &i))
103*45914Smckusick 			return (error);
104*45914Smckusick 		if (uap->j != i)
105*45914Smckusick 			panic("dup2: ufalloc");
106*45914Smckusick 	} else if (OFILE(fdp, uap->j)) {
107*45914Smckusick 		if (OFILEFLAGS(fdp, uap->j) & UF_MAPPED)
108*45914Smckusick 			(void) munmapfd(p, uap->j);
109*45914Smckusick 		error = closef(OFILE(fdp, uap->j));
1107422Sroot 	}
111*45914Smckusick 	OFILE(fdp, uap->j) = fp;
112*45914Smckusick 	OFILEFLAGS(fdp, uap->j) = OFILEFLAGS(fdp, uap->i) &~ UF_EXCLOSE;
11342863Smckusick 	fp->f_count++;
114*45914Smckusick 	if (uap->j > fdp->fd_lastfile)
115*45914Smckusick 		fdp->fd_lastfile = uap->j;
11639354Smckusick 	/*
11739354Smckusick 	 * dup2() must succeed even though the close had an error.
11839354Smckusick 	 */
11939354Smckusick 	error = 0;		/* XXX */
12044404Skarels 	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 {
136*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
13742863Smckusick 	register struct file *fp;
13812748Ssam 	register char *pop;
13942863Smckusick 	int i, error;
1407497Sroot 
141*45914Smckusick 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
142*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
14344404Skarels 		return (EBADF);
144*45914Smckusick 	pop = &OFILEFLAGS(fdp, uap->fdes);
14512748Ssam 	switch(uap->cmd) {
14615076Skarels 	case F_DUPFD:
147*45914Smckusick 		if ((unsigned)uap->arg >= nofile)
14844404Skarels 			return (EINVAL);
149*45914Smckusick 		if (error = ufalloc(fdp, uap->arg, &i))
15044404Skarels 			return (error);
151*45914Smckusick 		OFILE(fdp, i) = fp;
152*45914Smckusick 		OFILEFLAGS(fdp, i) = *pop &~ UF_EXCLOSE;
15342863Smckusick 		fp->f_count++;
154*45914Smckusick 		if (i > fdp->fd_lastfile)
155*45914Smckusick 			fdp->fd_lastfile = i;
15642863Smckusick 		*retval = i;
15744404Skarels 		return (0);
1587497Sroot 
15915076Skarels 	case F_GETFD:
16042863Smckusick 		*retval = *pop & 1;
16144404Skarels 		return (0);
1627422Sroot 
16315076Skarels 	case F_SETFD:
16412748Ssam 		*pop = (*pop &~ 1) | (uap->arg & 1);
16544404Skarels 		return (0);
1668145Sroot 
16715076Skarels 	case F_GETFL:
16842863Smckusick 		*retval = fp->f_flag + FOPEN;
16944404Skarels 		return (0);
1708145Sroot 
17115076Skarels 	case F_SETFL:
17212748Ssam 		fp->f_flag &= FCNTLCANT;
17312748Ssam 		fp->f_flag |= (uap->arg-FOPEN) &~ FCNTLCANT;
17442863Smckusick 		if (error = fset(fp, FNDELAY, fp->f_flag & FNDELAY))
17544404Skarels 			return (error);
17642863Smckusick 		if (error = fset(fp, FASYNC, fp->f_flag & FASYNC))
17712748Ssam 			(void) fset(fp, FNDELAY, 0);
17844404Skarels 		return (error);
1797422Sroot 
18015076Skarels 	case F_GETOWN:
18144404Skarels 		return (fgetown(fp, retval));
1827422Sroot 
18315076Skarels 	case F_SETOWN:
18444404Skarels 		return (fsetown(fp, uap->arg));
1858115Sroot 
18612748Ssam 	default:
18744404Skarels 		return (EINVAL);
1887422Sroot 	}
18942863Smckusick 	/* NOTREACHED */
1907422Sroot }
1917422Sroot 
19212748Ssam fset(fp, bit, value)
19312748Ssam 	struct file *fp;
19412748Ssam 	int bit, value;
1957422Sroot {
1967422Sroot 
19712748Ssam 	if (value)
19812748Ssam 		fp->f_flag |= bit;
19912748Ssam 	else
20012748Ssam 		fp->f_flag &= ~bit;
20112748Ssam 	return (fioctl(fp, (int)(bit == FNDELAY ? FIONBIO : FIOASYNC),
20212748Ssam 	    (caddr_t)&value));
20312748Ssam }
2047422Sroot 
20512748Ssam fgetown(fp, valuep)
20612748Ssam 	struct file *fp;
20712748Ssam 	int *valuep;
20812748Ssam {
20912748Ssam 	int error;
2108115Sroot 
21112748Ssam 	switch (fp->f_type) {
2128115Sroot 
21312748Ssam 	case DTYPE_SOCKET:
21435810Smarc 		*valuep = ((struct socket *)fp->f_data)->so_pgid;
21512748Ssam 		return (0);
2167497Sroot 
21712748Ssam 	default:
21812748Ssam 		error = fioctl(fp, (int)TIOCGPGRP, (caddr_t)valuep);
21912748Ssam 		*valuep = -*valuep;
22012748Ssam 		return (error);
2217422Sroot 	}
2227422Sroot }
2237422Sroot 
22412748Ssam fsetown(fp, value)
22512748Ssam 	struct file *fp;
22612748Ssam 	int value;
2277422Sroot {
22837728Smckusick 
22912748Ssam 	if (fp->f_type == DTYPE_SOCKET) {
23035810Smarc 		((struct socket *)fp->f_data)->so_pgid = value;
23112748Ssam 		return (0);
23212748Ssam 	}
23312748Ssam 	if (value > 0) {
23412748Ssam 		struct proc *p = pfind(value);
23512748Ssam 		if (p == 0)
23628201Skarels 			return (ESRCH);
23735810Smarc 		value = p->p_pgrp->pg_id;
23812748Ssam 	} else
23912748Ssam 		value = -value;
24012748Ssam 	return (fioctl(fp, (int)TIOCSPGRP, (caddr_t)&value));
2417422Sroot }
2427422Sroot 
24312748Ssam fioctl(fp, cmd, value)
24412748Ssam 	struct file *fp;
24512748Ssam 	int cmd;
24612748Ssam 	caddr_t value;
2477422Sroot {
2487422Sroot 
24912748Ssam 	return ((*fp->f_ops->fo_ioctl)(fp, cmd, value));
2507422Sroot }
2517422Sroot 
25242863Smckusick /*
25342863Smckusick  * Close a file descriptor.
25442863Smckusick  */
25542863Smckusick /* ARGSUSED */
25642863Smckusick close(p, uap, retval)
25742863Smckusick 	struct proc *p;
25842863Smckusick 	struct args {
25942863Smckusick 		int	fdes;
26042863Smckusick 	} *uap;
26142863Smckusick 	int *retval;
2628029Sroot {
263*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
26412748Ssam 	register struct file *fp;
26513044Ssam 	register u_char *pf;
2668029Sroot 
267*45914Smckusick 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
268*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
26944404Skarels 		return (EBADF);
270*45914Smckusick 	pf = (u_char *)&OFILEFLAGS(fdp, uap->fdes);
27113044Ssam 	if (*pf & UF_MAPPED)
272*45914Smckusick 		(void) munmapfd(p, uap->fdes);
273*45914Smckusick 	OFILE(fdp, uap->fdes) = NULL;
274*45914Smckusick 	while (fdp->fd_lastfile >= 0 && OFILE(fdp, fdp->fd_lastfile) == NULL)
275*45914Smckusick 		fdp->fd_lastfile--;
27615550Skarels 	*pf = 0;
27744404Skarels 	return (closef(fp));
2788029Sroot }
2798029Sroot 
28042863Smckusick /*
28142863Smckusick  * Return status information about a file descriptor.
28242863Smckusick  */
28342863Smckusick /* ARGSUSED */
28442863Smckusick fstat(p, uap, retval)
28542863Smckusick 	struct proc *p;
28642863Smckusick 	register struct args {
28742863Smckusick 		int	fdes;
28842863Smckusick 		struct	stat *sb;
28942863Smckusick 	} *uap;
29042863Smckusick 	int *retval;
29113044Ssam {
292*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
29313044Ssam 	register struct file *fp;
29413044Ssam 	struct stat ub;
29542863Smckusick 	int error;
29613044Ssam 
297*45914Smckusick 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
298*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
29944404Skarels 		return (EBADF);
30013044Ssam 	switch (fp->f_type) {
30113044Ssam 
30237728Smckusick 	case DTYPE_VNODE:
30342863Smckusick 		error = vn_stat((struct vnode *)fp->f_data, &ub);
30413044Ssam 		break;
30513044Ssam 
30613044Ssam 	case DTYPE_SOCKET:
30742863Smckusick 		error = soo_stat((struct socket *)fp->f_data, &ub);
30813044Ssam 		break;
30913044Ssam 
31013044Ssam 	default:
31113044Ssam 		panic("fstat");
31213044Ssam 		/*NOTREACHED*/
31313044Ssam 	}
31442863Smckusick 	if (error == 0)
31542863Smckusick 		error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
31644404Skarels 	return (error);
31713044Ssam }
31813044Ssam 
3197422Sroot /*
3207497Sroot  * Allocate a user file descriptor.
3217422Sroot  */
322*45914Smckusick int fdexpand, fdreexpand;
323*45914Smckusick 
324*45914Smckusick ufalloc(fdp, want, result)
325*45914Smckusick 	register struct filedesc *fdp;
32637728Smckusick 	register int want;
32737728Smckusick 	int *result;
3287422Sroot {
329*45914Smckusick 	int last, osize, ofiles, nfiles;
330*45914Smckusick 	struct file **newofile;
331*45914Smckusick 	char *newofileflags;
3327497Sroot 
333*45914Smckusick 	for (;;) {
334*45914Smckusick 		last = (fdp->fd_maxfiles < nofile) ? fdp->fd_maxfiles : nofile;
335*45914Smckusick 		for (; want < last; want++) {
336*45914Smckusick 			if (OFILE(fdp, want) == NULL) {
337*45914Smckusick 				OFILEFLAGS(fdp, want) = 0;
338*45914Smckusick 				if (want > fdp->fd_lastfile)
339*45914Smckusick 					fdp->fd_lastfile = want;
340*45914Smckusick 				*result = want;
341*45914Smckusick 				return (0);
342*45914Smckusick 			}
3437497Sroot 		}
344*45914Smckusick 		if (fdp->fd_maxfiles >= nofile)
345*45914Smckusick 			return (EMFILE);
346*45914Smckusick 		if (fdp->fd_maxfiles == NDFILE) {
347*45914Smckusick 			fdp->fd_moreofiles = (struct file **)
348*45914Smckusick 			    malloc(NDEXTENT * OFILESIZE, M_FILE, M_WAITOK);
349*45914Smckusick 			fdp->fd_moreofileflags =
350*45914Smckusick 			    (char *)&fdp->fd_moreofiles[NDEXTENT];
351*45914Smckusick 			bzero((char *)fdp->fd_moreofiles, NDEXTENT * OFILESIZE);
352*45914Smckusick 			fdp->fd_maxfiles = NDFILE + NDEXTENT;
353*45914Smckusick 			fdexpand++;
354*45914Smckusick 			continue;
355*45914Smckusick 		}
356*45914Smckusick 		ofiles = fdp->fd_maxfiles - NDFILE;
357*45914Smckusick 		osize = ofiles * OFILESIZE;
358*45914Smckusick 		nfiles = (2 * osize) / OFILESIZE;
359*45914Smckusick 		newofile = (struct file **) malloc(2 * osize, M_FILE, M_WAITOK);
360*45914Smckusick 		newofileflags = (char *)&newofile[nfiles];
361*45914Smckusick 		bzero((char *)newofile, 2 * osize);
362*45914Smckusick 		bcopy((char *)fdp->fd_moreofiles, (char *)newofile,
363*45914Smckusick 			sizeof(struct file *) * ofiles);
364*45914Smckusick 		bcopy((char *)fdp->fd_moreofileflags, (char *)newofileflags,
365*45914Smckusick 			sizeof(char) * ofiles);
366*45914Smckusick 		free(fdp->fd_moreofiles, M_FILE);
367*45914Smckusick 		fdp->fd_moreofiles = newofile;
368*45914Smckusick 		fdp->fd_moreofileflags = newofileflags;
369*45914Smckusick 		fdp->fd_maxfiles = NDFILE + nfiles;
370*45914Smckusick 		fdreexpand++;
37139733Smckusick 	}
3727497Sroot }
3737497Sroot 
37442863Smckusick /*
37542863Smckusick  * Check to see if any user file descriptors are available.
37642863Smckusick  */
377*45914Smckusick ufavail(fdp)
378*45914Smckusick 	register struct filedesc *fdp;
37912748Ssam {
380*45914Smckusick 	register int i, avail;
38112748Ssam 
382*45914Smckusick 	avail = nofile - fdp->fd_maxfiles;
383*45914Smckusick 	for (i = 0; i < fdp->fd_maxfiles; i++)
384*45914Smckusick 		if (OFILE(fdp, i) == NULL)
38512748Ssam 			avail++;
38612748Ssam 	return (avail);
38712748Ssam }
38812748Ssam 
3897497Sroot struct	file *lastf;
3907497Sroot /*
3917497Sroot  * Allocate a user file descriptor
3927497Sroot  * and a file structure.
3937497Sroot  * Initialize the descriptor
3947497Sroot  * to point at the file structure.
3957497Sroot  */
396*45914Smckusick falloc(p, resultfp, resultfd)
397*45914Smckusick 	register struct proc *p;
39837728Smckusick 	struct file **resultfp;
39937728Smckusick 	int *resultfd;
4007497Sroot {
4017422Sroot 	register struct file *fp;
40237728Smckusick 	int error, i;
4037422Sroot 
404*45914Smckusick 	if (error = ufalloc(p->p_fd, 0, &i))
40537728Smckusick 		return (error);
4067497Sroot 	if (lastf == 0)
4077497Sroot 		lastf = file;
4087497Sroot 	for (fp = lastf; fp < fileNFILE; fp++)
4097497Sroot 		if (fp->f_count == 0)
4107497Sroot 			goto slot;
4117497Sroot 	for (fp = file; fp < lastf; fp++)
4127497Sroot 		if (fp->f_count == 0)
4137497Sroot 			goto slot;
4147497Sroot 	tablefull("file");
41537728Smckusick 	return (ENFILE);
4167497Sroot slot:
417*45914Smckusick 	OFILE(p->p_fd, i) = fp;
41812748Ssam 	fp->f_count = 1;
41912748Ssam 	fp->f_data = 0;
4207497Sroot 	fp->f_offset = 0;
42137728Smckusick 	fp->f_cred = u.u_cred;
42237728Smckusick 	crhold(fp->f_cred);
4237497Sroot 	lastf = fp + 1;
42437728Smckusick 	if (resultfp)
42537728Smckusick 		*resultfp = fp;
42637728Smckusick 	if (resultfd)
42737728Smckusick 		*resultfd = i;
42837728Smckusick 	return (0);
4297497Sroot }
43012748Ssam 
4317497Sroot /*
432*45914Smckusick  * Duplicate a filedesc structure.
433*45914Smckusick  */
434*45914Smckusick struct filedesc *
435*45914Smckusick fddup(fdp, justref)
436*45914Smckusick 	register struct filedesc *fdp;
437*45914Smckusick 	int justref;
438*45914Smckusick {
439*45914Smckusick 	register struct filedesc *newfdp;
440*45914Smckusick 	register struct file *fp;
441*45914Smckusick 	register int i;
442*45914Smckusick 	int j, last;
443*45914Smckusick 
444*45914Smckusick 	if (justref) {
445*45914Smckusick 		fdp->fd_refcnt++;
446*45914Smckusick 		return (fdp);
447*45914Smckusick 	}
448*45914Smckusick 	MALLOC(newfdp, struct filedesc *, sizeof(*fdp), M_FILE, M_WAITOK);
449*45914Smckusick 	bcopy((char *)fdp, (char *)newfdp, sizeof(*fdp));
450*45914Smckusick 	VREF(newfdp->fd_cdir);
451*45914Smckusick 	if (newfdp->fd_rdir)
452*45914Smckusick 		VREF(newfdp->fd_rdir);
453*45914Smckusick 	newfdp->fd_refcnt = 1;
454*45914Smckusick 	newfdp->fd_maxfiles = NDFILE;
455*45914Smckusick 	if (fdp->fd_lastfile > NDFILE &&
456*45914Smckusick 	    ufalloc(newfdp, fdp->fd_lastfile, &j)) {
457*45914Smckusick 		log(LOG_ERR, "fddup: lost file descriptor(s)");
458*45914Smckusick 		last = newfdp->fd_maxfiles;
459*45914Smckusick 	} else
460*45914Smckusick 		last = fdp->fd_lastfile;
461*45914Smckusick 	for (i = 0; i <= last; i++) {
462*45914Smckusick 		fp = OFILE(fdp, i);
463*45914Smckusick 		if (fp == NULL)
464*45914Smckusick 			continue;
465*45914Smckusick 		fp->f_count++;
466*45914Smckusick 		OFILE(newfdp, i) = fp;
467*45914Smckusick 		OFILEFLAGS(newfdp, i) = OFILEFLAGS(fdp, i);
468*45914Smckusick 	}
469*45914Smckusick 	return (newfdp);
470*45914Smckusick }
471*45914Smckusick 
472*45914Smckusick /*
473*45914Smckusick  * Release a filedesc structure.
474*45914Smckusick  */
475*45914Smckusick fdrele(fdp)
476*45914Smckusick 	register struct filedesc *fdp;
477*45914Smckusick {
478*45914Smckusick 	struct file *f;
479*45914Smckusick 	register int i;
480*45914Smckusick 
481*45914Smckusick 	if (fdp->fd_refcnt > 1) {
482*45914Smckusick 		fdp->fd_refcnt--;
483*45914Smckusick 		return;
484*45914Smckusick 	}
485*45914Smckusick 	for (i = 0; i <= fdp->fd_lastfile; i++) {
486*45914Smckusick 		if (f = OFILE(fdp, i)) {
487*45914Smckusick 			OFILE(fdp, i) = NULL;
488*45914Smckusick 			OFILEFLAGS(fdp, i) = 0;
489*45914Smckusick 			(void) closef(f);
490*45914Smckusick 		}
491*45914Smckusick 	}
492*45914Smckusick 	if (fdp->fd_maxfiles > NDFILE)
493*45914Smckusick 		FREE(fdp->fd_moreofiles, M_FILE);
494*45914Smckusick 	vrele(fdp->fd_cdir);
495*45914Smckusick 	if (fdp->fd_rdir)
496*45914Smckusick 		vrele(fdp->fd_rdir);
497*45914Smckusick 	FREE(fdp, M_FILE);
498*45914Smckusick }
499*45914Smckusick 
500*45914Smckusick /*
5017497Sroot  * Internal form of close.
50212748Ssam  * Decrement reference count on file structure.
5037497Sroot  */
50413044Ssam closef(fp)
5057497Sroot 	register struct file *fp;
5067497Sroot {
50739354Smckusick 	int error;
5087497Sroot 
5097422Sroot 	if (fp == NULL)
51039354Smckusick 		return (0);
5117497Sroot 	if (fp->f_count > 1) {
5127497Sroot 		fp->f_count--;
51339354Smckusick 		return (0);
5147422Sroot 	}
51537728Smckusick 	if (fp->f_count < 1)
51637728Smckusick 		panic("closef: count < 1");
51739354Smckusick 	error = (*fp->f_ops->fo_close)(fp);
51837728Smckusick 	crfree(fp->f_cred);
5197497Sroot 	fp->f_count = 0;
52039354Smckusick 	return (error);
5217422Sroot }
52213044Ssam 
52313044Ssam /*
52413044Ssam  * Apply an advisory lock on a file descriptor.
52513044Ssam  */
52642863Smckusick /* ARGSUSED */
52742863Smckusick flock(p, uap, retval)
52842863Smckusick 	struct proc *p;
52942863Smckusick 	register struct args {
53037728Smckusick 		int	fdes;
53113044Ssam 		int	how;
53242863Smckusick 	} *uap;
53342863Smckusick 	int *retval;
53442863Smckusick {
535*45914Smckusick 	register struct filedesc *fdp = p->p_fd;
53613044Ssam 	register struct file *fp;
53713044Ssam 
538*45914Smckusick 	if ((unsigned)uap->fdes >= fdp->fd_maxfiles ||
539*45914Smckusick 	    (fp = OFILE(fdp, uap->fdes)) == NULL)
54044404Skarels 		return (EBADF);
54142863Smckusick 	if (fp->f_type != DTYPE_VNODE)
54244404Skarels 		return (EOPNOTSUPP);
54313101Ssam 	if (uap->how & LOCK_UN) {
54437728Smckusick 		vn_unlock(fp, FSHLOCK|FEXLOCK);
54544404Skarels 		return (0);
54613044Ssam 	}
54717434Skarels 	if ((uap->how & (LOCK_SH | LOCK_EX)) == 0)
54844404Skarels 		return (0);				/* error? */
54917998Skarels 	if (uap->how & LOCK_EX)
55017998Skarels 		uap->how &= ~LOCK_SH;
55113101Ssam 	/* avoid work... */
55217998Skarels 	if ((fp->f_flag & FEXLOCK) && (uap->how & LOCK_EX) ||
55317998Skarels 	    (fp->f_flag & FSHLOCK) && (uap->how & LOCK_SH))
55444404Skarels 		return (0);
55544404Skarels 	return (vn_lock(fp, uap->how));
55613044Ssam }
55737586Smarc 
55837586Smarc /*
55937586Smarc  * File Descriptor pseudo-device driver (/dev/fd/).
56037586Smarc  *
56137586Smarc  * Opening minor device N dup()s the file (if any) connected to file
56237586Smarc  * descriptor N belonging to the calling process.  Note that this driver
56337586Smarc  * consists of only the ``open()'' routine, because all subsequent
56437586Smarc  * references to this file will be direct to the other driver.
56537586Smarc  */
56637728Smckusick /* ARGSUSED */
56737728Smckusick fdopen(dev, mode, type)
56837586Smarc 	dev_t dev;
56937728Smckusick 	int mode, type;
57037586Smarc {
57143406Smckusick 	struct proc *p = u.u_procp;		/* XXX */
57237586Smarc 
57337586Smarc 	/*
57443449Smckusick 	 * XXX Kludge: set p->p_dupfd to contain the value of the
57543406Smckusick 	 * the file descriptor being sought for duplication. The error
57643406Smckusick 	 * return ensures that the vnode for this device will be released
57743406Smckusick 	 * by vn_open. Open will detect this special error and take the
57843406Smckusick 	 * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
57943406Smckusick 	 * will simply report the error.
58037586Smarc 	 */
58143449Smckusick 	p->p_dupfd = minor(dev);
58243406Smckusick 	return (ENODEV);
58343406Smckusick }
58440873Sbostic 
58543406Smckusick /*
58643406Smckusick  * Duplicate the specified descriptor to a free descriptor.
58743406Smckusick  */
588*45914Smckusick dupfdopen(fdp, indx, dfd, mode)
589*45914Smckusick 	register struct filedesc *fdp;
59043406Smckusick 	register int indx, dfd;
59143406Smckusick 	int mode;
59243406Smckusick {
59343406Smckusick 	register struct file *wfp;
59443406Smckusick 	struct file *fp;
59543406Smckusick 
59637586Smarc 	/*
59743406Smckusick 	 * If the to-be-dup'd fd number is greater than the allowed number
59843406Smckusick 	 * of file descriptors, or the fd to be dup'd has already been
59943406Smckusick 	 * closed, reject.  Note, check for new == old is necessary as
60043406Smckusick 	 * falloc could allocate an already closed to-be-dup'd descriptor
60143406Smckusick 	 * as the new descriptor.
60237586Smarc 	 */
603*45914Smckusick 	fp = OFILE(fdp, indx);
604*45914Smckusick 	if ((u_int)dfd >= fdp->fd_maxfiles || (wfp = OFILE(fdp, dfd)) == NULL ||
60540873Sbostic 	    fp == wfp)
60637586Smarc 		return (EBADF);
60740873Sbostic 
60837586Smarc 	/*
60940873Sbostic 	 * Check that the mode the file is being opened for is a subset
61040873Sbostic 	 * of the mode of the existing descriptor.
61137586Smarc 	 */
61243406Smckusick 	if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
61337586Smarc 		return (EACCES);
614*45914Smckusick 	OFILE(fdp, indx) = wfp;
615*45914Smckusick 	OFILEFLAGS(fdp, indx) = OFILEFLAGS(fdp, dfd);
61642863Smckusick 	wfp->f_count++;
617*45914Smckusick 	if (indx > fdp->fd_lastfile)
618*45914Smckusick 		fdp->fd_lastfile = indx;
61943406Smckusick 	return (0);
62037586Smarc }
621*45914Smckusick 
622*45914Smckusick #if defined(vax) || defined(tahoe)
623*45914Smckusick /*
624*45914Smckusick  * Brain dead routines to compensate for limitations in PCC
625*45914Smckusick  */
626*45914Smckusick struct file **
627*45914Smckusick ofilefunc(fdp, indx)
628*45914Smckusick 	struct filedesc *fdp;
629*45914Smckusick 	int indx;
630*45914Smckusick {
631*45914Smckusick 
632*45914Smckusick 	if (indx < NDFILE)
633*45914Smckusick 		return (&fdp->fd_ofile[indx]);
634*45914Smckusick 	return (&fdp->fd_moreofiles[indx - NDFILE]);
635*45914Smckusick }
636*45914Smckusick 
637*45914Smckusick char *
638*45914Smckusick ofileflagsfunc(fdp, indx)
639*45914Smckusick 	struct filedesc *fdp;
640*45914Smckusick 	int indx;
641*45914Smckusick {
642*45914Smckusick 
643*45914Smckusick 	if (indx < NDFILE)
644*45914Smckusick 		return (&fdp->fd_ofileflags[indx]);
645*45914Smckusick 	return (&fdp->fd_moreofileflags[indx - NDFILE]);
646*45914Smckusick }
647*45914Smckusick #endif
648