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