1 /* $Id: t_pty.c,v 1.2 2017/01/13 21:30:41 christos Exp $ */
4 * Allocates a pty(4) device, and sends the specified number of packets of the
5 * specified length though it, while a child reader process reads and reports
8 * Written by Matthew Mondor
11 #include <sys/cdefs.h>
12 __RCSID("$NetBSD: t_pty.c,v 1.2 2017/01/13 21:30:41 christos Exp $");
29 #include <sys/ioctl.h>
30 #include <sys/types.h>
34 static __dead void usage(const char *);
35 static void parse_args(int, char **);
41 static int pty_open(void);
42 static int tty_open(const char *);
43 static void fd_nonblock(int);
44 static pid_t child_spawn(const char *);
45 static void run(void);
47 static size_t buffer_size = 4096;
48 static size_t packets = 2;
61 if ((dbuf = calloc(1, buffer_size)) == NULL)
62 err(EXIT_FAILURE, "malloc(%zu)", buffer_size);
66 "parent: started; opening PTY and spawning child\n");
68 child = child_spawn(ptsname(pty));
70 (void)printf("parent: sleeping to make sure child is ready\n");
73 for (i = 0; i < buffer_size; i++)
77 (void)printf("parent: writing\n");
79 for (i = 0; i < packets; i++) {
84 "parent: attempting to write %zu bytes to PTY\n",
86 if ((size = write(pty, dbuf, buffer_size)) == -1) {
87 err(EXIT_FAILURE, "parent: write()");
91 (void)printf("parent: wrote %zd bytes to PTY\n", size);
95 (void)printf("parent: waiting for child to exit\n");
96 if (waitpid(child, &status, 0) == -1)
97 err(EXIT_FAILURE, "waitpid");
98 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
99 errx(EXIT_FAILURE, "child failed");
102 (void)printf("parent: closing PTY\n");
105 (void)printf("parent: exiting\n");
115 if (ioctl(fd, TIOCSQSIZE, &opt) == -1)
116 err(EXIT_FAILURE, "Couldn't set tty(4) buffer size");
117 if (ioctl(fd, TIOCGQSIZE, &opt) == -1)
118 err(EXIT_FAILURE, "Couldn't get tty(4) buffer size");
120 errx(EXIT_FAILURE, "Wrong qsize %d != %d\n",
123 if (tcgetattr(fd, &tios) == -1)
124 err(EXIT_FAILURE, "tcgetattr()");
126 cfsetspeed(&tios, B921600);
127 if (tcsetattr(fd, TCSANOW, &tios) == -1)
128 err(EXIT_FAILURE, "tcsetattr()");
136 if ((fd = posix_openpt(O_RDWR)) == -1)
137 err(EXIT_FAILURE, "Couldn't pty(4) device");
139 if (grantpt(fd) == -1)
141 "Couldn't grant permissions on tty(4) device");
146 if (unlockpt(fd) == -1)
147 err(EXIT_FAILURE, "unlockpt()");
153 tty_open(const char *ttydev)
157 if ((fd = open(ttydev, O_RDWR, 0)) == -1)
158 err(EXIT_FAILURE, "Couldn't open tty(4) device");
160 #ifdef USE_PPP_DISCIPLINE
163 if (ioctl(fd, TIOCSETD, &opt) == -1)
165 "Couldn't set tty(4) discipline to PPP");
179 if ((opt = fcntl(fd, F_GETFL, NULL)) == -1)
180 err(EXIT_FAILURE, "fcntl()");
181 if (fcntl(fd, F_SETFL, opt | O_NONBLOCK) == -1)
182 err(EXIT_FAILURE, "fcntl()");
186 child_spawn(const char *ttydev)
193 if ((pid = fork()) == -1)
194 err(EXIT_FAILURE, "fork()");
200 (void)printf("child: started; open \"%s\"\n", ttydev);
201 tty = tty_open(ttydev);
205 (void)printf("child: TTY open, starting read loop\n");
214 (void)printf("child: polling\n");
215 if ((ret = poll(&pfd, 1, 2000)) == -1)
216 err(EXIT_FAILURE, "child: poll()");
219 if ((pfd.revents & POLLERR) != 0)
221 if ((pfd.revents & POLLIN) != 0) {
225 "child: attempting to read %zu"
226 " bytes\n", buffer_size);
227 if ((size = read(tty, dbuf, buffer_size))
231 err(EXIT_FAILURE, "child: read()");
233 if (qsize && size < qsize &&
234 (size_t)size < buffer_size)
235 errx(EXIT_FAILURE, "read returned %zd "
236 "less than the queue size %d",
240 "child: read %zd bytes from TTY\n",
250 (void)printf("child: closing TTY %zu\n", total);
253 (void)printf("child: exiting\n");
254 if (total != buffer_size * packets)
256 "Lost data %zu != %zu\n", total, buffer_size * packets);
263 usage(const char *msg)
267 (void) fprintf(stderr, "\n%s\n\n", msg);
269 (void)fprintf(stderr,
270 "Usage: %s [-v] [-q <qsize>] [-s <packetsize>] [-n <packets>]\n",
277 parse_args(int argc, char **argv)
281 while ((ch = getopt(argc, argv, "n:q:s:v")) != -1) {
284 packets = (size_t)atoi(optarg);
287 qsize = atoi(optarg);
290 buffer_size = (size_t)atoi(optarg);
300 if (buffer_size < 0 || buffer_size > 65536)
301 usage("-s must be between 0 and 65536");
302 if (packets < 1 || packets > 100)
303 usage("-p must be between 1 and 100");
307 main(int argc, char **argv)
310 parse_args(argc, argv);
316 ATF_TC(pty_no_queue);
318 ATF_TC_HEAD(pty_no_queue, tc)
320 atf_tc_set_md_var(tc, "descr", "Checks that writing to pty "
321 "does not lose data with the default queue size of 1024");
324 ATF_TC_BODY(pty_no_queue, tc)
332 ATF_TC_HEAD(pty_queue, tc)
334 atf_tc_set_md_var(tc, "descr", "Checks that writing to pty "
335 "does not lose data with the a queue size of 4096");
338 ATF_TC_BODY(pty_queue, tc)
346 ATF_TP_ADD_TC(tp, pty_no_queue);
347 ATF_TP_ADD_TC(tp, pty_queue);
349 return atf_no_error();