Example #1
0
/*
 * Get device node names for the master and slave end of a free pseudo
 * terminal.  We don't want to replicate the entire openpty(3) logic here, so
 * start by letting openpty(3) do the work for us.  We make the assumption that
 * nobody snatches the pair while we are running.
 */
static void
get_names(char pname[PATH_MAX], char tname[PATH_MAX])
{
	int len, masterfd, slavefd;

	if (openpty(&masterfd, &slavefd, tname, NULL, NULL) < 0) e(300);

	/*
	 * openpty(3) gives us only the slave name, but we also need the master
	 * name.
	 */
	strlcpy(pname, tname, PATH_MAX);
	len = strlen(_PATH_DEV);

	if (strncmp(pname, _PATH_DEV, len)) e(301);

	/* If this fails, this test needs to be updated. */
	if (pname[len] != 't') e(302);

	pname[len] = 'p';

	test_comm(masterfd, slavefd);

	if (close(masterfd) < 0) e(303);
	if (close(slavefd) < 0) e(304);
}
Example #2
0
/*
 * Test opening a single side multiple times.
 */
static void
test77b(void)
{
    char pname[PATH_MAX], tname[PATH_MAX];
    int oldstyle, masterfd, slavefd, extrafd;

    subtest = 2;

    /* Obtain a pseudo terminal. */
    oldstyle = get_pty(&masterfd, pname, tname);

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    /*
     * It must not be possible to open the master multiple times.  Doing so
     * is possible only if we have a named master, i.e., an old-style PTY.
     */
    test_comm(masterfd, slavefd);

    if (oldstyle) {
        if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(0);
        if (errno != EIO) e(0);
    }

    test_comm(masterfd, slavefd);

    if (close(slavefd) < 0) e(0);
    if (close(masterfd) < 0) e(0);

    /* The slave can be opened multiple times, though. */
    oldstyle = get_pty(&masterfd, pname, tname);

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    test_comm(masterfd, slavefd);

    if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    test_comm(masterfd, extrafd);
    test_comm(masterfd, slavefd);

    if (close(slavefd) < 0) e(0);
    if (close(extrafd) < 0) e(0);
    if (close(masterfd) < 0) e(0);
}
Example #3
0
/*
 * Test opening a single side multiple times.
 */
static void
test77b(void)
{
	char pname[PATH_MAX], tname[PATH_MAX];
	int masterfd, slavefd, extrafd;

	subtest = 2;

	/* Get master and slave device names for a free pseudo terminal. */
	get_names(pname, tname);

	/* It must not be possible to open the master multiple times. */
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(1);
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(2);

	test_comm(masterfd, slavefd);

	if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(3);
	if (errno != EIO) e(4);

	test_comm(masterfd, slavefd);

	if (close(slavefd) < 0) e(5);
	if (close(masterfd) < 0) e(6);

	/* The slave can be opened multiple times, though. */
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(7);
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(8);

	test_comm(masterfd, slavefd);

	if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(9);

	test_comm(masterfd, extrafd);
	test_comm(masterfd, slavefd);

	if (close(slavefd) < 0) e(10);
	if (close(extrafd) < 0) e(11);
	if (close(masterfd) < 0) e(12);
}
Example #4
0
/*
 * Obtain a pseudo terminal.  The master end is opened and its file descriptor
 * stored in 'pfd'.  The slave path name is stored in 'tname'.  For old-style
 * PTYs, the function returns 1 and stores the master name in 'pname' if not
 * NULL.  For Unix98 PTYs, the function returns 0, in which case no master name
 * is available.  For old-style PTYs, the caller may close and reopen the
 * master.  In that case, we make the assumption that nobody snatches the pair
 * while we are running.  For Unix98 PTYs, the master must be kept open.
 */
static int
get_pty(int *pfd, char pname[PATH_MAX], char tname[PATH_MAX])
{
    char *name;
    int len, masterfd, slavefd;

    /*
     * First try Unix98 PTY allocation, mainly to avoid opening the slave
     * end immediately.  If this fails, try openpty(3) as well.
     */
    if ((masterfd = posix_openpt(O_RDWR | O_NOCTTY)) != -1) {
        if (grantpt(masterfd) != -1 && unlockpt(masterfd) != -1 &&
                (name = ptsname(masterfd)) != NULL) {
            *pfd = masterfd;
            strlcpy(tname, name, PATH_MAX);

            return 0;
        }
        if (close(masterfd) < 0) e(0);
    }

    if (openpty(&masterfd, &slavefd, tname, NULL, NULL) < 0) e(0);

    test_comm(masterfd, slavefd);

    *pfd = masterfd;

    if (close(slavefd) < 0) e(0);

    /*
     * openpty(3) gives us only the slave name, but we also want the master
     * name.
     */
    len = strlen(_PATH_DEV);
    if (strncmp(tname, _PATH_DEV, len)) e(0);

    if (strncmp(&tname[len], "tty", 3))
        return 0; /* Unix98 after all?  Well okay, whatever.. */

    if (pname != NULL) {
        strlcpy(pname, tname, PATH_MAX);
        pname[len] = 'p';
    }

    return 1;
}
Example #5
0
/*
 * Test communication on half-open pseudo terminals.
 */
static void
test77c(void)
{
	struct sigaction act, oact;
	char pname[PATH_MAX], tname[PATH_MAX];
	int masterfd, slavefd;
	char c;

	subtest = 3;

	/* We do not want to get SIGHUP signals in this test. */
	memset(&act, 0, sizeof(act));
	act.sa_handler = SIG_IGN;
	if (sigaction(SIGHUP, &act, &oact) < 0) e(1);

	/* Get master and slave device names for a free pseudo terminal. */
	get_names(pname, tname);

	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(2);

	/* Writes to the master should be buffered until there is a slave. */
	c = 'E';
	if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(3);

	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(4);

	make_raw(slavefd);

	if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(5);
	if (c != 'E') e(6);

	/* Discard the echo on the master. */
	if (tcflush(slavefd, TCOFLUSH) != 0) e(7);

	test_comm(masterfd, slavefd);

	if (close(slavefd) < 0) e(8);

	/* Writes to the master after the slave has been closed should fail. */
	if (write(masterfd, &c, sizeof(c)) >= 0) e(9);
	if (errno != EIO) e(10);

	if (close(masterfd) < 0) e(11);

	/* Writes to the slave should be buffered until there is a master. */
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(12);

	make_raw(slavefd);

	c = 'F';
	if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(13);

	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(14);

	if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(15);
	if (c != 'F') e(16);

	test_comm(masterfd, slavefd);

	if (close(masterfd) < 0) e(17);

	if (write(slavefd, &c, sizeof(c)) >= 0) e(18);
	if (errno != EIO) e(19);

	/* Reads from the slave should return EOF if the master is gone. */
	if (read(slavefd, &c, sizeof(c)) != 0) e(20);

	if (close(slavefd) < 0) e(21);

	if (sigaction(SIGHUP, &oact, NULL) < 0) e(22);
}
Example #6
0
/*
 * Test various orders of opening and closing the master and slave sides of a
 * pseudo terminal, as well as opening/closing one side without ever opening
 * the other.
 */
static void
test77a(void)
{
	struct sigaction act, oact;
	char pname[PATH_MAX], tname[PATH_MAX];
	int masterfd, slavefd;

	subtest = 1;

	/* We do not want to get SIGHUP signals in this test. */
	memset(&act, 0, sizeof(act));
	act.sa_handler = SIG_IGN;
	if (sigaction(SIGHUP, &act, &oact) < 0) e(1);

	/* Get master and slave device names for a free pseudo terminal. */
	get_names(pname, tname);

	/* Try opening and then closing the master. */
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(2);

	if (close(masterfd) < 0) e(3);

	/* Now see if we can reopen the master as well as the slave. */
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(4);
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(5);

	test_comm(masterfd, slavefd);

	/* In the meantime, test different closing orders. This is order A. */
	if (close(slavefd) < 0) e(6);
	if (close(masterfd) < 0) e(7);

	/* Now try opening the pair again. */
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(8);
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(9);

	test_comm(masterfd, slavefd);

	if (close(slavefd) < 0) e(10);

	/*
	 * Try reopening the slave after closing it.  It is not very important
	 * that this works, but the TTY driver should currently support it.
	 */
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(11);

	test_comm(masterfd, slavefd);

	/* This is closing order B. This may or may not cause a SIGHUP. */
	if (close(masterfd) < 0) e(12);
	if (close(slavefd) < 0) e(13);

	/* Try the normal open procedure. */
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(14);
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(15);

	test_comm(masterfd, slavefd);

	if (close(slavefd) < 0) e(16);
	if (close(masterfd) < 0) e(17);

	/* Try reopening and closing the slave, without opening the master. */
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(18);

	if (close(slavefd) < 0) e(19);

	/* Again, try the normal open procedure. */
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(20);
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(21);

	test_comm(masterfd, slavefd);

	if (close(slavefd) < 0) e(22);
	if (close(masterfd) < 0) e(23);

	/* Finally, try opening the slave first. */
	if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(24);
	if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(25);

	test_comm(masterfd, slavefd);

	if (close(slavefd) < 0) e(26);
	if (close(masterfd) < 0) e(27);

	if (sigaction(SIGHUP, &oact, NULL) < 0) e(28);
}
Example #7
0
/*
 * Test for Unix98 PTY support and PTYFS.
 */
static void
test77g(void)
{
    char *tname;
    struct stat buf;
    size_t len;
    int i, masterfd, slavefd, fd[3], array[3], present[3];

    subtest = 7;

    /*
     * Test basic operation, and verify that the slave node disappears
     * after both sides of the pseudo terminal have been closed.  We check
     * different combinations of open master and slave ends (with 'i'):
     * 0) opening and closing the master only, 1) closing a slave before
     * the master, and 2) closing the slave after the master.
     */
    for (i = 0; i <= 2; i++) {
        masterfd = get_unix98_pty(&tname);

        if (access(tname, R_OK | W_OK) < 0) e(0);

        if (i > 0) {
            if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0)
                e(0);

            if (access(tname, R_OK | W_OK) < 0) e(0);

            if (i > 1) {
                if (close(masterfd) < 0) e(0);

                masterfd = slavefd; /* ugly but saving code */
            } else if (close(slavefd) < 0) e(0);
        }

        if (access(tname, R_OK | W_OK) < 0) e(0);

        if (close(masterfd) < 0) e(0);

        if (access(tname, R_OK | W_OK) == 0) e(0);
    }

    /*
     * Test whether we can open multiple pseudo terminals.  We need to be
     * able to open three PTYs.  Verify that they are properly listed in
     * the /dev/pts directory contents, and have proper attributes set.
     */
    test_getdents(0, NULL, NULL);

    for (i = 0; i < 3; i++) {
        fd[i] = get_unix98_pty(&tname);

        /* Figure out the slave index number. */
        len = strlen(_PATH_DEV_PTS);
        if (strncmp(tname, _PATH_DEV_PTS, strlen(_PATH_DEV_PTS))) e(0);
        array[i] = atoi(&tname[len]);
        present[i] = 1;
    }

    test_getdents(3, array, present);

    if (close(fd[0]) < 0) e(0);
    present[0] = 0;

    test_getdents(3, array, present);

    if (close(fd[2]) < 0) e(0);
    present[2] = 0;

    test_getdents(3, array, present);

    if (close(fd[1]) < 0) e(0);
    present[1] = 0;

    test_getdents(3, array, present);

    /*
     * Test chmod(2) on a slave node, and multiple calls to grantpt(3).
     * The first grantpt(3) call should create the slave node (we currently
     * can not test this: the slave node may be created earlier as well,
     * but we do not know its name), whereas subsequent grantpt(3) calls
     * should reset its mode, uid, and gid.  Testing the latter two and
     * chown(2) on the slave node requires root, so we skip that part.
     *
     * Finally, NetBSD revokes access to existing slave file descriptors
     * upon a call to grantpt(3).  This is not a POSIX requirement, but
     * NetBSD needs this for security reasons because it already creates
     * the slave node when the master is opened (and it does not lock the
     * slave until a call to unlockpt(3)).  MINIX3 does not implement
     * revocation this way, because the slave node is created only upon the
     * call to grantpt(3), thus leaving no insecure window for the slave
     * side between posix_openpt(3) and grantpt(3).  While this behavior
     * may be changed later, we test for the lack of revocation here now.
     */
    masterfd = get_unix98_pty(&tname);

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    if (stat(tname, &buf) != 0) e(0);
    if (buf.st_mode != (S_IFCHR | 0620)) e(0);

    if (chmod(tname, S_IFCHR | 0630) != 0) e(0);

    if (stat(tname, &buf) != 0) e(0);
    if (buf.st_mode != (S_IFCHR | 0630)) e(0);

    if (grantpt(masterfd) != 0) e(0);

    if (stat(tname, &buf) != 0) e(0);
    if (buf.st_mode != (S_IFCHR | 0620)) e(0);

    test_comm(masterfd, slavefd);

    if (close(slavefd) < 0) e(0);
    if (close(masterfd) < 0) e(0);

    test_getdents(0, NULL, NULL);
}
Example #8
0
/*
 * Test communication on half-open pseudo terminals.
 */
static void
test77c(void)
{
    struct sigaction act, oact;
    char pname[PATH_MAX], tname[PATH_MAX];
    int oldstyle, masterfd, slavefd;
    char c;

    subtest = 3;

    /* We do not want to get SIGHUP signals in this test. */
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_IGN;
    if (sigaction(SIGHUP, &act, &oact) < 0) e(0);

    /* Obtain a pseudo terminal. */
    oldstyle = get_pty(&masterfd, pname, tname);

    /*
     * For old-style pseudo terminals, we have just opened and closed the
     * slave end, which alters the behavior we are testing below.  Close
     * and reopen the master to start fresh.
     */
    if (oldstyle) {
        if (close(masterfd) < 0) e(0);

        if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
    }

    /* Writes to the master should be buffered until there is a slave. */
    c = 'E';
    if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    make_raw(slavefd);

    if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
    if (c != 'E') e(0);

    /* Discard the echo on the master. */
    if (tcflush(slavefd, TCOFLUSH) != 0) e(0);

    test_comm(masterfd, slavefd);

    if (close(slavefd) < 0) e(0);

    /* Writes to the master after the slave has been closed should fail. */
    if (write(masterfd, &c, sizeof(c)) >= 0) e(0);
    if (errno != EIO) e(0);

    if (oldstyle)
        if (close(masterfd) < 0) e(0);

    /*
     * Writes to the slave should be buffered until there is a master.
     * This applies to old-style PTYs only.
     */
    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    if (oldstyle) {
        make_raw(slavefd);

        c = 'F';
        if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);

        if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);

        if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
        if (c != 'F') e(0);
    }

    test_comm(masterfd, slavefd);

    if (close(masterfd) < 0) e(0);

    if (write(slavefd, &c, sizeof(c)) >= 0) e(0);
    if (errno != EIO) e(0);

    /* Reads from the slave should return EOF if the master is gone. */
    if (read(slavefd, &c, sizeof(c)) != 0) e(0);

    if (close(slavefd) < 0) e(0);

    if (sigaction(SIGHUP, &oact, NULL) < 0) e(0);
}
Example #9
0
/*
 * Test various orders of opening and closing the master and slave sides of a
 * pseudo terminal, as well as opening/closing one side without ever opening
 * the other.  This test is meaningful mainly for old-style pseudoterminals.
 */
static void
test77a(void)
{
    struct sigaction act, oact;
    char pname[PATH_MAX], tname[PATH_MAX];
    int oldstyle, masterfd, slavefd;

    subtest = 1;

    /* We do not want to get SIGHUP signals in this test. */
    memset(&act, 0, sizeof(act));
    act.sa_handler = SIG_IGN;
    if (sigaction(SIGHUP, &act, &oact) < 0) e(0);

    /* Obtain a pseudo terminal. */
    oldstyle = get_pty(&masterfd, pname, tname);

    if (oldstyle) {
        /* Try closing the master. */
        if (close(masterfd) < 0) e(0);

        /* See if we can reopen the master. */
        if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
    }

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    test_comm(masterfd, slavefd);

    /* In the meantime, test different closing orders. This is order A. */
    if (close(slavefd) < 0) e(0);
    if (close(masterfd) < 0) e(0);

    /* Now try opening the pair (or a new pair) again. */
    if (!oldstyle)
        oldstyle = get_pty(&masterfd, pname, tname);
    else if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    test_comm(masterfd, slavefd);

    if (close(slavefd) < 0) e(0);

    /*
     * Try reopening the slave after closing it.  It is not very important
     * that this works, but the TTY driver should currently support it.
     */
    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    test_comm(masterfd, slavefd);

    /* This is closing order B. This may or may not cause a SIGHUP. */
    if (close(masterfd) < 0) e(0);
    if (close(slavefd) < 0) e(0);

    /* Try the normal open procedure. */
    if (!oldstyle)
        oldstyle = get_pty(&masterfd, pname, tname);
    else if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    test_comm(masterfd, slavefd);

    if (close(slavefd) < 0) e(0);
    if (close(masterfd) < 0) e(0);

    /*
     * Try reopening and closing the slave, without opening the master.
     * This should work on old-style PTYS, but not on Unix98 PTYs.
     */
    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) >= 0) {
        if (!oldstyle) e(0);

        if (close(slavefd) < 0) e(0);
    } else if (oldstyle) e(0);

    /* Again, try the normal open procedure. */
    if (!oldstyle)
        oldstyle = get_pty(&masterfd, pname, tname);
    else if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);

    if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);

    test_comm(masterfd, slavefd);

    if (close(slavefd) < 0) e(0);
    if (close(masterfd) < 0) e(0);

    /*
     * Finally, try opening the slave first.  This does not work with
     * Unix98 PTYs.
     */
    if (oldstyle) {
        if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
        if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);

        test_comm(masterfd, slavefd);

        if (close(slavefd) < 0) e(0);
        if (close(masterfd) < 0) e(0);
    }

    if (sigaction(SIGHUP, &oact, NULL) < 0) e(0);
}