Blame exp_tty.c

Packit a69f91
/* exp_tty.c - tty support routines */
Packit a69f91
Packit a69f91
#include "expect_cf.h"
Packit a69f91
#include <stdio.h>
Packit a69f91
#include <signal.h>
Packit a69f91
#include "string.h"
Packit a69f91
Packit a69f91
#ifdef HAVE_SYS_FCNTL_H
Packit a69f91
#  include <sys/fcntl.h>
Packit a69f91
#else
Packit a69f91
#  include <fcntl.h>
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#include <sys/stat.h>
Packit a69f91
Packit a69f91
#ifdef HAVE_INTTYPES_H
Packit a69f91
#  include <inttypes.h>
Packit a69f91
#endif
Packit a69f91
#include <sys/types.h>
Packit a69f91
Packit a69f91
#ifdef HAVE_UNISTD_H
Packit a69f91
# include <unistd.h>
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#ifdef HAVE_SYS_WAIT_H
Packit a69f91
#include <sys/wait.h>
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#if defined(SIGCLD) && !defined(SIGCHLD)
Packit a69f91
#define SIGCHLD SIGCLD
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#include "tcl.h"
Packit a69f91
#include "exp_prog.h"
Packit a69f91
#include "exp_rename.h"
Packit a69f91
#include "exp_tty_in.h"
Packit a69f91
#include "exp_command.h"
Packit a69f91
#include "exp_log.h"
Packit a69f91
#include "exp_win.h"
Packit a69f91
Packit a69f91
static int is_raw = FALSE;
Packit a69f91
static int is_noecho = FALSE;
Packit a69f91
Packit a69f91
int exp_ioctled_devtty = FALSE;
Packit a69f91
int exp_stdin_is_tty;
Packit a69f91
int exp_stdout_is_tty;
Packit a69f91
Packit a69f91
/*static*/ extern exp_tty exp_tty_current, exp_tty_cooked;
Packit a69f91
#define tty_current exp_tty_current
Packit a69f91
#define tty_cooked exp_tty_cooked
Packit a69f91
Packit a69f91
int
Packit a69f91
exp_israw(void)
Packit a69f91
{
Packit a69f91
	return is_raw;
Packit a69f91
}
Packit a69f91
Packit a69f91
int
Packit a69f91
exp_isecho(void)
Packit a69f91
{
Packit a69f91
	return !is_noecho;
Packit a69f91
}
Packit a69f91
Packit a69f91
/* if set == 1, set it to raw, else unset it */
Packit a69f91
void
Packit a69f91
exp_tty_raw(int set)
Packit a69f91
{
Packit a69f91
	if (set == 1) {
Packit a69f91
		is_raw = TRUE;
Packit a69f91
#if defined(HAVE_TERMIOS) || defined(HAVE_TERMIO) /* had POSIX too */
Packit a69f91
		tty_current.c_iflag = 0;
Packit a69f91
		tty_current.c_oflag = 0;
Packit a69f91
		tty_current.c_lflag &= ECHO;  /* disable everything but echo */
Packit a69f91
		tty_current.c_cc[VMIN] = 1;
Packit a69f91
		tty_current.c_cc[VTIME] = 0;
Packit a69f91
	} else {
Packit a69f91
		tty_current.c_iflag = tty_cooked.c_iflag;
Packit a69f91
		tty_current.c_oflag = tty_cooked.c_oflag;
Packit a69f91
/*		tty_current.c_lflag = tty_cooked.c_lflag;*/
Packit a69f91
/* attempt 2	tty_current.c_lflag = tty_cooked.c_lflag & ~ECHO;*/
Packit a69f91
		/* retain current echo setting */
Packit a69f91
		tty_current.c_lflag = (tty_cooked.c_lflag & ~ECHO) | (tty_current.c_lflag & ECHO);
Packit a69f91
		tty_current.c_cc[VMIN] = tty_cooked.c_cc[VMIN];
Packit a69f91
		tty_current.c_cc[VTIME] = tty_cooked.c_cc[VTIME];
Packit a69f91
#else
Packit a69f91
#  if defined(HAVE_SGTTYB)
Packit a69f91
		tty_current.sg_flags |= RAW;
Packit a69f91
	} else {
Packit a69f91
		tty_current.sg_flags = tty_cooked.sg_flags;
Packit a69f91
#  endif
Packit a69f91
#endif
Packit a69f91
		is_raw = FALSE;
Packit a69f91
	}
Packit a69f91
}
Packit a69f91
	
Packit a69f91
void
Packit a69f91
exp_tty_echo(int set)
Packit a69f91
{
Packit a69f91
	if (set == 1) {
Packit a69f91
		is_noecho = FALSE;
Packit a69f91
#if defined(HAVE_TERMIOS) || defined(HAVE_TERMIO) /* had POSIX too */
Packit a69f91
		tty_current.c_lflag |= ECHO;
Packit a69f91
	} else {
Packit a69f91
		tty_current.c_lflag &= ~ECHO;
Packit a69f91
#else
Packit a69f91
		tty_current.sg_flags |= ECHO;
Packit a69f91
	} else {
Packit a69f91
		tty_current.sg_flags &= ~ECHO;
Packit a69f91
#endif
Packit a69f91
		is_noecho = TRUE;
Packit a69f91
	}
Packit a69f91
}
Packit a69f91
Packit a69f91
int
Packit a69f91
exp_tty_set_simple(exp_tty *tty)
Packit a69f91
{
Packit a69f91
#ifdef HAVE_TCSETATTR
Packit a69f91
	return(tcsetattr(exp_dev_tty, TCSADRAIN,tty));
Packit a69f91
#else
Packit a69f91
	return(ioctl    (exp_dev_tty, TCSETSW  ,tty));
Packit a69f91
#endif
Packit a69f91
}
Packit a69f91
Packit a69f91
int
Packit a69f91
exp_tty_get_simple(exp_tty *tty)
Packit a69f91
{
Packit a69f91
#ifdef HAVE_TCSETATTR
Packit a69f91
	return(tcgetattr(exp_dev_tty,         tty));
Packit a69f91
#else
Packit a69f91
	return(ioctl    (exp_dev_tty, TCGETS, tty));
Packit a69f91
#endif
Packit a69f91
}
Packit a69f91
Packit a69f91
/* returns 0 if nothing changed */
Packit a69f91
/* if something changed, the out parameters are changed as well */
Packit a69f91
int
Packit a69f91
exp_tty_raw_noecho(
Packit a69f91
    Tcl_Interp *interp,
Packit a69f91
    exp_tty *tty_old,
Packit a69f91
    int *was_raw,
Packit a69f91
    int *was_echo)
Packit a69f91
{
Packit a69f91
	if (exp_disconnected) return(0);
Packit a69f91
	if (is_raw && is_noecho) return(0);
Packit a69f91
	if (exp_dev_tty == -1) return(0);
Packit a69f91
Packit a69f91
	*tty_old = tty_current;		/* save old parameters */
Packit a69f91
	*was_raw = is_raw;
Packit a69f91
	*was_echo = !is_noecho;
Packit a69f91
	expDiagLog("tty_raw_noecho: was raw = %d  echo = %d\r\n",is_raw,!is_noecho);
Packit a69f91
Packit a69f91
	exp_tty_raw(1);
Packit a69f91
	exp_tty_echo(-1);
Packit a69f91
Packit a69f91
	if (exp_tty_set_simple(&tty_current) == -1) {
Packit a69f91
		expErrorLog("ioctl(raw): %s\r\n",Tcl_PosixError(interp));
Packit a69f91
Packit a69f91
		/* SF #439042 -- Allow overide of "exit" by user / script
Packit a69f91
		 */
Packit a69f91
		{
Packit a69f91
		  char buffer [] = "exit 1";
Packit a69f91
		  Tcl_Eval(interp, buffer); 
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
Packit a69f91
	exp_ioctled_devtty = TRUE;
Packit a69f91
	return(1);
Packit a69f91
}
Packit a69f91
Packit a69f91
/* returns 0 if nothing changed */
Packit a69f91
/* if something changed, the out parameters are changed as well */
Packit a69f91
int
Packit a69f91
exp_tty_cooked_echo(
Packit a69f91
    Tcl_Interp *interp,
Packit a69f91
    exp_tty *tty_old,
Packit a69f91
    int *was_raw,
Packit a69f91
    int *was_echo)
Packit a69f91
{
Packit a69f91
	if (exp_disconnected) return(0);
Packit a69f91
	if (!is_raw && !is_noecho) return(0);
Packit a69f91
	if (exp_dev_tty == -1) return(0);
Packit a69f91
Packit a69f91
	*tty_old = tty_current;		/* save old parameters */
Packit a69f91
	*was_raw = is_raw;
Packit a69f91
	*was_echo = !is_noecho;
Packit a69f91
	expDiagLog("tty_cooked_echo: was raw = %d  echo = %d\r\n",is_raw,!is_noecho);
Packit a69f91
Packit a69f91
	exp_tty_raw(-1);
Packit a69f91
	exp_tty_echo(1);
Packit a69f91
Packit a69f91
	if (exp_tty_set_simple(&tty_current) == -1) {
Packit a69f91
		expErrorLog("ioctl(noraw): %s\r\n",Tcl_PosixError(interp));
Packit a69f91
Packit a69f91
		/* SF #439042 -- Allow overide of "exit" by user / script
Packit a69f91
		 */
Packit a69f91
		{
Packit a69f91
		  char buffer [] = "exit 1";
Packit a69f91
		  Tcl_Eval(interp, buffer); 
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
	exp_ioctled_devtty = TRUE;
Packit a69f91
Packit a69f91
	return(1);
Packit a69f91
}
Packit a69f91
Packit a69f91
void
Packit a69f91
exp_tty_set(
Packit a69f91
    Tcl_Interp *interp,
Packit a69f91
    exp_tty *tty,
Packit a69f91
    int raw,
Packit a69f91
    int echo)
Packit a69f91
{
Packit a69f91
	if (exp_tty_set_simple(tty) == -1) {
Packit a69f91
		expErrorLog("ioctl(set): %s\r\n",Tcl_PosixError(interp));
Packit a69f91
Packit a69f91
		/* SF #439042 -- Allow overide of "exit" by user / script
Packit a69f91
		 */
Packit a69f91
		{
Packit a69f91
		  char buffer [] = "exit 1";
Packit a69f91
		  Tcl_Eval(interp, buffer); 
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
	is_raw = raw;
Packit a69f91
	is_noecho = !echo;
Packit a69f91
	tty_current = *tty;
Packit a69f91
	expDiagLog("tty_set: raw = %d, echo = %d\r\n",is_raw,!is_noecho);
Packit a69f91
	exp_ioctled_devtty = TRUE;
Packit a69f91
}	
Packit a69f91
Packit a69f91
#if 0
Packit a69f91
/* avoids scoping problems */
Packit a69f91
void
Packit a69f91
exp_update_cooked_from_current() {
Packit a69f91
	tty_cooked = tty_current;
Packit a69f91
}
Packit a69f91
Packit a69f91
int
Packit a69f91
exp_update_real_tty_from_current() {
Packit a69f91
	return(exp_tty_set_simple(&tty_current));
Packit a69f91
}
Packit a69f91
Packit a69f91
int
Packit a69f91
exp_update_current_from_real_tty() {
Packit a69f91
	return(exp_tty_get_simple(&tty_current));
Packit a69f91
}
Packit a69f91
#endif
Packit a69f91
Packit a69f91
void
Packit a69f91
exp_init_stdio()
Packit a69f91
{
Packit a69f91
	exp_stdin_is_tty = isatty(0);
Packit a69f91
	exp_stdout_is_tty = isatty(1);
Packit a69f91
Packit a69f91
	setbuf(stdout,(char *)0);	/* unbuffer stdout */
Packit a69f91
}
Packit a69f91
Packit a69f91
/*ARGSUSED*/
Packit a69f91
void
Packit a69f91
exp_tty_break(
Packit a69f91
    Tcl_Interp *interp,
Packit a69f91
    int fd)
Packit a69f91
{
Packit a69f91
#ifdef POSIX
Packit a69f91
	tcsendbreak(fd,0);
Packit a69f91
#else
Packit a69f91
# ifdef TIOCSBRK
Packit a69f91
	ioctl(fd,TIOCSBRK,0);
Packit a69f91
	exp_dsleep(interp,0.25); /* sleep for at least a quarter of a second */
Packit a69f91
	ioctl(fd,TIOCCBRK,0);
Packit a69f91
# else
Packit a69f91
	/* dunno how to do this - ignore */
Packit a69f91
# endif
Packit a69f91
#endif
Packit a69f91
}
Packit a69f91
Packit a69f91
/* take strings with newlines and insert carriage-returns.  This allows user */
Packit a69f91
/* to write send_user strings without always putting in \r. */
Packit a69f91
/* If len == 0, use strlen to compute it */
Packit a69f91
/* NB: if terminal is not in raw mode, nothing is done. */
Packit a69f91
char *
Packit a69f91
exp_cook(
Packit a69f91
    char *s,
Packit a69f91
    int *len)	/* current and new length of s */
Packit a69f91
{
Packit a69f91
	static int destlen = 0;
Packit a69f91
	static char *dest = 0;
Packit a69f91
	char *d;		/* ptr into dest */
Packit a69f91
	unsigned int need;
Packit a69f91
Packit a69f91
	if (s == 0) return("<null>");
Packit a69f91
Packit a69f91
	if (!is_raw) return(s);
Packit a69f91
Packit a69f91
	/* worst case is every character takes 2 to represent */
Packit a69f91
	need = 1 + 2*(len?*len:strlen(s));
Packit a69f91
	if (need > destlen) {
Packit a69f91
		if (dest) ckfree(dest);
Packit a69f91
		dest = ckalloc(need);
Packit a69f91
		destlen = need;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	for (d = dest;*s;s++) {
Packit a69f91
		if (*s == '\n') {
Packit a69f91
			*d++ = '\r';
Packit a69f91
			*d++ = '\n';
Packit a69f91
		} else {
Packit a69f91
			*d++ = *s;
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
	*d = '\0';
Packit a69f91
	if (len) *len = d-dest;
Packit a69f91
	return(dest);
Packit a69f91
}
Packit a69f91
Packit a69f91
static int		/* returns TCL_whatever */
Packit a69f91
exec_stty(
Packit a69f91
    Tcl_Interp *interp,
Packit a69f91
    int argc,
Packit a69f91
    char **argv,
Packit a69f91
    int devtty)		/* if true, redirect to /dev/tty */
Packit a69f91
{
Packit a69f91
	int i;
Packit a69f91
	int rc;
Packit a69f91
Packit a69f91
	Tcl_Obj *cmdObj = Tcl_NewStringObj("",0);
Packit a69f91
	Tcl_IncrRefCount(cmdObj);
Packit a69f91
Packit a69f91
	Tcl_AppendStringsToObj(cmdObj,"exec ",(char *)0);
Packit a69f91
	Tcl_AppendStringsToObj(cmdObj,STTY_BIN,(char *)0);
Packit a69f91
	for (i=1;i
Packit a69f91
	    Tcl_AppendStringsToObj(cmdObj," ",argv[i],(char *)0);
Packit a69f91
	}
Packit a69f91
	if (devtty) Tcl_AppendStringsToObj(cmdObj,
Packit a69f91
#ifdef STTY_READS_STDOUT
Packit a69f91
		" >/dev/tty",
Packit a69f91
#else
Packit a69f91
		" 
Packit a69f91
#endif
Packit a69f91
		(char *)0);
Packit a69f91
Packit a69f91
	Tcl_ResetResult(interp);
Packit a69f91
Packit a69f91
	/*
Packit a69f91
	 * normally, I wouldn't set one of Tcl's own variables, but in this
Packit a69f91
	 * case, I only want to see if Tcl resets it to non-NONE, and I don't
Packit a69f91
	 * know any other way of doing it
Packit a69f91
	 */
Packit a69f91
Packit a69f91
	Tcl_SetVar(interp,"errorCode","NONE",0);
Packit a69f91
	rc = Tcl_EvalObjEx(interp,cmdObj,TCL_EVAL_DIRECT);
Packit a69f91
Packit a69f91
	Tcl_DecrRefCount(cmdObj);
Packit a69f91
Packit a69f91
	/* if stty-reads-stdout, stty will fail since Exec */
Packit a69f91
	/* will detect the stderr.  Only by examining errorCode */
Packit a69f91
	/* can we tell if a real error occurred. */	
Packit a69f91
Packit a69f91
#ifdef STTY_READS_STDOUT
Packit a69f91
	if (rc == TCL_ERROR) {
Packit a69f91
		char *ec = Tcl_GetVar(interp,"errorCode",TCL_GLOBAL_ONLY);
Packit a69f91
		if (ec && !streq(ec,"NONE")) return TCL_ERROR;
Packit a69f91
	}
Packit a69f91
#endif
Packit a69f91
	return TCL_OK;
Packit a69f91
}
Packit a69f91
Packit a69f91
/*ARGSUSED*/
Packit a69f91
static int
Packit a69f91
Exp_SttyCmd(
Packit a69f91
    ClientData clientData,
Packit a69f91
    Tcl_Interp *interp,
Packit a69f91
    int argc,
Packit a69f91
    char **argv)
Packit a69f91
{
Packit a69f91
	/* redirection symbol is not counted as a stty arg in terms */
Packit a69f91
	/* of recognition. */
Packit a69f91
	int saw_unknown_stty_arg = FALSE;
Packit a69f91
	int saw_known_stty_arg = FALSE;
Packit a69f91
	int no_args = TRUE;
Packit a69f91
Packit a69f91
	int rc = TCL_OK;
Packit a69f91
	int cooked = FALSE;
Packit a69f91
	int was_raw, was_echo;
Packit a69f91
Packit a69f91
	char **redirect;	/* location of "<" */
Packit a69f91
	char *infile = 0;
Packit a69f91
	int fd;			/* (slave) fd of infile */
Packit a69f91
	int master = -1;	/* master fd of infile */
Packit a69f91
	char **argv0 = argv;
Packit a69f91
Packit a69f91
	for (argv=argv0+1;*argv;argv++) {
Packit a69f91
		if (argv[0][0] == '<') {
Packit a69f91
			redirect = argv;
Packit a69f91
			infile = *(argv+1);
Packit a69f91
			if (!infile) {
Packit a69f91
				expErrorLog("usage: < ttyname");
Packit a69f91
				return TCL_ERROR;
Packit a69f91
			}
Packit a69f91
			if (streq(infile,"/dev/tty")) {
Packit a69f91
				infile = 0;
Packit a69f91
				*argv = 0;
Packit a69f91
				*(argv+1) = 0;
Packit a69f91
				argc -= 2;
Packit a69f91
			} else {
Packit a69f91
				master = exp_trap_off(infile);
Packit a69f91
				if (-1 == (fd = open(infile,2))) {
Packit a69f91
					expErrorLog("couldn't open %s: %s",
Packit a69f91
					 infile,Tcl_PosixError(interp));
Packit a69f91
					return TCL_ERROR;
Packit a69f91
				}
Packit a69f91
			}
Packit a69f91
			break;
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (!infile) {		/* work on /dev/tty */
Packit a69f91
		was_raw = exp_israw();
Packit a69f91
		was_echo = exp_isecho();
Packit a69f91
Packit a69f91
		for (argv=argv0+1;*argv;argv++) {
Packit a69f91
			if (streq(*argv,"raw") ||
Packit a69f91
			    streq(*argv,"-cooked")) {
Packit a69f91
				exp_tty_raw(1);
Packit a69f91
				saw_known_stty_arg = TRUE;
Packit a69f91
				no_args = FALSE;
Packit a69f91
				exp_ioctled_devtty = TRUE;
Packit a69f91
			} else if (streq(*argv,"-raw") ||
Packit a69f91
				   streq(*argv,"cooked")) {
Packit a69f91
				cooked = TRUE;
Packit a69f91
				exp_tty_raw(-1);
Packit a69f91
				saw_known_stty_arg = TRUE;
Packit a69f91
				no_args = FALSE;
Packit a69f91
				exp_ioctled_devtty = TRUE;
Packit a69f91
			} else if (streq(*argv,"echo")) {
Packit a69f91
				exp_tty_echo(1);
Packit a69f91
				saw_known_stty_arg = TRUE;
Packit a69f91
				no_args = FALSE;
Packit a69f91
				exp_ioctled_devtty = TRUE;
Packit a69f91
			} else if (streq(*argv,"-echo")) {
Packit a69f91
				exp_tty_echo(-1);
Packit a69f91
				saw_known_stty_arg = TRUE;
Packit a69f91
				no_args = FALSE;
Packit a69f91
				exp_ioctled_devtty = TRUE;
Packit a69f91
			} else if (streq(*argv,"rows")) {
Packit a69f91
				if (*(argv+1)) {
Packit a69f91
					exp_win_rows_set(*(argv+1));
Packit a69f91
					argv++;
Packit a69f91
					no_args = FALSE;
Packit a69f91
					exp_ioctled_devtty = TRUE;
Packit a69f91
				} else {
Packit a69f91
		    Tcl_SetResult (interp, exp_win_rows_get(), TCL_VOLATILE);
Packit a69f91
					return TCL_OK;
Packit a69f91
				}
Packit a69f91
			} else if (streq(*argv,"columns")) {
Packit a69f91
				if (*(argv+1)) {
Packit a69f91
					exp_win_columns_set(*(argv+1));
Packit a69f91
					argv++;
Packit a69f91
					no_args = FALSE;
Packit a69f91
					exp_ioctled_devtty = TRUE;
Packit a69f91
				} else {
Packit a69f91
		    Tcl_SetResult (interp, exp_win_columns_get(), TCL_VOLATILE);
Packit a69f91
					return TCL_OK;
Packit a69f91
				}
Packit a69f91
			} else {
Packit a69f91
				saw_unknown_stty_arg = TRUE;
Packit a69f91
			}
Packit a69f91
		}
Packit a69f91
		/* if any unknown args, let real stty try */
Packit a69f91
		if (saw_unknown_stty_arg || no_args) {
Packit a69f91
			if (saw_unknown_stty_arg) {
Packit a69f91
			    exp_ioctled_devtty = TRUE;
Packit a69f91
			}
Packit a69f91
Packit a69f91
			/* let real stty try */
Packit a69f91
			rc = exec_stty(interp,argc,argv0,1);
Packit a69f91
Packit a69f91
			/* find out what weird options user asked for */
Packit a69f91
			if (exp_tty_get_simple(&tty_current) == -1) {
Packit a69f91
				exp_error(interp,"stty: ioctl(get): %s\r\n",Tcl_PosixError(interp));
Packit a69f91
				rc = TCL_ERROR;
Packit a69f91
			}
Packit a69f91
			if (cooked) {
Packit a69f91
				/* find out user's new defn of 'cooked' */
Packit a69f91
				tty_cooked = tty_current;
Packit a69f91
			}
Packit a69f91
		} else if (saw_known_stty_arg) {
Packit a69f91
			if (exp_tty_set_simple(&tty_current) == -1) {
Packit a69f91
			    if (exp_disconnected || (exp_dev_tty == -1) || !isatty(exp_dev_tty)) {
Packit a69f91
				expErrorLog("stty: impossible in this context\n");
Packit a69f91
				expErrorLog("are you disconnected or in a batch, at, or cron script?");
Packit a69f91
				/* user could've conceivably closed /dev/tty as well */
Packit a69f91
			    }
Packit a69f91
			    exp_error(interp,"stty: ioctl(user): %s\r\n",Tcl_PosixError(interp));
Packit a69f91
			    rc = TCL_ERROR;
Packit a69f91
			}
Packit a69f91
		}
Packit a69f91
Packit a69f91
		/* if no result, make a crude one */
Packit a69f91
		if (0 == strcmp(Tcl_GetString(Tcl_GetObjResult(interp)),"")) {
Packit a69f91
		    char buf [11];
Packit a69f91
		    sprintf(buf,"%sraw %secho",
Packit a69f91
			    (was_raw?"":"-"),
Packit a69f91
			    (was_echo?"":"-"));
Packit a69f91
		    Tcl_SetResult (interp, buf, TCL_VOLATILE);
Packit a69f91
		}
Packit a69f91
	} else {
Packit a69f91
		/* a different tty */
Packit a69f91
Packit a69f91
		/* temporarily zap redirect */
Packit a69f91
		char *redirect_save = *redirect;
Packit a69f91
		*redirect = 0;
Packit a69f91
Packit a69f91
		for (argv=argv0+1;*argv;argv++) {
Packit a69f91
			if (streq(*argv,"rows")) {
Packit a69f91
				if (*(argv+1)) {
Packit a69f91
					exp_win2_rows_set(fd,*(argv+1));
Packit a69f91
					argv++;
Packit a69f91
					no_args = FALSE;
Packit a69f91
				} else {
Packit a69f91
		    Tcl_SetResult (interp, exp_win2_rows_get(fd), TCL_VOLATILE);
Packit a69f91
					goto done;
Packit a69f91
				}
Packit a69f91
			} else if (streq(*argv,"columns")) {
Packit a69f91
				if (*(argv+1)) {
Packit a69f91
					exp_win2_columns_set(fd,*(argv+1));
Packit a69f91
					argv++;
Packit a69f91
					no_args = FALSE;
Packit a69f91
				} else {
Packit a69f91
		    Tcl_SetResult (interp, exp_win2_columns_get(fd), TCL_VOLATILE);
Packit a69f91
					goto done;
Packit a69f91
				}
Packit a69f91
			} else if (streq(*argv,"<")) {
Packit a69f91
				break;
Packit a69f91
			} else {
Packit a69f91
				saw_unknown_stty_arg = TRUE;
Packit a69f91
				break;
Packit a69f91
			}
Packit a69f91
		}
Packit a69f91
Packit a69f91
		/* restore redirect */
Packit a69f91
		*redirect = redirect_save;
Packit a69f91
Packit a69f91
		close(fd);	/* no more use for this, from now on */
Packit a69f91
				/* pass by name */
Packit a69f91
Packit a69f91
		if (saw_unknown_stty_arg || no_args) {
Packit a69f91
#ifdef STTY_READS_STDOUT
Packit a69f91
			/* switch "<" to ">" */
Packit a69f91
			char original_redirect_char = (*redirect)[0];
Packit a69f91
			(*redirect)[0] = '>';
Packit a69f91
			/* stderr unredirected so we can get it directly! */
Packit a69f91
#endif
Packit a69f91
			rc = exec_stty(interp,argc,argv0,0);
Packit a69f91
#ifdef STTY_READS_STDOUT
Packit a69f91
			/* restore redirect - don't know if necessary */
Packit a69f91
			(*redirect)[0] = original_redirect_char;
Packit a69f91
#endif
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
 done:
Packit a69f91
	exp_trap_on(master);
Packit a69f91
Packit a69f91
	return rc;
Packit a69f91
}
Packit a69f91
Packit a69f91
/*ARGSUSED*/
Packit a69f91
static int
Packit a69f91
Exp_SystemCmd(
Packit a69f91
    ClientData clientData,
Packit a69f91
    Tcl_Interp *interp,
Packit a69f91
    int argc,
Packit a69f91
    char **argv)
Packit a69f91
{
Packit a69f91
	int result = TCL_OK;
Packit a69f91
	RETSIGTYPE (*old)();	/* save old sigalarm handler */
Packit a69f91
#define MAX_ARGLIST 10240
Packit a69f91
	int i;
Packit a69f91
Packit a69f91
	WAIT_STATUS_TYPE waitStatus;
Packit a69f91
	int systemStatus
Packit a69f91
;
Packit a69f91
	int abnormalExit = FALSE;
Packit a69f91
	char buf[MAX_ARGLIST];
Packit a69f91
	char *bufp = buf;
Packit a69f91
	int total_len = 0, arg_len;
Packit a69f91
Packit a69f91
	int stty_args_recognized = TRUE;
Packit a69f91
	int cmd_is_stty = FALSE;
Packit a69f91
	int cooked = FALSE;
Packit a69f91
	int was_raw, was_echo;
Packit a69f91
Packit a69f91
	if (argc == 1) return TCL_OK;
Packit a69f91
Packit a69f91
	if (streq(argv[1],"stty")) {
Packit a69f91
		expDiagLogU("system stty is deprecated, use stty\r\n");
Packit a69f91
Packit a69f91
		cmd_is_stty = TRUE;
Packit a69f91
		was_raw = exp_israw();
Packit a69f91
		was_echo = exp_isecho();
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (argc > 2 && cmd_is_stty) {
Packit a69f91
		exp_ioctled_devtty = TRUE;
Packit a69f91
Packit a69f91
		for (i=2;i
Packit a69f91
			if (streq(argv[i],"raw") ||
Packit a69f91
			    streq(argv[i],"-cooked")) {
Packit a69f91
				exp_tty_raw(1);
Packit a69f91
			} else if (streq(argv[i],"-raw") ||
Packit a69f91
				   streq(argv[i],"cooked")) {
Packit a69f91
				cooked = TRUE;
Packit a69f91
				exp_tty_raw(-1);
Packit a69f91
			} else if (streq(argv[i],"echo")) {
Packit a69f91
				exp_tty_echo(1);
Packit a69f91
			} else if (streq(argv[i],"-echo")) {
Packit a69f91
				exp_tty_echo(-1);
Packit a69f91
			} else stty_args_recognized = FALSE;
Packit a69f91
		}
Packit a69f91
Packit a69f91
		/* if unknown args, fall thru and let real stty have a go */
Packit a69f91
		if (stty_args_recognized) {
Packit a69f91
	    if (
Packit a69f91
#ifdef HAVE_TCSETATTR
Packit a69f91
		tcsetattr(exp_dev_tty,TCSADRAIN, &tty_current) == -1
Packit a69f91
#else
Packit a69f91
		ioctl(exp_dev_tty, TCSETSW, &tty_current) == -1
Packit a69f91
#endif
Packit a69f91
		) {
Packit a69f91
			    if (exp_disconnected || (exp_dev_tty == -1) || !isatty(exp_dev_tty)) {
Packit a69f91
				expErrorLog("system stty: impossible in this context\n");
Packit a69f91
				expErrorLog("are you disconnected or in a batch, at, or cron script?");
Packit a69f91
				/* user could've conceivably closed /dev/tty as well */
Packit a69f91
			    }
Packit a69f91
			    exp_error(interp,"system stty: ioctl(user): %s\r\n",Tcl_PosixError(interp));
Packit a69f91
			    return(TCL_ERROR);
Packit a69f91
			}
Packit a69f91
			if (cmd_is_stty) {
Packit a69f91
			    char buf [11];
Packit a69f91
			    sprintf(buf,"%sraw %secho",
Packit a69f91
				    (was_raw?"":"-"),
Packit a69f91
				    (was_echo?"":"-"));
Packit a69f91
			    Tcl_SetResult (interp, buf, TCL_VOLATILE);
Packit a69f91
			}
Packit a69f91
			return(TCL_OK);
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
Packit a69f91
	for (i = 1;i
Packit a69f91
		total_len += (1 + (arg_len = strlen(argv[i])));
Packit a69f91
		if (total_len > MAX_ARGLIST) {
Packit a69f91
			exp_error(interp,"args too long (>=%d chars)",
Packit a69f91
				total_len);
Packit a69f91
			return(TCL_ERROR);
Packit a69f91
		}
Packit a69f91
		memcpy(bufp,argv[i],arg_len);
Packit a69f91
		bufp += arg_len;
Packit a69f91
		/* no need to check bounds, we accted for it earlier */
Packit a69f91
		memcpy(bufp," ",1);
Packit a69f91
		bufp += 1;
Packit a69f91
	}
Packit a69f91
Packit a69f91
	*(bufp-1) = '\0';
Packit a69f91
Packit a69f91
	old = signal(SIGCHLD, SIG_DFL);
Packit a69f91
	systemStatus = system(buf);
Packit a69f91
	signal(SIGCHLD, old);	/* restore signal handler */
Packit a69f91
	expDiagLogU("system(");
Packit a69f91
	expDiagLogU(buf);
Packit a69f91
	expDiagLog(") = %d\r\n",i);
Packit a69f91
Packit a69f91
	if (systemStatus == -1) {
Packit a69f91
		exp_error(interp,Tcl_PosixError(interp));
Packit a69f91
		return TCL_ERROR;
Packit a69f91
	}
Packit a69f91
	*(int *)&waitStatus = systemStatus;
Packit a69f91
Packit a69f91
	if (!stty_args_recognized) {
Packit a69f91
		/* find out what weird options user asked for */
Packit a69f91
	if (
Packit a69f91
#ifdef HAVE_TCSETATTR
Packit a69f91
	    tcgetattr(exp_dev_tty, &tty_current) == -1
Packit a69f91
#else
Packit a69f91
	    ioctl(exp_dev_tty, TCGETS, &tty_current) == -1
Packit a69f91
#endif
Packit a69f91
	    ) {
Packit a69f91
			expErrorLog("ioctl(get): %s\r\n",Tcl_PosixError(interp));
Packit a69f91
Packit a69f91
			/* SF #439042 -- Allow overide of "exit" by user / script
Packit a69f91
			 */
Packit a69f91
			{
Packit a69f91
			  char buffer [] = "exit 1";
Packit a69f91
			  Tcl_Eval(interp, buffer); 
Packit a69f91
			}
Packit a69f91
		}
Packit a69f91
		if (cooked) {
Packit a69f91
			/* find out user's new defn of 'cooked' */
Packit a69f91
			tty_cooked = tty_current;
Packit a69f91
		}
Packit a69f91
	}
Packit a69f91
Packit a69f91
	if (cmd_is_stty) {
Packit a69f91
	    char buf [11];
Packit a69f91
	    sprintf(buf,"%sraw %secho",
Packit a69f91
		    (was_raw?"":"-"),
Packit a69f91
		    (was_echo?"":"-"));
Packit a69f91
	    Tcl_SetResult (interp, buf, TCL_VOLATILE);
Packit a69f91
	}
Packit a69f91
Packit a69f91
/* following macros stolen from Tcl's tclUnix.h file */
Packit a69f91
/* we can't include the whole thing because it depends on other macros */
Packit a69f91
/* that come out of Tcl's Makefile, sigh */
Packit a69f91
Packit a69f91
#if 0
Packit a69f91
Packit a69f91
#undef WIFEXITED
Packit a69f91
#ifndef WIFEXITED
Packit a69f91
#   define WIFEXITED(stat)  (((*((int *) &(stat))) & 0xff) == 0)
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#undef WEXITSTATUS
Packit a69f91
#ifndef WEXITSTATUS
Packit a69f91
#   define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff)
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#undef WIFSIGNALED
Packit a69f91
#ifndef WIFSIGNALED
Packit a69f91
#   define WIFSIGNALED(stat) (((*((int *) &(stat)))) && ((*((int *) &(stat))) == ((*((int *) &(stat))) & 0x00ff)))
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#undef WTERMSIG
Packit a69f91
#ifndef WTERMSIG
Packit a69f91
#   define WTERMSIG(stat)    ((*((int *) &(stat))) & 0x7f)
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#undef WIFSTOPPED
Packit a69f91
#ifndef WIFSTOPPED
Packit a69f91
#   define WIFSTOPPED(stat)  (((*((int *) &(stat))) & 0xff) == 0177)
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#undef WSTOPSIG
Packit a69f91
#ifndef WSTOPSIG
Packit a69f91
#   define WSTOPSIG(stat)    (((*((int *) &(stat))) >> 8) & 0xff)
Packit a69f91
#endif
Packit a69f91
Packit a69f91
#endif /* 0 */
Packit a69f91
Packit a69f91
/* stolen from Tcl.    Again, this is embedded in another routine */
Packit a69f91
/* (CleanupChildren in tclUnixAZ.c) that we can't use directly. */
Packit a69f91
Packit a69f91
	if (!WIFEXITED(waitStatus) || (WEXITSTATUS(waitStatus) != 0)) {
Packit a69f91
	    char msg1[20], msg2[20];
Packit a69f91
	    int pid = 0;	/* fake a pid, since system() won't tell us */ 
Packit a69f91
Packit a69f91
	    result = TCL_ERROR;
Packit a69f91
	    sprintf(msg1, "%d", pid);
Packit a69f91
	    if (WIFEXITED(waitStatus)) {
Packit a69f91
		sprintf(msg2, "%d", WEXITSTATUS(waitStatus));
Packit a69f91
		Tcl_SetErrorCode(interp, "CHILDSTATUS", msg1, msg2,
Packit a69f91
			(char *) NULL);
Packit a69f91
		abnormalExit = TRUE;
Packit a69f91
	    } else if (WIFSIGNALED(waitStatus)) {
Packit a69f91
		CONST char *p;
Packit a69f91
	
Packit a69f91
		p = Tcl_SignalMsg((int) (WTERMSIG(waitStatus)));
Packit a69f91
		Tcl_SetErrorCode(interp, "CHILDKILLED", msg1,
Packit a69f91
			Tcl_SignalId((int) (WTERMSIG(waitStatus))), p,
Packit a69f91
			(char *) NULL);
Packit a69f91
		Tcl_AppendResult(interp, "child killed: ", p, "\n",
Packit a69f91
			(char *) NULL);
Packit a69f91
	    } else if (WIFSTOPPED(waitStatus)) {
Packit a69f91
		CONST char *p;
Packit a69f91
Packit a69f91
		p = Tcl_SignalMsg((int) (WSTOPSIG(waitStatus)));
Packit a69f91
		Tcl_SetErrorCode(interp, "CHILDSUSP", msg1,
Packit a69f91
			Tcl_SignalId((int) (WSTOPSIG(waitStatus))), p, (char *) NULL);
Packit a69f91
		Tcl_AppendResult(interp, "child suspended: ", p, "\n",
Packit a69f91
			(char *) NULL);
Packit a69f91
	    } else {
Packit a69f91
		Tcl_AppendResult(interp,
Packit a69f91
			"child wait status didn't make sense\n",
Packit a69f91
			(char *) NULL);
Packit a69f91
	    }
Packit a69f91
	}
Packit a69f91
Packit a69f91
    if (abnormalExit && (Tcl_GetStringResult (interp)[0] == 0)) {
Packit a69f91
	Tcl_AppendResult(interp, "child process exited abnormally",
Packit a69f91
		(char *) NULL);
Packit a69f91
    }
Packit a69f91
Packit a69f91
    return result;
Packit a69f91
}
Packit a69f91
Packit a69f91
static struct exp_cmd_data
Packit a69f91
cmd_data[]  = {
Packit a69f91
{"stty",	exp_proc(Exp_SttyCmd),	0,	0},
Packit a69f91
{"system",	exp_proc(Exp_SystemCmd),	0,	0},
Packit a69f91
{0}};
Packit a69f91
Packit a69f91
void
Packit a69f91
exp_init_tty_cmds(struct Tcl_Interp *interp)
Packit a69f91
{
Packit a69f91
	exp_create_commands(interp,cmd_data);
Packit a69f91
}
Packit a69f91

Packit a69f91
/*
Packit a69f91
 * Local Variables:
Packit a69f91
 * mode: c
Packit a69f91
 * c-basic-offset: 4
Packit a69f91
 * fill-column: 78
Packit a69f91
 * End:
Packit a69f91
 */