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