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 <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