Example #1
0
int
do_pty(void)
{
	struct kevent ev[4];
	struct termios tt;
	int kq, massa, slave;
	char buf[1024];

	tcgetattr(STDIN_FILENO, &tt);
	cfmakeraw(&tt);
	tt.c_lflag &= ~ECHO;
	if (openpty(&massa, &slave, NULL, &tt, NULL) < 0)
		err(1, "openpty");
	if (fcntl(massa, F_SETFL, O_NONBLOCK) < 0)
		err(1, "massa: fcntl");
	if (fcntl(slave, F_SETFL, O_NONBLOCK) < 0)
		err(1, "massa: fcntl");
	if ((kq = kqueue()) == -1)
		err(1, "kqueue");

	/* test the read from the slave works */
	EV_SET(&ev[0], massa, EVFILT_READ,  EV_ADD|EV_ENABLE, 0, 0, NULL);
	EV_SET(&ev[1], massa, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, NULL);
	EV_SET(&ev[2], slave, EVFILT_READ,  EV_ADD|EV_ENABLE, 0, 0, NULL);
	EV_SET(&ev[3], slave, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, NULL);
	if (kevent(kq, ev, 4, NULL, 0, NULL) < 0)
		err(1, "slave: kevent add");

	memset(buf, 0, sizeof buf);

	if (write(massa, " ", 1) != 1)
		err(1, "massa: write");

	if (pty_check(kq, ev, 4, -massa, slave, massa, slave))
		return (1);

	read(slave, buf, sizeof(buf));

	if (pty_check(kq, ev, 4, -massa, -slave, massa, slave))
		return (1);

	while (write(massa, buf, sizeof(buf)) > 0)
		continue;

	if (pty_check(kq, ev, 4, -massa, slave, -massa, slave))
		return (1);

	read(slave, buf, 1);

	if (pty_check(kq, ev, 4, -massa, slave, massa, slave))
		return (1);

	while (read(slave, buf, sizeof(buf)) > 0)
		continue;

	if (pty_check(kq, ev, 4, -massa, -slave, massa, slave))
		return (1);

	return (0);
}
Example #2
0
static int
pty_alloc_master(struct lwp *l, int *fd, dev_t *dev, struct mount *mp)
{
	int error;
	struct file *fp;
	struct vnode *vp;
	int md;

	if ((error = fd_allocfile(&fp, fd)) != 0) {
		DPRINTF(("fd_allocfile %d\n", error));
		return error;
	}
retry:
	/* Find and open a free master pty. */
	*dev = pty_getfree();
	md = minor(*dev);
	if ((error = pty_check(md)) != 0) {
		DPRINTF(("pty_check %d\n", error));
		goto bad;
	}
	if (ptm == NULL) {
		DPRINTF(("no ptm\n"));
		error = EOPNOTSUPP;
		goto bad;
	}
	/*
	 * XXX Since PTYFS has now multiple instance support, if we mounted
	 * more than one PTYFS we must check here the ptyfs_used_tbl, to find
	 * out if the ptyfsnode is under the appropriate mount and skip the
	 * node if not, because the pty could has been released, but
	 * ptyfs_reclaim didn't get a chance to release the corresponding
	 * node other mount point yet.
	 *
	 * It's important to have only one mount point's ptyfsnode for each
	 * appropriate device in ptyfs_used_tbl, else we will have a security 
	 * problem, because every entry will have access to this device.
	 *
	 * Also we will not have not efficient vnode and memory usage.
	 * You can test this by changing a_recycle from true to false
	 * in ptyfs_inactive.
	 */
	if ((error = (*ptm->allocvp)(mp, l, &vp, *dev, 'p')) != 0) {
		DPRINTF(("pty_allocvp %d\n", error));
		goto bad;
	}

	if ((error = pty_vn_open(vp, l)) != 0) {
		DPRINTF(("pty_vn_open %d\n", error));
		/*
		 * Check if the master open failed because we lost
		 * the race to grab it.
		 */
		if (error != EIO)
			goto bad;
		error = !pty_isfree(md, 1);
		DPRINTF(("pty_isfree %d\n", error));
		if (error)
			goto retry;
		else
			goto bad;
	}
	fp->f_flag = FREAD|FWRITE;
	fp->f_type = DTYPE_VNODE;
	fp->f_ops = &vnops;
	fp->f_data = vp;
	VOP_UNLOCK(vp);
	fd_affix(curproc, fp, *fd);
	return 0;
bad:
	fd_abort(curproc, fp, *fd);
	return error;
}