1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1982, 1986, 1989, 1991, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
|
|
|
* (c) UNIX System Laboratories, Inc.
|
|
|
|
* All or some portions of this file are derived from material licensed
|
|
|
|
* to the University of California by American Telephone and Telegraph
|
|
|
|
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
|
|
|
|
* the permission of UNIX System Laboratories, Inc.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. All advertising materials mentioning features or use of this software
|
|
|
|
* must display the following acknowledgement:
|
|
|
|
* This product includes software developed by the University of
|
|
|
|
* California, Berkeley and its contributors.
|
|
|
|
* 4. Neither the name of the University nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*
|
|
|
|
* @(#)kern_descrip.c 8.6 (Berkeley) 4/19/94
|
1999-08-28 01:08:13 +00:00
|
|
|
* $FreeBSD$
|
1994-05-24 10:09:53 +00:00
|
|
|
*/
|
|
|
|
|
1997-12-16 17:40:42 +00:00
|
|
|
#include "opt_compat.h"
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
1995-11-12 06:43:28 +00:00
|
|
|
#include <sys/sysproto.h>
|
1995-12-02 18:58:56 +00:00
|
|
|
#include <sys/conf.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/filedesc.h>
|
|
|
|
#include <sys/kernel.h>
|
1995-11-14 08:58:35 +00:00
|
|
|
#include <sys/sysctl.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/vnode.h>
|
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/file.h>
|
|
|
|
#include <sys/socketvar.h>
|
|
|
|
#include <sys/stat.h>
|
1996-09-28 16:33:21 +00:00
|
|
|
#include <sys/filio.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
#include <sys/fcntl.h>
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/unistd.h>
|
|
|
|
#include <sys/resourcevar.h>
|
1996-01-28 23:41:40 +00:00
|
|
|
#include <sys/pipe.h>
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1995-12-05 21:51:45 +00:00
|
|
|
#include <vm/vm.h>
|
1995-12-07 12:48:31 +00:00
|
|
|
#include <vm/vm_extern.h>
|
1995-12-05 21:51:45 +00:00
|
|
|
|
1997-10-12 20:26:33 +00:00
|
|
|
static MALLOC_DEFINE(M_FILEDESC, "file desc", "Open file descriptor table");
|
1997-11-23 10:43:49 +00:00
|
|
|
MALLOC_DEFINE(M_FILE, "file", "Open file structure");
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
static MALLOC_DEFINE(M_SIGIO, "sigio", "sigio structures");
|
1997-10-12 20:26:33 +00:00
|
|
|
|
1997-10-11 18:31:40 +00:00
|
|
|
|
1995-12-08 11:19:42 +00:00
|
|
|
static d_open_t fdopen;
|
|
|
|
#define NUMFDESC 64
|
|
|
|
|
1995-11-29 10:49:16 +00:00
|
|
|
#define CDEV_MAJOR 22
|
1999-05-30 16:53:49 +00:00
|
|
|
static struct cdevsw fildesc_cdevsw = {
|
|
|
|
/* open */ fdopen,
|
|
|
|
/* close */ noclose,
|
|
|
|
/* read */ noread,
|
|
|
|
/* write */ nowrite,
|
|
|
|
/* ioctl */ noioctl,
|
|
|
|
/* poll */ nopoll,
|
|
|
|
/* mmap */ nommap,
|
|
|
|
/* strategy */ nostrategy,
|
|
|
|
/* name */ "FD",
|
|
|
|
/* maj */ CDEV_MAJOR,
|
|
|
|
/* dump */ nodump,
|
|
|
|
/* psize */ nopsize,
|
|
|
|
/* flags */ 0,
|
|
|
|
/* bmaj */ -1
|
|
|
|
};
|
1995-11-29 10:49:16 +00:00
|
|
|
|
1998-06-10 10:27:43 +00:00
|
|
|
static int finishdup __P((struct filedesc *fdp, int old, int new, register_t *retval));
|
1999-08-04 18:53:50 +00:00
|
|
|
static int badfo_readwrite __P((struct file *fp, struct uio *uio,
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
struct ucred *cred, int flags, struct proc *p));
|
1999-08-04 18:53:50 +00:00
|
|
|
static int badfo_ioctl __P((struct file *fp, u_long com, caddr_t data,
|
|
|
|
struct proc *p));
|
|
|
|
static int badfo_poll __P((struct file *fp, int events,
|
|
|
|
struct ucred *cred, struct proc *p));
|
1999-11-08 03:27:14 +00:00
|
|
|
static int badfo_stat __P((struct file *fp, struct stat *sb, struct proc *p));
|
1999-08-04 18:53:50 +00:00
|
|
|
static int badfo_close __P((struct file *fp, struct proc *p));
|
1999-11-08 03:27:14 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Descriptor management.
|
|
|
|
*/
|
1996-03-11 02:17:30 +00:00
|
|
|
struct filelist filehead; /* head of list of open files */
|
|
|
|
int nfiles; /* actual number of open files */
|
1996-02-23 18:49:25 +00:00
|
|
|
extern int cmask;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* System calls on descriptors.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-05-24 10:09:53 +00:00
|
|
|
struct getdtablesize_args {
|
|
|
|
int dummy;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
getdtablesize(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
struct getdtablesize_args *uap;
|
|
|
|
{
|
|
|
|
|
1997-11-06 19:29:57 +00:00
|
|
|
p->p_retval[0] =
|
|
|
|
min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Duplicate a file descriptor to a particular value.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-05-24 10:09:53 +00:00
|
|
|
struct dup2_args {
|
|
|
|
u_int from;
|
|
|
|
u_int to;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
dup2(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
struct dup2_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register u_int old = uap->from, new = uap->to;
|
|
|
|
int i, error;
|
|
|
|
|
|
|
|
if (old >= fdp->fd_nfiles ||
|
|
|
|
fdp->fd_ofiles[old] == NULL ||
|
|
|
|
new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
|
1995-02-20 19:42:42 +00:00
|
|
|
new >= maxfilesperproc)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (EBADF);
|
|
|
|
if (old == new) {
|
1997-11-06 19:29:57 +00:00
|
|
|
p->p_retval[0] = new;
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (new >= fdp->fd_nfiles) {
|
1994-09-25 19:34:02 +00:00
|
|
|
if ((error = fdalloc(p, new, &i)))
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
if (new != i)
|
|
|
|
panic("dup2: fdalloc");
|
|
|
|
} else if (fdp->fd_ofiles[new]) {
|
|
|
|
if (fdp->fd_ofileflags[new] & UF_MAPPED)
|
|
|
|
(void) munmapfd(p, new);
|
|
|
|
/*
|
|
|
|
* dup2() must succeed even if the close has an error.
|
|
|
|
*/
|
|
|
|
(void) closef(fdp->fd_ofiles[new], p);
|
|
|
|
}
|
1997-11-06 19:29:57 +00:00
|
|
|
return (finishdup(fdp, (int)old, (int)new, p->p_retval));
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
1994-09-25 19:34:02 +00:00
|
|
|
/*
|
|
|
|
* Duplicate a file descriptor.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-09-25 19:34:02 +00:00
|
|
|
struct dup_args {
|
|
|
|
u_int fd;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-09-25 19:34:02 +00:00
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
dup(p, uap)
|
1994-09-25 19:34:02 +00:00
|
|
|
struct proc *p;
|
|
|
|
struct dup_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp;
|
|
|
|
u_int old;
|
|
|
|
int new, error;
|
|
|
|
|
|
|
|
old = uap->fd;
|
1994-12-12 12:27:39 +00:00
|
|
|
|
|
|
|
#if 0
|
1994-09-25 19:34:02 +00:00
|
|
|
/*
|
|
|
|
* XXX Compatibility
|
|
|
|
*/
|
1997-11-23 12:24:59 +00:00
|
|
|
if (old &~ 077) { uap->fd &= 077; return (dup2(p, uap, p->p_retval)); }
|
1994-12-12 12:27:39 +00:00
|
|
|
#endif
|
1994-09-25 19:34:02 +00:00
|
|
|
|
|
|
|
fdp = p->p_fd;
|
|
|
|
if (old >= fdp->fd_nfiles || fdp->fd_ofiles[old] == NULL)
|
|
|
|
return (EBADF);
|
|
|
|
if ((error = fdalloc(p, 0, &new)))
|
|
|
|
return (error);
|
1997-11-06 19:29:57 +00:00
|
|
|
return (finishdup(fdp, (int)old, new, p->p_retval));
|
1994-09-25 19:34:02 +00:00
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* The file control system call.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-05-24 10:09:53 +00:00
|
|
|
struct fcntl_args {
|
|
|
|
int fd;
|
|
|
|
int cmd;
|
1998-07-15 06:10:16 +00:00
|
|
|
long arg;
|
1994-05-24 10:09:53 +00:00
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
fcntl(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
register struct fcntl_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register struct file *fp;
|
|
|
|
register char *pop;
|
|
|
|
struct vnode *vp;
|
|
|
|
int i, tmp, error, flg = F_POSIX;
|
|
|
|
struct flock fl;
|
|
|
|
u_int newmin;
|
|
|
|
|
|
|
|
if ((unsigned)uap->fd >= fdp->fd_nfiles ||
|
|
|
|
(fp = fdp->fd_ofiles[uap->fd]) == NULL)
|
|
|
|
return (EBADF);
|
|
|
|
pop = &fdp->fd_ofileflags[uap->fd];
|
|
|
|
switch (uap->cmd) {
|
|
|
|
|
|
|
|
case F_DUPFD:
|
|
|
|
newmin = uap->arg;
|
|
|
|
if (newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur ||
|
1995-02-20 19:42:42 +00:00
|
|
|
newmin >= maxfilesperproc)
|
1994-05-24 10:09:53 +00:00
|
|
|
return (EINVAL);
|
1994-09-25 19:34:02 +00:00
|
|
|
if ((error = fdalloc(p, newmin, &i)))
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
1997-11-06 19:29:57 +00:00
|
|
|
return (finishdup(fdp, uap->fd, i, p->p_retval));
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
case F_GETFD:
|
1997-11-06 19:29:57 +00:00
|
|
|
p->p_retval[0] = *pop & 1;
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
case F_SETFD:
|
|
|
|
*pop = (*pop &~ 1) | (uap->arg & 1);
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
case F_GETFL:
|
1997-11-06 19:29:57 +00:00
|
|
|
p->p_retval[0] = OFLAGS(fp->f_flag);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
|
|
|
|
case F_SETFL:
|
|
|
|
fp->f_flag &= ~FCNTLFLAGS;
|
1997-11-23 12:24:59 +00:00
|
|
|
fp->f_flag |= FFLAGS(uap->arg & ~O_ACCMODE) & FCNTLFLAGS;
|
1994-05-24 10:09:53 +00:00
|
|
|
tmp = fp->f_flag & FNONBLOCK;
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
error = fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
tmp = fp->f_flag & FASYNC;
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
error = fo_ioctl(fp, FIOASYNC, (caddr_t)&tmp, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (!error)
|
|
|
|
return (0);
|
|
|
|
fp->f_flag &= ~FNONBLOCK;
|
|
|
|
tmp = 0;
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
(void)fo_ioctl(fp, FIONBIO, (caddr_t)&tmp, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
case F_GETOWN:
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
return (fo_ioctl(fp, FIOGETOWN, (caddr_t)p->p_retval, p));
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
case F_SETOWN:
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
return (fo_ioctl(fp, FIOSETOWN, (caddr_t)&uap->arg, p));
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
case F_SETLKW:
|
|
|
|
flg |= F_WAIT;
|
|
|
|
/* Fall into F_SETLK */
|
|
|
|
|
|
|
|
case F_SETLK:
|
|
|
|
if (fp->f_type != DTYPE_VNODE)
|
|
|
|
return (EBADF);
|
|
|
|
vp = (struct vnode *)fp->f_data;
|
|
|
|
/* Copy in the lock structure */
|
1998-07-15 06:10:16 +00:00
|
|
|
error = copyin((caddr_t)(intptr_t)uap->arg, (caddr_t)&fl,
|
|
|
|
sizeof(fl));
|
1994-05-24 10:09:53 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
if (fl.l_whence == SEEK_CUR)
|
|
|
|
fl.l_start += fp->f_offset;
|
|
|
|
switch (fl.l_type) {
|
|
|
|
|
|
|
|
case F_RDLCK:
|
|
|
|
if ((fp->f_flag & FREAD) == 0)
|
|
|
|
return (EBADF);
|
|
|
|
p->p_flag |= P_ADVLOCK;
|
1999-06-07 20:37:29 +00:00
|
|
|
return (VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK, &fl, flg));
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
case F_WRLCK:
|
|
|
|
if ((fp->f_flag & FWRITE) == 0)
|
|
|
|
return (EBADF);
|
|
|
|
p->p_flag |= P_ADVLOCK;
|
1999-06-07 20:37:29 +00:00
|
|
|
return (VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_SETLK, &fl, flg));
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
case F_UNLCK:
|
1999-06-07 20:37:29 +00:00
|
|
|
return (VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK, &fl,
|
1994-05-24 10:09:53 +00:00
|
|
|
F_POSIX));
|
|
|
|
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
case F_GETLK:
|
|
|
|
if (fp->f_type != DTYPE_VNODE)
|
|
|
|
return (EBADF);
|
|
|
|
vp = (struct vnode *)fp->f_data;
|
|
|
|
/* Copy in the lock structure */
|
1998-07-15 06:10:16 +00:00
|
|
|
error = copyin((caddr_t)(intptr_t)uap->arg, (caddr_t)&fl,
|
|
|
|
sizeof(fl));
|
1994-05-24 10:09:53 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
1996-12-19 19:59:51 +00:00
|
|
|
if (fl.l_type != F_RDLCK && fl.l_type != F_WRLCK &&
|
|
|
|
fl.l_type != F_UNLCK)
|
|
|
|
return (EINVAL);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (fl.l_whence == SEEK_CUR)
|
|
|
|
fl.l_start += fp->f_offset;
|
1999-06-07 20:37:29 +00:00
|
|
|
if ((error = VOP_ADVLOCK(vp,(caddr_t)p->p_leader,F_GETLK,&fl,F_POSIX)))
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
1998-07-15 06:10:16 +00:00
|
|
|
return (copyout((caddr_t)&fl, (caddr_t)(intptr_t)uap->arg,
|
|
|
|
sizeof(fl)));
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Common code for dup, dup2, and fcntl(F_DUPFD).
|
|
|
|
*/
|
1995-12-14 08:32:45 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
finishdup(fdp, old, new, retval)
|
|
|
|
register struct filedesc *fdp;
|
1998-06-10 10:27:43 +00:00
|
|
|
register int old, new;
|
|
|
|
register_t *retval;
|
1994-05-24 10:09:53 +00:00
|
|
|
{
|
|
|
|
register struct file *fp;
|
|
|
|
|
|
|
|
fp = fdp->fd_ofiles[old];
|
|
|
|
fdp->fd_ofiles[new] = fp;
|
|
|
|
fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE;
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
fhold(fp);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (new > fdp->fd_lastfile)
|
|
|
|
fdp->fd_lastfile = new;
|
|
|
|
*retval = new;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
/*
|
|
|
|
* If sigio is on the list associated with a process or process group,
|
|
|
|
* disable signalling from the device, remove sigio from the list and
|
|
|
|
* free sigio.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
funsetown(sigio)
|
|
|
|
struct sigio *sigio;
|
|
|
|
{
|
|
|
|
int s;
|
|
|
|
|
|
|
|
if (sigio == NULL)
|
|
|
|
return;
|
|
|
|
s = splhigh();
|
|
|
|
*(sigio->sio_myref) = NULL;
|
|
|
|
splx(s);
|
|
|
|
if (sigio->sio_pgid < 0) {
|
|
|
|
SLIST_REMOVE(&sigio->sio_pgrp->pg_sigiolst, sigio,
|
|
|
|
sigio, sio_pgsigio);
|
|
|
|
} else /* if ((*sigiop)->sio_pgid > 0) */ {
|
|
|
|
SLIST_REMOVE(&sigio->sio_proc->p_sigiolst, sigio,
|
|
|
|
sigio, sio_pgsigio);
|
|
|
|
}
|
|
|
|
crfree(sigio->sio_ucred);
|
|
|
|
FREE(sigio, M_SIGIO);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free a list of sigio structures. */
|
|
|
|
void
|
|
|
|
funsetownlst(sigiolst)
|
|
|
|
struct sigiolst *sigiolst;
|
|
|
|
{
|
|
|
|
struct sigio *sigio;
|
|
|
|
|
1999-11-16 10:56:05 +00:00
|
|
|
while ((sigio = SLIST_FIRST(sigiolst)) != NULL)
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
funsetown(sigio);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is common code for FIOSETOWN ioctl called by fcntl(fd, F_SETOWN, arg).
|
|
|
|
*
|
|
|
|
* After permission checking, add a sigio structure to the sigio list for
|
|
|
|
* the process or process group.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
fsetown(pgid, sigiop)
|
|
|
|
pid_t pgid;
|
|
|
|
struct sigio **sigiop;
|
|
|
|
{
|
1998-11-11 10:56:07 +00:00
|
|
|
struct proc *proc;
|
|
|
|
struct pgrp *pgrp;
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
struct sigio *sigio;
|
|
|
|
int s;
|
|
|
|
|
|
|
|
if (pgid == 0) {
|
|
|
|
funsetown(*sigiop);
|
|
|
|
return (0);
|
1998-11-11 10:56:07 +00:00
|
|
|
}
|
|
|
|
if (pgid > 0) {
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
proc = pfind(pgid);
|
|
|
|
if (proc == NULL)
|
|
|
|
return (ESRCH);
|
|
|
|
/*
|
|
|
|
* Policy - Don't allow a process to FSETOWN a process
|
|
|
|
* in another session.
|
|
|
|
*
|
|
|
|
* Remove this test to allow maximum flexibility or
|
|
|
|
* restrict FSETOWN to the current process or process
|
|
|
|
* group for maximum safety.
|
|
|
|
*/
|
|
|
|
else if (proc->p_session != curproc->p_session)
|
|
|
|
return (EPERM);
|
1998-11-11 10:56:07 +00:00
|
|
|
pgrp = NULL;
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
} else /* if (pgid < 0) */ {
|
|
|
|
pgrp = pgfind(-pgid);
|
|
|
|
if (pgrp == NULL)
|
|
|
|
return (ESRCH);
|
|
|
|
/*
|
|
|
|
* Policy - Don't allow a process to FSETOWN a process
|
|
|
|
* in another session.
|
|
|
|
*
|
|
|
|
* Remove this test to allow maximum flexibility or
|
|
|
|
* restrict FSETOWN to the current process or process
|
|
|
|
* group for maximum safety.
|
|
|
|
*/
|
|
|
|
else if (pgrp->pg_session != curproc->p_session)
|
|
|
|
return (EPERM);
|
1998-11-11 10:56:07 +00:00
|
|
|
proc = NULL;
|
Installed the second patch attached to kern/7899 with some changes suggested
by bde, a few other tweaks to get the patch to apply cleanly again and
some improvements to the comments.
This change closes some fairly minor security holes associated with
F_SETOWN, fixes a few bugs, and removes some limitations that F_SETOWN
had on tty devices. For more details, see the description on the PR.
Because this patch increases the size of the proc and pgrp structures,
it is necessary to re-install the includes and recompile libkvm,
the vinum lkm, fstat, gcore, gdb, ipfilter, ps, top, and w.
PR: kern/7899
Reviewed by: bde, elvind
1998-11-11 10:04:13 +00:00
|
|
|
}
|
|
|
|
funsetown(*sigiop);
|
|
|
|
MALLOC(sigio, struct sigio *, sizeof(struct sigio), M_SIGIO,
|
|
|
|
M_WAITOK);
|
|
|
|
if (pgid > 0) {
|
|
|
|
SLIST_INSERT_HEAD(&proc->p_sigiolst, sigio, sio_pgsigio);
|
|
|
|
sigio->sio_proc = proc;
|
|
|
|
} else {
|
|
|
|
SLIST_INSERT_HEAD(&pgrp->pg_sigiolst, sigio, sio_pgsigio);
|
|
|
|
sigio->sio_pgrp = pgrp;
|
|
|
|
}
|
|
|
|
sigio->sio_pgid = pgid;
|
|
|
|
crhold(curproc->p_ucred);
|
|
|
|
sigio->sio_ucred = curproc->p_ucred;
|
|
|
|
/* It would be convenient if p_ruid was in ucred. */
|
|
|
|
sigio->sio_ruid = curproc->p_cred->p_ruid;
|
|
|
|
sigio->sio_myref = sigiop;
|
|
|
|
s = splhigh();
|
|
|
|
*sigiop = sigio;
|
|
|
|
splx(s);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This is common code for FIOGETOWN ioctl called by fcntl(fd, F_GETOWN, arg).
|
|
|
|
*/
|
|
|
|
pid_t
|
|
|
|
fgetown(sigio)
|
|
|
|
struct sigio *sigio;
|
|
|
|
{
|
|
|
|
return (sigio != NULL ? sigio->sio_pgid : 0);
|
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Close a file descriptor.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1995-10-08 00:06:22 +00:00
|
|
|
struct close_args {
|
|
|
|
int fd;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
close(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
struct close_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register struct file *fp;
|
|
|
|
register int fd = uap->fd;
|
|
|
|
register u_char *pf;
|
|
|
|
|
|
|
|
if ((unsigned)fd >= fdp->fd_nfiles ||
|
|
|
|
(fp = fdp->fd_ofiles[fd]) == NULL)
|
|
|
|
return (EBADF);
|
|
|
|
pf = (u_char *)&fdp->fd_ofileflags[fd];
|
|
|
|
if (*pf & UF_MAPPED)
|
|
|
|
(void) munmapfd(p, fd);
|
|
|
|
fdp->fd_ofiles[fd] = NULL;
|
|
|
|
while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
|
|
|
|
fdp->fd_lastfile--;
|
|
|
|
if (fd < fdp->fd_freefile)
|
|
|
|
fdp->fd_freefile = fd;
|
|
|
|
*pf = 0;
|
|
|
|
return (closef(fp, p));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
|
|
|
|
/*
|
|
|
|
* Return status information about a file descriptor.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-05-24 10:09:53 +00:00
|
|
|
struct ofstat_args {
|
|
|
|
int fd;
|
|
|
|
struct ostat *sb;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
ofstat(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
register struct ofstat_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register struct file *fp;
|
|
|
|
struct stat ub;
|
|
|
|
struct ostat oub;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((unsigned)uap->fd >= fdp->fd_nfiles ||
|
|
|
|
(fp = fdp->fd_ofiles[uap->fd]) == NULL)
|
|
|
|
return (EBADF);
|
1999-11-08 03:27:14 +00:00
|
|
|
error = fo_stat(fp, &ub, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
cvtstat(&ub, &oub);
|
|
|
|
if (error == 0)
|
|
|
|
error = copyout((caddr_t)&oub, (caddr_t)uap->sb, sizeof (oub));
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
#endif /* COMPAT_43 || COMPAT_SUNOS */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return status information about a file descriptor.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-05-24 10:09:53 +00:00
|
|
|
struct fstat_args {
|
|
|
|
int fd;
|
|
|
|
struct stat *sb;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
fstat(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
register struct fstat_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register struct file *fp;
|
|
|
|
struct stat ub;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((unsigned)uap->fd >= fdp->fd_nfiles ||
|
|
|
|
(fp = fdp->fd_ofiles[uap->fd]) == NULL)
|
|
|
|
return (EBADF);
|
1999-11-08 03:27:14 +00:00
|
|
|
error = fo_stat(fp, &ub, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (error == 0)
|
|
|
|
error = copyout((caddr_t)&ub, (caddr_t)uap->sb, sizeof (ub));
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1998-05-11 03:55:28 +00:00
|
|
|
/*
|
|
|
|
* Return status information about a file descriptor.
|
|
|
|
*/
|
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
|
|
|
struct nfstat_args {
|
|
|
|
int fd;
|
|
|
|
struct nstat *sb;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
/* ARGSUSED */
|
|
|
|
int
|
|
|
|
nfstat(p, uap)
|
|
|
|
struct proc *p;
|
|
|
|
register struct nfstat_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register struct file *fp;
|
|
|
|
struct stat ub;
|
|
|
|
struct nstat nub;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if ((unsigned)uap->fd >= fdp->fd_nfiles ||
|
|
|
|
(fp = fdp->fd_ofiles[uap->fd]) == NULL)
|
|
|
|
return (EBADF);
|
1999-11-08 03:27:14 +00:00
|
|
|
error = fo_stat(fp, &ub, p);
|
1998-05-11 03:55:28 +00:00
|
|
|
if (error == 0) {
|
|
|
|
cvtnstat(&ub, &nub);
|
|
|
|
error = copyout((caddr_t)&nub, (caddr_t)uap->sb, sizeof (nub));
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Return pathconf information about a file descriptor.
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-05-24 10:09:53 +00:00
|
|
|
struct fpathconf_args {
|
|
|
|
int fd;
|
|
|
|
int name;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
fpathconf(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
register struct fpathconf_args *uap;
|
|
|
|
{
|
|
|
|
struct filedesc *fdp = p->p_fd;
|
|
|
|
struct file *fp;
|
|
|
|
struct vnode *vp;
|
|
|
|
|
|
|
|
if ((unsigned)uap->fd >= fdp->fd_nfiles ||
|
|
|
|
(fp = fdp->fd_ofiles[uap->fd]) == NULL)
|
|
|
|
return (EBADF);
|
|
|
|
switch (fp->f_type) {
|
|
|
|
|
1996-01-28 23:41:40 +00:00
|
|
|
case DTYPE_PIPE:
|
1994-05-24 10:09:53 +00:00
|
|
|
case DTYPE_SOCKET:
|
|
|
|
if (uap->name != _PC_PIPE_BUF)
|
|
|
|
return (EINVAL);
|
1997-11-06 19:29:57 +00:00
|
|
|
p->p_retval[0] = PIPE_BUF;
|
1994-05-24 10:09:53 +00:00
|
|
|
return (0);
|
|
|
|
|
1996-12-19 19:42:37 +00:00
|
|
|
case DTYPE_FIFO:
|
1994-05-24 10:09:53 +00:00
|
|
|
case DTYPE_VNODE:
|
|
|
|
vp = (struct vnode *)fp->f_data;
|
1997-11-06 19:29:57 +00:00
|
|
|
return (VOP_PATHCONF(vp, uap->name, p->p_retval));
|
1994-05-24 10:09:53 +00:00
|
|
|
|
|
|
|
default:
|
|
|
|
panic("fpathconf");
|
|
|
|
}
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a file descriptor for the process.
|
|
|
|
*/
|
1995-12-14 08:32:45 +00:00
|
|
|
static int fdexpand;
|
|
|
|
SYSCTL_INT(_debug, OID_AUTO, fdexpand, CTLFLAG_RD, &fdexpand, 0, "");
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
fdalloc(p, want, result)
|
|
|
|
struct proc *p;
|
|
|
|
int want;
|
|
|
|
int *result;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register int i;
|
|
|
|
int lim, last, nfiles;
|
|
|
|
struct file **newofile;
|
|
|
|
char *newofileflags;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search for a free descriptor starting at the higher
|
|
|
|
* of want or fd_freefile. If that fails, consider
|
|
|
|
* expanding the ofile array.
|
|
|
|
*/
|
1995-02-20 19:42:42 +00:00
|
|
|
lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
|
1994-05-24 10:09:53 +00:00
|
|
|
for (;;) {
|
|
|
|
last = min(fdp->fd_nfiles, lim);
|
|
|
|
if ((i = want) < fdp->fd_freefile)
|
|
|
|
i = fdp->fd_freefile;
|
|
|
|
for (; i < last; i++) {
|
|
|
|
if (fdp->fd_ofiles[i] == NULL) {
|
|
|
|
fdp->fd_ofileflags[i] = 0;
|
|
|
|
if (i > fdp->fd_lastfile)
|
|
|
|
fdp->fd_lastfile = i;
|
|
|
|
if (want <= fdp->fd_freefile)
|
|
|
|
fdp->fd_freefile = i;
|
|
|
|
*result = i;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No space in current array. Expand?
|
|
|
|
*/
|
|
|
|
if (fdp->fd_nfiles >= lim)
|
|
|
|
return (EMFILE);
|
|
|
|
if (fdp->fd_nfiles < NDEXTENT)
|
|
|
|
nfiles = NDEXTENT;
|
|
|
|
else
|
|
|
|
nfiles = 2 * fdp->fd_nfiles;
|
|
|
|
MALLOC(newofile, struct file **, nfiles * OFILESIZE,
|
|
|
|
M_FILEDESC, M_WAITOK);
|
|
|
|
newofileflags = (char *) &newofile[nfiles];
|
|
|
|
/*
|
|
|
|
* Copy the existing ofile and ofileflags arrays
|
|
|
|
* and zero the new portion of each array.
|
|
|
|
*/
|
|
|
|
bcopy(fdp->fd_ofiles, newofile,
|
|
|
|
(i = sizeof(struct file *) * fdp->fd_nfiles));
|
|
|
|
bzero((char *)newofile + i, nfiles * sizeof(struct file *) - i);
|
|
|
|
bcopy(fdp->fd_ofileflags, newofileflags,
|
|
|
|
(i = sizeof(char) * fdp->fd_nfiles));
|
|
|
|
bzero(newofileflags + i, nfiles * sizeof(char) - i);
|
|
|
|
if (fdp->fd_nfiles > NDFILE)
|
|
|
|
FREE(fdp->fd_ofiles, M_FILEDESC);
|
|
|
|
fdp->fd_ofiles = newofile;
|
|
|
|
fdp->fd_ofileflags = newofileflags;
|
|
|
|
fdp->fd_nfiles = nfiles;
|
|
|
|
fdexpand++;
|
|
|
|
}
|
1994-05-25 09:21:21 +00:00
|
|
|
return (0);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see whether n user file descriptors
|
|
|
|
* are available to the process p.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
fdavail(p, n)
|
|
|
|
struct proc *p;
|
|
|
|
register int n;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register struct file **fpp;
|
1996-08-15 16:33:32 +00:00
|
|
|
register int i, lim, last;
|
1994-05-24 10:09:53 +00:00
|
|
|
|
1995-02-20 19:42:42 +00:00
|
|
|
lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfilesperproc);
|
1994-05-24 10:09:53 +00:00
|
|
|
if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
|
|
|
|
return (1);
|
1996-08-15 16:33:32 +00:00
|
|
|
|
|
|
|
last = min(fdp->fd_nfiles, lim);
|
1994-05-24 10:09:53 +00:00
|
|
|
fpp = &fdp->fd_ofiles[fdp->fd_freefile];
|
1996-08-15 16:33:32 +00:00
|
|
|
for (i = last - fdp->fd_freefile; --i >= 0; fpp++)
|
1994-05-24 10:09:53 +00:00
|
|
|
if (*fpp == NULL && --n <= 0)
|
|
|
|
return (1);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create a new open file structure and allocate
|
|
|
|
* a file decriptor for the process that refers to it.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
falloc(p, resultfp, resultfd)
|
|
|
|
register struct proc *p;
|
|
|
|
struct file **resultfp;
|
|
|
|
int *resultfd;
|
|
|
|
{
|
1996-03-11 02:17:30 +00:00
|
|
|
register struct file *fp, *fq;
|
1994-05-24 10:09:53 +00:00
|
|
|
int error, i;
|
|
|
|
|
1994-09-25 19:34:02 +00:00
|
|
|
if ((error = fdalloc(p, 0, &i)))
|
1994-05-24 10:09:53 +00:00
|
|
|
return (error);
|
|
|
|
if (nfiles >= maxfiles) {
|
|
|
|
tablefull("file");
|
|
|
|
return (ENFILE);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Allocate a new file descriptor.
|
|
|
|
* If the process has file descriptor zero open, add to the list
|
|
|
|
* of open files at that point, otherwise put it at the front of
|
|
|
|
* the list of open files.
|
|
|
|
*/
|
|
|
|
nfiles++;
|
|
|
|
MALLOC(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK);
|
|
|
|
bzero(fp, sizeof(struct file));
|
1999-08-04 18:53:50 +00:00
|
|
|
fp->f_count = 1;
|
|
|
|
fp->f_cred = p->p_ucred;
|
|
|
|
fp->f_ops = &badfileops;
|
|
|
|
fp->f_seqcount = 1;
|
|
|
|
crhold(fp->f_cred);
|
1996-03-11 02:17:30 +00:00
|
|
|
if ((fq = p->p_fd->fd_ofiles[0])) {
|
|
|
|
LIST_INSERT_AFTER(fq, fp, f_list);
|
|
|
|
} else {
|
|
|
|
LIST_INSERT_HEAD(&filehead, fp, f_list);
|
|
|
|
}
|
1994-05-24 10:09:53 +00:00
|
|
|
p->p_fd->fd_ofiles[i] = fp;
|
|
|
|
if (resultfp)
|
|
|
|
*resultfp = fp;
|
|
|
|
if (resultfd)
|
|
|
|
*resultfd = i;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Free a file descriptor.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
void
|
1994-05-24 10:09:53 +00:00
|
|
|
ffree(fp)
|
|
|
|
register struct file *fp;
|
|
|
|
{
|
1996-03-11 02:17:30 +00:00
|
|
|
LIST_REMOVE(fp, f_list);
|
1994-05-24 10:09:53 +00:00
|
|
|
crfree(fp->f_cred);
|
1999-01-08 17:31:30 +00:00
|
|
|
#if defined(DIAGNOSTIC) || defined(INVARIANTS)
|
1994-05-24 10:09:53 +00:00
|
|
|
fp->f_count = 0;
|
|
|
|
#endif
|
|
|
|
nfiles--;
|
|
|
|
FREE(fp, M_FILE);
|
|
|
|
}
|
|
|
|
|
1996-02-23 18:49:25 +00:00
|
|
|
/*
|
|
|
|
* Build a new filedesc structure.
|
|
|
|
*/
|
|
|
|
struct filedesc *
|
|
|
|
fdinit(p)
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
register struct filedesc0 *newfdp;
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
|
|
|
|
MALLOC(newfdp, struct filedesc0 *, sizeof(struct filedesc0),
|
|
|
|
M_FILEDESC, M_WAITOK);
|
|
|
|
bzero(newfdp, sizeof(struct filedesc0));
|
|
|
|
newfdp->fd_fd.fd_cdir = fdp->fd_cdir;
|
|
|
|
VREF(newfdp->fd_fd.fd_cdir);
|
|
|
|
newfdp->fd_fd.fd_rdir = fdp->fd_rdir;
|
1998-02-15 04:17:09 +00:00
|
|
|
VREF(newfdp->fd_fd.fd_rdir);
|
1999-09-25 14:14:21 +00:00
|
|
|
newfdp->fd_fd.fd_jdir = fdp->fd_jdir;
|
|
|
|
if (newfdp->fd_fd.fd_jdir)
|
|
|
|
VREF(newfdp->fd_fd.fd_jdir);
|
1996-02-23 18:49:25 +00:00
|
|
|
|
|
|
|
/* Create the file descriptor table. */
|
|
|
|
newfdp->fd_fd.fd_refcnt = 1;
|
|
|
|
newfdp->fd_fd.fd_cmask = cmask;
|
|
|
|
newfdp->fd_fd.fd_ofiles = newfdp->fd_dfiles;
|
|
|
|
newfdp->fd_fd.fd_ofileflags = newfdp->fd_dfileflags;
|
|
|
|
newfdp->fd_fd.fd_nfiles = NDFILE;
|
|
|
|
|
|
|
|
newfdp->fd_fd.fd_freefile = 0;
|
|
|
|
newfdp->fd_fd.fd_lastfile = 0;
|
|
|
|
|
|
|
|
return (&newfdp->fd_fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Share a filedesc structure.
|
|
|
|
*/
|
|
|
|
struct filedesc *
|
|
|
|
fdshare(p)
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
p->p_fd->fd_refcnt++;
|
|
|
|
return (p->p_fd);
|
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Copy a filedesc structure.
|
|
|
|
*/
|
|
|
|
struct filedesc *
|
|
|
|
fdcopy(p)
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
register struct filedesc *newfdp, *fdp = p->p_fd;
|
|
|
|
register struct file **fpp;
|
|
|
|
register int i;
|
|
|
|
|
1997-11-29 01:33:10 +00:00
|
|
|
/*
|
|
|
|
* Certain daemons might not have file descriptors
|
|
|
|
*/
|
|
|
|
if (fdp == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
|
|
|
|
M_FILEDESC, M_WAITOK);
|
|
|
|
bcopy(fdp, newfdp, sizeof(struct filedesc));
|
|
|
|
VREF(newfdp->fd_cdir);
|
1998-02-15 04:17:09 +00:00
|
|
|
VREF(newfdp->fd_rdir);
|
1999-09-25 14:14:21 +00:00
|
|
|
if (newfdp->fd_jdir)
|
|
|
|
VREF(newfdp->fd_jdir);
|
1994-05-24 10:09:53 +00:00
|
|
|
newfdp->fd_refcnt = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the number of open files fits in the internal arrays
|
|
|
|
* of the open file structure, use them, otherwise allocate
|
|
|
|
* additional memory for the number of descriptors currently
|
|
|
|
* in use.
|
|
|
|
*/
|
|
|
|
if (newfdp->fd_lastfile < NDFILE) {
|
|
|
|
newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
|
|
|
|
newfdp->fd_ofileflags =
|
|
|
|
((struct filedesc0 *) newfdp)->fd_dfileflags;
|
|
|
|
i = NDFILE;
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Compute the smallest multiple of NDEXTENT needed
|
|
|
|
* for the file descriptors currently in use,
|
|
|
|
* allowing the table to shrink.
|
|
|
|
*/
|
|
|
|
i = newfdp->fd_nfiles;
|
|
|
|
while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2)
|
|
|
|
i /= 2;
|
|
|
|
MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
|
|
|
|
M_FILEDESC, M_WAITOK);
|
|
|
|
newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
|
|
|
|
}
|
|
|
|
newfdp->fd_nfiles = i;
|
|
|
|
bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
|
|
|
|
bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
|
|
|
|
fpp = newfdp->fd_ofiles;
|
|
|
|
for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
|
|
|
|
if (*fpp != NULL)
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
fhold(*fpp);
|
1994-05-24 10:09:53 +00:00
|
|
|
return (newfdp);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release a filedesc structure.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fdfree(p)
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
struct file **fpp;
|
|
|
|
register int i;
|
|
|
|
|
1997-11-29 01:33:10 +00:00
|
|
|
/*
|
|
|
|
* Certain daemons might not have file descriptors
|
|
|
|
*/
|
|
|
|
if (fdp == NULL)
|
|
|
|
return;
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
if (--fdp->fd_refcnt > 0)
|
|
|
|
return;
|
|
|
|
fpp = fdp->fd_ofiles;
|
|
|
|
for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
|
|
|
|
if (*fpp)
|
|
|
|
(void) closef(*fpp, p);
|
|
|
|
if (fdp->fd_nfiles > NDFILE)
|
|
|
|
FREE(fdp->fd_ofiles, M_FILEDESC);
|
|
|
|
vrele(fdp->fd_cdir);
|
1998-02-15 04:17:09 +00:00
|
|
|
vrele(fdp->fd_rdir);
|
1999-09-25 14:14:21 +00:00
|
|
|
if(fdp->fd_jdir)
|
|
|
|
vrele(fdp->fd_jdir);
|
1994-05-24 10:09:53 +00:00
|
|
|
FREE(fdp, M_FILEDESC);
|
|
|
|
}
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
/*
|
|
|
|
* Close any files on exec?
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
fdcloseexec(p)
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
struct filedesc *fdp = p->p_fd;
|
|
|
|
struct file **fpp;
|
|
|
|
char *fdfp;
|
|
|
|
register int i;
|
|
|
|
|
1997-11-29 01:33:10 +00:00
|
|
|
/*
|
|
|
|
* Certain daemons might not have file descriptors
|
|
|
|
*/
|
|
|
|
if (fdp == NULL)
|
|
|
|
return;
|
|
|
|
|
1994-05-25 09:21:21 +00:00
|
|
|
fpp = fdp->fd_ofiles;
|
|
|
|
fdfp = fdp->fd_ofileflags;
|
|
|
|
for (i = 0; i <= fdp->fd_lastfile; i++, fpp++, fdfp++)
|
|
|
|
if (*fpp != NULL && (*fdfp & UF_EXCLOSE)) {
|
|
|
|
if (*fdfp & UF_MAPPED)
|
1994-09-02 10:17:30 +00:00
|
|
|
(void) munmapfd(p, i);
|
1994-05-25 09:21:21 +00:00
|
|
|
(void) closef(*fpp, p);
|
|
|
|
*fpp = NULL;
|
|
|
|
*fdfp = 0;
|
|
|
|
if (i < fdp->fd_freefile)
|
|
|
|
fdp->fd_freefile = i;
|
|
|
|
}
|
|
|
|
while (fdp->fd_lastfile > 0 && fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
|
|
|
|
fdp->fd_lastfile--;
|
|
|
|
}
|
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* Internal form of close.
|
|
|
|
* Decrement reference count on file structure.
|
|
|
|
* Note: p may be NULL when closing a file
|
|
|
|
* that was being passed in a message.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
closef(fp, p)
|
|
|
|
register struct file *fp;
|
|
|
|
register struct proc *p;
|
|
|
|
{
|
|
|
|
struct vnode *vp;
|
|
|
|
struct flock lf;
|
|
|
|
|
|
|
|
if (fp == NULL)
|
|
|
|
return (0);
|
|
|
|
/*
|
|
|
|
* POSIX record locking dictates that any close releases ALL
|
|
|
|
* locks owned by this process. This is handled by setting
|
|
|
|
* a flag in the unlock to free ONLY locks obeying POSIX
|
|
|
|
* semantics, and not to free BSD-style file locks.
|
|
|
|
* If the descriptor was in a message, POSIX-style locks
|
|
|
|
* aren't passed with the descriptor.
|
|
|
|
*/
|
|
|
|
if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) {
|
|
|
|
lf.l_whence = SEEK_SET;
|
|
|
|
lf.l_start = 0;
|
|
|
|
lf.l_len = 0;
|
|
|
|
lf.l_type = F_UNLCK;
|
|
|
|
vp = (struct vnode *)fp->f_data;
|
1999-06-07 20:37:29 +00:00
|
|
|
(void) VOP_ADVLOCK(vp, (caddr_t)p->p_leader, F_UNLCK, &lf, F_POSIX);
|
1994-05-24 10:09:53 +00:00
|
|
|
}
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
return (fdrop(fp, p));
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
fdrop(fp, p)
|
|
|
|
struct file *fp;
|
|
|
|
struct proc *p;
|
|
|
|
{
|
1999-11-07 05:58:38 +00:00
|
|
|
struct flock lf;
|
|
|
|
struct vnode *vp;
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
int error;
|
|
|
|
|
|
|
|
if (--fp->f_count > 0)
|
|
|
|
return (0);
|
|
|
|
if (fp->f_count < 0)
|
|
|
|
panic("fdrop: count < 0");
|
1999-11-07 05:58:38 +00:00
|
|
|
if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) {
|
|
|
|
lf.l_whence = SEEK_SET;
|
|
|
|
lf.l_start = 0;
|
|
|
|
lf.l_len = 0;
|
|
|
|
lf.l_type = F_UNLCK;
|
|
|
|
vp = (struct vnode *)fp->f_data;
|
|
|
|
(void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK);
|
|
|
|
}
|
1999-08-04 18:53:50 +00:00
|
|
|
if (fp->f_ops != &badfileops)
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
error = fo_close(fp, p);
|
1994-05-24 10:09:53 +00:00
|
|
|
else
|
|
|
|
error = 0;
|
|
|
|
ffree(fp);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Apply an advisory lock on a file descriptor.
|
|
|
|
*
|
|
|
|
* Just attempt to get a record lock of the requested type on
|
|
|
|
* the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0).
|
|
|
|
*/
|
1995-11-12 06:43:28 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-05-24 10:09:53 +00:00
|
|
|
struct flock_args {
|
|
|
|
int fd;
|
|
|
|
int how;
|
|
|
|
};
|
1995-11-12 06:43:28 +00:00
|
|
|
#endif
|
1994-05-24 10:09:53 +00:00
|
|
|
/* ARGSUSED */
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1997-11-06 19:29:57 +00:00
|
|
|
flock(p, uap)
|
1994-05-24 10:09:53 +00:00
|
|
|
struct proc *p;
|
|
|
|
register struct flock_args *uap;
|
|
|
|
{
|
|
|
|
register struct filedesc *fdp = p->p_fd;
|
|
|
|
register struct file *fp;
|
|
|
|
struct vnode *vp;
|
|
|
|
struct flock lf;
|
|
|
|
|
|
|
|
if ((unsigned)uap->fd >= fdp->fd_nfiles ||
|
|
|
|
(fp = fdp->fd_ofiles[uap->fd]) == NULL)
|
|
|
|
return (EBADF);
|
|
|
|
if (fp->f_type != DTYPE_VNODE)
|
|
|
|
return (EOPNOTSUPP);
|
|
|
|
vp = (struct vnode *)fp->f_data;
|
|
|
|
lf.l_whence = SEEK_SET;
|
|
|
|
lf.l_start = 0;
|
|
|
|
lf.l_len = 0;
|
|
|
|
if (uap->how & LOCK_UN) {
|
|
|
|
lf.l_type = F_UNLCK;
|
|
|
|
fp->f_flag &= ~FHASLOCK;
|
|
|
|
return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK));
|
|
|
|
}
|
|
|
|
if (uap->how & LOCK_EX)
|
|
|
|
lf.l_type = F_WRLCK;
|
|
|
|
else if (uap->how & LOCK_SH)
|
|
|
|
lf.l_type = F_RDLCK;
|
|
|
|
else
|
|
|
|
return (EBADF);
|
|
|
|
fp->f_flag |= FHASLOCK;
|
|
|
|
if (uap->how & LOCK_NB)
|
|
|
|
return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK));
|
|
|
|
return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* File Descriptor pseudo-device driver (/dev/fd/).
|
|
|
|
*
|
|
|
|
* Opening minor device N dup()s the file (if any) connected to file
|
|
|
|
* descriptor N belonging to the calling process. Note that this driver
|
|
|
|
* consists of only the ``open()'' routine, because all subsequent
|
|
|
|
* references to this file will be direct to the other driver.
|
|
|
|
*/
|
|
|
|
/* ARGSUSED */
|
1995-12-08 11:19:42 +00:00
|
|
|
static int
|
1994-05-24 10:09:53 +00:00
|
|
|
fdopen(dev, mode, type, p)
|
|
|
|
dev_t dev;
|
|
|
|
int mode, type;
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* XXX Kludge: set curproc->p_dupfd to contain the value of the
|
1995-05-30 08:16:23 +00:00
|
|
|
* the file descriptor being sought for duplication. The error
|
1994-05-24 10:09:53 +00:00
|
|
|
* return ensures that the vnode for this device will be released
|
|
|
|
* by vn_open. Open will detect this special error and take the
|
|
|
|
* actions in dupfdopen below. Other callers of vn_open or VOP_OPEN
|
|
|
|
* will simply report the error.
|
|
|
|
*/
|
|
|
|
p->p_dupfd = minor(dev);
|
|
|
|
return (ENODEV);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Duplicate the specified descriptor to a free descriptor.
|
|
|
|
*/
|
1994-05-25 09:21:21 +00:00
|
|
|
int
|
1994-05-24 10:09:53 +00:00
|
|
|
dupfdopen(fdp, indx, dfd, mode, error)
|
|
|
|
register struct filedesc *fdp;
|
|
|
|
register int indx, dfd;
|
|
|
|
int mode;
|
|
|
|
int error;
|
|
|
|
{
|
|
|
|
register struct file *wfp;
|
|
|
|
struct file *fp;
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1994-05-24 10:09:53 +00:00
|
|
|
/*
|
|
|
|
* If the to-be-dup'd fd number is greater than the allowed number
|
|
|
|
* of file descriptors, or the fd to be dup'd has already been
|
|
|
|
* closed, reject. Note, check for new == old is necessary as
|
|
|
|
* falloc could allocate an already closed to-be-dup'd descriptor
|
|
|
|
* as the new descriptor.
|
|
|
|
*/
|
|
|
|
fp = fdp->fd_ofiles[indx];
|
|
|
|
if ((u_int)dfd >= fdp->fd_nfiles ||
|
|
|
|
(wfp = fdp->fd_ofiles[dfd]) == NULL || fp == wfp)
|
|
|
|
return (EBADF);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* There are two cases of interest here.
|
|
|
|
*
|
|
|
|
* For ENODEV simply dup (dfd) to file descriptor
|
|
|
|
* (indx) and return.
|
|
|
|
*
|
|
|
|
* For ENXIO steal away the file structure from (dfd) and
|
|
|
|
* store it in (indx). (dfd) is effectively closed by
|
|
|
|
* this operation.
|
|
|
|
*
|
|
|
|
* Any other error code is just returned.
|
|
|
|
*/
|
|
|
|
switch (error) {
|
|
|
|
case ENODEV:
|
|
|
|
/*
|
|
|
|
* Check that the mode the file is being opened for is a
|
|
|
|
* subset of the mode of the existing descriptor.
|
|
|
|
*/
|
|
|
|
if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag)
|
|
|
|
return (EACCES);
|
|
|
|
fdp->fd_ofiles[indx] = wfp;
|
|
|
|
fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
fhold(wfp);
|
1994-05-24 10:09:53 +00:00
|
|
|
if (indx > fdp->fd_lastfile)
|
|
|
|
fdp->fd_lastfile = indx;
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
case ENXIO:
|
|
|
|
/*
|
|
|
|
* Steal away the file pointer from dfd, and stuff it into indx.
|
|
|
|
*/
|
|
|
|
fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd];
|
|
|
|
fdp->fd_ofiles[dfd] = NULL;
|
|
|
|
fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd];
|
|
|
|
fdp->fd_ofileflags[dfd] = 0;
|
|
|
|
/*
|
|
|
|
* Complete the clean up of the filedesc structure by
|
|
|
|
* recomputing the various hints.
|
|
|
|
*/
|
|
|
|
if (indx > fdp->fd_lastfile)
|
|
|
|
fdp->fd_lastfile = indx;
|
|
|
|
else
|
|
|
|
while (fdp->fd_lastfile > 0 &&
|
|
|
|
fdp->fd_ofiles[fdp->fd_lastfile] == NULL)
|
|
|
|
fdp->fd_lastfile--;
|
|
|
|
if (dfd < fdp->fd_freefile)
|
|
|
|
fdp->fd_freefile = dfd;
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
default:
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
/* NOTREACHED */
|
|
|
|
}
|
1995-11-14 08:58:35 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Get file structures.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
sysctl_kern_file SYSCTL_HANDLER_ARGS
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
struct file *fp;
|
|
|
|
|
|
|
|
if (!req->oldptr) {
|
|
|
|
/*
|
|
|
|
* overestimate by 10 files
|
|
|
|
*/
|
|
|
|
return (SYSCTL_OUT(req, 0, sizeof(filehead) +
|
|
|
|
(nfiles + 10) * sizeof(struct file)));
|
|
|
|
}
|
|
|
|
|
|
|
|
error = SYSCTL_OUT(req, (caddr_t)&filehead, sizeof(filehead));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* followed by an array of file structures
|
|
|
|
*/
|
1999-11-16 10:56:05 +00:00
|
|
|
LIST_FOREACH(fp, &filehead, f_list) {
|
1995-11-14 08:58:35 +00:00
|
|
|
error = SYSCTL_OUT(req, (caddr_t)fp, sizeof (struct file));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
return (0);
|
|
|
|
}
|
1995-12-04 16:48:58 +00:00
|
|
|
|
|
|
|
SYSCTL_PROC(_kern, KERN_FILE, file, CTLTYPE_OPAQUE|CTLFLAG_RD,
|
1999-05-03 23:57:32 +00:00
|
|
|
0, 0, sysctl_kern_file, "S,file", "Entire file table");
|
1995-12-04 16:48:58 +00:00
|
|
|
|
1999-05-03 23:57:32 +00:00
|
|
|
SYSCTL_INT(_kern, KERN_MAXFILESPERPROC, maxfilesperproc, CTLFLAG_RW,
|
|
|
|
&maxfilesperproc, 0, "Maximum files allowed open per process");
|
1995-12-04 16:48:58 +00:00
|
|
|
|
1999-05-03 23:57:32 +00:00
|
|
|
SYSCTL_INT(_kern, KERN_MAXFILES, maxfiles, CTLFLAG_RW,
|
|
|
|
&maxfiles, 0, "Maximum number of files");
|
1995-12-04 16:48:58 +00:00
|
|
|
|
1999-08-23 20:59:21 +00:00
|
|
|
static void
|
|
|
|
fildesc_drvinit(void *unused)
|
1995-11-29 10:49:16 +00:00
|
|
|
{
|
1996-03-27 19:19:58 +00:00
|
|
|
int fd;
|
1995-11-29 10:49:16 +00:00
|
|
|
|
1999-08-23 20:59:21 +00:00
|
|
|
for (fd = 0; fd < NUMFDESC; fd++)
|
|
|
|
make_dev(&fildesc_cdevsw, fd,
|
|
|
|
UID_BIN, GID_BIN, 0666, "fd/%d", fd);
|
|
|
|
make_dev(&fildesc_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, "stdin");
|
|
|
|
make_dev(&fildesc_cdevsw, 1, UID_ROOT, GID_WHEEL, 0666, "stdout");
|
|
|
|
make_dev(&fildesc_cdevsw, 2, UID_ROOT, GID_WHEEL, 0666, "stderr");
|
1995-11-29 10:49:16 +00:00
|
|
|
}
|
|
|
|
|
1999-08-04 18:53:50 +00:00
|
|
|
struct fileops badfileops = {
|
|
|
|
badfo_readwrite,
|
|
|
|
badfo_readwrite,
|
|
|
|
badfo_ioctl,
|
|
|
|
badfo_poll,
|
1999-11-08 03:27:14 +00:00
|
|
|
badfo_stat,
|
1999-08-04 18:53:50 +00:00
|
|
|
badfo_close
|
|
|
|
};
|
|
|
|
|
|
|
|
static int
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
badfo_readwrite(fp, uio, cred, flags, p)
|
1999-08-04 18:53:50 +00:00
|
|
|
struct file *fp;
|
|
|
|
struct uio *uio;
|
|
|
|
struct ucred *cred;
|
This is what was "fdfix2.patch," a fix for fd sharing. It's pretty
far-reaching in fd-land, so you'll want to consult the code for
changes. The biggest change is that now, you don't use
fp->f_ops->fo_foo(fp, bar)
but instead
fo_foo(fp, bar),
which increments and decrements the fp refcount upon entry and exit.
Two new calls, fhold() and fdrop(), are provided. Each does what it
seems like it should, and if fdrop() brings the refcount to zero, the
fd is freed as well.
Thanks to peter ("to hell with it, it looks ok to me.") for his review.
Thanks to msmith for keeping me from putting locks everywhere :)
Reviewed by: peter
1999-09-19 17:00:25 +00:00
|
|
|
struct proc *p;
|
1999-08-04 18:53:50 +00:00
|
|
|
int flags;
|
|
|
|
{
|
|
|
|
|
|
|
|
return (EBADF);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
badfo_ioctl(fp, com, data, p)
|
|
|
|
struct file *fp;
|
|
|
|
u_long com;
|
|
|
|
caddr_t data;
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
|
|
|
|
return (EBADF);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
badfo_poll(fp, events, cred, p)
|
|
|
|
struct file *fp;
|
|
|
|
int events;
|
|
|
|
struct ucred *cred;
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1999-11-08 03:27:14 +00:00
|
|
|
static int
|
|
|
|
badfo_stat(fp, sb, p)
|
|
|
|
struct file *fp;
|
|
|
|
struct stat *sb;
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
|
|
|
|
return (EBADF);
|
|
|
|
}
|
|
|
|
|
1999-08-04 18:53:50 +00:00
|
|
|
static int
|
|
|
|
badfo_close(fp, p)
|
|
|
|
struct file *fp;
|
|
|
|
struct proc *p;
|
|
|
|
{
|
|
|
|
|
|
|
|
return (EBADF);
|
|
|
|
}
|
|
|
|
|
1995-11-29 10:49:16 +00:00
|
|
|
SYSINIT(fildescdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,
|
|
|
|
fildesc_drvinit,NULL)
|