• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/23/2002	Port to LTP	robbiew@us.ibm.com */
21 /* 06/30/2001	Port to Linux	nsharoff@us.ibm.com */
22 
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE 1
25 #endif
26 
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <sys/wait.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <termio.h>
36 #include <unistd.h>
37 
38 /** LTP Port **/
39 #include "test.h"
40 
41 char *TCID = "pty01";		/* Test program identifier.    */
42 int TST_TOTAL = 5;		/* Total number of test cases. */
43 /**************/
44 
45 /*
46  * pty master clone device
47  */
48 #define MASTERCLONE "/dev/ptmx"
49 
50 /*
51  * string for testing read/write on ptys
52  */
53 #define STRING "Linux Test Project\n"
54 
55 /*
56  * test buffer size
57  */
58 #define TESTSIZE 1024
59 
60 /*
61  * mode we expect grantpt() to leave pty as
62  */
63 #define PTY_MODE 020622
64 
65 /*
66  * number of procs for parallel test
67  */
68 #define NUMPROCS 15
69 
70 /*
71  * test slave locking
72  */
test1(void)73 static int test1(void)
74 {
75 	int masterfd;		/* master pty fd */
76 	int slavefd;		/* slave pty fd */
77 	char *slavename;
78 	struct stat st;
79 	char buf[TESTSIZE];
80 
81 	masterfd = open(MASTERCLONE, O_RDWR);
82 	if (masterfd < 0) {
83 		tst_brkm(TBROK | TERRNO, NULL, MASTERCLONE);
84 	}
85 
86 	slavename = ptsname(masterfd);
87 	if (slavename == NULL) {
88 		tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed");
89 	}
90 
91 	if (grantpt(masterfd) != 0) {
92 		tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed");
93 	}
94 
95 	if (stat(slavename, &st) != 0) {
96 		tst_brkm(TBROK | TERRNO, NULL, "stat(%s) failed", slavename);
97 	}
98 	if (st.st_uid != getuid()) {
99 		tst_brkm(TBROK, NULL, "uid mismatch");
100 	}
101 
102 	if (st.st_mode != (S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP)) {
103 		tst_brkm(TBROK, NULL, "mode mismatch (mode=%o)", st.st_mode);
104 	}
105 
106 	slavefd = open(slavename, O_RDWR);
107 	if (slavefd >= 0) {
108 		tst_brkm(TBROK, NULL, "open didn't fail as expected!");
109 	}
110 
111 	if (unlockpt(masterfd) != 0) {
112 		tst_brkm(TBROK | TERRNO, NULL, "unlockpt() failed");
113 	}
114 
115 	slavefd = open(slavename, O_RDWR);
116 	if (slavefd < 0) {
117 		tst_brkm(TBROK, NULL, "Could not open %s", slavename);
118 	}
119 
120 	/*
121 	 * test writing to the master / reading from the slave
122 	 */
123 	if (write(masterfd, STRING, strlen(STRING)) != strlen(STRING)) {
124 		/*
125 		 * XXX: the errno printout might be garbage, but better to be
126 		 * safe than sorry..
127 		 */
128 		tst_brkm(TFAIL | TERRNO, NULL, "write to master");
129 	}
130 
131 	if (read(slavefd, buf, strlen(STRING)) != strlen(STRING)) {
132 		/* XXX: Same as write above.. */
133 		tst_brkm(TFAIL | TERRNO, NULL, "read from slave");
134 	}
135 	if (strncmp(STRING, buf, strlen(STRING) - 1) != 0) {
136 		tst_brkm(TFAIL, NULL,
137 			 "strings are different (STRING = '%s' != buf = '%s')",
138 			 STRING, buf);
139 	}
140 
141 	/*
142 	 * test writing to the slave / reading from the master
143 	 */
144 	if (write(slavefd, STRING, strlen(STRING)) != strlen(STRING)) {
145 		/* XXX: Same as write above.. */
146 		tst_brkm(TFAIL | TERRNO, NULL, "write to slave");
147 	}
148 
149 	if (read(masterfd, buf, strlen(STRING)) != strlen(STRING)) {
150 		/* XXX: Same as write above.. */
151 		tst_brkm(TFAIL | TERRNO, NULL, "read from master");
152 	}
153 	if (strncmp(STRING, buf, strlen(STRING) - 1) != 0) {
154 		tst_brkm(TFAIL, NULL,
155 			 "strings are different (STRING = '%s' != buf = '%s').",
156 			 STRING, buf);
157 	}
158 
159 	/*
160 	 * try an invalid ioctl on the slave...
161 	 */
162 	if (ioctl(slavefd, TIOCGWINSZ, NULL) == 0) {
163 		tst_brkm(TFAIL, NULL,
164 			 "invalid slave TIOCGWINSZ ioctl succeeded.. it should "
165 			 "have failed");
166 	}
167 
168 	/*
169 	 * try an invalid ioctl on the master...
170 	 */
171 	if (ioctl(masterfd, TIOCGWINSZ, NULL) == 0) {
172 		tst_brkm(TFAIL, NULL,
173 			 "invalid master TIOCGWINSZ ioctl succeeded.. it should "
174 			 "have failed");
175 	}
176 
177 	/*
178 	 * close pty fds
179 	 */
180 	if (close(slavefd) != 0) {
181 		tst_brkm(TBROK | TERRNO, NULL, "close of slave");
182 	}
183 	if (close(masterfd) != 0) {
184 		tst_brkm(TBROK | TERRNO, NULL, "close of master");
185 	}
186 	tst_resm(TPASS, "test1");
187 	/** NOTREACHED **/
188 	return 0;
189 }
190 
191 /*
192  * test slave operations with closed master
193  */
test2(void)194 static void test2(void)
195 {
196 	int masterfd;		/* master pty fd */
197 	int slavefd;		/* slave pty fd */
198 	int i;
199 	char *slavename;
200 	char c;
201 
202 	masterfd = open(MASTERCLONE, O_RDWR);
203 	if (masterfd < 0) {
204 		tst_brkm(TBROK | TERRNO, NULL, MASTERCLONE);
205 	}
206 
207 	slavename = ptsname(masterfd);
208 	if (slavename == NULL) {
209 		tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed");
210 	}
211 
212 	if (grantpt(masterfd) != 0) {
213 		tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed");
214 	}
215 
216 	if (unlockpt(masterfd) != 0) {
217 		tst_brkm(TBROK | TERRNO, NULL, "unlockpt() call failed");
218 	}
219 
220 	slavefd = open(slavename, O_RDWR);
221 	if (slavefd < 0) {
222 		tst_brkm(TBROK | TERRNO, NULL, "Could not open %s", slavename);
223 	}
224 
225 	/*
226 	 * close pty fds.  See what happens when we close the master
227 	 * first.
228 	 */
229 	if (close(masterfd) != 0) {
230 		tst_brkm(TBROK | TERRNO, NULL, "close()");
231 	}
232 
233 	errno = 0;
234 	if ((i = read(slavefd, &c, 1)) == 1) {
235 		tst_brkm(TFAIL, NULL,
236 			 "reading from slave fd should have failed, but didn't"
237 			 "(read '%c')", c);
238 	}
239 
240 	if ((i = write(slavefd, &c, 1)) == 1) {
241 		tst_brkm(TFAIL, NULL,
242 			 "writing to slave fd should have failed, but didn't");
243 	}
244 
245 	if (ioctl(slavefd, TIOCGWINSZ, NULL) == 0) {
246 		tst_brkm(TFAIL, NULL,
247 			 "trying TIOCGWINSZ on slave fd should have failed, "
248 			 "but didn't");
249 	}
250 
251 	if (close(slavefd) != 0) {
252 		tst_brkm(TBROK, NULL, "close");
253 	}
254 	tst_resm(TPASS, "test2");
255 }
256 
257 /*
258  * test operations on master with closed slave
259  */
test3(void)260 static void test3(void)
261 {
262 	int masterfd;		/* master pty fd */
263 
264 	masterfd = open(MASTERCLONE, O_RDWR);
265 	if (masterfd < 0) {
266 		tst_brkm(TBROK, NULL, MASTERCLONE);
267 	}
268 
269 	if (ioctl(masterfd, TIOCGWINSZ, NULL) == 0) {
270 		tst_brkm(TFAIL | TERRNO, NULL,
271 			 "trying TIOCGWINSZ on master with no open slave "
272 			 "succeeded unexpectedly");
273 	}
274 	tst_resm(TPASS, "test3");
275 }
276 
277 /*
278  * test multiple opens on slave side of pty
279  */
test4(void)280 static void test4(void)
281 {
282 	int masterfd;		/* master pty fd */
283 	int slavefd;		/* slave pty fd */
284 	int slavefd2;
285 	int slavefd3;
286 	char *slavename;
287 
288 	masterfd = open(MASTERCLONE, O_RDWR);
289 	if (masterfd < 0) {
290 		tst_brkm(TBROK, NULL, "%s", MASTERCLONE);
291 	}
292 
293 	slavename = ptsname(masterfd);
294 	if (slavename == NULL) {
295 		tst_brkm(TBROK, NULL, "ptsname() call failed");
296 	}
297 
298 	if (grantpt(masterfd) != 0) {
299 		tst_brkm(TBROK, NULL, "grantpt() call failed");
300 	}
301 
302 	if (unlockpt(masterfd) != 0) {
303 		tst_brkm(TBROK | TERRNO, NULL, "unlockpt() call failed");
304 	}
305 
306 	slavefd = open(slavename, O_RDWR);
307 	if (slavefd < 0) {
308 		tst_brkm(TBROK | TERRNO, NULL, "Could not open %s", slavename);
309 	}
310 
311 	slavefd2 = open(slavename, O_RDWR);
312 	if (slavefd < 0) {
313 		tst_brkm(TFAIL | TERRNO, NULL, "Could not open %s (again)",
314 			 slavename);
315 	}
316 
317 	slavefd3 = open(slavename, O_RDWR);
318 	if (slavefd < 0) {
319 		tst_brkm(TFAIL | TERRNO, NULL, "Could not open %s (once more)",
320 			 slavename);
321 	}
322 
323 	/*
324 	 * close pty fds.
325 	 */
326 	if (close(slavefd) != 0) {
327 		tst_brkm(TBROK | TERRNO, NULL, "close slave");
328 	}
329 
330 	if (close(slavefd2) != 0) {
331 		tst_brkm(TBROK, NULL, "close slave again");
332 	}
333 
334 	if (close(slavefd3) != 0) {
335 		tst_brkm(TBROK, NULL, "close slave once more");
336 	}
337 
338 	if (close(masterfd) != 0) {
339 		tst_brkm(TBROK, NULL, "close master");
340 	}
341 	tst_resm(TPASS, "test4");
342 }
343 
344 /*
345  * test opening/closing lots of ptys in parallel.  We may run out
346  * of ptys for this test depending on how the system is configured,
347  * but that's not a fatal error.
348  */
test5(void)349 static void test5(void)
350 {
351 	int masterfd;		/* master pty fd */
352 	char *slavename;
353 	int status;
354 	int i;
355 
356 	for (i = 0; i < NUMPROCS; ++i) {
357 		switch (fork()) {
358 		case -1:
359 			tst_brkm(TBROK, NULL, "fork()");
360 			break;
361 		case 0:
362 			masterfd = open(MASTERCLONE, O_RDWR);
363 			if (masterfd < 0) {
364 				printf("proc %d: opening %s failed: %s",
365 				       i, MASTERCLONE, strerror(errno));
366 				exit(1);
367 			}
368 			if (grantpt(masterfd) != 0) {
369 				printf("proc %d: grantpt() call failed: %s",
370 				       i, strerror(errno));
371 				exit(1);
372 			}
373 			slavename = ptsname(masterfd);
374 			if (slavename == NULL) {
375 				printf("proc %d: ptsname() call failed: %s",
376 				       i, strerror(errno));
377 				exit(1);
378 			}
379 			sleep(10);
380 			if (close(masterfd) != 0) {
381 				printf("proc %d: close failed: %s",
382 				       i, strerror(errno));
383 				exit(1);
384 			}
385 			exit(0);
386 		default:
387 			break;
388 		}
389 	}
390 	while (wait(&status) > 0) {
391 		if (status) {
392 			tst_brkm(TFAIL, NULL,
393 				 "child exited with non-zero status %d",
394 				 status);
395 		}
396 	}
397 	tst_resm(TPASS, "test5");
398 }
399 
400 /*
401  * main test driver
402  */
main(int argc,char ** argv)403 int main(int argc, char **argv)
404 {
405 	test1();
406 	test2();
407 	test3();
408 	test4();
409 	test5();
410 
411 	/*
412 	 * all done
413 	 */
414 	tst_exit();
415 }
416