+/*
+ * Check to see whether n user file descriptors
+ * are available to the process p.
+ */
+int
+fdavail(p, n)
+ struct proc *p;
+ int n;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc **fpp;
+ char *flags;
+ int i, lim;
+
+ lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
+ if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0)
+ return (1);
+ fpp = &fdp->fd_ofiles[fdp->fd_freefile];
+ flags = &fdp->fd_ofileflags[fdp->fd_freefile];
+ for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++)
+ if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0)
+ return (1);
+ return (0);
+}
+
+void
+fdrelse(p, fd)
+ struct proc *p;
+ int fd;
+{
+ _fdrelse(p->p_fd, fd);
+}
+
+void
+fddrop(p, fd)
+ struct proc *p;
+ int fd;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ if (fd < fdp->fd_freefile)
+ fdp->fd_freefile = fd;
+#if DIAGNOSTIC
+ if (fd > fdp->fd_lastfile)
+ panic("fdrelse: fd_lastfile inconsistent");
+#endif
+ fp = fdp->fd_ofiles[fd];
+ fdp->fd_ofiles[fd] = NULL;
+ fdp->fd_ofileflags[fd] = 0;
+
+ while ((fd = fdp->fd_lastfile) > 0 &&
+ fdp->fd_ofiles[fd] == NULL &&
+ !(fdp->fd_ofileflags[fd] & UF_RESERVED))
+ fdp->fd_lastfile--;
+ FREE_ZONE(fp, sizeof *fp, M_FILEPROC);
+}
+
+
+int
+fdgetf_noref(p, fd, resultfp)
+ struct proc *p;
+ int fd;
+ struct fileproc **resultfp;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ if (fd < 0 || fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ return (EBADF);
+ }
+ if (resultfp)
+ *resultfp = fp;
+ return (0);
+}
+
+
+/* should be called only when proc_fdlock is held */
+void
+fp_setflags(proc_t p, struct fileproc * fp, int flags)
+{
+ proc_fdlock(p);
+ fp->f_flags |= flags;
+ proc_fdunlock(p);
+}
+
+void
+fp_clearflags(proc_t p, struct fileproc * fp, int flags)
+{
+
+ proc_fdlock(p);
+ if (fp)
+ fp->f_flags &= ~flags;
+ proc_fdunlock(p);
+}
+
+int
+fp_getfvp(p, fd, resultfp, resultvp)
+ struct proc *p;
+ int fd;
+ struct fileproc **resultfp;
+ struct vnode **resultvp;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock(p);
+ if (fd < 0 || fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ proc_fdunlock(p);
+ return (EBADF);
+ }
+ if (fp->f_type != DTYPE_VNODE) {
+ proc_fdunlock(p);
+ return(ENOTSUP);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (resultvp)
+ *resultvp = (struct vnode *)fp->f_data;
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+
+/*
+ * Returns: EBADF The file descriptor is invalid
+ * EOPNOTSUPP The file descriptor is not a socket
+ * 0 Success
+ *
+ * Notes: EOPNOTSUPP should probably be ENOTSOCK; this function is only
+ * ever called from accept1().
+ */
+int
+fp_getfsock(p, fd, resultfp, results)
+ struct proc *p;
+ int fd;
+ struct fileproc **resultfp;
+ struct socket **results;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock(p);
+ if (fd < 0 || fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ proc_fdunlock(p);
+ return (EBADF);
+ }
+ if (fp->f_type != DTYPE_SOCKET) {
+ proc_fdunlock(p);
+ return(EOPNOTSUPP);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (results)
+ *results = (struct socket *)fp->f_data;
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+
+int
+fp_getfkq(p, fd, resultfp, resultkq)
+ struct proc *p;
+ int fd;
+ struct fileproc **resultfp;
+ struct kqueue **resultkq;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock(p);
+ if ( fd < 0 || fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ proc_fdunlock(p);
+ return (EBADF);
+ }
+ if (fp->f_type != DTYPE_KQUEUE) {
+ proc_fdunlock(p);
+ return(EBADF);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (resultkq)
+ *resultkq = (struct kqueue *)fp->f_data;
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+int
+fp_getfpshm(p, fd, resultfp, resultpshm)
+ struct proc *p;
+ int fd;
+ struct fileproc **resultfp;
+ struct pshmnode **resultpshm;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock(p);
+ if (fd < 0 || fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ proc_fdunlock(p);
+ return (EBADF);
+ }
+ if (fp->f_type != DTYPE_PSXSHM) {
+
+ proc_fdunlock(p);
+ return(EBADF);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (resultpshm)
+ *resultpshm = (struct pshmnode *)fp->f_data;
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+
+int
+fp_getfpsem(p, fd, resultfp, resultpsem)
+ struct proc *p;
+ int fd;
+ struct fileproc **resultfp;
+ struct psemnode **resultpsem;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock(p);
+ if (fd < 0 || fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ proc_fdunlock(p);
+ return (EBADF);
+ }
+ if (fp->f_type != DTYPE_PSXSEM) {
+ proc_fdunlock(p);
+ return(EBADF);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (resultpsem)
+ *resultpsem = (struct psemnode *)fp->f_data;
+ proc_fdunlock(p);
+
+ return (0);
+}
+int
+fp_lookup(p, fd, resultfp, locked)
+ struct proc *p;
+ int fd;
+ struct fileproc **resultfp;
+ int locked;
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ if (!locked)
+ proc_fdlock(p);
+ if (fd < 0 || fd >= fdp->fd_nfiles ||
+ (fp = fdp->fd_ofiles[fd]) == NULL ||
+ (fdp->fd_ofileflags[fd] & UF_RESERVED)) {
+ if (!locked)
+ proc_fdunlock(p);
+ return (EBADF);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (!locked)
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+int
+fp_drop_written(proc_t p, int fd, struct fileproc *fp)
+{
+ int error;
+
+ proc_fdlock(p);
+
+ fp->f_flags |= FP_WRITTEN;
+
+ error = fp_drop(p, fd, fp, 1);
+
+ proc_fdunlock(p);
+
+ return (error);
+}
+
+
+int
+fp_drop_event(proc_t p, int fd, struct fileproc *fp)
+{
+ int error;
+
+ proc_fdlock(p);
+
+ fp->f_flags |= FP_WAITEVENT;
+
+ error = fp_drop(p, fd, fp, 1);
+
+ proc_fdunlock(p);
+
+ return (error);
+}
+