1 /* $Id: t_pty.c,v 1.1 2011/09/24 15:53:01 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.1 2011/09/24 15:53:01 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 **);
38 #include "../h_macros.h"
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();