xref: /aosp_15_r20/external/ltp/testcases/kernel/pty/ptem01.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 /*
2  *   Copyright (c) International Business Machines  Corp., 2002
3  *   Copyright (c) 2020 Petr Vorel <[email protected]>
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     [email protected] */
21 /* 06/30/2001   Port to Linux   [email protected] */
22 
23 #define _GNU_SOURCE
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <termios.h>
29 #include <fcntl.h>
30 #include <sys/stat.h>
31 #include <sys/poll.h>
32 #include <sys/types.h>
33 
34 #include "test.h"
35 #include "safe_macros.h"
36 #include "lapi/ioctl.h"
37 
38 char *TCID = "ptem01";		/* Test program identifier.    */
39 int TST_TOTAL = 6;		/* Total number of test cases. */
40 /**************/
41 
42 /*
43  * pty master clone device
44  */
45 #define MASTERCLONE "/dev/ptmx"
46 
47 #define BUFSZ 4096
48 
49 /*
50  * test termio/termios ioctls
51  */
test1(void)52 int test1(void)
53 {
54 	int masterfd, slavefd;
55 	char *slavename;
56 	struct termio termio;
57 	struct termios termios;
58 
59 	masterfd = SAFE_OPEN(NULL, MASTERCLONE, O_RDWR);
60 
61 	slavename = ptsname(masterfd);
62 	if (slavename == NULL) {
63 		tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed");
64 	}
65 
66 	if (grantpt(masterfd) != 0) {
67 		tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed");
68 	}
69 
70 	if (unlockpt(masterfd) != 0) {
71 		tst_brkm(TBROK, NULL, "unlockpt() call failed");
72 	}
73 
74 	if ((slavefd = open(slavename, O_RDWR)) < 0) {
75 		tst_brkm(TFAIL, NULL, "Could not open %s", slavename);
76 	}
77 
78 	if (ioctl(slavefd, TCGETS, &termios) != 0) {
79 		tst_brkm(TFAIL, NULL, "TCGETS");
80 	}
81 
82 	if (ioctl(slavefd, TCSETS, &termios) != 0) {
83 		tst_brkm(TFAIL, NULL, "TCSETS");
84 	}
85 
86 	if (ioctl(slavefd, TCSETSW, &termios) != 0) {
87 		tst_brkm(TFAIL, NULL, "TCSETSW");
88 	}
89 
90 	if (ioctl(slavefd, TCSETSF, &termios) != 0) {
91 		tst_brkm(TFAIL, NULL, "TCSETSF");
92 	}
93 
94 	if (ioctl(slavefd, TCSETS, &termios) != 0) {
95 		tst_brkm(TFAIL, NULL, "TCSETS");
96 	}
97 
98 	if (ioctl(slavefd, TCGETA, &termio) != 0) {
99 		tst_brkm(TFAIL, NULL, "TCGETA");
100 	}
101 
102 	if (ioctl(slavefd, TCSETA, &termio) != 0) {
103 		tst_brkm(TFAIL, NULL, "TCSETA");
104 	}
105 
106 	if (ioctl(slavefd, TCSETAW, &termio) != 0) {
107 		tst_brkm(TFAIL, NULL, "TCSETAW");
108 	}
109 
110 	if (ioctl(slavefd, TCSETAF, &termio) != 0) {
111 		tst_brkm(TFAIL, NULL, "TCSETAF");
112 	}
113 
114 	if (close(slavefd) != 0) {
115 		tst_brkm(TBROK, NULL, "close slave");
116 	}
117 
118 	if (close(masterfd) != 0) {
119 		tst_brkm(TBROK, NULL, "close master");
120 	}
121 	tst_resm(TPASS, "test1");
122 
123 	/** NOT REACHED **/
124 	return 0;
125 }
126 
127 /*
128  * test window size setting and getting
129  */
test2(void)130 int test2(void)
131 {
132 	int masterfd, slavefd;
133 	char *slavename;
134 	struct winsize wsz;
135 	struct winsize wsz1 = { 24, 80, 5, 10 };
136 	struct winsize wsz2 = { 60, 100, 11, 777 };
137 
138 	masterfd = SAFE_OPEN(NULL, MASTERCLONE, O_RDWR);
139 
140 	slavename = ptsname(masterfd);
141 	if (slavename == NULL) {
142 		tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed");
143 	}
144 
145 	if (grantpt(masterfd) != 0) {
146 		tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed");
147 	}
148 
149 	if (unlockpt(masterfd) != 0) {
150 		tst_brkm(TBROK, NULL, "unlockpt() call failed");
151 	}
152 
153 	if ((slavefd = open(slavename, O_RDWR)) < 0) {
154 		tst_brkm(TBROK, NULL, "Could not open %s", slavename);
155 	}
156 
157 	if (ioctl(masterfd, TIOCSWINSZ, &wsz1) != 0) {
158 		tst_brkm(TFAIL, NULL, "TIOCSWINSZ");
159 	}
160 
161 	if (ioctl(slavefd, TIOCGWINSZ, &wsz) != 0) {
162 		tst_brkm(TFAIL, NULL, "TIOCGWINSZ");
163 	}
164 
165 	if (wsz.ws_row != wsz1.ws_row || wsz.ws_col != wsz1.ws_col ||
166 	    wsz.ws_xpixel != wsz1.ws_xpixel ||
167 	    wsz.ws_ypixel != wsz1.ws_ypixel) {
168 		tst_brkm(TFAIL, NULL, "unexpected window size returned");
169 	}
170 
171 	if (ioctl(masterfd, TIOCGWINSZ, &wsz) != 0) {
172 		tst_brkm(TFAIL, NULL, "TIOCGWINSZ");
173 	}
174 
175 	if (wsz.ws_row != wsz1.ws_row || wsz.ws_col != wsz1.ws_col ||
176 	    wsz.ws_xpixel != wsz1.ws_xpixel ||
177 	    wsz.ws_ypixel != wsz1.ws_ypixel) {
178 		tst_brkm(TFAIL, NULL, "unexpected window size returned");
179 	}
180 
181 	if (ioctl(slavefd, TIOCSWINSZ, &wsz2) != 0) {
182 		tst_brkm(TFAIL, NULL, "TIOCSWINSZ");
183 	}
184 
185 	if (ioctl(slavefd, TIOCGWINSZ, &wsz) != 0) {
186 		tst_brkm(TFAIL, NULL, "TIOCGWINSZ");
187 	}
188 
189 	if (wsz.ws_row != wsz2.ws_row || wsz.ws_col != wsz2.ws_col ||
190 	    wsz.ws_xpixel != wsz2.ws_xpixel ||
191 	    wsz.ws_ypixel != wsz2.ws_ypixel) {
192 		tst_brkm(TFAIL, NULL, "unexpected window size returned");
193 	}
194 
195 	if (close(slavefd) != 0) {
196 		tst_brkm(TBROK, NULL, "close");
197 	}
198 
199 	if (close(masterfd) != 0) {
200 		tst_brkm(TBROK, NULL, "close");
201 	}
202 	tst_resm(TPASS, "test2");
203 
204 	/** NOT REACHED **/
205 	return 0;
206 }
207 
208 /*
209  * test sending a break
210  */
test3(void)211 int test3(void)
212 {
213 	int masterfd, slavefd;
214 	char *slavename;
215 
216 	masterfd = SAFE_OPEN(NULL, MASTERCLONE, O_RDWR);
217 
218 	slavename = ptsname(masterfd);
219 	if (slavename == NULL) {
220 		tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed");
221 	}
222 
223 	if (grantpt(masterfd) != 0) {
224 		tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed");
225 	}
226 
227 	if (unlockpt(masterfd) != 0) {
228 		tst_brkm(TBROK, NULL, "unlockpt() call failed");
229 	}
230 
231 	if ((slavefd = open(slavename, O_RDWR)) < 0) {
232 		tst_brkm(TBROK, NULL, "Could not open %s", slavename);
233 	}
234 
235 	if (tcsendbreak(masterfd, 10) != 0) {
236 		tst_brkm(TFAIL, NULL, "tcsendbreak");
237 	}
238 
239 	if (tcsendbreak(slavefd, 10) != 0) {
240 		tst_brkm(TFAIL, NULL, "tcsendbreak");
241 	}
242 
243 	if (close(slavefd) != 0) {
244 		tst_brkm(TBROK, NULL, "close slave");
245 	}
246 
247 	if (close(masterfd) != 0) {
248 		tst_brkm(TBROK, NULL, "close master");
249 	}
250 	tst_resm(TPASS, "test3");
251 
252 	/** NOT REACHED **/
253 	return 0;
254 }
255 
256 /*
257  * test multiple opens of slave side
258  */
test4(void)259 int test4(void)
260 {
261 	int masterfd, slavefd, slavefd2, slavefd3;
262 	char *slavename;
263 
264 	masterfd = SAFE_OPEN(NULL, MASTERCLONE, O_RDWR);
265 
266 	slavename = ptsname(masterfd);
267 	if (slavename == NULL) {
268 		tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed");
269 	}
270 
271 	if (grantpt(masterfd) != 0) {
272 		tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed");
273 	}
274 
275 	if (unlockpt(masterfd) != 0) {
276 		tst_brkm(TBROK, NULL, "unlockpt() call failed");
277 	}
278 
279 	if ((slavefd = open(slavename, O_RDWR)) < 0) {
280 		tst_brkm(TBROK, NULL, "Could not open %s", slavename);
281 	}
282 
283 	if ((slavefd2 = open(slavename, O_RDWR)) < 0) {
284 		tst_brkm(TFAIL, NULL, "Could not open %s (again)", slavename);
285 	}
286 
287 	if ((slavefd3 = open(slavename, O_RDWR)) < 0) {
288 		tst_brkm(TFAIL, NULL, "Could not open %s (once more)",
289 			 slavename);
290 	}
291 
292 	if (close(slavefd) != 0) {
293 		tst_brkm(TBROK, NULL, "close slave");
294 	}
295 	if (close(slavefd2) != 0) {
296 		tst_brkm(TBROK, NULL, "close slave again");
297 	}
298 	if (close(slavefd3) != 0) {
299 		tst_brkm(TBROK, NULL, "close slave once more");
300 	}
301 	if (close(masterfd) != 0) {
302 		tst_brkm(TBROK, NULL, "close master");
303 	}
304 	tst_resm(TPASS, "test4");
305 
306 	/** NOT REACHED **/
307 	return 0;
308 }
309 
310 #define NUMOPENS 6
311 
312 /*
313  * test several simultaneous opens
314  */
test5(void)315 int test5(void)
316 {
317 	static int masterfd[NUMOPENS];
318 	static int slavefd[NUMOPENS];
319 	char *slavename;
320 	int i;
321 
322 	for (i = 0; i < NUMOPENS; ++i) {
323 		masterfd[i] = open(MASTERCLONE, O_RDWR);
324 		if (masterfd[i] < 0) {
325 			tst_resm(TBROK, "%s", MASTERCLONE);
326 			tst_resm(TBROK, "out of ptys");
327 			for (i = 0; i < NUMOPENS; ++i) {
328 				if (masterfd[i] != 0) {
329 					(void)close(masterfd[i]);
330 				}
331 				if (slavefd[i] != 0) {
332 					(void)close(slavefd[i]);
333 				}
334 			}
335 			tst_exit();
336 		}
337 
338 		slavename = ptsname(masterfd[i]);
339 		if (slavename == NULL) {
340 			tst_brkm(TBROK | TERRNO, NULL,
341 				 "ptsname() call failed");
342 		}
343 
344 		if (grantpt(masterfd[i]) != 0) {
345 			tst_brkm(TBROK | TERRNO, NULL,
346 				 "grantpt() call failed");
347 		}
348 
349 		if (unlockpt(masterfd[i]) != 0) {
350 			tst_brkm(TBROK, NULL, "unlockpt() call failed");
351 		}
352 
353 		if ((slavefd[i] = open(slavename, O_RDWR)) < 0) {
354 			tst_brkm(TFAIL, NULL,
355 				 "Iteration %d: Could not open %s", i,
356 				 slavename);
357 		}
358 
359 	}
360 
361 	for (i = 0; i < NUMOPENS; ++i) {
362 		if (close(slavefd[i]) != 0) {
363 			tst_brkm(TBROK, NULL, "Iteration %d: close slave", i);
364 		}
365 		if (close(masterfd[i]) != 0) {
366 			tst_brkm(TBROK, NULL, "close master");
367 		}
368 	}
369 	tst_resm(TPASS, "test5");
370 
371 	/** NOT REACHED **/
372 	return 0;
373 }
374 
375 /*
376  * test hangup semantics
377  */
test6(void)378 int test6(void)
379 {
380 	static int masterfd;
381 	static int slavefd;
382 	char *slavename;
383 	struct termios termios;
384 
385 	masterfd = SAFE_OPEN(NULL, MASTERCLONE, O_RDWR);
386 
387 	slavename = ptsname(masterfd);
388 	if (slavename == NULL) {
389 		tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed");
390 	}
391 
392 	if (grantpt(masterfd) != 0) {
393 		tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed");
394 	}
395 
396 	if (unlockpt(masterfd) != 0) {
397 		tst_brkm(TBROK, NULL, "unlockpt() call failed");
398 	}
399 
400 	if ((slavefd = open(slavename, O_RDWR)) < 0) {
401 		tst_brkm(TBROK, NULL, "Could not open %s", slavename);
402 	}
403 
404 	if (ioctl(slavefd, TCGETS, &termios) != 0) {
405 		tst_brkm(TFAIL, NULL, "TCGETS");
406 	}
407 
408 	termios.c_cflag &= ~CBAUD;
409 	termios.c_cflag |= B0 & CBAUD;
410 	if (ioctl(slavefd, TCSETS, &termios) != 0) {
411 		tst_brkm(TFAIL, NULL, "TCGETS");
412 	}
413 
414 	if (close(slavefd) != 0) {
415 		tst_brkm(TBROK, NULL, "close");
416 	}
417 	if (close(masterfd) != 0) {
418 		tst_brkm(TBROK, NULL, "close");
419 	}
420 	tst_resm(TPASS, "test6");
421 
422 	/** NOT REACHED **/
423 	return 0;
424 }
425 
426 /*
427  * main test driver
428  */
main(void)429 int main(void)
430 {
431 	test1();
432 	test2();
433 	test3();
434 	test4();
435 	test5();
436 	test6();
437 	/*
438 	 * all done
439 	 */
440 	tst_exit();
441 }
442