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 #ifndef _GNU_SOURCE 24 #define _GNU_SOURCE 1 25 #endif 26 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 #include <sys/wait.h> 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <termio.h> 36 #include <unistd.h> 37 38 /** LTP Port **/ 39 #include "test.h" 40 41 char *TCID = "pty01"; /* Test program identifier. */ 42 int TST_TOTAL = 5; /* Total number of test cases. */ 43 /**************/ 44 45 /* 46 * pty master clone device 47 */ 48 #define MASTERCLONE "/dev/ptmx" 49 50 /* 51 * string for testing read/write on ptys 52 */ 53 #define STRING "Linux Test Project\n" 54 55 /* 56 * test buffer size 57 */ 58 #define TESTSIZE 1024 59 60 /* 61 * mode we expect grantpt() to leave pty as 62 */ 63 #define PTY_MODE 020622 64 65 /* 66 * number of procs for parallel test 67 */ 68 #define NUMPROCS 15 69 70 /* 71 * test slave locking 72 */ 73 static int test1(void) 74 { 75 int masterfd; /* master pty fd */ 76 int slavefd; /* slave pty fd */ 77 char *slavename; 78 struct stat st; 79 char buf[TESTSIZE]; 80 81 masterfd = open(MASTERCLONE, O_RDWR); 82 if (masterfd < 0) { 83 tst_brkm(TBROK | TERRNO, NULL, MASTERCLONE); 84 } 85 86 slavename = ptsname(masterfd); 87 if (slavename == NULL) { 88 tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed"); 89 } 90 91 if (grantpt(masterfd) != 0) { 92 tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed"); 93 } 94 95 if (stat(slavename, &st) != 0) { 96 tst_brkm(TBROK | TERRNO, NULL, "stat(%s) failed", slavename); 97 } 98 if (st.st_uid != getuid()) { 99 tst_brkm(TBROK, NULL, "uid mismatch"); 100 } 101 102 if (st.st_mode != (S_IFCHR | S_IRUSR | S_IWUSR | S_IWGRP)) { 103 tst_brkm(TBROK, NULL, "mode mismatch (mode=%o)", st.st_mode); 104 } 105 106 slavefd = open(slavename, O_RDWR); 107 if (slavefd >= 0) { 108 tst_brkm(TBROK, NULL, "open didn't fail as expected!"); 109 } 110 111 if (unlockpt(masterfd) != 0) { 112 tst_brkm(TBROK | TERRNO, NULL, "unlockpt() failed"); 113 } 114 115 slavefd = open(slavename, O_RDWR); 116 if (slavefd < 0) { 117 tst_brkm(TBROK, NULL, "Could not open %s", slavename); 118 } 119 120 /* 121 * test writing to the master / reading from the slave 122 */ 123 if (write(masterfd, STRING, strlen(STRING)) != strlen(STRING)) { 124 /* 125 * XXX: the errno printout might be garbage, but better to be 126 * safe than sorry.. 127 */ 128 tst_brkm(TFAIL | TERRNO, NULL, "write to master"); 129 } 130 131 if (read(slavefd, buf, strlen(STRING)) != strlen(STRING)) { 132 /* XXX: Same as write above.. */ 133 tst_brkm(TFAIL | TERRNO, NULL, "read from slave"); 134 } 135 if (strncmp(STRING, buf, strlen(STRING) - 1) != 0) { 136 tst_brkm(TFAIL, NULL, 137 "strings are different (STRING = '%s' != buf = '%s')", 138 STRING, buf); 139 } 140 141 /* 142 * test writing to the slave / reading from the master 143 */ 144 if (write(slavefd, STRING, strlen(STRING)) != strlen(STRING)) { 145 /* XXX: Same as write above.. */ 146 tst_brkm(TFAIL | TERRNO, NULL, "write to slave"); 147 } 148 149 if (read(masterfd, buf, strlen(STRING)) != strlen(STRING)) { 150 /* XXX: Same as write above.. */ 151 tst_brkm(TFAIL | TERRNO, NULL, "read from master"); 152 } 153 if (strncmp(STRING, buf, strlen(STRING) - 1) != 0) { 154 tst_brkm(TFAIL, NULL, 155 "strings are different (STRING = '%s' != buf = '%s').", 156 STRING, buf); 157 } 158 159 /* 160 * try an invalid ioctl on the slave... 161 */ 162 if (ioctl(slavefd, TIOCGWINSZ, NULL) == 0) { 163 tst_brkm(TFAIL, NULL, 164 "invalid slave TIOCGWINSZ ioctl succeeded.. it should " 165 "have failed"); 166 } 167 168 /* 169 * try an invalid ioctl on the master... 170 */ 171 if (ioctl(masterfd, TIOCGWINSZ, NULL) == 0) { 172 tst_brkm(TFAIL, NULL, 173 "invalid master TIOCGWINSZ ioctl succeeded.. it should " 174 "have failed"); 175 } 176 177 /* 178 * close pty fds 179 */ 180 if (close(slavefd) != 0) { 181 tst_brkm(TBROK | TERRNO, NULL, "close of slave"); 182 } 183 if (close(masterfd) != 0) { 184 tst_brkm(TBROK | TERRNO, NULL, "close of master"); 185 } 186 tst_resm(TPASS, "test1"); 187 /** NOTREACHED **/ 188 return 0; 189 } 190 191 /* 192 * test slave operations with closed master 193 */ 194 static void test2(void) 195 { 196 int masterfd; /* master pty fd */ 197 int slavefd; /* slave pty fd */ 198 int i; 199 char *slavename; 200 char c; 201 202 masterfd = open(MASTERCLONE, O_RDWR); 203 if (masterfd < 0) { 204 tst_brkm(TBROK | TERRNO, NULL, MASTERCLONE); 205 } 206 207 slavename = ptsname(masterfd); 208 if (slavename == NULL) { 209 tst_brkm(TBROK | TERRNO, NULL, "ptsname() call failed"); 210 } 211 212 if (grantpt(masterfd) != 0) { 213 tst_brkm(TBROK | TERRNO, NULL, "grantpt() call failed"); 214 } 215 216 if (unlockpt(masterfd) != 0) { 217 tst_brkm(TBROK | TERRNO, NULL, "unlockpt() call failed"); 218 } 219 220 slavefd = open(slavename, O_RDWR); 221 if (slavefd < 0) { 222 tst_brkm(TBROK | TERRNO, NULL, "Could not open %s", slavename); 223 } 224 225 /* 226 * close pty fds. See what happens when we close the master 227 * first. 228 */ 229 if (close(masterfd) != 0) { 230 tst_brkm(TBROK | TERRNO, NULL, "close()"); 231 } 232 233 errno = 0; 234 if ((i = read(slavefd, &c, 1)) == 1) { 235 tst_brkm(TFAIL, NULL, 236 "reading from slave fd should have failed, but didn't" 237 "(read '%c')", c); 238 } 239 240 if ((i = write(slavefd, &c, 1)) == 1) { 241 tst_brkm(TFAIL, NULL, 242 "writing to slave fd should have failed, but didn't"); 243 } 244 245 if (ioctl(slavefd, TIOCGWINSZ, NULL) == 0) { 246 tst_brkm(TFAIL, NULL, 247 "trying TIOCGWINSZ on slave fd should have failed, " 248 "but didn't"); 249 } 250 251 if (close(slavefd) != 0) { 252 tst_brkm(TBROK, NULL, "close"); 253 } 254 tst_resm(TPASS, "test2"); 255 } 256 257 /* 258 * test operations on master with closed slave 259 */ 260 static void test3(void) 261 { 262 int masterfd; /* master pty fd */ 263 264 masterfd = open(MASTERCLONE, O_RDWR); 265 if (masterfd < 0) { 266 tst_brkm(TBROK, NULL, MASTERCLONE); 267 } 268 269 if (ioctl(masterfd, TIOCGWINSZ, NULL) == 0) { 270 tst_brkm(TFAIL | TERRNO, NULL, 271 "trying TIOCGWINSZ on master with no open slave " 272 "succeeded unexpectedly"); 273 } 274 tst_resm(TPASS, "test3"); 275 } 276 277 /* 278 * test multiple opens on slave side of pty 279 */ 280 static void test4(void) 281 { 282 int masterfd; /* master pty fd */ 283 int slavefd; /* slave pty fd */ 284 int slavefd2; 285 int slavefd3; 286 char *slavename; 287 288 masterfd = open(MASTERCLONE, O_RDWR); 289 if (masterfd < 0) { 290 tst_brkm(TBROK, NULL, "%s", MASTERCLONE); 291 } 292 293 slavename = ptsname(masterfd); 294 if (slavename == NULL) { 295 tst_brkm(TBROK, NULL, "ptsname() call failed"); 296 } 297 298 if (grantpt(masterfd) != 0) { 299 tst_brkm(TBROK, NULL, "grantpt() call failed"); 300 } 301 302 if (unlockpt(masterfd) != 0) { 303 tst_brkm(TBROK | TERRNO, NULL, "unlockpt() call failed"); 304 } 305 306 slavefd = open(slavename, O_RDWR); 307 if (slavefd < 0) { 308 tst_brkm(TBROK | TERRNO, NULL, "Could not open %s", slavename); 309 } 310 311 slavefd2 = open(slavename, O_RDWR); 312 if (slavefd < 0) { 313 tst_brkm(TFAIL | TERRNO, NULL, "Could not open %s (again)", 314 slavename); 315 } 316 317 slavefd3 = open(slavename, O_RDWR); 318 if (slavefd < 0) { 319 tst_brkm(TFAIL | TERRNO, NULL, "Could not open %s (once more)", 320 slavename); 321 } 322 323 /* 324 * close pty fds. 325 */ 326 if (close(slavefd) != 0) { 327 tst_brkm(TBROK | TERRNO, NULL, "close slave"); 328 } 329 330 if (close(slavefd2) != 0) { 331 tst_brkm(TBROK, NULL, "close slave again"); 332 } 333 334 if (close(slavefd3) != 0) { 335 tst_brkm(TBROK, NULL, "close slave once more"); 336 } 337 338 if (close(masterfd) != 0) { 339 tst_brkm(TBROK, NULL, "close master"); 340 } 341 tst_resm(TPASS, "test4"); 342 } 343 344 /* 345 * test opening/closing lots of ptys in parallel. We may run out 346 * of ptys for this test depending on how the system is configured, 347 * but that's not a fatal error. 348 */ 349 static void test5(void) 350 { 351 int masterfd; /* master pty fd */ 352 char *slavename; 353 int status; 354 int i; 355 356 for (i = 0; i < NUMPROCS; ++i) { 357 switch (fork()) { 358 case -1: 359 tst_brkm(TBROK, NULL, "fork()"); 360 break; 361 case 0: 362 masterfd = open(MASTERCLONE, O_RDWR); 363 if (masterfd < 0) { 364 printf("proc %d: opening %s failed: %s", 365 i, MASTERCLONE, strerror(errno)); 366 exit(1); 367 } 368 if (grantpt(masterfd) != 0) { 369 printf("proc %d: grantpt() call failed: %s", 370 i, strerror(errno)); 371 exit(1); 372 } 373 slavename = ptsname(masterfd); 374 if (slavename == NULL) { 375 printf("proc %d: ptsname() call failed: %s", 376 i, strerror(errno)); 377 exit(1); 378 } 379 sleep(10); 380 if (close(masterfd) != 0) { 381 printf("proc %d: close failed: %s", 382 i, strerror(errno)); 383 exit(1); 384 } 385 exit(0); 386 default: 387 break; 388 } 389 } 390 while (wait(&status) > 0) { 391 if (status) { 392 tst_brkm(TFAIL, NULL, 393 "child exited with non-zero status %d", 394 status); 395 } 396 } 397 tst_resm(TPASS, "test5"); 398 } 399 400 /* 401 * main test driver 402 */ 403 int main(int argc, char **argv) 404 { 405 test1(); 406 test2(); 407 test3(); 408 test4(); 409 test5(); 410 411 /* 412 * all done 413 */ 414 tst_exit(); 415 } 416