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