#include "expect_cf.h"
#include <stdio.h>
#include <signal.h>
#if defined(SIGCLD) && !defined(SIGCHLD)
#define SIGCHLD SIGCLD
#endif
extern char *TclGetRegError();
#if defined(HAVE_PTYM) && defined(HAVE_PTMX)
#undef HAVE_PTMX
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#ifdef NO_STDLIB_H
#include "../compat/stdlib.h"
#else
#include <stdlib.h>
#endif
#ifdef HAVE_SYSMACROS_H
#include <sys/sysmacros.h>
#endif
#ifdef HAVE_PTYTRAP
#include <sys/ptyio.h>
#endif
#include <sys/file.h>
#ifdef HAVE_SYS_FCNTL_H
# include <sys/fcntl.h>
#else
# include <fcntl.h>
#endif
#if defined(_SEQUENT_)
# include <sys/strpty.h>
#endif
#if defined(HAVE_PTMX) && !defined(__CYGWIN32__)
# include <sys/stropts.h>
#endif
#include "exp_win.h"
#include "exp_tty_in.h"
#include "exp_rename.h"
#include "exp_pty.h"
void debuglog();
#include <errno.h>
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#if defined(HAVE_GETPTY) && defined(CONVEX)
#undef HAVE_GETPTY
#define HAVE_CONVEX_GETPTY
extern char *getpty();
static char *master_name;
static char slave_name[] = "/dev/ptyXX";
static char *tty_bank;
static char *tty_num;
#endif
#if defined(_SEQUENT_) && !defined(HAVE_PTMX)
static char *master_name, *slave_name;
#endif
#if defined(HAVE__GETPTY) && defined(HAVE_PTC) && !defined(HAVE_GETPTY)
#undef HAVE_PTC
#endif
#if defined(HAVE_PTC)
static char slave_name[] = "/dev/ttyqXXX";
#undef HAVE_GETPTY
#undef HAVE__GETPTY
#endif
#if defined(HAVE__GETPTY) || defined(HAVE_PTC_PTS) || defined(HAVE_PTMX)
static char *slave_name;
#endif
#if defined(HAVE_GETPTY)
#include <sys/vty.h>
static char master_name[MAXPTYNAMELEN];
static char slave_name[MAXPTYNAMELEN];
#endif
#if !defined(HAVE_GETPTY) && !defined(HAVE__GETPTY) && !defined(HAVE_PTC) && !defined(HAVE_PTC_PTS) && !defined(HAVE_PTMX) && !defined(HAVE_CONVEX_GETPTY) && !defined(_SEQUENT_) && !defined(HAVE_SCO_CLIST_PTYS) && !defined(HAVE_OPENPTY)
#ifdef HAVE_PTYM
static char banks[] = "pqrstuvwxyzabcefghijklo";
static char master_name[] = "/dev/ptym/ptyXXXX";
static char slave_name[] = "/dev/pty/ttyXXXX";
static char *slave_bank;
static char *slave_num;
#else
static char banks[] = "pqrstuvwxyzPQRSTUVWXYZ";
static char master_name[] = "/dev/ptyXX";
static char slave_name [] = "/dev/ttyXX";
#endif
static char *tty_type;
static char *tty_bank;
static char *tty_num;
#endif
#if defined(HAVE_SCO_CLIST_PTYS)
# define MAXPTYNAMELEN 64
static char master_name[MAXPTYNAMELEN];
static char slave_name[MAXPTYNAMELEN];
#endif
#ifdef HAVE_OPENPTY
static char master_name[64];
static char slave_name[64];
#endif
char *exp_pty_slave_name;
char *exp_pty_error;
#if 0
static void
pty_stty(s,name)
char *s;
char *name;
{
#define MAX_ARGLIST 10240
char buf[MAX_ARGLIST];
RETSIGTYPE (*old)();
int pid;
old = signal(SIGCHLD, SIG_DFL);
switch (pid = fork()) {
case 0:
exec_stty("/bin/stty","/bin/stty",s);
break;
case -1:
default:
waitpid(pid);
break;
}
signal(SIGCHLD, old);
}
exec_stty(s)
char *s;
{
char *args[50];
char *cp;
int argi = 0;
int quoting = FALSE;
int in_token = FALSE;
args[0] = cp = s;
while (*s) {
if (quoting) {
if (*s == '\\' && *(s+1) == '"') {
s++;
*cp++ = *s++;
} else if (*s == '\"') {
end_token
quoting = FALSE;
} else *cp++ = *s++;
} else if (*s == '\"') {
in_token = TRUE;
quoting = TRUE;
s++;
} else if (isspace(*s)) {
end_token
} else {
*cp++ = *s++;
in_token = TRUE;
}
}
end_token
args[argi] = (char *) 0;
execvp(args[0],args);
}
#endif
static void
pty_stty(s,name)
char *s;
char *name;
{
#define MAX_ARGLIST 10240
char buf[MAX_ARGLIST];
RETSIGTYPE (*old)();
#ifdef STTY_READS_STDOUT
sprintf(buf,"/bin/stty %s > %s",s,name);
#else
#ifdef __CYGWIN32__
sprintf(buf,"stty %s < %s",s,name);
#else
sprintf(buf,"/bin/stty %s < %s",s,name);
#endif
#endif
old = signal(SIGCHLD, SIG_DFL);
system(buf);
signal(SIGCHLD, old);
}
int exp_dev_tty;
static int knew_dev_tty;
exp_tty exp_tty_original;
#define GET_TTYTYPE 0
#define SET_TTYTYPE 1
static void
ttytype(request,fd,ttycopy,ttyinit,s)
int request;
int fd;
int ttycopy;
int ttyinit;
char *s;
{
if (request == GET_TTYTYPE) {
#ifdef HAVE_TCSETATTR
if (-1 == tcgetattr(fd, &exp_tty_original)) {
#else
if (-1 == ioctl(fd, TCGETS, (char *)&exp_tty_original)) {
#endif
knew_dev_tty = FALSE;
exp_dev_tty = -1;
}
exp_window_size_get(fd);
} else {
if (ttycopy && knew_dev_tty) {
#ifdef HAVE_TCSETATTR
(void) tcsetattr(fd, TCSADRAIN, &exp_tty_current);
#else
(void) ioctl(fd, TCSETS, (char *)&exp_tty_current);
#endif
exp_window_size_set(fd);
}
#ifdef __CENTERLINE__
#undef DFLT_STTY
#define DFLT_STTY "sane"
#endif
#ifdef DFLT_STTY
if (ttyinit) {
pty_stty(DFLT_STTY,slave_name);
}
#endif
if (s) {
pty_stty(s,slave_name);
}
}
}
void
exp_init_pty()
{
#if !defined(HAVE_GETPTY) && !defined(HAVE__GETPTY) && !defined(HAVE_PTC) && !defined(HAVE_PTC_PTS) && !defined(HAVE_PTMX) && !defined(HAVE_CONVEX_GETPTY) && !defined(_SEQUENT_) && !defined(HAVE_SCO_CLIST_PTYS) && !defined(HAVE_OPENPTY)
#ifdef HAVE_PTYM
static char dummy;
tty_bank = &master_name[strlen("/dev/ptym/pty")];
tty_num = &master_name[strlen("/dev/ptym/ptyX")];
slave_bank = &slave_name[strlen("/dev/pty/tty")];
slave_num = &slave_name[strlen("/dev/pty/ttyX")];
#else
tty_bank = &master_name[strlen("/dev/pty")];
tty_num = &master_name[strlen("/dev/ptyp")];
tty_type = &slave_name[strlen("/dev/")];
#endif
#endif
exp_dev_tty = open("/dev/tty",O_RDWR);
knew_dev_tty = (exp_dev_tty != -1);
if (knew_dev_tty) ttytype(GET_TTYTYPE,exp_dev_tty,0,0,(char *)0);
}
#ifndef R_OK
#define R_OK 04
#define W_OK 02
#endif
int
getptymaster()
{
char *hex, *bank;
struct stat stat_buf;
int master = -1;
int slave = -1;
int num;
exp_pty_error = 0;
#define TEST_PTY 1
#if defined(HAVE_PTMX) || defined(HAVE_PTMX_BSD)
#undef TEST_PTY
#if defined(HAVE_PTMX_BSD)
if ((master = open("/dev/ptmx_bsd", O_RDWR)) == -1) return(-1);
#else
if ((master = open("/dev/ptmx", O_RDWR)) == -1) return(-1);
#endif
if ((slave_name = (char *)ptsname(master)) == NULL || unlockpt(master)) {
close(master);
return(-1);
} else if (grantpt(master)) {
static char buf[500];
exp_pty_error = buf;
sprintf(exp_pty_error,"grantpt(%d) failed - likely reason is that your system administrator (in a rage of blind passion to rid the system of security holes) removed setuid from the utility used internally by grantpt to change pty permissions. Tell your system admin to reestablish setuid on the utility. Get the utility name by running Expect under truss or trace.");
close(master);
return(-1);
}
#ifdef TIOCFLUSH
(void) ioctl(master,TIOCFLUSH,(char *)0);
#endif
exp_pty_slave_name = slave_name;
return(master);
#endif
#if defined(HAVE__GETPTY)
#undef TEST_PTY
slave_name = _getpty(&master, O_RDWR, 0600, 0);
if (slave_name == NULL)
return (-1);
exp_pty_slave_name = slave_name;
return(master);
#endif
#if defined(HAVE_PTC) && !defined(HAVE__GETPTY)
#undef TEST_PTY
master = open("/dev/ptc", O_RDWR);
if (master >= 0) {
int ptynum;
if (fstat(master, &stat_buf) < 0) {
close(master);
return(-1);
}
ptynum = minor(stat_buf.st_rdev);
sprintf(slave_name,"/dev/ttyq%d",ptynum);
}
exp_pty_slave_name = slave_name;
return(master);
#endif
#if defined(HAVE_GETPTY) && !defined(HAVE__GETPTY)
#undef TEST_PTY
master = getpty(master_name, slave_name, O_RDWR);
exp_pty_slave_name = slave_name;
return master;
#endif
#if defined(HAVE_PTC_PTS)
#undef TEST_PTY
master = open("/dev/ptc",O_RDWR);
if (master >= 0) {
slave_name = ttyname(master);
}
exp_pty_slave_name = slave_name;
return(master);
#endif
#if defined(_SEQUENT_) && !defined(HAVE_PTMX)
#undef TEST_PTY
master = getpseudotty(&slave_name, &master_name);
exp_pty_slave_name = slave_name;
return(master);
#endif
#if defined(HAVE_OPENPTY)
#undef TEST_PTY
if (openpty(&master, &slave, master_name, 0, 0) != 0) {
close(master);
close(slave);
return -1;
}
strcpy(slave_name, ttyname(slave));
exp_pty_slave_name = slave_name;
close(slave);
return master;
#endif
#if defined(TEST_PTY)
if (exp_pty_test_start() == -1) return -1;
#if !defined(HAVE_CONVEX_GETPTY) && !defined(HAVE_PTYM) && !defined(HAVE_SCO_CLIST_PTYS)
for (bank = banks;*bank;bank++) {
*tty_bank = *bank;
*tty_num = '0';
if (stat(master_name, &stat_buf) < 0) break;
for (hex = "0123456789abcdef";*hex;hex++) {
*tty_num = *hex;
strcpy(slave_name,master_name);
*tty_type = 't';
master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num);
if (master >= 0) goto done;
}
}
#endif
#ifdef HAVE_SCO_CLIST_PTYS
for (num = 0; ; num++) {
char num_str [16];
sprintf (num_str, "%d", num);
sprintf (master_name, "%s%s", "/dev/ptyp", num_str);
if (stat (master_name, &stat_buf) < 0)
break;
sprintf (slave_name, "%s%s", "/dev/ttyp", num_str);
master = exp_pty_test (master_name, slave_name, 0, num_str);
if (master >= 0)
goto done;
}
#endif
#ifdef HAVE_PTYM
for (bank = banks;*bank;bank++) {
*tty_bank = *bank;
sprintf(tty_num,"0");
if (stat(master_name, &stat_buf) < 0) break;
*(slave_num+1) = '\0';
for (hex = "0123456789abcdef";*hex;hex++) {
*tty_num = *hex;
*slave_bank = *tty_bank;
*slave_num = *tty_num;
master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num);
if (master >= 0) goto done;
}
}
for (bank = banks;*bank;bank++) {
*tty_bank = *bank;
sprintf(tty_num,"00");
if (stat(master_name, &stat_buf) < 0) break;
for (num = 0; num<100; num++) {
*slave_bank = *tty_bank;
sprintf(tty_num,"%02d",num);
strcpy(slave_num,tty_num);
master = exp_pty_test(master_name,slave_name,tty_bank,tty_num);
if (master >= 0) goto done;
}
}
for (bank = banks;*bank;bank++) {
*tty_bank = *bank;
sprintf(tty_num,"000");
if (stat(master_name, &stat_buf) < 0) break;
for (num = 0; num<1000; num++) {
*slave_bank = *tty_bank;
sprintf(tty_num,"%03d",num);
strcpy(slave_num,tty_num);
master = exp_pty_test(master_name,slave_name,tty_bank,tty_num);
if (master >= 0) goto done;
}
}
#endif
#if defined(HAVE_CONVEX_GETPTY)
for (;;) {
if ((master_name = getpty()) == NULL) return -1;
strcpy(slave_name,master_name);
slave_name[5] = 't';
tty_bank = &slave_name[8];
tty_num = &slave_name[9];
master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num);
if (master >= 0) goto done;
}
#endif
done:
exp_pty_test_end();
exp_pty_slave_name = slave_name;
return(master);
#endif
}
void
exp_slave_control(master,control)
int master;
int control;
{
#ifdef HAVE_PTYTRAP
ioctl(master, TIOCTRAP, &control);
#endif
}
int
getptyslave(ttycopy,ttyinit,stty_args)
int ttycopy;
int ttyinit;
char *stty_args;
{
int slave, slave2;
char buf[10240];
if (0 > (slave = open(slave_name, O_RDWR))) return(-1);
#if defined(HAVE_PTMX_BSD)
if (ioctl (slave, I_LOOK, buf) != 0)
if (ioctl (slave, I_PUSH, "ldterm")) {
debuglog("ioctl(%s,I_PUSH,\"ldterm\") = %s\n",Tcl_ErrnoMsg(errno));
}
#else
#if defined(HAVE_PTMX) && ! defined(__CYGWIN32__)
if (ioctl(slave, I_PUSH, "ptem")) {
debuglog("ioctl(%s,I_PUSH,\"ptem\") = %s\n",Tcl_ErrnoMsg(errno));
}
if (ioctl(slave, I_PUSH, "ldterm")) {
debuglog("ioctl(%s,I_PUSH,\"ldterm\") = %s\n",Tcl_ErrnoMsg(errno));
}
if (ioctl(slave, I_PUSH, "ttcompat")) {
debuglog("ioctl(%s,I_PUSH,\"ttcompat\") = %s\n",Tcl_ErrnoMsg(errno));
}
#endif
#endif
if (0 == slave) {
fcntl(0,F_DUPFD,1);
fcntl(0,F_DUPFD,2);
}
ttytype(SET_TTYTYPE,slave,ttycopy,ttyinit,stty_args);
#if 0
#ifdef HAVE_PTYTRAP
if (0 > (slave2 = open(slave_name, O_RDWR))) return(-1);
close(slave2);
#endif
#endif
(void) exp_pty_unlock();
return(slave);
}
#ifdef HAVE_PTYTRAP
#include <sys/ptyio.h>
#include <sys/time.h>
int
exp_wait_for_slave_open(fd)
int fd;
{
fd_set excep;
struct timeval t;
struct request_info ioctl_info;
int rc;
int found = 0;
int maxfds = sysconf(_SC_OPEN_MAX);
t.tv_sec = 30;
t.tv_usec = 0;
FD_ZERO(&excep);
FD_SET(fd,&excep);
rc = select(maxfds,
(SELECT_MASK_TYPE *)0,
(SELECT_MASK_TYPE *)0,
(SELECT_MASK_TYPE *)&excep,
&t);
if (rc != 1) {
debuglog("spawned process never started, errno = %d\n",errno);
return(-1);
}
if (ioctl(fd,TIOCREQCHECK,&ioctl_info) < 0) {
debuglog("ioctl(TIOCREQCHECK) failed, errno = %d\n",errno);
return(-1);
}
found = ioctl_info.request;
debuglog("trapped pty op = %x",found);
if (found == TIOCOPEN) {
debuglog(" TIOCOPEN");
} else if (found == TIOCCLOSE) {
debuglog(" TIOCCLOSE");
}
#ifdef TIOCSCTTY
if (found == TIOCSCTTY) {
debuglog(" TIOCSCTTY");
}
#endif
if (found & IOC_IN) {
debuglog(" IOC_IN (set)");
} else if (found & IOC_OUT) {
debuglog(" IOC_OUT (get)");
}
debuglog("\n");
if (ioctl(fd, TIOCREQSET, &ioctl_info) < 0) {
debuglog("ioctl(TIOCREQSET) failed, errno = %d\n",errno);
return(-1);
}
return(found);
}
#endif
void
exp_pty_exit()
{
}