1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2002 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 12/24/2002 Port to LTP robbiew (at) us.ibm.com */ 21 /* 06/30/2001 Port to Linux nsharoff (at) us.ibm.com */ 22 23 #ifndef _GNU_SOURCE 24 #define _GNU_SOURCE 1 25 #endif 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <errno.h> 31 #include <signal.h> 32 #include <sys/fcntl.h> 33 #include <sys/wait.h> 34 #include <sys/poll.h> 35 36 /** LTP Port **/ 37 #include "test.h" 38 39 char *TCID = "hangup01"; /* Test program identifier. */ 40 int TST_TOTAL = 5; /* Total number of test cases. */ 41 /**************/ 42 43 /* 44 * pty master clone device 45 */ 46 #define MASTERCLONE "/dev/ptmx" 47 48 #define MESSAGE1 "I love Linux!" 49 #define MESSAGE2 "Use the LTP for all your Linux testing needs." 50 #define MESSAGE3 "For the latest version of the LTP tests, visit http://ltp.sourceforge.net" 51 52 #define NUMMESSAGES 3 53 54 #define BUFSZ 4096 55 56 void cleanup(void); 57 58 pid_t childpid; 59 60 void cleanup(void) 61 { 62 63 int status; 64 65 if (0 < childpid) { 66 67 /* If the PID is still alive... */ 68 if (kill(childpid, 0) == 0 || errno == ESRCH) { 69 70 /* KILL IT! */ 71 (void)kill(childpid, 15); 72 73 /* And take care of any leftover zombies. */ 74 if (waitpid(childpid, &status, WNOHANG) < 0) { 75 tst_resm(TWARN | TERRNO, 76 "waitpid(%d, ...) failed", childpid); 77 } 78 79 } 80 81 } 82 83 } 84 85 /* 86 * parent process for hangup test 87 */ 88 void parent(int masterfd, int childpid) 89 { 90 char buf[BUFSZ]; 91 struct pollfd pollfds[1]; 92 size_t len = strlen(MESSAGE1); 93 int hangupcount = 0; 94 int datacount = 0; 95 int status; 96 int i; 97 98 pollfds[0].fd = masterfd; 99 pollfds[0].events = POLLIN; 100 101 sleep(1); 102 103 while ((i = poll(pollfds, 1, -1)) == 1) { 104 if (read(masterfd, buf, len) == -1) { 105 ++hangupcount; 106 #ifdef DEBUG 107 tst_resm(TINFO, "hangup %d", hangupcount); 108 #endif 109 if (hangupcount == NUMMESSAGES) { 110 break; 111 } 112 } else { 113 ++datacount; 114 switch (datacount) { 115 case 1: 116 if (strncmp(buf, MESSAGE1, 117 strlen(MESSAGE1)) != 0) { 118 tst_brkm(TFAIL, cleanup, 119 "unexpected message 1"); 120 } 121 len = strlen(MESSAGE2); 122 break; 123 case 2: 124 if (strncmp(buf, MESSAGE2, 125 strlen(MESSAGE2)) != 0) { 126 tst_brkm(TFAIL, cleanup, 127 "unexpected message 2"); 128 } 129 len = strlen(MESSAGE3); 130 break; 131 case 3: 132 if (strncmp(buf, MESSAGE3, 133 strlen(MESSAGE3)) != 0) { 134 tst_brkm(TFAIL, cleanup, 135 "unexpected message 3"); 136 } 137 break; 138 default: 139 tst_brkm(TFAIL, cleanup, 140 "unexpected data message"); 141 142 } 143 } 144 } 145 if (i != 1) { 146 tst_brkm(TFAIL, cleanup, "poll"); 147 } 148 while (waitpid(childpid, &status, WNOHANG) < 0 && errno != ESRCH) ; 149 150 tst_resm((status == 0 ? TPASS : TFAIL), 151 "child process exited with status %d", status); 152 } 153 154 /* 155 * Child process for hangup test. Write three messages to the slave 156 * pty, with a hangup after each. 157 */ 158 int child(int masterfd) 159 { 160 int slavefd; 161 char *slavename; 162 163 if ((slavename = ptsname(masterfd)) == NULL) { 164 printf("ptsname[child] failed: %s\n", strerror(errno)); 165 return 1; 166 } 167 if ((slavefd = open(slavename, O_RDWR)) < 0) { 168 printf("open[1] failed: %s\n", strerror(errno)); 169 return 1; 170 } 171 if (write(slavefd, MESSAGE1, strlen(MESSAGE1)) != strlen(MESSAGE1)) { 172 printf("write failed: %s\n", strerror(errno)); 173 return 1; 174 } 175 if (close(slavefd) != 0) { 176 printf("close[1] failed: %s\n", strerror(errno)); 177 return 1; 178 } 179 if ((slavefd = open(slavename, O_RDWR)) < 0) { 180 printf("open[2] failed: %s\n", strerror(errno)); 181 return 1; 182 } 183 if (write(slavefd, MESSAGE2, strlen(MESSAGE2)) != strlen(MESSAGE2)) { 184 printf("write[2] failed: %s\n", strerror(errno)); 185 return 1; 186 } 187 if (close(slavefd) != 0) { 188 printf("close[2] failed: %s\n", strerror(errno)); 189 return 1; 190 } 191 if ((slavefd = open(slavename, O_RDWR)) < 0) { 192 printf("open[3] failed: %s\n", strerror(errno)); 193 return 1; 194 } 195 if (write(slavefd, MESSAGE3, strlen(MESSAGE3)) != strlen(MESSAGE3)) { 196 printf("write[3] failed: %s\n", strerror(errno)); 197 return 1; 198 } 199 if (close(slavefd) != 0) { 200 printf("close[3] failed: %s\n", strerror(errno)); 201 return 1; 202 } 203 return 0; 204 } 205 206 /* 207 * main test driver 208 */ 209 int main(int argc, char **argv) 210 { 211 int masterfd; /* master pty fd */ 212 char *slavename; 213 pid_t childpid; 214 215 /*--------------------------------------------------------------------*/ 216 masterfd = open(MASTERCLONE, O_RDWR); 217 if (masterfd < 0) 218 tst_brkm(TBROK | TERRNO, NULL, "open %s", MASTERCLONE); 219 220 slavename = ptsname(masterfd); 221 if (slavename == NULL) 222 tst_brkm(TBROK | TERRNO, NULL, "ptsname"); 223 224 if (grantpt(masterfd) != 0) 225 tst_brkm(TBROK | TERRNO, NULL, "grantpt"); 226 227 if (unlockpt(masterfd) != 0) 228 tst_brkm(TBROK | TERRNO, NULL, "unlockpt"); 229 230 childpid = fork(); 231 if (childpid == -1) 232 tst_brkm(TBROK | TERRNO, NULL, "fork"); 233 else if (childpid == 0) 234 exit(child(masterfd)); 235 else 236 parent(masterfd, childpid); 237 /*--------------------------------------------------------------------*/ 238 cleanup(); 239 240 tst_exit(); 241 } 242