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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
38 #ifdef HAVE_SYS_SELECT_H
39 #include <sys/select.h>
45 #include <sys/types.h>
50 #include <stropts.h> /* System-V stream I/O */
51 char *ptsname(int fd
);
59 * Pseudo-terminal devices are found in the following directory.
61 #define PTY_DEV_DIR "/dev/"
64 * Pseudo-terminal controller device file names start with the following
67 #define PTY_CNTRL "pty"
70 * Pseudo-terminal slave device file names start with the following
73 #define PTY_SLAVE "tty"
76 * Specify the maximum suffix length for the control and slave device
79 #define PTY_MAX_SUFFIX 10
82 * Set the maximum length of the master and slave terminal device filenames,
83 * including space for a terminating '\0'.
85 #define PTY_MAX_NAME (sizeof(PTY_DEV_DIR)-1 + \
86 (sizeof(PTY_SLAVE) > sizeof(PTY_CNTRL) ? \
87 sizeof(PTY_SLAVE) : sizeof(PTY_CNTRL))-1 \
90 * Set the maximum length of an input line.
92 #define PTY_MAX_LINE 4096
95 * Set the size of the buffer used for accumulating bytes written by the
96 * user's terminal to its stdout.
98 #define PTY_MAX_READ 1000
101 * Set the amount of memory used to record history.
103 #define PTY_HIST_SIZE 10000
106 * Set the timeout delay used to check for quickly arriving
107 * sequential output from the application.
109 #define PTY_READ_TIMEOUT 100000 /* micro-seconds */
111 static int pty_open_master(const char *prog
, int *cntrl
, char *slave_name
);
112 static int pty_open_slave(const char *prog
, char *slave_name
);
113 static int pty_child(const char *prog
, int slave
, char *argv
[]);
114 static int pty_parent(const char *prog
, int cntrl
);
115 static int pty_stop_parent(int waserr
, int cntrl
, GetLine
*gl
, char *rbuff
);
116 static GL_FD_EVENT_FN(pty_read_from_program
);
117 static int pty_write_to_fd(int fd
, const char *string
, int n
);
118 static void pty_child_exited(int sig
);
119 static int pty_master_readable(int fd
, long usec
);
121 /*.......................................................................
122 * Run a program with enhanced terminal editing facilities.
125 * enhance program [args...]
127 int main(int argc
, char *argv
[])
129 int cntrl
= -1; /* The fd of the pseudo-terminal controller device */
130 int slave
= -1; /* The fd of the pseudo-terminal slave device */
131 pid_t pid
; /* The return value of fork() */
132 int status
; /* The return statuses of the parent and child functions */
133 char slave_name
[PTY_MAX_NAME
]; /* The filename of the slave end of the */
134 /* pseudo-terminal. */
135 char *prog
; /* The name of the program (ie. argv[0]) */
137 * Check the arguments.
140 fprintf(stderr
, "Usage: %s <program> [arguments...]\n", argv
[0]);
144 * Get the name of the program.
148 * If the user has the LC_CTYPE or LC_ALL environment variables set,
149 * enable display of characters corresponding to the specified locale.
151 (void) setlocale(LC_CTYPE
, "");
153 * If the program is taking its input from a pipe or a file, or
154 * sending its output to something other than a terminal, run the
155 * program without tecla.
157 if(!isatty(STDIN_FILENO
) || !isatty(STDOUT_FILENO
)) {
158 if(execvp(argv
[1], argv
+ 1) < 0) {
159 fprintf(stderr
, "%s: Unable to execute %s (%s).\n", prog
, argv
[1],
166 * Open the master side of a pseudo-terminal pair, and return
167 * the corresponding file descriptor and the filename of the
168 * slave end of the pseudo-terminal.
170 if(pty_open_master(prog
, &cntrl
, slave_name
))
173 * Set up a signal handler to watch for the child process exiting.
175 signal(SIGCHLD
, pty_child_exited
);
177 * The above signal handler sends the parent process a SIGINT signal.
178 * This signal is caught by gl_get_line(), which resets the terminal
179 * settings, and if the application signal handler for this signal
180 * doesn't abort the process, gl_get_line() returns NULL with errno
181 * set to EINTR. Arrange to ignore the signal, so that gl_get_line()
182 * returns and we have a chance to cleanup.
184 signal(SIGINT
, SIG_IGN
);
186 * We will read user input in one process, and run the user's program
187 * in a child process.
191 fprintf(stderr
, "%s: Unable to fork child process (%s).\n", prog
,
199 status
= pty_parent(prog
, cntrl
);
202 close(cntrl
); /* The child doesn't use the slave device */
203 signal(SIGCHLD
, pty_child_exited
);
204 if((slave
= pty_open_slave(prog
, slave_name
)) >= 0) {
205 status
= pty_child(prog
, slave
, argv
+ 1);
214 /*.......................................................................
215 * Open the master side of a pseudo-terminal pair, and return
216 * the corresponding file descriptor and the filename of the
217 * slave end of the pseudo-terminal.
220 * prog const char * The name of this program.
221 * cntrl int * The file descriptor of the pseudo-terminal
222 * controller device will be assigned tp *cntrl.
223 * slave_name char * The file-name of the pseudo-terminal slave device
224 * will be recorded in slave_name[], which must have
225 * at least PTY_MAX_NAME elements.
230 static int pty_open_master(const char *prog
, int *cntrl
, char *slave_name
)
232 char master_name
[PTY_MAX_NAME
]; /* The filename of the master device */
233 DIR *dir
; /* The directory iterator */
234 struct dirent
*file
; /* A file in "/dev" */
236 * Mark the controller device as not opened yet.
240 * On systems with the Sys-V pseudo-terminal interface, we don't
241 * have to search for a free master terminal. We just open /dev/ptmx,
242 * and if there is a free master terminal device, we are given a file
243 * descriptor connected to it.
246 *cntrl
= open("/dev/ptmx", O_RDWR
);
249 * Get the filename of the slave side of the pseudo-terminal.
251 char *name
= ptsname(*cntrl
);
253 if(strlen(name
)+1 > PTY_MAX_NAME
) {
254 fprintf(stderr
, "%s: Slave pty filename too long.\n", prog
);
257 strlcpy(slave_name
, name
, PTY_MAX_NAME
);
259 * If unable to get the slave name, discard the controller file descriptor,
260 * ready to try a search instead.
269 * On systems without /dev/ptmx, or if opening /dev/ptmx failed,
270 * we open one master terminal after another, until one that isn't
271 * in use by another program is found.
273 * Open the devices directory.
275 dir
= opendir(PTY_DEV_DIR
);
277 fprintf(stderr
, "%s: Couldn't open %s (%s)\n", prog
, PTY_DEV_DIR
,
282 * Look for pseudo-terminal controller device files in the devices
285 while(*cntrl
< 0 && (file
= readdir(dir
))) {
286 if(strncmp(file
->d_name
, PTY_CNTRL
, sizeof(PTY_CNTRL
)-1) == 0) {
288 * Get the common extension of the control and slave filenames.
290 const char *ext
= file
->d_name
+ sizeof(PTY_CNTRL
)-1;
291 if(strlen(ext
) > PTY_MAX_SUFFIX
)
294 * Attempt to open the control file.
296 strlcpy(master_name
, PTY_DEV_DIR
, sizeof(master_name
));
297 strlcat(master_name
, PTY_CNTRL
, sizeof(master_name
));
298 strlcat(master_name
, ext
, sizeof(master_name
));
299 *cntrl
= open(master_name
, O_RDWR
);
303 * Attempt to open the matching slave file.
305 strlcpy(slave_name
, PTY_DEV_DIR
, PTY_MAX_NAME
);
306 strlcat(slave_name
, PTY_SLAVE
, PTY_MAX_NAME
);
307 strlcat(slave_name
, ext
, PTY_MAX_NAME
);
315 * Did we fail to find a pseudo-terminal pair that we could open?
318 fprintf(stderr
, "%s: Unable to find a free pseudo-terminal.\n", prog
);
322 * System V systems require the program that opens the master to
323 * grant access to the slave side of the pseudo-terminal.
326 if(grantpt(*cntrl
) < 0 ||
327 unlockpt(*cntrl
) < 0) {
328 fprintf(stderr
, "%s: Unable to unlock terminal (%s).\n", prog
,
339 /*.......................................................................
340 * Open the slave end of a pseudo-terminal.
343 * prog const char * The name of this program.
344 * slave_name char * The filename of the slave device.
346 * return int The file descriptor of the successfully opened
347 * slave device, or < 0 on error.
349 static int pty_open_slave(const char *prog
, char *slave_name
)
351 int fd
; /* The file descriptor of the slave device */
353 * Place the process in its own process group. In system-V based
354 * OS's, this ensures that when the pseudo-terminal is opened, it
355 * becomes the controlling terminal of the process.
358 fprintf(stderr
, "%s: Unable to form new process group (%s).\n", prog
,
363 * Attempt to open the specified device.
365 fd
= open(slave_name
, O_RDWR
);
367 fprintf(stderr
, "%s: Unable to open pseudo-terminal slave device (%s).\n",
368 prog
, strerror(errno
));
372 * On system-V streams based systems, we need to push the stream modules
373 * that implement pseudo-terminal and termio interfaces. At least on
374 * Solaris, which pushes these automatically when a slave is opened,
375 * this is redundant, so ignore errors when pushing the modules.
378 (void) ioctl(fd
, I_PUSH
, "ptem");
379 (void) ioctl(fd
, I_PUSH
, "ldterm");
381 * On BSD based systems other than SunOS 4.x, the following makes the
382 * pseudo-terminal the controlling terminal of the child process.
383 * According to the pseudo-terminal example code in Steven's
384 * Advanced programming in the unix environment, the !defined(CIBAUD)
385 * part of the clause prevents this from being used under SunOS. Since
386 * I only have his code with me, and won't have access to the book,
387 * I don't know why this is necessary.
389 #elif defined(TIOCSCTTY) && !defined(CIBAUD)
390 if(ioctl(fd
, TIOCSCTTY
, (char *) 0) < 0) {
391 fprintf(stderr
, "%s: Unable to establish controlling terminal (%s).\n",
392 prog
, strerror(errno
));
400 /*.......................................................................
401 * Read input from the controlling terminal of the program, using
402 * gl_get_line(), and feed it to the user's program running in a child
403 * process, via the controller side of the pseudo-terminal. Also pass
404 * data received from the user's program via the conroller end of
405 * the pseudo-terminal, to stdout.
408 * prog const char * The name of this program.
409 * cntrl int The file descriptor of the controller end of the
415 static int pty_parent(const char *prog
, int cntrl
)
417 GetLine
*gl
= NULL
; /* The gl_get_line() resource object */
418 char *line
; /* An input line read from the user */
419 char *rbuff
=NULL
; /* A buffer for reading from the pseudo terminal */
421 * Allocate the gl_get_line() resource object.
423 gl
= new_GetLine(PTY_MAX_LINE
, PTY_HIST_SIZE
);
425 return pty_stop_parent(1, cntrl
, gl
, rbuff
);
427 * Allocate a buffer to use to accumulate bytes read from the
430 rbuff
= (char *) malloc(PTY_MAX_READ
+1);
432 return pty_stop_parent(1, cntrl
, gl
, rbuff
);
435 * Register an event handler to watch for data appearing from the
436 * user's program on the controller end of the pseudo terminal.
438 if(gl_watch_fd(gl
, cntrl
, GLFD_READ
, pty_read_from_program
, rbuff
))
439 return pty_stop_parent(1, cntrl
, gl
, rbuff
);
441 * Read input lines from the user and pass them on to the user's program,
442 * by writing to the controller end of the pseudo-terminal.
444 while((line
=gl_get_line(gl
, rbuff
, NULL
, 0))) {
445 if(pty_write_to_fd(cntrl
, line
, strlen(line
)))
446 return pty_stop_parent(1, cntrl
, gl
, rbuff
);
449 return pty_stop_parent(0, cntrl
, gl
, rbuff
);
452 /*.......................................................................
453 * This is a private return function of pty_parent(), used to release
454 * dynamically allocated resources, close the controller end of the
455 * pseudo-terminal, and wait for the child to exit. It returns the
456 * exit status of the child process, unless the caller reports an
457 * error itself, in which case the caller's error status is returned.
460 * waserr int True if the caller is calling this function because
462 * cntrl int The file descriptor of the controller end of the
464 * gl GetLine * The resource object of gl_get_line().
465 * rbuff char * The buffer used to accumulate bytes read from
466 * the pseudo-terminal.
468 * return int The desired exit status of the program.
470 static int pty_stop_parent(int waserr
, int cntrl
, GetLine
*gl
, char *rbuff
)
472 int status
; /* The return status of the child process */
474 * Close the controller end of the terminal.
478 * Delete the resource object.
480 gl
= del_GetLine(gl
);
482 * Delete the read buffer.
486 * Wait for the user's program to end.
488 (void) wait(&status
);
490 * Return either our error status, or the return status of the child
493 return waserr
? 1 : status
;
496 /*.......................................................................
497 * Run the user's program, with its stdin and stdout connected to the
498 * slave end of the psuedo-terminal.
501 * prog const char * The name of this program.
502 * slave int The file descriptor of the slave end of the
504 * argv char *[] The argument vector to pass to the user's program,
505 * where argv[0] is the name of the user's program,
506 * and the last argument is followed by a pointer
509 * return int If this function returns at all, an error must
510 * have occured when trying to overlay the process
511 * with the user's program. In this case 1 is
514 static int pty_child(const char *prog
, int slave
, char *argv
[])
516 struct termios attr
; /* The terminal attributes */
518 * We need to stop the pseudo-terminal from echoing everything that we send it.
520 if(tcgetattr(slave
, &attr
)) {
521 fprintf(stderr
, "%s: Can't get pseudo-terminal attributes (%s).\n", prog
,
525 attr
.c_lflag
&= ~(ECHO
);
526 while(tcsetattr(slave
, TCSADRAIN
, &attr
)) {
528 fprintf(stderr
, "%s: tcsetattr error: %s\n", prog
, strerror(errno
));
533 * Arrange for stdin, stdout and stderr to be connected to the slave device,
534 * ignoring errors that imply that either stdin or stdout is closed.
536 while(dup2(slave
, STDIN_FILENO
) < 0 && errno
==EINTR
)
538 while(dup2(slave
, STDOUT_FILENO
) < 0 && errno
==EINTR
)
540 while(dup2(slave
, STDERR_FILENO
) < 0 && errno
==EINTR
)
543 * Run the user's program.
545 if(execvp(argv
[0], argv
) < 0) {
546 fprintf(stderr
, "%s: Unable to execute %s (%s).\n", prog
, argv
[0],
551 return 0; /* This should never be reached */
554 /*.......................................................................
555 * This is the event-handler that is called by gl_get_line() whenever
556 * there is tet waiting to be read from the user's program, via the
557 * controller end of the pseudo-terminal. See libtecla.h for details
558 * about its arguments.
560 static GL_FD_EVENT_FN(pty_read_from_program
)
562 char *nlptr
; /* A pointer to the last newline in the accumulated string */
563 char *crptr
; /* A pointer to the last '\r' in the accumulated string */
564 char *nextp
; /* A pointer to the next unprocessed character */
566 * Get the read buffer in which we are accumulating a line to be
567 * forwarded to stdout.
569 char *rbuff
= (char *) data
;
571 * New data may arrive while we are processing the current read, and
572 * it is more efficient to display this here than to keep returning to
573 * gl_get_line() and have it display the latest prefix as a prompt,
574 * followed by the current input line, so we loop, delaying a bit at
575 * the end of each iteration to check for more data arriving from
576 * the application, before finally returning to gl_get_line() when
577 * no more input is available.
581 * Get the current length of the output string.
583 int len
= strlen(rbuff
);
585 * Read the text from the program.
587 int nnew
= read(fd
, rbuff
+ len
, PTY_MAX_READ
- len
);
592 * Nul terminate the accumulated string.
596 * Find the last newline and last carriage return in the buffer, if any.
598 nlptr
= strrchr(rbuff
, '\n');
599 crptr
= strrchr(rbuff
, '\r');
601 * We want to output up to just before the last newline or carriage
602 * return. If there are no newlines of carriage returns in the line,
603 * and the buffer is full, then we should output the whole line. In
604 * all cases a new output line will be started after the latest text
605 * has been output. The intention is to leave any incomplete line
606 * in the buffer, for (perhaps temporary) use as the current prompt.
609 nextp
= crptr
&& crptr
< nlptr
? crptr
: nlptr
;
612 } else if(len
>= PTY_MAX_READ
) {
618 * Do we have any text to output yet?
622 * If there was already some text in rbuff before this function
623 * was called, then it will have been used as a prompt. Arrange
624 * to rewrite this prefix, plus the new suffix, by moving back to
625 * the start of the line.
628 (void) pty_write_to_fd(STDOUT_FILENO
, "\r", 1);
630 * Write everything up to the last newline to stdout.
632 (void) pty_write_to_fd(STDOUT_FILENO
, rbuff
, nextp
- rbuff
);
636 (void) pty_write_to_fd(STDOUT_FILENO
, "\r\n", 2);
638 * Skip trailing carriage returns and newlines.
640 while(*nextp
=='\n' || *nextp
=='\r')
643 * Move any unwritten text following the newline, to the start of the
646 memmove(rbuff
, nextp
, len
- (nextp
- rbuff
) + 1);
648 } while(pty_master_readable(fd
, PTY_READ_TIMEOUT
));
650 * Make the incomplete line in the output buffer the current prompt.
652 gl_replace_prompt(gl
, rbuff
);
656 /*.......................................................................
657 * Write a given string to a specified file descriptor.
660 * fd int The file descriptor to write to.
661 * string const char * The string to write (of at least 'n' characters).
662 * n int The number of characters to write.
667 static int pty_write_to_fd(int fd
, const char *string
, int n
)
669 int ndone
= 0; /* The number of characters written so far */
671 * Do as many writes as are needed to write the whole string.
674 int nnew
= write(fd
, string
+ ndone
, n
- ndone
);
677 else if(errno
!= EINTR
)
683 /*.......................................................................
684 * This is the signal handler that is called when the child process
685 * that is running the user's program exits for any reason. It closes
686 * the slave end of the terminal, so that gl_get_line() in the parent
687 * process sees an end of file.
689 static void pty_child_exited(int sig
)
694 /*.......................................................................
695 * Return non-zero after a given amount of time if there is data waiting
696 * to be read from a given file descriptor.
699 * fd int The descriptor to watch.
700 * usec long The number of micro-seconds to wait for input to
701 * arrive before giving up.
703 * return int 0 - No data is waiting to be read (or select isn't
705 * 1 - Data is waiting to be read.
707 static int pty_master_readable(int fd
, long usec
)
710 fd_set rfds
; /* The set of file descriptors to check */
711 struct timeval timeout
; /* The timeout */
715 timeout
.tv_usec
= usec
;
716 return select(fd
+1, &rfds
, NULL
, NULL
, &timeout
) == 1;