1 /*
2 * Copyright (c) 2013 Todd C. Miller <millert@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include <sys/types.h>
18 #include <sys/wait.h>
19
20 #include <err.h>
21 #include <errno.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <termios.h>
27 #include <unistd.h>
28 #include <util.h>
29
30 #define BUF_SIZE 1024
31
32 /*
33 * Exercise a bug in ptcwrite() when we hit the TTYHOG limit if
34 * the tty is in raw mode.
35 */
sigalrm(int signo)36 static void sigalrm(int signo)
37 {
38 /* just return */
39 return;
40 }
41
42 int
main(int argc,char * argv[])43 main(int argc, char *argv[])
44 {
45 struct sigaction sa;
46 unsigned char buf[BUF_SIZE];
47 int mfd, sfd, status;
48 struct termios term;
49 size_t i, nwritten = 0, nread= 0;
50 ssize_t n;
51
52 /*
53 * Open pty and set slave to raw mode.
54 */
55 if (openpty(&mfd, &sfd, NULL, NULL, NULL) == -1)
56 err(1, "openpty");
57 if (tcgetattr(sfd, &term) == -1)
58 err(1, "tcgetattr");
59 cfmakeraw(&term);
60 if (tcsetattr(sfd, TCSAFLUSH, &term) == -1)
61 err(1, "tcsetattr");
62
63 switch (fork()) {
64 case -1:
65 err(1, "fork");
66 case 0:
67 /* prevent a hang if the bug is present */
68 memset(&sa, 0, sizeof(sa));
69 sa.sa_handler = sigalrm;
70 sigemptyset(&sa.sa_mask);
71 sigaction(SIGALRM, &sa, NULL);
72 alarm(5);
73
74 /* child, read data from slave */
75 do {
76 n = read(sfd, buf + nread, sizeof(buf) - nread);
77 if (n == -1) {
78 if (errno == EINTR)
79 errx(1, "timed out @ %zd", nread);
80 err(1, "read @ %zd", nread);
81 }
82 nread += n;
83 } while (nread != sizeof(buf));
84 for (i = 0; i < sizeof(buf); i++) {
85 if (buf[i] != (i & 0xff)) {
86 errx(1, "buffer corrupted at %zd "
87 "(got %u, expected %zd)", i,
88 buf[i], (i & 0xff));
89 }
90 }
91 printf("all data received\n");
92 exit(0);
93 default:
94 /* parent, write data to master */
95 for (i = 0; i < sizeof(buf); i++)
96 buf[i] = (i & 0xff);
97 do {
98 n = write(mfd, buf + nwritten, sizeof(buf) - nwritten);
99 if (n == -1)
100 err(1, "write @ %zd", nwritten);
101 nwritten += n;
102 } while (nwritten != sizeof(buf));
103 wait(&status);
104 exit(WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status) + 128);
105 }
106 }
107