/* * canon_switch2.c * * Test read() after non-canon -> canon switch * w/ EOL push immediately after * * gcc -Wall -o canon_switch canon_switch.c * * Based on orginal code by Ilya Zykov */ #include #include #include #include #include #include #include #include #include #include #include static int fd; static void error_exit(char *f, ...) { va_list va; va_start(va, f); vprintf(f, va); if (errno) printf(": %s (code: %d)\n", strerror(errno), errno); else printf("\n"); va_end(va); if (fd >= 0) close(fd); exit(EXIT_FAILURE); } static void fill_pattern(char *pattern, size_t len) { size_t i, n; const char test[] = "1234567890"; n = strlen(test); for (i = 0; i <= len - n; i += n) strncpy(&pattern[i], test, n); strncpy(&pattern[i], test, len % n); } int main(int argc, char *argv[]) { int child_id; char pts_name[24]; int ptn, unlock = 0; struct termios termios, save; setbuf(stdout, NULL); fd = open("/dev/ptmx", O_RDWR); if (fd < 0) error_exit("opening pty master"); if (ioctl(fd, TIOCGPTN, &ptn) < 0) error_exit("getting pty #"); if (ioctl(fd, TIOCSPTLCK, &unlock) < 0) error_exit("unlocking pty pair"); snprintf(pts_name, sizeof(pts_name), "/dev/pts/%d", ptn); if (tcgetattr(fd, &termios) < 0) error_exit("tcgetattr"); save = termios; termios.c_lflag &= ~(ICANON | ECHO | ISIG); termios.c_iflag &= ~(IXON | IXOFF | ICRNL | INLCR); if ((termios.c_cflag & CSIZE) == CS8) termios.c_cflag &= ~(ISTRIP | INPCK); termios.c_cc[VMIN] = 1; termios.c_cc[VTIME] = 0; termios.c_cc[VLNEXT] = _POSIX_VDISABLE; termios.c_oflag &= ~OPOST; if (tcsetattr(fd, TCSAFLUSH, &termios) < 0) error_exit("tcsetattr master"); child_id = fork(); switch (child_id) { case -1: error_exit("forking child"); case 0: { /* child */ printf("Child [%ld] on slave pty %s\n", (long)getpid(), pts_name); close(fd); /* master pty no longer needed */ fd = open(pts_name, O_RDWR); if (fd < 0) error_exit("opening pty slave"); /* wait for master write in non-canon mode */ { struct pollfd pollfds[1] = { { fd, POLLIN }, }; poll(pollfds, 1, -1); } sleep(1); if (tcsetattr(fd, TCSANOW, &save)) error_exit("tcsetattr restore"); { char buf[8192]; int n; n = read(fd, buf, sizeof(buf)); if (n < 0) error_exit("slave reading"); printf("read: %d\n", n); printf("%.*s", n, buf); n = read(fd, buf, sizeof(buf)); if (n < 0) error_exit("slave reading"); printf("read: %d\n", n); if (n == 0) error_exit("unexpected EOF"); printf("%.*s", n, buf); n = read(fd, buf, sizeof(buf)); if (n < 0) error_exit("slave reading"); printf("read: %d\n", n); printf("%.*s", n, buf); } close(fd); } return 0; default: { /* parent */ int n, id, status, c; char pattern[4096]; char pattern2[] = "The quick brown fox jumped over the lazy dog.\r"; /* Simulate an input pattern that was supposed to be * all 4096 chars of pattern (which terminates in an EOF push) * but was received as 4095 (because that's the maximum raw mode * allows in the input buffer at once). */ fill_pattern(pattern, sizeof(pattern)); pattern[4095] = termios.c_cc[VEOF]; c = 4096; n = write(fd, pattern, c); if (n < 0) error_exit("master writing"); printf("write: %d, wrote: %d\n", c, n); c = strlen(pattern2); n = write(fd, pattern2, c); if (n < 0) error_exit("master writing"); printf("write: %d, wrote: %d\n", c, n); id = waitpid(child_id, &status, 0); if (id < 0 || id != child_id) error_exit("waiting for child"); printf("[%ld] exited status: %d\n", (long) child_id, status); } return 0; } }