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 <fcntl.h> 33 #include <sys/wait.h> 34 #include <sys/poll.h> 35 36 /** LTP Port **/ 37 #include "test.h" 38 #include "safe_macros.h" 39 40 char *TCID = "hangup01"; /* Test program identifier. */ 41 int TST_TOTAL = 5; /* Total number of test cases. */ 42 /**************/ 43 44 /* 45 * pty master clone device 46 */ 47 #define MASTERCLONE "/dev/ptmx" 48 49 #define MESSAGE1 "I love Linux!" 50 #define MESSAGE2 "Use the LTP for all your Linux testing needs." 51 #define MESSAGE3 "For the latest version of the LTP tests, visit http://ltp.sourceforge.net" 52 53 #define NUMMESSAGES 3 54 55 #define BUFSZ 4096 56 57 void cleanup(void); 58 59 pid_t childpid; 60 61 void cleanup(void) 62 { 63 64 int status; 65 66 if (0 < childpid) { 67 68 /* If the PID is still alive... */ 69 if (kill(childpid, 0) == 0 || errno == ESRCH) { 70 71 /* KILL IT! */ 72 (void)kill(childpid, 15); 73 74 /* And take care of any leftover zombies. */ 75 if (waitpid(childpid, &status, WNOHANG) < 0) { 76 tst_resm(TWARN | TERRNO, 77 "waitpid(%d, ...) failed", childpid); 78 } 79 80 } 81 82 } 83 84 } 85 86 /* 87 * parent process for hangup test 88 */ 89 void parent(int masterfd, int childpid) 90 { 91 char buf[BUFSZ]; 92 struct pollfd pollfds[1]; 93 size_t len = strlen(MESSAGE1); 94 int hangupcount = 0; 95 int datacount = 0; 96 int status; 97 int i; 98 99 pollfds[0].fd = masterfd; 100 pollfds[0].events = POLLIN; 101 102 sleep(1); 103 104 while ((i = poll(pollfds, 1, -1)) == 1) { 105 if (read(masterfd, buf, len) == -1) { 106 ++hangupcount; 107 #ifdef DEBUG 108 tst_resm(TINFO, "hangup %d", hangupcount); 109 #endif 110 if (hangupcount == NUMMESSAGES) { 111 break; 112 } 113 } else { 114 ++datacount; 115 switch (datacount) { 116 case 1: 117 if (strncmp(buf, MESSAGE1, 118 strlen(MESSAGE1)) != 0) { 119 tst_brkm(TFAIL, cleanup, 120 "unexpected message 1"); 121 } 122 len = strlen(MESSAGE2); 123 break; 124 case 2: 125 if (strncmp(buf, MESSAGE2, 126 strlen(MESSAGE2)) != 0) { 127 tst_brkm(TFAIL, cleanup, 128 "unexpected message 2"); 129 } 130 len = strlen(MESSAGE3); 131 break; 132 case 3: 133 if (strncmp(buf, MESSAGE3, 134 strlen(MESSAGE3)) != 0) { 135 tst_brkm(TFAIL, cleanup, 136 "unexpected message 3"); 137 } 138 break; 139 default: 140 tst_brkm(TFAIL, cleanup, 141 "unexpected data message"); 142 143 } 144 } 145 } 146 if (i != 1) { 147 tst_brkm(TFAIL, cleanup, "poll"); 148 } 149 while (waitpid(childpid, &status, WNOHANG) < 0 && errno != ESRCH) ; 150 151 tst_resm((status == 0 ? TPASS : TFAIL), 152 "child process exited with status %d", status); 153 } 154 155 /* 156 * Child process for hangup test. Write three messages to the slave 157 * pty, with a hangup after each. 158 */ 159 int child(int masterfd) 160 { 161 int slavefd; 162 char *slavename; 163 164 if ((slavename = ptsname(masterfd)) == NULL) { 165 printf("ptsname[child] failed: %s\n", strerror(errno)); 166 return 1; 167 } 168 if ((slavefd = open(slavename, O_RDWR)) < 0) { 169 printf("open[1] failed: %s\n", strerror(errno)); 170 return 1; 171 } 172 if (write(slavefd, MESSAGE1, strlen(MESSAGE1)) != strlen(MESSAGE1)) { 173 printf("write failed: %s\n", strerror(errno)); 174 return 1; 175 } 176 if (close(slavefd) != 0) { 177 printf("close[1] failed: %s\n", strerror(errno)); 178 return 1; 179 } 180 if ((slavefd = open(slavename, O_RDWR)) < 0) { 181 printf("open[2] failed: %s\n", strerror(errno)); 182 return 1; 183 } 184 if (write(slavefd, MESSAGE2, strlen(MESSAGE2)) != strlen(MESSAGE2)) { 185 printf("write[2] failed: %s\n", strerror(errno)); 186 return 1; 187 } 188 if (close(slavefd) != 0) { 189 printf("close[2] failed: %s\n", strerror(errno)); 190 return 1; 191 } 192 if ((slavefd = open(slavename, O_RDWR)) < 0) { 193 printf("open[3] failed: %s\n", strerror(errno)); 194 return 1; 195 } 196 if (write(slavefd, MESSAGE3, strlen(MESSAGE3)) != strlen(MESSAGE3)) { 197 printf("write[3] failed: %s\n", strerror(errno)); 198 return 1; 199 } 200 if (close(slavefd) != 0) { 201 printf("close[3] failed: %s\n", strerror(errno)); 202 return 1; 203 } 204 return 0; 205 } 206 207 /* 208 * main test driver 209 */ 210 int main(int argc, char **argv) 211 { 212 int masterfd; /* master pty fd */ 213 char *slavename; 214 pid_t childpid; 215 216 /*--------------------------------------------------------------------*/ 217 masterfd = SAFE_OPEN(NULL, MASTERCLONE, O_RDWR); 218 219 slavename = ptsname(masterfd); 220 if (slavename == NULL) 221 tst_brkm(TBROK | TERRNO, NULL, "ptsname"); 222 223 if (grantpt(masterfd) != 0) 224 tst_brkm(TBROK | TERRNO, NULL, "grantpt"); 225 226 if (unlockpt(masterfd) != 0) 227 tst_brkm(TBROK | TERRNO, NULL, "unlockpt"); 228 229 childpid = fork(); 230 if (childpid == -1) 231 tst_brkm(TBROK | TERRNO, NULL, "fork"); 232 else if (childpid == 0) 233 exit(child(masterfd)); 234 else 235 parent(masterfd, childpid); 236 /*--------------------------------------------------------------------*/ 237 cleanup(); 238 239 tst_exit(); 240 } 241