+ * close_internal_locked
+ *
+ * Close a file descriptor.
+ *
+ * Parameters: p Process in whose per process file table
+ * the close is to occur
+ * fd fd to be closed
+ * fp fileproc associated with the fd
+ *
+ * Returns: 0 Success
+ * EBADF fd already in close wait state
+ * closef_locked:??? Anything returnable by a per-fileops
+ * close function
+ *
+ * Locks: Assumes proc_fdlock for process is held by the caller and returns
+ * with lock held
+ *
+ * Notes: This function may drop and reacquire this lock; it is unsafe
+ * for a caller to assume that other state protected by the lock
+ * has not been subsequently changes out from under it, if the
+ * caller made the call with the lock held.
+ */
+static int
+close_internal_locked(proc_t p, int fd, struct fileproc *fp, int flags)
+{
+ struct filedesc *fdp = p->p_fd;
+ int error =0;
+ int resvfd = flags & FD_DUP2RESV;
+
+
+#if DIAGNOSTIC
+ proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
+#endif
+
+ /* Keep people from using the filedesc while we are closing it */
+ procfdtbl_markclosefd(p, fd);
+
+
+ if ((fp->f_flags & FP_CLOSING) == FP_CLOSING) {
+ panic("close_internal_locked: being called on already closing fd\n");
+ }
+
+
+#if DIAGNOSTIC
+ if ((fdp->fd_ofileflags[fd] & UF_RESERVED) == 0)
+ panic("close_internal: unreserved fileflags with fd %d\n", fd);
+#endif
+
+ fp->f_flags |= FP_CLOSING;
+
+ if ( (fp->f_flags & FP_AIOISSUED) || kauth_authorize_fileop_has_listeners() ) {
+
+ proc_fdunlock(p);
+
+ if ( (fp->f_type == DTYPE_VNODE) && kauth_authorize_fileop_has_listeners() ) {
+ /*
+ * call out to allow 3rd party notification of close.
+ * Ignore result of kauth_authorize_fileop call.
+ */
+ if (vnode_getwithref((vnode_t)fp->f_data) == 0) {
+ u_int fileop_flags = 0;
+ if ((fp->f_flags & FP_WRITTEN) != 0)
+ fileop_flags |= KAUTH_FILEOP_CLOSE_MODIFIED;
+ kauth_authorize_fileop(fp->f_fglob->fg_cred, KAUTH_FILEOP_CLOSE,
+ (uintptr_t)fp->f_data, (uintptr_t)fileop_flags);
+ vnode_put((vnode_t)fp->f_data);
+ }
+ }
+ if (fp->f_flags & FP_AIOISSUED)
+ /*
+ * cancel all async IO requests that can be cancelled.
+ */
+ _aio_close( p, fd );
+
+ proc_fdlock(p);
+ }
+
+ if (fd < fdp->fd_knlistsize)
+ knote_fdclose(p, fd);
+
+ if (fp->f_flags & FP_WAITEVENT)
+ (void)waitevent_close(p, fp);
+
+ if ((fp->f_flags & FP_INCHRREAD) == 0)
+ fileproc_drain(p, fp);
+
+ if (resvfd == 0)
+ _fdrelse(p, fd);
+
+ error = closef_locked(fp, fp->f_fglob, p);
+ if ((fp->f_flags & FP_WAITCLOSE) == FP_WAITCLOSE)
+ wakeup(&fp->f_flags);
+ fp->f_flags &= ~(FP_WAITCLOSE | FP_CLOSING);
+
+ proc_fdunlock(p);
+
+ FREE_ZONE(fp, sizeof(*fp), M_FILEPROC);
+
+ proc_fdlock(p);
+
+#if DIAGNOSTIC
+ if (resvfd != 0) {
+ if ((fdp->fd_ofileflags[fd] & UF_RESERVED) == 0)
+ panic("close with reserved fd returns with freed fd:%d: proc: %x\n", fd, (unsigned int)p);
+ }
+#endif
+
+ return(error);
+}
+
+
+/*
+ * fstat1
+ *
+ * Description: Return status information about a file descriptor.
+ *
+ * Parameters: p The process doing the fstat
+ * fd The fd to stat
+ * ub The user stat buffer
+ * xsecurity The user extended security
+ * buffer, or 0 if none
+ * xsecurity_size The size of xsecurity, or 0
+ * if no xsecurity
+ * isstat64 Flag to indicate 64 bit version
+ * for inode size, etc.
+ *
+ * Returns: 0 Success
+ * EBADF
+ * EFAULT
+ * fp_lookup:EBADF Bad file descriptor
+ * vnode_getwithref:???
+ * copyout:EFAULT
+ * vnode_getwithref:???
+ * vn_stat:???
+ * soo_stat:???
+ * pipe_stat:???
+ * pshm_stat:???
+ * kqueue_stat:???
+ *
+ * Notes: Internal implementation for all other fstat() related
+ * functions
+ *
+ * XXX switch on node type is bogus; need a stat in struct
+ * XXX fileops instead.
+ */
+static int
+fstat1(proc_t p, int fd, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size, int isstat64)
+{
+ struct fileproc *fp;
+ struct stat sb;
+ struct stat64 sb64;
+ struct user_stat user_sb;
+ struct user_stat64 user_sb64;
+ int error, my_size;
+ int funnel_state;
+ file_type_t type;
+ caddr_t data;
+ kauth_filesec_t fsec;
+ user_size_t xsecurity_bufsize;
+ vfs_context_t ctx = vfs_context_current();
+ void * sbptr;
+
+
+ AUDIT_ARG(fd, fd);
+
+ if ((error = fp_lookup(p, fd, &fp, 0)) != 0) {
+ return(error);
+ }
+ type = fp->f_type;
+ data = fp->f_data;
+ fsec = KAUTH_FILESEC_NONE;
+
+ sbptr = (isstat64 != 0) ? (void *)&sb64: (void *)&sb;
+
+ switch (type) {
+
+ case DTYPE_VNODE:
+ if ((error = vnode_getwithref((vnode_t)data)) == 0) {
+ /*
+ * If the caller has the file open, and is not
+ * requesting extended security information, we are
+ * going to let them get the basic stat information.
+ */
+ if (xsecurity == USER_ADDR_NULL) {
+ error = vn_stat_noauth((vnode_t)data, sbptr, NULL, isstat64, ctx);
+ } else {
+ error = vn_stat((vnode_t)data, sbptr, &fsec, isstat64, ctx);
+ }
+
+ AUDIT_ARG(vnpath, (struct vnode *)data, ARG_VNODE1);
+ (void)vnode_put((vnode_t)data);
+ }
+ break;
+
+#if SOCKETS
+ case DTYPE_SOCKET:
+ error = soo_stat((struct socket *)data, sbptr, isstat64);
+ break;
+#endif /* SOCKETS */
+
+ case DTYPE_PIPE:
+ error = pipe_stat((void *)data, sbptr, isstat64);
+ break;
+
+ case DTYPE_PSXSHM:
+ error = pshm_stat((void *)data, sbptr, isstat64);
+ break;
+
+ case DTYPE_KQUEUE:
+ funnel_state = thread_funnel_set(kernel_flock, TRUE);
+ error = kqueue_stat(fp, sbptr, isstat64, p);
+ thread_funnel_set(kernel_flock, funnel_state);
+ break;
+
+ default:
+ error = EBADF;
+ goto out;
+ }
+ if (error == 0) {
+ caddr_t sbp;
+
+ if (isstat64 != 0) {
+ sb64.st_lspare = 0;
+ sb64.st_qspare[0] = 0LL;
+ sb64.st_qspare[1] = 0LL;
+ if (IS_64BIT_PROCESS(current_proc())) {
+ munge_stat64(&sb64, &user_sb64);
+ my_size = sizeof(user_sb64);
+ sbp = (caddr_t)&user_sb64;
+ } else {
+ my_size = sizeof(sb64);
+ sbp = (caddr_t)&sb64;
+ }
+ } else {
+ sb.st_lspare = 0;
+ sb.st_qspare[0] = 0LL;
+ sb.st_qspare[1] = 0LL;
+ if (IS_64BIT_PROCESS(current_proc())) {
+ munge_stat(&sb, &user_sb);
+ my_size = sizeof(user_sb);
+ sbp = (caddr_t)&user_sb;
+ } else {
+ my_size = sizeof(sb);
+ sbp = (caddr_t)&sb;
+ }
+ }
+
+ error = copyout(sbp, ub, my_size);
+ }
+
+ /* caller wants extended security information? */
+ if (xsecurity != USER_ADDR_NULL) {
+
+ /* did we get any? */
+ if (fsec == KAUTH_FILESEC_NONE) {
+ if (susize(xsecurity_size, 0) != 0) {
+ error = EFAULT;
+ goto out;
+ }
+ } else {
+ /* find the user buffer size */
+ xsecurity_bufsize = fusize(xsecurity_size);
+
+ /* copy out the actual data size */
+ if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) {
+ error = EFAULT;
+ goto out;
+ }
+
+ /* if the caller supplied enough room, copy out to it */
+ if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec))
+ error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec));
+ }
+ }
+out:
+ fp_drop(p, fd, fp, 0);
+ if (fsec != NULL)
+ kauth_filesec_free(fsec);
+ return (error);
+}
+
+
+/*
+ * fstat_extended
+ *
+ * Description: Extended version of fstat supporting returning extended
+ * security information
+ *
+ * Parameters: p The process doing the fstat
+ * uap->fd The fd to stat
+ * uap->ub The user stat buffer
+ * uap->xsecurity The user extended security
+ * buffer, or 0 if none
+ * uap->xsecurity_size The size of xsecurity, or 0
+ *
+ * Returns: 0 Success
+ * !0 Errno (see fstat1)
+ */
+int
+fstat_extended(proc_t p, struct fstat_extended_args *uap, __unused register_t *retval)
+{
+ return(fstat1(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 0));
+}
+
+
+/*
+ * fstat
+ *
+ * Description: Get file status for the file associated with fd
+ *
+ * Parameters: p The process doing the fstat
+ * uap->fd The fd to stat
+ * uap->ub The user stat buffer
+ *
+ * Returns: 0 Success
+ * !0 Errno (see fstat1)
+ */
+int
+fstat(proc_t p, register struct fstat_args *uap, __unused register_t *retval)
+{
+ return(fstat1(p, uap->fd, uap->ub, 0, 0, 0));
+}
+
+
+/*
+ * fstat64_extended
+ *
+ * Description: Extended version of fstat64 supporting returning extended
+ * security information
+ *
+ * Parameters: p The process doing the fstat
+ * uap->fd The fd to stat
+ * uap->ub The user stat buffer
+ * uap->xsecurity The user extended security
+ * buffer, or 0 if none
+ * uap->xsecurity_size The size of xsecurity, or 0
+ *
+ * Returns: 0 Success
+ * !0 Errno (see fstat1)
+ */
+int
+fstat64_extended(proc_t p, struct fstat64_extended_args *uap, __unused register_t *retval)
+{
+ return(fstat1(p, uap->fd, uap->ub, uap->xsecurity, uap->xsecurity_size, 1));
+}
+
+
+/*
+ * fstat64
+ *
+ * Description: Get 64 bit version of the file status for the file associated
+ * with fd
+ *
+ * Parameters: p The process doing the fstat
+ * uap->fd The fd to stat
+ * uap->ub The user stat buffer
+ *
+ * Returns: 0 Success
+ * !0 Errno (see fstat1)
+ */
+int
+fstat64(proc_t p, register struct fstat64_args *uap, __unused register_t *retval)
+{
+ return(fstat1(p, uap->fd, uap->ub, 0, 0, 1));
+}
+
+
+/*
+ * fpathconf
+ *
+ * Description: Return pathconf information about a file descriptor.
+ *
+ * Parameters: p Process making the request
+ * uap->fd fd to get information about
+ * uap->name Name of information desired
+ * retval Pointer to the call return area
+ *
+ * Returns: 0 Success
+ * EINVAL
+ * fp_lookup:EBADF Bad file descriptor
+ * vnode_getwithref:???
+ * vn_pathconf:???
+ *
+ * Implicit returns:
+ * *retval (modified) Returned information (numeric)
+ */
+int
+fpathconf(proc_t p, struct fpathconf_args *uap, register_t *retval)
+{
+ int fd = uap->fd;
+ struct fileproc *fp;
+ struct vnode *vp;
+ int error = 0;
+ file_type_t type;
+ caddr_t data;
+
+
+ AUDIT_ARG(fd, uap->fd);
+ if ( (error = fp_lookup(p, fd, &fp, 0)) )
+ return(error);
+ type = fp->f_type;
+ data = fp->f_data;
+
+ switch (type) {
+
+ case DTYPE_SOCKET:
+ if (uap->name != _PC_PIPE_BUF) {
+ error = EINVAL;
+ goto out;
+ }
+ *retval = PIPE_BUF;
+ error = 0;
+ goto out;
+
+ case DTYPE_PIPE:
+ *retval = PIPE_BUF;
+ error = 0;
+ goto out;
+
+ case DTYPE_VNODE:
+ vp = (struct vnode *)data;
+
+ if ( (error = vnode_getwithref(vp)) == 0) {
+ AUDIT_ARG(vnpath, vp, ARG_VNODE1);
+
+ error = vn_pathconf(vp, uap->name, retval, vfs_context_current());
+
+ (void)vnode_put(vp);
+ }
+ goto out;
+
+ case DTYPE_PSXSHM:
+ case DTYPE_PSXSEM:
+ case DTYPE_KQUEUE:
+ case DTYPE_FSEVENTS:
+ error = EINVAL;
+ goto out;
+
+ }
+ /*NOTREACHED*/
+out:
+ fp_drop(p, fd, fp, 0);
+ return(error);
+}
+
+/*
+ * Statistics counter for the number of times a process calling fdalloc()
+ * has resulted in an expansion of the per process open file table.
+ *
+ * XXX This would likely be of more use if it were per process
+ */
+int fdexpand;
+
+
+/*
+ * fdalloc
+ *
+ * Description: Allocate a file descriptor for the process.
+ *
+ * Parameters: p Process to allocate the fd in
+ * want The fd we would prefer to get
+ * result Pointer to fd we got
+ *
+ * Returns: 0 Success
+ * EMFILE
+ * ENOMEM
+ *
+ * Implicit returns:
+ * *result (modified) The fd which was allocated
+ */
+int
+fdalloc(proc_t p, int want, int *result)
+{
+ struct filedesc *fdp = p->p_fd;
+ int i;
+ int lim, last, numfiles, oldnfiles;
+ struct fileproc **newofiles, **ofiles;
+ char *newofileflags;
+
+ /*
+ * Search for a free descriptor starting at the higher
+ * of want or fd_freefile. If that fails, consider
+ * expanding the ofile array.
+ */
+#if DIAGNOSTIC
+ proc_fdlock_assert(p, LCK_MTX_ASSERT_OWNED);
+#endif
+
+ lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles);
+ 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] & UF_RESERVED)) {
+ procfdtbl_reservefd(p, i);
+ 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)
+ numfiles = NDEXTENT;
+ else
+ numfiles = 2 * fdp->fd_nfiles;
+ /* Enforce lim */
+ if (numfiles > lim)
+ numfiles = lim;
+ proc_fdunlock(p);
+ MALLOC_ZONE(newofiles, struct fileproc **,
+ numfiles * OFILESIZE, M_OFILETABL, M_WAITOK);
+ proc_fdlock(p);
+ if (newofiles == NULL) {
+ return (ENOMEM);
+ }
+ if (fdp->fd_nfiles >= numfiles) {
+ FREE_ZONE(newofiles, numfiles * OFILESIZE, M_OFILETABL);
+ continue;
+ }
+ newofileflags = (char *) &newofiles[numfiles];
+ /*
+ * Copy the existing ofile and ofileflags arrays
+ * and zero the new portion of each array.
+ */
+ oldnfiles = fdp->fd_nfiles;
+ (void) memcpy(newofiles, fdp->fd_ofiles,
+ oldnfiles * sizeof(*fdp->fd_ofiles));
+ (void) memset(&newofiles[oldnfiles], 0,
+ (numfiles - oldnfiles) * sizeof(*fdp->fd_ofiles));
+
+ (void) memcpy(newofileflags, fdp->fd_ofileflags,
+ oldnfiles * sizeof(*fdp->fd_ofileflags));
+ (void) memset(&newofileflags[oldnfiles], 0,
+ (numfiles - oldnfiles) *
+ sizeof(*fdp->fd_ofileflags));
+ ofiles = fdp->fd_ofiles;
+ fdp->fd_ofiles = newofiles;
+ fdp->fd_ofileflags = newofileflags;
+ fdp->fd_nfiles = numfiles;
+ FREE_ZONE(ofiles, oldnfiles * OFILESIZE, M_OFILETABL);
+ fdexpand++;
+ }
+}
+
+
+/*
+ * fdavail
+ *
+ * Description: Check to see whether n user file descriptors are available
+ * to the process p.
+ *
+ * Parameters: p Process to check in
+ * n The number of fd's desired
+ *
+ * Returns: 0 No
+ * 1 Yes
+ *
+ * Locks: Assumes proc_fdlock for process is held by the caller
+ *
+ * Notes: The answer only remains valid so long as the proc_fdlock is
+ * held by the caller.
+ */
+int
+fdavail(proc_t 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);
+}
+
+
+/*
+ * fdrelse
+ *
+ * Description: Legacy KPI wrapper function for _fdrelse
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to free
+ *
+ * Returns: void
+ *
+ * Locks: Assumes proc_fdlock for process is held by the caller
+ */
+void
+fdrelse(proc_t p, int fd)
+{
+ _fdrelse(p, fd);
+}
+
+
+/*
+ * fdgetf_noref
+ *
+ * Description: Get the fileproc pointer for the given fd from the per process
+ * open file table without taking an explicit reference on it.
+ *
+ * Parameters: p Process containing fd
+ * fd fd to obtain fileproc for
+ * resultfp Pointer to pointer return area
+ *
+ * Returns: 0 Success
+ * EBADF
+ *
+ * Implicit returns:
+ * *resultfp (modified) Pointer to fileproc pointer
+ *
+ * Locks: Assumes proc_fdlock for process is held by the caller
+ *
+ * Notes: Because there is no reference explicitly taken, the returned
+ * fileproc pointer is only valid so long as the proc_fdlock
+ * remains held by the caller.
+ */
+int
+fdgetf_noref(proc_t 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);
+}
+
+
+/*
+ * fp_getfvp
+ *
+ * Description: Get fileproc and vnode pointer for a given fd from the per
+ * process open file table of the specified process, and if
+ * successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * resultvp Pointer to result vnode pointer
+ * area, or 0 if none
+ *
+ * Returns: 0 Success
+ * EBADF Bad file descriptor
+ * ENOTSUP fd does not refer to a vnode
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *resultvp (modified) vnode pointer
+ *
+ * Notes: The resultfp and resultvp fields are optional, and may be
+ * independently specified as NULL to skip returning information
+ *
+ * Locks: Internally takes and releases proc_fdlock
+ */
+int
+fp_getfvp(proc_t p, int fd, struct fileproc **resultfp, struct vnode **resultvp)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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);
+}
+
+
+/*
+ * fp_getfvpandvid
+ *
+ * Description: Get fileproc, vnode pointer, and vid for a given fd from the
+ * per process open file table of the specified process, and if
+ * successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * resultvp Pointer to result vnode pointer
+ * area, or 0 if none
+ * vidp Pointer to resuld vid area
+ *
+ * Returns: 0 Success
+ * EBADF Bad file descriptor
+ * ENOTSUP fd does not refer to a vnode
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *resultvp (modified) vnode pointer
+ * *vidp vid value
+ *
+ * Notes: The resultfp and resultvp fields are optional, and may be
+ * independently specified as NULL to skip returning information
+ *
+ * Locks: Internally takes and releases proc_fdlock
+ */
+int
+fp_getfvpandvid(proc_t p, int fd, struct fileproc **resultfp,
+ struct vnode **resultvp, uint32_t *vidp)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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;
+ if (vidp)
+ *vidp = (uint32_t)vnode_vid((struct vnode *)fp->f_data);
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+
+/*
+ * fp_getfsock
+ *
+ * Description: Get fileproc and socket pointer for a given fd from the
+ * per process open file table of the specified process, and if
+ * successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * results Pointer to result socket
+ * pointer area, or 0 if none
+ *
+ * Returns: EBADF The file descriptor is invalid
+ * EOPNOTSUPP The file descriptor is not a socket
+ * 0 Success
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *results (modified) socket pointer
+ *
+ * Notes: EOPNOTSUPP should probably be ENOTSOCK; this function is only
+ * ever called from accept1().
+ */
+int
+fp_getfsock(proc_t p, int fd, struct fileproc **resultfp,
+ struct socket **results)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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);
+}
+
+
+/*
+ * fp_getfkq
+ *
+ * Description: Get fileproc and kqueue pointer for a given fd from the
+ * per process open file table of the specified process, and if
+ * successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * resultkq Pointer to result kqueue
+ * pointer area, or 0 if none
+ *
+ * Returns: EBADF The file descriptor is invalid
+ * EBADF The file descriptor is not a socket
+ * 0 Success
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *resultkq (modified) kqueue pointer
+ *
+ * Notes: The second EBADF should probably be something else to make
+ * the error condition distinct.
+ */
+int
+fp_getfkq(proc_t p, int fd, struct fileproc **resultfp,
+ struct kqueue **resultkq)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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);
+}
+
+
+/*
+ * fp_getfpshm
+ *
+ * Description: Get fileproc and POSIX shared memory pointer for a given fd
+ * from the per process open file table of the specified process
+ * and if successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * resultpshm Pointer to result POSIX
+ * shared memory pointer
+ * pointer area, or 0 if none
+ *
+ * Returns: EBADF The file descriptor is invalid
+ * EBADF The file descriptor is not a POSIX
+ * shared memory area
+ * 0 Success
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *resultpshm (modified) POSIX shared memory pointer
+ *
+ * Notes: The second EBADF should probably be something else to make
+ * the error condition distinct.
+ */
+int
+fp_getfpshm(proc_t p, int fd, struct fileproc **resultfp,
+ struct pshmnode **resultpshm)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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);
+}
+
+
+/*
+ * fp_getfsem
+ *
+ * Description: Get fileproc and POSIX semaphore pointer for a given fd from
+ * the per process open file table of the specified process
+ * and if successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * resultpsem Pointer to result POSIX
+ * semaphore pointer area, or
+ * 0 if none
+ *
+ * Returns: EBADF The file descriptor is invalid
+ * EBADF The file descriptor is not a POSIX
+ * semaphore
+ * 0 Success
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *resultpsem (modified) POSIX semaphore pointer
+ *
+ * Notes: The second EBADF should probably be something else to make
+ * the error condition distinct.
+ *
+ * In order to support unnamed POSIX semaphores, the named
+ * POSIX semaphores will have to move out of the per-process
+ * open filetable, and into a global table that is shared with
+ * unnamed POSIX semaphores, since unnamed POSIX semaphores
+ * are typically used by declaring instances in shared memory,
+ * and there's no other way to do this without changing the
+ * underlying type, which would introduce binary compatibility
+ * issues.
+ */
+int
+fp_getfpsem(proc_t p, int fd, struct fileproc **resultfp,
+ struct psemnode **resultpsem)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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);
+}
+
+
+/*
+ * fp_getfpipe
+ *
+ * Description: Get fileproc and pipe pointer for a given fd from the
+ * per process open file table of the specified process
+ * and if successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * resultpipe Pointer to result pipe
+ * pointer area, or 0 if none
+ *
+ * Returns: EBADF The file descriptor is invalid
+ * EBADF The file descriptor is not a socket
+ * 0 Success
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *resultpipe (modified) pipe pointer
+ *
+ * Notes: The second EBADF should probably be something else to make
+ * the error condition distinct.
+ */
+int
+fp_getfpipe(proc_t p, int fd, struct fileproc **resultfp,
+ struct pipe **resultpipe)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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_PIPE) {
+ proc_fdunlock(p);
+ return(EBADF);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (resultpipe)
+ *resultpipe = (struct pipe *)fp->f_data;
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+
+#define DTYPE_ATALK -1 /* XXX This does not belong here */
+
+
+/*
+ * fp_getfatalk
+ *
+ * Description: Get fileproc and atalk pointer for a given fd from the
+ * per process open file table of the specified process
+ * and if successful, increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * resultatalk Pointer to result atalk
+ * pointer area, or 0 if none
+ * Returns: EBADF The file descriptor is invalid
+ * EBADF The file descriptor is not a socket
+ * 0 Success
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ * *resultatalk (modified) atalk pointer
+ *
+ * Notes: The second EBADF should probably be something else to make
+ * the error condition distinct.
+ *
+ * XXX This code is specific to AppleTalk protocol support, and
+ * XXX should be conditionally compiled
+ */
+int
+fp_getfatalk(proc_t p, int fd, struct fileproc **resultfp,
+ struct atalk **resultatalk)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ proc_fdlock_spin(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_ATALK+1)) {
+ proc_fdunlock(p);
+ return(EBADF);
+ }
+ fp->f_iocount++;
+
+ if (resultfp)
+ *resultfp = fp;
+ if (resultatalk)
+ *resultatalk = (struct atalk *)fp->f_data;
+ proc_fdunlock(p);
+
+ return (0);
+}
+
+
+/*
+ * fp_lookup
+ *
+ * Description: Get fileproc pointer for a given fd from the per process
+ * open file table of the specified process and if successful,
+ * increment the f_iocount
+ *
+ * Parameters: p Process in which fd lives
+ * fd fd to get information for
+ * resultfp Pointer to result fileproc
+ * pointer area, or 0 if none
+ * locked !0 if the caller holds the
+ * proc_fdlock, 0 otherwise
+ *
+ * Returns: 0 Success
+ * EBADF Bad file descriptor
+ *
+ * Implicit returns:
+ * *resultfp (modified) Fileproc pointer
+ *
+ * Locks: If the argument 'locked' is non-zero, then the caller is
+ * expected to have taken and held the proc_fdlock; if it is
+ * zero, than this routine internally takes and drops this lock.
+ */
+int
+fp_lookup(proc_t p, int fd, struct fileproc **resultfp, int locked)
+{
+ struct filedesc *fdp = p->p_fd;
+ struct fileproc *fp;
+
+ if (!locked)
+ proc_fdlock_spin(p);
+ if (fd < 0 || fdp == NULL || 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);
+}
+
+
+/*
+ * fp_drop_written
+ *
+ * Description: Set the FP_WRITTEN flag on the fileproc and drop the I/O
+ * reference previously taken by calling fp_lookup et. al.
+ *
+ * Parameters: p Process in which the fd lives
+ * fd fd associated with the fileproc
+ * fp fileproc on which to set the
+ * flag and drop the reference
+ *
+ * Returns: 0 Success
+ * fp_drop:EBADF Bad file descriptor
+ *
+ * Locks: This function internally takes and drops the proc_fdlock for
+ * the supplied process
+ *
+ * Notes: The fileproc must correspond to the fd in the supplied proc
+ */
+int
+fp_drop_written(proc_t p, int fd, struct fileproc *fp)
+{
+ int error;
+
+ proc_fdlock_spin(p);
+
+ fp->f_flags |= FP_WRITTEN;
+
+ error = fp_drop(p, fd, fp, 1);
+
+ proc_fdunlock(p);
+
+ return (error);
+}
+
+
+/*
+ * fp_drop_event
+ *
+ * Description: Set the FP_WAITEVENT flag on the fileproc and drop the I/O
+ * reference previously taken by calling fp_lookup et. al.
+ *
+ * Parameters: p Process in which the fd lives
+ * fd fd associated with the fileproc
+ * fp fileproc on which to set the
+ * flag and drop the reference
+ *
+ * Returns: 0 Success
+ * fp_drop:EBADF Bad file descriptor
+ *
+ * Locks: This function internally takes and drops the proc_fdlock for
+ * the supplied process
+ *
+ * Notes: The fileproc must correspond to the fd in the supplied proc