1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <errno.h> 33 #include <signal.h> 34 #include <locale.h> 35 36 #include <unistd.h> 37 #include <termios.h> 38 39 #ifdef HAVE_SELECT 40 #ifdef HAVE_SYS_SELECT_H 41 #include <sys/select.h> 42 #endif 43 #endif 44 45 #include <fcntl.h> 46 #include <sys/time.h> 47 #include <sys/types.h> 48 #include <sys/wait.h> 49 #include <dirent.h> 50 51 #if HAVE_SYSV_PTY 52 #include <stropts.h> /* System-V stream I/O */ 53 char *ptsname(int fd); 54 int grantpt(int fd); 55 int unlockpt(int fd); 56 #endif 57 58 #include "libtecla.h" 59 60 /* 61 * Pseudo-terminal devices are found in the following directory. 62 */ 63 #define PTY_DEV_DIR "/dev/" 64 65 /* 66 * Pseudo-terminal controller device file names start with the following 67 * prefix. 68 */ 69 #define PTY_CNTRL "pty" 70 71 /* 72 * Pseudo-terminal slave device file names start with the following 73 * prefix. 74 */ 75 #define PTY_SLAVE "tty" 76 77 /* 78 * Specify the maximum suffix length for the control and slave device 79 * names. 80 */ 81 #define PTY_MAX_SUFFIX 10 82 83 /* 84 * Set the maximum length of the master and slave terminal device filenames, 85 * including space for a terminating '\0'. 86 */ 87 #define PTY_MAX_NAME (sizeof(PTY_DEV_DIR)-1 + \ 88 (sizeof(PTY_SLAVE) > sizeof(PTY_CNTRL) ? \ 89 sizeof(PTY_SLAVE) : sizeof(PTY_CNTRL))-1 \ 90 + PTY_MAX_SUFFIX + 1) 91 /* 92 * Set the maximum length of an input line. 93 */ 94 #define PTY_MAX_LINE 4096 95 96 /* 97 * Set the size of the buffer used for accumulating bytes written by the 98 * user's terminal to its stdout. 99 */ 100 #define PTY_MAX_READ 1000 101 102 /* 103 * Set the amount of memory used to record history. 104 */ 105 #define PTY_HIST_SIZE 10000 106 107 /* 108 * Set the timeout delay used to check for quickly arriving 109 * sequential output from the application. 110 */ 111 #define PTY_READ_TIMEOUT 100000 /* micro-seconds */ 112 113 static int pty_open_master(const char *prog, int *cntrl, char *slave_name); 114 static int pty_open_slave(const char *prog, char *slave_name); 115 static int pty_child(const char *prog, int slave, char *argv[]); 116 static int pty_parent(const char *prog, int cntrl); 117 static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff); 118 static GL_FD_EVENT_FN(pty_read_from_program); 119 static int pty_write_to_fd(int fd, const char *string, int n); 120 static void pty_child_exited(int sig); 121 static int pty_master_readable(int fd, long usec); 122 123 /*....................................................................... 124 * Run a program with enhanced terminal editing facilities. 125 * 126 * Usage: 127 * enhance program [args...] 128 */ 129 int main(int argc, char *argv[]) 130 { 131 int cntrl = -1; /* The fd of the pseudo-terminal controller device */ 132 int slave = -1; /* The fd of the pseudo-terminal slave device */ 133 pid_t pid; /* The return value of fork() */ 134 int status; /* The return statuses of the parent and child functions */ 135 char slave_name[PTY_MAX_NAME]; /* The filename of the slave end of the */ 136 /* pseudo-terminal. */ 137 char *prog; /* The name of the program (ie. argv[0]) */ 138 /* 139 * Check the arguments. 140 */ 141 if(argc < 2) { 142 fprintf(stderr, "Usage: %s <program> [arguments...]\n", argv[0]); 143 return 1; 144 }; 145 /* 146 * Get the name of the program. 147 */ 148 prog = argv[0]; 149 /* 150 * If the user has the LC_CTYPE or LC_ALL environment variables set, 151 * enable display of characters corresponding to the specified locale. 152 */ 153 (void) setlocale(LC_CTYPE, ""); 154 /* 155 * If the program is taking its input from a pipe or a file, or 156 * sending its output to something other than a terminal, run the 157 * program without tecla. 158 */ 159 if(!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO)) { 160 if(execvp(argv[1], argv + 1) < 0) { 161 fprintf(stderr, "%s: Unable to execute %s (%s).\n", prog, argv[1], 162 strerror(errno)); 163 fflush(stderr); 164 _exit(1); 165 }; 166 }; 167 /* 168 * Open the master side of a pseudo-terminal pair, and return 169 * the corresponding file descriptor and the filename of the 170 * slave end of the pseudo-terminal. 171 */ 172 if(pty_open_master(prog, &cntrl, slave_name)) 173 return 1; 174 /* 175 * Set up a signal handler to watch for the child process exiting. 176 */ 177 signal(SIGCHLD, pty_child_exited); 178 /* 179 * The above signal handler sends the parent process a SIGINT signal. 180 * This signal is caught by gl_get_line(), which resets the terminal 181 * settings, and if the application signal handler for this signal 182 * doesn't abort the process, gl_get_line() returns NULL with errno 183 * set to EINTR. Arrange to ignore the signal, so that gl_get_line() 184 * returns and we have a chance to cleanup. 185 */ 186 signal(SIGINT, SIG_IGN); 187 /* 188 * We will read user input in one process, and run the user's program 189 * in a child process. 190 */ 191 pid = fork(); 192 if(pid < 0) { 193 fprintf(stderr, "%s: Unable to fork child process (%s).\n", prog, 194 strerror(errno)); 195 return 1; 196 }; 197 /* 198 * Are we the parent? 199 */ 200 if(pid!=0) { 201 status = pty_parent(prog, cntrl); 202 close(cntrl); 203 } else { 204 close(cntrl); /* The child doesn't use the slave device */ 205 signal(SIGCHLD, pty_child_exited); 206 if((slave = pty_open_slave(prog, slave_name)) >= 0) { 207 status = pty_child(prog, slave, argv + 1); 208 close(slave); 209 } else { 210 status = 1; 211 }; 212 }; 213 return status; 214 } 215 216 /*....................................................................... 217 * Open the master side of a pseudo-terminal pair, and return 218 * the corresponding file descriptor and the filename of the 219 * slave end of the pseudo-terminal. 220 * 221 * Input/Output: 222 * prog const char * The name of this program. 223 * cntrl int * The file descriptor of the pseudo-terminal 224 * controller device will be assigned tp *cntrl. 225 * slave_name char * The file-name of the pseudo-terminal slave device 226 * will be recorded in slave_name[], which must have 227 * at least PTY_MAX_NAME elements. 228 * Output: 229 * return int 0 - OK. 230 * 1 - Error. 231 */ 232 static int pty_open_master(const char *prog, int *cntrl, char *slave_name) 233 { 234 char master_name[PTY_MAX_NAME]; /* The filename of the master device */ 235 DIR *dir; /* The directory iterator */ 236 struct dirent *file; /* A file in "/dev" */ 237 /* 238 * Mark the controller device as not opened yet. 239 */ 240 *cntrl = -1; 241 /* 242 * On systems with the Sys-V pseudo-terminal interface, we don't 243 * have to search for a free master terminal. We just open /dev/ptmx, 244 * and if there is a free master terminal device, we are given a file 245 * descriptor connected to it. 246 */ 247 #if HAVE_SYSV_PTY 248 *cntrl = open("/dev/ptmx", O_RDWR); 249 if(*cntrl >= 0) { 250 /* 251 * Get the filename of the slave side of the pseudo-terminal. 252 */ 253 char *name = ptsname(*cntrl); 254 if(name) { 255 if(strlen(name)+1 > PTY_MAX_NAME) { 256 fprintf(stderr, "%s: Slave pty filename too long.\n", prog); 257 return 1; 258 }; 259 strlcpy(slave_name, name, PTY_MAX_NAME); 260 /* 261 * If unable to get the slave name, discard the controller file descriptor, 262 * ready to try a search instead. 263 */ 264 } else { 265 close(*cntrl); 266 *cntrl = -1; 267 }; 268 } else { 269 #endif 270 /* 271 * On systems without /dev/ptmx, or if opening /dev/ptmx failed, 272 * we open one master terminal after another, until one that isn't 273 * in use by another program is found. 274 * 275 * Open the devices directory. 276 */ 277 dir = opendir(PTY_DEV_DIR); 278 if(!dir) { 279 fprintf(stderr, "%s: Couldn't open %s (%s)\n", prog, PTY_DEV_DIR, 280 strerror(errno)); 281 return 1; 282 }; 283 /* 284 * Look for pseudo-terminal controller device files in the devices 285 * directory. 286 */ 287 while(*cntrl < 0 && (file = readdir(dir))) { 288 if(strncmp(file->d_name, PTY_CNTRL, sizeof(PTY_CNTRL)-1) == 0) { 289 /* 290 * Get the common extension of the control and slave filenames. 291 */ 292 const char *ext = file->d_name + sizeof(PTY_CNTRL)-1; 293 if(strlen(ext) > PTY_MAX_SUFFIX) 294 continue; 295 /* 296 * Attempt to open the control file. 297 */ 298 strlcpy(master_name, PTY_DEV_DIR, sizeof(master_name)); 299 strlcat(master_name, PTY_CNTRL, sizeof(master_name)); 300 strlcat(master_name, ext, sizeof(master_name)); 301 *cntrl = open(master_name, O_RDWR); 302 if(*cntrl < 0) 303 continue; 304 /* 305 * Attempt to open the matching slave file. 306 */ 307 strlcpy(slave_name, PTY_DEV_DIR, PTY_MAX_NAME); 308 strlcat(slave_name, PTY_SLAVE, PTY_MAX_NAME); 309 strlcat(slave_name, ext, PTY_MAX_NAME); 310 }; 311 }; 312 closedir(dir); 313 #if HAVE_SYSV_PTY 314 }; 315 #endif 316 /* 317 * Did we fail to find a pseudo-terminal pair that we could open? 318 */ 319 if(*cntrl < 0) { 320 fprintf(stderr, "%s: Unable to find a free pseudo-terminal.\n", prog); 321 return 1; 322 }; 323 /* 324 * System V systems require the program that opens the master to 325 * grant access to the slave side of the pseudo-terminal. 326 */ 327 #ifdef HAVE_SYSV_PTY 328 if(grantpt(*cntrl) < 0 || 329 unlockpt(*cntrl) < 0) { 330 fprintf(stderr, "%s: Unable to unlock terminal (%s).\n", prog, 331 strerror(errno)); 332 return 1; 333 }; 334 #endif 335 /* 336 * Success. 337 */ 338 return 0; 339 } 340 341 /*....................................................................... 342 * Open the slave end of a pseudo-terminal. 343 * 344 * Input: 345 * prog const char * The name of this program. 346 * slave_name char * The filename of the slave device. 347 * Output: 348 * return int The file descriptor of the successfully opened 349 * slave device, or < 0 on error. 350 */ 351 static int pty_open_slave(const char *prog, char *slave_name) 352 { 353 int fd; /* The file descriptor of the slave device */ 354 /* 355 * Place the process in its own process group. In system-V based 356 * OS's, this ensures that when the pseudo-terminal is opened, it 357 * becomes the controlling terminal of the process. 358 */ 359 if(setsid() < 0) { 360 fprintf(stderr, "%s: Unable to form new process group (%s).\n", prog, 361 strerror(errno)); 362 return -1; 363 }; 364 /* 365 * Attempt to open the specified device. 366 */ 367 fd = open(slave_name, O_RDWR); 368 if(fd < 0) { 369 fprintf(stderr, "%s: Unable to open pseudo-terminal slave device (%s).\n", 370 prog, strerror(errno)); 371 return -1; 372 }; 373 /* 374 * On system-V streams based systems, we need to push the stream modules 375 * that implement pseudo-terminal and termio interfaces. At least on 376 * Solaris, which pushes these automatically when a slave is opened, 377 * this is redundant, so ignore errors when pushing the modules. 378 */ 379 #if HAVE_SYSV_PTY 380 (void) ioctl(fd, I_PUSH, "ptem"); 381 (void) ioctl(fd, I_PUSH, "ldterm"); 382 /* 383 * On BSD based systems other than SunOS 4.x, the following makes the 384 * pseudo-terminal the controlling terminal of the child process. 385 * According to the pseudo-terminal example code in Steven's 386 * Advanced programming in the unix environment, the !defined(CIBAUD) 387 * part of the clause prevents this from being used under SunOS. Since 388 * I only have his code with me, and won't have access to the book, 389 * I don't know why this is necessary. 390 */ 391 #elif defined(TIOCSCTTY) && !defined(CIBAUD) 392 if(ioctl(fd, TIOCSCTTY, (char *) 0) < 0) { 393 fprintf(stderr, "%s: Unable to establish controlling terminal (%s).\n", 394 prog, strerror(errno)); 395 close(fd); 396 return -1; 397 }; 398 #endif 399 return fd; 400 } 401 402 /*....................................................................... 403 * Read input from the controlling terminal of the program, using 404 * gl_get_line(), and feed it to the user's program running in a child 405 * process, via the controller side of the pseudo-terminal. Also pass 406 * data received from the user's program via the conroller end of 407 * the pseudo-terminal, to stdout. 408 * 409 * Input: 410 * prog const char * The name of this program. 411 * cntrl int The file descriptor of the controller end of the 412 * pseudo-terminal. 413 * Output: 414 * return int 0 - OK. 415 * 1 - Error. 416 */ 417 static int pty_parent(const char *prog, int cntrl) 418 { 419 GetLine *gl = NULL; /* The gl_get_line() resource object */ 420 char *line; /* An input line read from the user */ 421 char *rbuff=NULL; /* A buffer for reading from the pseudo terminal */ 422 /* 423 * Allocate the gl_get_line() resource object. 424 */ 425 gl = new_GetLine(PTY_MAX_LINE, PTY_HIST_SIZE); 426 if(!gl) 427 return pty_stop_parent(1, cntrl, gl, rbuff); 428 /* 429 * Allocate a buffer to use to accumulate bytes read from the 430 * pseudo-terminal. 431 */ 432 rbuff = (char *) malloc(PTY_MAX_READ+1); 433 if(!rbuff) 434 return pty_stop_parent(1, cntrl, gl, rbuff); 435 rbuff[0] = '\0'; 436 /* 437 * Register an event handler to watch for data appearing from the 438 * user's program on the controller end of the pseudo terminal. 439 */ 440 if(gl_watch_fd(gl, cntrl, GLFD_READ, pty_read_from_program, rbuff)) 441 return pty_stop_parent(1, cntrl, gl, rbuff); 442 /* 443 * Read input lines from the user and pass them on to the user's program, 444 * by writing to the controller end of the pseudo-terminal. 445 */ 446 while((line=gl_get_line(gl, rbuff, NULL, 0))) { 447 if(pty_write_to_fd(cntrl, line, strlen(line))) 448 return pty_stop_parent(1, cntrl, gl, rbuff); 449 rbuff[0] = '\0'; 450 }; 451 return pty_stop_parent(0, cntrl, gl, rbuff); 452 } 453 454 /*....................................................................... 455 * This is a private return function of pty_parent(), used to release 456 * dynamically allocated resources, close the controller end of the 457 * pseudo-terminal, and wait for the child to exit. It returns the 458 * exit status of the child process, unless the caller reports an 459 * error itself, in which case the caller's error status is returned. 460 * 461 * Input: 462 * waserr int True if the caller is calling this function because 463 * an error occured. 464 * cntrl int The file descriptor of the controller end of the 465 * pseudo-terminal. 466 * gl GetLine * The resource object of gl_get_line(). 467 * rbuff char * The buffer used to accumulate bytes read from 468 * the pseudo-terminal. 469 * Output: 470 * return int The desired exit status of the program. 471 */ 472 static int pty_stop_parent(int waserr, int cntrl, GetLine *gl, char *rbuff) 473 { 474 int status; /* The return status of the child process */ 475 /* 476 * Close the controller end of the terminal. 477 */ 478 close(cntrl); 479 /* 480 * Delete the resource object. 481 */ 482 gl = del_GetLine(gl); 483 /* 484 * Delete the read buffer. 485 */ 486 if(rbuff) 487 free(rbuff); 488 /* 489 * Wait for the user's program to end. 490 */ 491 (void) wait(&status); 492 /* 493 * Return either our error status, or the return status of the child 494 * program. 495 */ 496 return waserr ? 1 : status; 497 } 498 499 /*....................................................................... 500 * Run the user's program, with its stdin and stdout connected to the 501 * slave end of the psuedo-terminal. 502 * 503 * Input: 504 * prog const char * The name of this program. 505 * slave int The file descriptor of the slave end of the 506 * pseudo terminal. 507 * argv char *[] The argument vector to pass to the user's program, 508 * where argv[0] is the name of the user's program, 509 * and the last argument is followed by a pointer 510 * to NULL. 511 * Output: 512 * return int If this function returns at all, an error must 513 * have occured when trying to overlay the process 514 * with the user's program. In this case 1 is 515 * returned. 516 */ 517 static int pty_child(const char *prog, int slave, char *argv[]) 518 { 519 struct termios attr; /* The terminal attributes */ 520 /* 521 * We need to stop the pseudo-terminal from echoing everything that we send it. 522 */ 523 if(tcgetattr(slave, &attr)) { 524 fprintf(stderr, "%s: Can't get pseudo-terminal attributes (%s).\n", prog, 525 strerror(errno)); 526 return 1; 527 }; 528 attr.c_lflag &= ~(ECHO); 529 while(tcsetattr(slave, TCSADRAIN, &attr)) { 530 if(errno != EINTR) { 531 fprintf(stderr, "%s: tcsetattr error: %s\n", prog, strerror(errno)); 532 return 1; 533 }; 534 }; 535 /* 536 * Arrange for stdin, stdout and stderr to be connected to the slave device, 537 * ignoring errors that imply that either stdin or stdout is closed. 538 */ 539 while(dup2(slave, STDIN_FILENO) < 0 && errno==EINTR) 540 ; 541 while(dup2(slave, STDOUT_FILENO) < 0 && errno==EINTR) 542 ; 543 while(dup2(slave, STDERR_FILENO) < 0 && errno==EINTR) 544 ; 545 /* 546 * Run the user's program. 547 */ 548 if(execvp(argv[0], argv) < 0) { 549 fprintf(stderr, "%s: Unable to execute %s (%s).\n", prog, argv[0], 550 strerror(errno)); 551 fflush(stderr); 552 _exit(1); 553 }; 554 return 0; /* This should never be reached */ 555 } 556 557 /*....................................................................... 558 * This is the event-handler that is called by gl_get_line() whenever 559 * there is tet waiting to be read from the user's program, via the 560 * controller end of the pseudo-terminal. See libtecla.h for details 561 * about its arguments. 562 */ 563 static GL_FD_EVENT_FN(pty_read_from_program) 564 { 565 char *nlptr; /* A pointer to the last newline in the accumulated string */ 566 char *crptr; /* A pointer to the last '\r' in the accumulated string */ 567 char *nextp; /* A pointer to the next unprocessed character */ 568 /* 569 * Get the read buffer in which we are accumulating a line to be 570 * forwarded to stdout. 571 */ 572 char *rbuff = (char *) data; 573 /* 574 * New data may arrive while we are processing the current read, and 575 * it is more efficient to display this here than to keep returning to 576 * gl_get_line() and have it display the latest prefix as a prompt, 577 * followed by the current input line, so we loop, delaying a bit at 578 * the end of each iteration to check for more data arriving from 579 * the application, before finally returning to gl_get_line() when 580 * no more input is available. 581 */ 582 do { 583 /* 584 * Get the current length of the output string. 585 */ 586 int len = strlen(rbuff); 587 /* 588 * Read the text from the program. 589 */ 590 int nnew = read(fd, rbuff + len, PTY_MAX_READ - len); 591 if(nnew < 0) 592 return GLFD_ABORT; 593 len += nnew; 594 /* 595 * Nul terminate the accumulated string. 596 */ 597 rbuff[len] = '\0'; 598 /* 599 * Find the last newline and last carriage return in the buffer, if any. 600 */ 601 nlptr = strrchr(rbuff, '\n'); 602 crptr = strrchr(rbuff, '\r'); 603 /* 604 * We want to output up to just before the last newline or carriage 605 * return. If there are no newlines of carriage returns in the line, 606 * and the buffer is full, then we should output the whole line. In 607 * all cases a new output line will be started after the latest text 608 * has been output. The intention is to leave any incomplete line 609 * in the buffer, for (perhaps temporary) use as the current prompt. 610 */ 611 if(nlptr) { 612 nextp = crptr && crptr < nlptr ? crptr : nlptr; 613 } else if(crptr) { 614 nextp = crptr; 615 } else if(len >= PTY_MAX_READ) { 616 nextp = rbuff + len; 617 } else { 618 nextp = NULL; 619 }; 620 /* 621 * Do we have any text to output yet? 622 */ 623 if(nextp) { 624 /* 625 * If there was already some text in rbuff before this function 626 * was called, then it will have been used as a prompt. Arrange 627 * to rewrite this prefix, plus the new suffix, by moving back to 628 * the start of the line. 629 */ 630 if(len > 0) 631 (void) pty_write_to_fd(STDOUT_FILENO, "\r", 1); 632 /* 633 * Write everything up to the last newline to stdout. 634 */ 635 (void) pty_write_to_fd(STDOUT_FILENO, rbuff, nextp - rbuff); 636 /* 637 * Start a new line. 638 */ 639 (void) pty_write_to_fd(STDOUT_FILENO, "\r\n", 2); 640 /* 641 * Skip trailing carriage returns and newlines. 642 */ 643 while(*nextp=='\n' || *nextp=='\r') 644 nextp++; 645 /* 646 * Move any unwritten text following the newline, to the start of the 647 * buffer. 648 */ 649 memmove(rbuff, nextp, len - (nextp - rbuff) + 1); 650 }; 651 } while(pty_master_readable(fd, PTY_READ_TIMEOUT)); 652 /* 653 * Make the incomplete line in the output buffer the current prompt. 654 */ 655 gl_replace_prompt(gl, rbuff); 656 return GLFD_REFRESH; 657 } 658 659 /*....................................................................... 660 * Write a given string to a specified file descriptor. 661 * 662 * Input: 663 * fd int The file descriptor to write to. 664 * string const char * The string to write (of at least 'n' characters). 665 * n int The number of characters to write. 666 * Output: 667 * return int 0 - OK. 668 * 1 - Error. 669 */ 670 static int pty_write_to_fd(int fd, const char *string, int n) 671 { 672 int ndone = 0; /* The number of characters written so far */ 673 /* 674 * Do as many writes as are needed to write the whole string. 675 */ 676 while(ndone < n) { 677 int nnew = write(fd, string + ndone, n - ndone); 678 if(nnew > 0) 679 ndone += nnew; 680 else if(errno != EINTR) 681 return 1; 682 }; 683 return 0; 684 } 685 686 /*....................................................................... 687 * This is the signal handler that is called when the child process 688 * that is running the user's program exits for any reason. It closes 689 * the slave end of the terminal, so that gl_get_line() in the parent 690 * process sees an end of file. 691 */ 692 static void pty_child_exited(int sig) 693 { 694 raise(SIGINT); 695 } 696 697 /*....................................................................... 698 * Return non-zero after a given amount of time if there is data waiting 699 * to be read from a given file descriptor. 700 * 701 * Input: 702 * fd int The descriptor to watch. 703 * usec long The number of micro-seconds to wait for input to 704 * arrive before giving up. 705 * Output: 706 * return int 0 - No data is waiting to be read (or select isn't 707 * available). 708 * 1 - Data is waiting to be read. 709 */ 710 static int pty_master_readable(int fd, long usec) 711 { 712 #if HAVE_SELECT 713 fd_set rfds; /* The set of file descriptors to check */ 714 struct timeval timeout; /* The timeout */ 715 FD_ZERO(&rfds); 716 FD_SET(fd, &rfds); 717 timeout.tv_sec = 0; 718 timeout.tv_usec = usec; 719 return select(fd+1, &rfds, NULL, NULL, &timeout) == 1; 720 #else 721 return 0; 722 #endif 723 } 724