/*
 * 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;
}
Ejemplo n.º 2
0
/*
 * 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;
}