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 */
main(int argc,char * argv[])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 */
pty_open_master(const char * prog,int * cntrl,char * slave_name)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 */
pty_open_slave(const char * prog,char * slave_name)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 */
pty_parent(const char * prog,int cntrl)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 */
pty_stop_parent(int waserr,int cntrl,GetLine * gl,char * rbuff)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 */
pty_child(const char * prog,int slave,char * argv[])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 */
GL_FD_EVENT_FN(pty_read_from_program)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 */
pty_write_to_fd(int fd,const char * string,int n)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 */
pty_child_exited(int sig)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 */
pty_master_readable(int fd,long usec)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