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