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 */ 36 static void sigalrm(int signo) 37 { 38 /* just return */ 39 return; 40 } 41 42 int 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