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