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