Home | History | Annotate | Download | only in pty
      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