xref: /third_party/ltp/testcases/kernel/pty/ptem01.c (revision f08c3bdf)
1/*
2 *   Copyright (c) International Business Machines  Corp., 2002
3 *   Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
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 <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
38char *TCID = "ptem01";		/* Test program identifier.    */
39int 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 */
52int 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 */
130int 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 */
211int 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 */
259int 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 */
315int 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 */
378int 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 */
429int 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