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