/* * Get a ptyfsnode from the free table, or allocate one. * Removes the node from the free table. */ struct ptyfsnode * ptyfs_free_get(ptyfstype type, int pty, struct lwp *l) { struct ptyfs_hashhead *ppp; struct ptyfsnode *pp; mutex_enter(&ptyfs_free_slock); ppp = &ptyfs_free_tbl[PTYHASH(type, pty, ptyfs_free_mask)]; LIST_FOREACH(pp, ppp, ptyfs_hash) { if (pty == pp->ptyfs_pty && pp->ptyfs_type == type) { LIST_REMOVE(pp, ptyfs_hash); mutex_exit(&ptyfs_free_slock); return pp; } } mutex_exit(&ptyfs_free_slock); pp = malloc(sizeof(struct ptyfsnode), M_TEMP, M_WAITOK); pp->ptyfs_pty = pty; pp->ptyfs_type = type; pp->ptyfs_fileno = PTYFS_FILENO(pty, type); ptyfs_getinfo(pp, l); return pp; }
/* * readdir returns directory entries from ptyfsnode (vp). * * the strategy here with ptyfs is to generate a single * directory entry at a time (struct dirent) and then * copy that out to userland using uiomove. a more efficent * though more complex implementation, would try to minimize * the number of calls to uiomove(). for ptyfs, this is * hardly worth the added code complexity. * * this should just be done through read() */ int ptyfs_readdir(void *v) { struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; kauth_cred_t a_cred; int *a_eofflag; off_t **a_cookies; int *a_ncookies; } */ *ap = v; struct uio *uio = ap->a_uio; struct dirent *dp; struct ptyfsnode *ptyfs; off_t i; int error; off_t *cookies = NULL; int ncookies; struct vnode *vp; int nc = 0; vp = ap->a_vp; ptyfs = VTOPTYFS(vp); if (uio->uio_resid < UIO_MX) return EINVAL; if (uio->uio_offset < 0) return EINVAL; dp = malloc(sizeof(struct dirent), M_PTYFSTMP, M_WAITOK | M_ZERO); error = 0; i = uio->uio_offset; dp->d_reclen = UIO_MX; ncookies = uio->uio_resid / UIO_MX; if (ptyfs->ptyfs_type != PTYFSroot) { error = ENOTDIR; goto out; } if (i >= npty) goto out; if (ap->a_ncookies) { ncookies = min(ncookies, (npty + 2 - i)); cookies = malloc(ncookies * sizeof (off_t), M_TEMP, M_WAITOK); *ap->a_cookies = cookies; } for (; i < 2; i++) { /* `.' and/or `..' */ dp->d_fileno = PTYFS_FILENO(0, PTYFSroot); dp->d_namlen = i + 1; (void)memcpy(dp->d_name, "..", dp->d_namlen); dp->d_name[i + 1] = '\0'; dp->d_type = DT_DIR; if ((error = uiomove(dp, UIO_MX, uio)) != 0) goto out; if (cookies) *cookies++ = i + 1; nc++; } for (; uio->uio_resid >= UIO_MX && i < npty; i++) { /* check for used ptys */ if (pty_isfree(i - 2, 1)) continue; dp->d_fileno = PTYFS_FILENO(i - 2, PTYFSpts); dp->d_namlen = snprintf(dp->d_name, sizeof(dp->d_name), "%lld", (long long)(i - 2)); dp->d_type = DT_CHR; if ((error = uiomove(dp, UIO_MX, uio)) != 0) goto out; if (cookies) *cookies++ = i + 1; nc++; } out: /* not pertinent in error cases */ ncookies = nc; if (ap->a_ncookies) { if (error) { if (cookies) free(*ap->a_cookies, M_TEMP); *ap->a_ncookies = 0; *ap->a_cookies = NULL; } else *ap->a_ncookies = ncookies; } uio->uio_offset = i; free(dp, M_PTYFSTMP); return error; }