#define RES_OFFSET(field) XtOffsetOf(XTERM_RESOURCE, field)
#include <xterm.h>
#include <X11/cursorfont.h>
#include <X11/Xlocale.h>
#if OPT_TOOLBAR
#if defined(HAVE_LIB_XAW)
#include <X11/Xaw/Form.h>
#elif defined(HAVE_LIB_XAW3D)
#include <X11/Xaw3d/Form.h>
#elif defined(HAVE_LIB_NEXTAW)
#include <X11/neXtaw/Form.h>
#elif defined(HAVE_LIB_XAWPLUS)
#include <X11/XawPlus/Form.h>
#endif
#endif
#include <pwd.h>
#include <ctype.h>
#include <data.h>
#include <error.h>
#include <menu.h>
#include <main.h>
#include <xstrings.h>
#include <xtermcap.h>
#include <xterm_io.h>
#if OPT_WIDE_CHARS
#include <charclass.h>
#endif
#ifdef __osf__
#define USE_SYSV_SIGNALS
#define WTMP
#include <pty.h>
#endif
#ifdef __sgi
#include <grp.h>
#endif
#ifdef USE_ISPTS_FLAG
static Bool IsPts = False;
#endif
#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE)
#define USE_POSIX_SIGNALS
#endif
#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
#define USE_SYSV_SIGHUP
#endif
#if defined(sony) && defined(bsd43) && !defined(KANJI)
#define KANJI
#endif
#ifdef linux
#define USE_SYSV_PGRP
#define USE_SYSV_SIGNALS
#define WTMP
#ifdef __GLIBC__
#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
#include <pty.h>
#endif
#endif
#endif
#ifdef __MVS__
#define USE_SYSV_PGRP
#define USE_SYSV_SIGNALS
#endif
#ifdef __CYGWIN__
#define WTMP
#endif
#ifdef __SCO__
#ifndef _SVID3
#define _SVID3
#endif
#endif
#if defined(__GLIBC__) && !defined(linux)
#define USE_SYSV_PGRP
#define WTMP
#define HAS_BSD_GROUPS
#endif
#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID)
#include <grp.h>
#endif
#ifndef TTY_GROUP_NAME
#define TTY_GROUP_NAME "tty"
#endif
#include <sys/stat.h>
#ifdef Lynx
#ifndef BSDLY
#define BSDLY 0
#endif
#ifndef VTDLY
#define VTDLY 0
#endif
#ifndef FFDLY
#define FFDLY 0
#endif
#endif
#ifdef SYSV
#ifdef USE_USG_PTYS
#include <sys/stropts.h>
#include <poll.h>
#endif
#define USE_SYSV_SIGNALS
#define USE_SYSV_PGRP
#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
#define USE_SYSV_ENVVARS
#endif
#ifdef CRAY
#define HAS_BSD_GROUPS
#endif
#ifdef macII
#define HAS_BSD_GROUPS
#include <sys/ttychars.h>
#undef USE_SYSV_ENVVARS
#undef FIOCLEX
#undef FIONCLEX
#define setpgrp2 setpgrp
#include <sgtty.h>
#include <sys/resource.h>
#endif
#ifdef __hpux
#define HAS_BSD_GROUPS
#include <sys/ptyio.h>
#endif
#ifdef __osf__
#define HAS_BSD_GROUPS
#undef USE_SYSV_PGRP
#define setpgrp setpgid
#endif
#ifdef __sgi
#define HAS_BSD_GROUPS
#include <sys/sysmacros.h>
#endif
#ifdef sun
#include <sys/strredir.h>
#endif
#else
#ifdef __QNX__
#ifndef __QNXNTO__
#define ttyslot() 1
#else
#define USE_SYSV_PGRP
extern __inline__
int
ttyslot(void)
{
return 1;
}
#endif
#else
#if defined(__INTERIX) || defined(__APPLE__)
#define setpgrp setpgid
#endif
#ifndef linux
#ifndef VMS
#ifndef USE_POSIX_TERMIOS
#ifndef USE_ANY_SYSV_TERMIO
#include <sgtty.h>
#endif
#endif
#ifdef Lynx
#include <resource.h>
#else
#include <sys/resource.h>
#endif
#ifndef __INTERIX
#define HAS_BSD_GROUPS
#endif
#endif
#endif
#endif
#endif
#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
#ifndef NOFILE
#define NOFILE OPEN_MAX
#endif
#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
#include <sys/param.h>
#endif
#if defined(BSD) && (BSD >= 199103)
#define WTMP
#endif
#include <stdio.h>
#ifdef __hpux
#include <sys/utsname.h>
#endif
#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
#define ttyslot() 1
#endif
#if defined(UTMPX_FOR_UTMP)
#define UTMP_STR utmpx
#else
#define UTMP_STR utmp
#endif
#if defined(USE_UTEMPTER)
#include <utempter.h>
#endif
#if defined(UTMPX_FOR_UTMP)
#include <utmpx.h>
#define call_endutent endutxent
#define call_getutid getutxid
#define call_pututline pututxline
#define call_setutent setutxent
#define call_updwtmp updwtmpx
#elif defined(HAVE_UTMP)
#include <utmp.h>
#if defined(_CRAY) && (OSMAJORVERSION < 8)
extern struct utmp *getutid __((struct utmp * _Id));
#endif
#define call_endutent endutent
#define call_getutid getutid
#define call_pututline pututline
#define call_setutent setutent
#define call_updwtmp updwtmp
#endif
#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
#include <lastlog.h>
#endif
#ifndef USE_LASTLOGX
#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
#define USE_LASTLOGX 1
#endif
#endif
#ifdef PUCC_PTYD
#include <local/openpty.h>
#endif
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
#include <util.h>
#endif
#ifdef __FreeBSD__
#include <libutil.h>
#endif
#if !defined(UTMP_FILENAME)
#if defined(UTMP_FILE)
#define UTMP_FILENAME UTMP_FILE
#elif defined(_PATH_UTMP)
#define UTMP_FILENAME _PATH_UTMP
#else
#define UTMP_FILENAME "/etc/utmp"
#endif
#endif
#ifndef LASTLOG_FILENAME
#ifdef _PATH_LASTLOG
#define LASTLOG_FILENAME _PATH_LASTLOG
#else
#define LASTLOG_FILENAME "/usr/adm/lastlog"
#endif
#endif
#if !defined(WTMP_FILENAME)
#if defined(WTMP_FILE)
#define WTMP_FILENAME WTMP_FILE
#elif defined(_PATH_WTMP)
#define WTMP_FILENAME _PATH_WTMP
#elif defined(SYSV)
#define WTMP_FILENAME "/etc/wtmp"
#else
#define WTMP_FILENAME "/usr/adm/wtmp"
#endif
#endif
#include <signal.h>
#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
#undef SIGTSTP
#endif
#ifdef SIGTSTP
#include <sys/wait.h>
#endif
#if defined(__SCO__) || defined(__UNIXWARE__)
#undef ECHOKE
#undef ECHOCTL
#endif
#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
#include <sys/ttydefaults.h>
#endif
#ifdef X_NOT_POSIX
extern long lseek();
#if defined(USG) || defined(SVR4)
extern unsigned sleep();
#else
extern void sleep();
#endif
extern char *ttyname();
#endif
#if defined(SYSV) && defined(DECL_PTSNAME)
extern char *ptsname(int);
#endif
#ifndef VMS
static SIGNAL_T reapchild(int n);
static int spawnXTerm(XtermWidget );
static void remove_termcap_entry(char *buf, char *str);
#ifdef USE_PTY_SEARCH
static int pty_search(int *pty);
#endif
#endif
static int get_pty(int *pty, char *from);
static void resize_termcap(XtermWidget xw, char *newtc);
static void set_owner(char *device, uid_t uid, gid_t gid, mode_t mode);
static Bool added_utmp_entry = False;
#ifdef HAVE_POSIX_SAVED_IDS
static uid_t save_euid;
static gid_t save_egid;
#endif
static uid_t save_ruid;
static gid_t save_rgid;
#if defined(USE_UTMP_SETGID)
static int really_get_pty(int *pty, char *from);
#endif
#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
static Bool xterm_exiting = False;
#endif
static char *explicit_shname = NULL;
static char **command_to_exec = NULL;
#if OPT_LUIT_PROG
static char **command_to_exec_with_luit = NULL;
#endif
#define TERMCAP_ERASE "kb"
#define VAL_INITIAL_ERASE A2E(8)
#ifdef B38400
#define VAL_LINE_SPEED B38400
#else
#define VAL_LINE_SPEED B9600
#endif
#ifndef CBRK
#define CBRK 0xff
#endif
#ifndef CDISCARD
#define CDISCARD CONTROL('O')
#endif
#ifndef CDSUSP
#define CDSUSP CONTROL('Y')
#endif
#ifndef CEOF
#define CEOF CONTROL('D')
#endif
#ifndef CEOL
#define CEOL 0xff
#endif
#ifndef CERASE
#define CERASE 0177
#endif
#ifndef CERASE2
#define CERASE2 CONTROL('H')
#endif
#ifndef CFLUSH
#define CFLUSH CONTROL('O')
#endif
#ifndef CINTR
#define CINTR CONTROL('C')
#endif
#ifndef CKILL
#define CKILL CONTROL('U')
#endif
#ifndef CLNEXT
#define CLNEXT CONTROL('V')
#endif
#ifndef CNUL
#define CNUL 0
#endif
#ifndef CQUIT
#define CQUIT CONTROL('\\')
#endif
#ifndef CRPRNT
#define CRPRNT CONTROL('R')
#endif
#ifndef CREPRINT
#define CREPRINT CRPRNT
#endif
#ifndef CSTART
#define CSTART CONTROL('Q')
#endif
#ifndef CSTATUS
#define CSTATUS CONTROL('T')
#endif
#ifndef CSTOP
#define CSTOP CONTROL('S')
#endif
#ifndef CSUSP
#define CSUSP CONTROL('Z')
#endif
#ifndef CSWTCH
#define CSWTCH 0
#endif
#ifndef CWERASE
#define CWERASE CONTROL('W')
#endif
#ifdef USE_ANY_SYSV_TERMIO
#define TERMIO_STRUCT struct termio
#define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
#define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
#define ttyFlush(fd) ioctl(fd, TCFLSH, 1)
#elif defined(USE_POSIX_TERMIOS)
#define TERMIO_STRUCT struct termios
#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
#define ttyFlush(fd) tcflush(fd, TCOFLUSH)
#endif
#ifndef VMS
#ifdef TERMIO_STRUCT
static TERMIO_STRUCT d_tio;
#ifdef HAS_LTCHARS
static struct ltchars d_ltc;
#endif
#ifdef TIOCLSET
static unsigned int d_lmode;
#endif
#else
static struct sgttyb d_sg =
{
0, 0, 0177, CKILL, (EVENP | ODDP | ECHO | XTABS | CRMOD)
};
static struct tchars d_tc =
{
CINTR, CQUIT, CSTART,
CSTOP, CEOF, CBRK
};
static struct ltchars d_ltc =
{
CSUSP, CDSUSP, CRPRNT,
CFLUSH, CWERASE, CLNEXT
};
static int d_disipline = NTTYDISC;
static long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
#ifdef sony
static long int d_jmode = KM_SYSSJIS | KM_ASCII;
static struct jtchars d_jtc =
{
'J', 'B'
};
#endif
#endif
#endif
#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
static Boolean override_tty_modes = False;
static struct _xttymodes {
char *name;
size_t len;
int set;
int value;
} ttymodelist[] = {
TTYMODE("intr"),
#define XTTYMODE_intr 0
TTYMODE("quit"),
#define XTTYMODE_quit 1
TTYMODE("erase"),
#define XTTYMODE_erase 2
TTYMODE("kill"),
#define XTTYMODE_kill 3
TTYMODE("eof"),
#define XTTYMODE_eof 4
TTYMODE("eol"),
#define XTTYMODE_eol 5
TTYMODE("swtch"),
#define XTTYMODE_swtch 6
TTYMODE("start"),
#define XTTYMODE_start 7
TTYMODE("stop"),
#define XTTYMODE_stop 8
TTYMODE("brk"),
#define XTTYMODE_brk 9
TTYMODE("susp"),
#define XTTYMODE_susp 10
TTYMODE("dsusp"),
#define XTTYMODE_dsusp 11
TTYMODE("rprnt"),
#define XTTYMODE_rprnt 12
TTYMODE("flush"),
#define XTTYMODE_flush 13
TTYMODE("weras"),
#define XTTYMODE_weras 14
TTYMODE("lnext"),
#define XTTYMODE_lnext 15
TTYMODE("status"),
#define XTTYMODE_status 16
TTYMODE("erase2"),
#define XTTYMODE_erase2 17
TTYMODE("eol2"),
#define XTTYMODE_eol2 18
{ NULL, 0, 0, '\0' },
};
#define validTtyChar(data, n) \
(known_ttyChars[n].sysMode >= 0 && \
known_ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
static const struct {
int sysMode;
int myMode;
int myDefault;
} known_ttyChars[] = {
#ifdef VINTR
{ VINTR, XTTYMODE_intr, CINTR },
#endif
#ifdef VQUIT
{ VQUIT, XTTYMODE_quit, CQUIT },
#endif
#ifdef VERASE
{ VERASE, XTTYMODE_erase, CERASE },
#endif
#ifdef VKILL
{ VKILL, XTTYMODE_kill, CKILL },
#endif
#ifdef VEOF
{ VEOF, XTTYMODE_eof, CEOF },
#endif
#ifdef VEOL
{ VEOL, XTTYMODE_eol, CEOL },
#endif
#ifdef VSWTCH
{ VSWTCH, XTTYMODE_swtch, CNUL },
#endif
#ifdef VSTART
{ VSTART, XTTYMODE_start, CSTART },
#endif
#ifdef VSTOP
{ VSTOP, XTTYMODE_stop, CSTOP },
#endif
#ifdef VSUSP
{ VSUSP, XTTYMODE_susp, CSUSP },
#endif
#ifdef VDSUSP
{ VDSUSP, XTTYMODE_dsusp, CDSUSP },
#endif
#ifdef VREPRINT
{ VREPRINT, XTTYMODE_rprnt, CREPRINT },
#endif
#ifdef VDISCARD
{ VDISCARD, XTTYMODE_flush, CDISCARD },
#endif
#ifdef VWERASE
{ VWERASE, XTTYMODE_weras, CWERASE },
#endif
#ifdef VLNEXT
{ VLNEXT, XTTYMODE_lnext, CLNEXT },
#endif
#ifdef VSTATUS
{ VSTATUS, XTTYMODE_status, CSTATUS },
#endif
#ifdef VERASE2
{ VERASE2, XTTYMODE_erase2, CERASE2 },
#endif
#ifdef VEOL2
{ VEOL2, XTTYMODE_eol2, CNUL },
#endif
};
#define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value
static int parse_tty_modes(char *s, struct _xttymodes *modelist);
#ifndef USE_UTEMPTER
#ifdef USE_SYSV_UTMP
#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
extern struct utmp *getutid();
#endif
#else
static char etc_utmp[] = UTMP_FILENAME;
#endif
#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
static char etc_lastlog[] = LASTLOG_FILENAME;
#else
#undef USE_LASTLOG
#endif
#ifdef WTMP
static char etc_wtmp[] = WTMP_FILENAME;
#endif
#endif
#ifdef USE_LOGIN_DASH_P
#ifndef LOGIN_FILENAME
#define LOGIN_FILENAME "/bin/login"
#endif
static char bin_login[] = LOGIN_FILENAME;
#endif
static char passedPty[PTYCHARLEN + 1];
#if defined(TIOCCONS) || defined(SRIOCSREDIR)
static int Console;
#include <X11/Xmu/SysUtil.h>
#define MIT_CONSOLE_LEN 12
#define MIT_CONSOLE "MIT_CONSOLE_"
static char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
static Atom mit_console;
#endif
#ifndef USE_SYSV_UTMP
static int tslot;
#endif
static sigjmp_buf env;
#define SetUtmpHost(dst, screen) \
{ \
char host[sizeof(dst) + 1]; \
strncpy(host, DisplayString(screen->display), sizeof(host)); \
TRACE(("DisplayString(%s)\n", host)); \
if (!resource.utmpDisplayId) { \
char *endptr = strrchr(host, ':'); \
if (endptr) { \
TRACE(("trimming display-id '%s'\n", host)); \
*endptr = '\0'; \
} \
} \
strncpy(dst, host, sizeof(dst)); \
}
#ifdef HAVE_UTMP_UT_SYSLEN
# define SetUtmpSysLen(utmp) \
{ \
utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
utmp.ut_syslen = strlen(utmp.ut_host) + 1; \
}
#endif
static XtResource application_resources[] =
{
Sres("name", "Name", xterm_name, DFT_TERMTYPE),
Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
Sres(XtNtitle, XtCTitle, title, NULL),
Sres(XtNiconName, XtCIconName, icon_name, NULL),
Sres("termName", "TermName", term_name, NULL),
Sres("ttyModes", "TtyModes", tty_modes, NULL),
Bres("hold", "Hold", hold_screen, False),
Bres("utmpInhibit", "UtmpInhibit", utmpInhibit, False),
Bres("utmpDisplayId", "UtmpDisplayId", utmpDisplayId, True),
Bres("messages", "Messages", messages, True),
Ires("minBufSize", "MinBufSize", minBufSize, 4096),
Ires("maxBufSize", "MaxBufSize", maxBufSize, 32768),
Sres("menuLocale", "MenuLocale", menuLocale, ""),
Sres("keyboardType", "KeyboardType", keyboardType, "unknown"),
#if OPT_SUNPC_KBD
Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
#endif
#if OPT_HP_FUNC_KEYS
Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
#endif
#if OPT_SCO_FUNC_KEYS
Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
#endif
#if OPT_SUN_FUNC_KEYS
Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
#endif
#if OPT_TCAP_FKEYS
Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
#endif
#if OPT_INITIAL_ERASE
Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
#endif
Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
#if OPT_ZICONBEEP
Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
#endif
#if OPT_PTY_HANDSHAKE
Bres("waitForMap", "WaitForMap", wait_for_map, False),
Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
#endif
#if OPT_SAME_NAME
Bres("sameName", "SameName", sameName, True),
#endif
#if OPT_SESSION_MGT
Bres("sessionMgt", "SessionMgt", sessionMgt, True),
#endif
#if OPT_TOOLBAR
Bres(XtNtoolBar, XtCToolBar, toolBar, True),
#endif
#if OPT_MAXIMIZE
Bres(XtNmaximized, XtCMaximized, maximized, False),
#endif
};
static char *fallback_resources[] =
{
"*SimpleMenu*menuLabel.vertSpace: 100",
"*SimpleMenu*HorizontalMargins: 16",
"*SimpleMenu*Sme.height: 16",
"*SimpleMenu*Cursor: left_ptr",
"*mainMenu.Label: Main Options (no app-defaults)",
"*vtMenu.Label: VT Options (no app-defaults)",
"*fontMenu.Label: VT Fonts (no app-defaults)",
#if OPT_TEK4014
"*tekMenu.Label: Tek Options (no app-defaults)",
#endif
NULL
};
static XrmOptionDescRec optionDescList[] = {
{"-geometry", "*vt100.geometry",XrmoptionSepArg, (caddr_t) NULL},
{"-132", "*c132", XrmoptionNoArg, (caddr_t) "on"},
{"+132", "*c132", XrmoptionNoArg, (caddr_t) "off"},
{"-ah", "*alwaysHighlight", XrmoptionNoArg, (caddr_t) "on"},
{"+ah", "*alwaysHighlight", XrmoptionNoArg, (caddr_t) "off"},
{"-aw", "*autoWrap", XrmoptionNoArg, (caddr_t) "on"},
{"+aw", "*autoWrap", XrmoptionNoArg, (caddr_t) "off"},
#ifndef NO_ACTIVE_ICON
{"-ai", "*activeIcon", XrmoptionNoArg, (caddr_t) "off"},
{"+ai", "*activeIcon", XrmoptionNoArg, (caddr_t) "on"},
#endif
{"-b", "*internalBorder",XrmoptionSepArg, (caddr_t) NULL},
{"-bc", "*cursorBlink", XrmoptionNoArg, (caddr_t) "on"},
{"+bc", "*cursorBlink", XrmoptionNoArg, (caddr_t) "off"},
{"-bcf", "*cursorOffTime",XrmoptionSepArg, (caddr_t) NULL},
{"-bcn", "*cursorOnTime",XrmoptionSepArg, (caddr_t) NULL},
{"-bdc", "*colorBDMode", XrmoptionNoArg, (caddr_t) "off"},
{"+bdc", "*colorBDMode", XrmoptionNoArg, (caddr_t) "on"},
{"-cb", "*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "off"},
{"+cb", "*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "on"},
{"-cc", "*charClass", XrmoptionSepArg, (caddr_t) NULL},
{"-cm", "*colorMode", XrmoptionNoArg, (caddr_t) "off"},
{"+cm", "*colorMode", XrmoptionNoArg, (caddr_t) "on"},
{"-cn", "*cutNewline", XrmoptionNoArg, (caddr_t) "off"},
{"+cn", "*cutNewline", XrmoptionNoArg, (caddr_t) "on"},
{"-cr", "*cursorColor", XrmoptionSepArg, (caddr_t) NULL},
{"-cu", "*curses", XrmoptionNoArg, (caddr_t) "on"},
{"+cu", "*curses", XrmoptionNoArg, (caddr_t) "off"},
{"-dc", "*dynamicColors",XrmoptionNoArg, (caddr_t) "off"},
{"+dc", "*dynamicColors",XrmoptionNoArg, (caddr_t) "on"},
{"-fb", "*boldFont", XrmoptionSepArg, (caddr_t) NULL},
{"-fbb", "*freeBoldBox", XrmoptionNoArg, (caddr_t)"off"},
{"+fbb", "*freeBoldBox", XrmoptionNoArg, (caddr_t)"on"},
{"-fbx", "*forceBoxChars", XrmoptionNoArg, (caddr_t)"off"},
{"+fbx", "*forceBoxChars", XrmoptionNoArg, (caddr_t)"on"},
#ifndef NO_ACTIVE_ICON
{"-fi", "*iconFont", XrmoptionSepArg, (caddr_t) NULL},
#endif
#if OPT_RENDERFONT
{"-fa", "*faceName", XrmoptionSepArg, (caddr_t) NULL},
{"-fd", "*faceNameDoublesize", XrmoptionSepArg, (caddr_t) NULL},
{"-fs", "*faceSize", XrmoptionSepArg, (caddr_t) NULL},
#endif
#if OPT_WIDE_CHARS
{"-fw", "*wideFont", XrmoptionSepArg, (caddr_t) NULL},
{"-fwb", "*wideBoldFont", XrmoptionSepArg, (caddr_t) NULL},
#endif
#if OPT_INPUT_METHOD
{"-fx", "*ximFont", XrmoptionSepArg, (caddr_t) NULL},
#endif
#if OPT_HIGHLIGHT_COLOR
{"-hc", "*highlightColor", XrmoptionSepArg, (caddr_t) NULL},
{"-hm", "*highlightColorMode", XrmoptionNoArg, (caddr_t) "on"},
{"+hm", "*highlightColorMode", XrmoptionNoArg, (caddr_t) "off"},
{"-selfg", "*highlightTextColor", XrmoptionSepArg, (caddr_t) NULL},
{"-selbg", "*highlightColor", XrmoptionSepArg, (caddr_t) NULL},
#endif
#if OPT_HP_FUNC_KEYS
{"-hf", "*hpFunctionKeys",XrmoptionNoArg, (caddr_t) "on"},
{"+hf", "*hpFunctionKeys",XrmoptionNoArg, (caddr_t) "off"},
#endif
{"-hold", "*hold", XrmoptionNoArg, (caddr_t) "on"},
{"+hold", "*hold", XrmoptionNoArg, (caddr_t) "off"},
#if OPT_INITIAL_ERASE
{"-ie", "*ptyInitialErase", XrmoptionNoArg, (caddr_t) "on"},
{"+ie", "*ptyInitialErase", XrmoptionNoArg, (caddr_t) "off"},
#endif
{"-j", "*jumpScroll", XrmoptionNoArg, (caddr_t) "on"},
{"+j", "*jumpScroll", XrmoptionNoArg, (caddr_t) "off"},
#if OPT_C1_PRINT
{"-k8", "*allowC1Printable", XrmoptionNoArg, (caddr_t) "on"},
{"+k8", "*allowC1Printable", XrmoptionNoArg, (caddr_t) "off"},
#endif
{"-kt", "*keyboardType", XrmoptionSepArg, (caddr_t) NULL},
{"+kt", "*keyboardType", XrmoptionSepArg, (caddr_t) NULL},
{"-l", "*logging", XrmoptionNoArg, (caddr_t) "on"},
{"+l", "*logging", XrmoptionNoArg, (caddr_t) "off"},
{"-lf", "*logFile", XrmoptionSepArg, (caddr_t) NULL},
{"-ls", "*loginShell", XrmoptionNoArg, (caddr_t) "on"},
{"+ls", "*loginShell", XrmoptionNoArg, (caddr_t) "off"},
{"-mb", "*marginBell", XrmoptionNoArg, (caddr_t) "on"},
{"+mb", "*marginBell", XrmoptionNoArg, (caddr_t) "off"},
{"-mc", "*multiClickTime", XrmoptionSepArg, (caddr_t) NULL},
{"-mesg", "*messages", XrmoptionNoArg, (caddr_t) "off"},
{"+mesg", "*messages", XrmoptionNoArg, (caddr_t) "on"},
{"-ms", "*pointerColor",XrmoptionSepArg, (caddr_t) NULL},
{"-nb", "*nMarginBell", XrmoptionSepArg, (caddr_t) NULL},
{"-nul", "*underLine", XrmoptionNoArg, (caddr_t) "off"},
{"+nul", "*underLine", XrmoptionNoArg, (caddr_t) "on"},
{"-pc", "*boldColors", XrmoptionNoArg, (caddr_t) "on"},
{"+pc", "*boldColors", XrmoptionNoArg, (caddr_t) "off"},
{"-rw", "*reverseWrap", XrmoptionNoArg, (caddr_t) "on"},
{"+rw", "*reverseWrap", XrmoptionNoArg, (caddr_t) "off"},
{"-s", "*multiScroll", XrmoptionNoArg, (caddr_t) "on"},
{"+s", "*multiScroll", XrmoptionNoArg, (caddr_t) "off"},
{"-sb", "*scrollBar", XrmoptionNoArg, (caddr_t) "on"},
{"+sb", "*scrollBar", XrmoptionNoArg, (caddr_t) "off"},
#ifdef SCROLLBAR_RIGHT
{"-leftbar", "*rightScrollBar", XrmoptionNoArg, (caddr_t) "off"},
{"-rightbar", "*rightScrollBar", XrmoptionNoArg, (caddr_t) "on"},
#endif
{"-rvc", "*colorRVMode", XrmoptionNoArg, (caddr_t) "off"},
{"+rvc", "*colorRVMode", XrmoptionNoArg, (caddr_t) "on"},
{"-sf", "*sunFunctionKeys", XrmoptionNoArg, (caddr_t) "on"},
{"+sf", "*sunFunctionKeys", XrmoptionNoArg, (caddr_t) "off"},
{"-si", "*scrollTtyOutput", XrmoptionNoArg, (caddr_t) "off"},
{"+si", "*scrollTtyOutput", XrmoptionNoArg, (caddr_t) "on"},
{"-sk", "*scrollKey", XrmoptionNoArg, (caddr_t) "on"},
{"+sk", "*scrollKey", XrmoptionNoArg, (caddr_t) "off"},
{"-sl", "*saveLines", XrmoptionSepArg, (caddr_t) NULL},
#if OPT_SUNPC_KBD
{"-sp", "*sunKeyboard", XrmoptionNoArg, (caddr_t) "on"},
{"+sp", "*sunKeyboard", XrmoptionNoArg, (caddr_t) "off"},
#endif
#if OPT_TEK4014
{"-t", "*tekStartup", XrmoptionNoArg, (caddr_t) "on"},
{"+t", "*tekStartup", XrmoptionNoArg, (caddr_t) "off"},
#endif
{"-ti", "*decTerminalID",XrmoptionSepArg, (caddr_t) NULL},
{"-tm", "*ttyModes", XrmoptionSepArg, (caddr_t) NULL},
{"-tn", "*termName", XrmoptionSepArg, (caddr_t) NULL},
#if OPT_WIDE_CHARS
{"-u8", "*utf8", XrmoptionNoArg, (caddr_t) "2"},
{"+u8", "*utf8", XrmoptionNoArg, (caddr_t) "0"},
#endif
#if OPT_LUIT_PROG
{"-lc", "*locale", XrmoptionNoArg, (caddr_t) "on"},
{"+lc", "*locale", XrmoptionNoArg, (caddr_t) "off"},
{"-lcc", "*localeFilter",XrmoptionSepArg, (caddr_t) NULL},
{"-en", "*locale", XrmoptionSepArg, (caddr_t) NULL},
#endif
{"-uc", "*cursorUnderLine", XrmoptionNoArg, (caddr_t) "on"},
{"+uc", "*cursorUnderLine", XrmoptionNoArg, (caddr_t) "off"},
{"-ulc", "*colorULMode", XrmoptionNoArg, (caddr_t) "off"},
{"+ulc", "*colorULMode", XrmoptionNoArg, (caddr_t) "on"},
{"-ulit", "*italicULMode", XrmoptionNoArg, (caddr_t) "off"},
{"+ulit", "*italicULMode", XrmoptionNoArg, (caddr_t) "on"},
{"-ut", "*utmpInhibit", XrmoptionNoArg, (caddr_t) "on"},
{"+ut", "*utmpInhibit", XrmoptionNoArg, (caddr_t) "off"},
{"-im", "*useInsertMode", XrmoptionNoArg, (caddr_t) "on"},
{"+im", "*useInsertMode", XrmoptionNoArg, (caddr_t) "off"},
{"-vb", "*visualBell", XrmoptionNoArg, (caddr_t) "on"},
{"+vb", "*visualBell", XrmoptionNoArg, (caddr_t) "off"},
{"-pob", "*popOnBell", XrmoptionNoArg, (caddr_t) "on"},
{"+pob", "*popOnBell", XrmoptionNoArg, (caddr_t) "off"},
#if OPT_WIDE_CHARS
{"-wc", "*wideChars", XrmoptionNoArg, (caddr_t) "on"},
{"+wc", "*wideChars", XrmoptionNoArg, (caddr_t) "off"},
{"-mk_width", "*mkWidth", XrmoptionNoArg, (caddr_t) "on"},
{"+mk_width", "*mkWidth", XrmoptionNoArg, (caddr_t) "off"},
{"-cjk_width", "*cjkWidth", XrmoptionNoArg, (caddr_t) "on"},
{"+cjk_width", "*cjkWidth", XrmoptionNoArg, (caddr_t) "off"},
#endif
{"-wf", "*waitForMap", XrmoptionNoArg, (caddr_t) "on"},
{"+wf", "*waitForMap", XrmoptionNoArg, (caddr_t) "off"},
#if OPT_ZICONBEEP
{"-ziconbeep", "*zIconBeep", XrmoptionSepArg, (caddr_t) NULL},
#endif
#if OPT_SAME_NAME
{"-samename", "*sameName", XrmoptionNoArg, (caddr_t) "on"},
{"+samename", "*sameName", XrmoptionNoArg, (caddr_t) "off"},
#endif
#if OPT_SESSION_MGT
{"-sm", "*sessionMgt", XrmoptionNoArg, (caddr_t) "on"},
{"+sm", "*sessionMgt", XrmoptionNoArg, (caddr_t) "off"},
#endif
#if OPT_TOOLBAR
{"-tb", "*"XtNtoolBar, XrmoptionNoArg, (caddr_t) "on"},
{"+tb", "*"XtNtoolBar, XrmoptionNoArg, (caddr_t) "off"},
#endif
#if OPT_MAXIMIZE
{"-maximized", "*maximized", XrmoptionNoArg, (caddr_t) "on"},
{"+maximized", "*maximized", XrmoptionNoArg, (caddr_t) "off"},
#endif
{"-help", NULL, XrmoptionSkipNArgs, (caddr_t) NULL},
{"-version", NULL, XrmoptionSkipNArgs, (caddr_t) NULL},
{"-class", NULL, XrmoptionSkipArg, (caddr_t) NULL},
{"-e", NULL, XrmoptionSkipLine, (caddr_t) NULL},
{"-into", NULL, XrmoptionSkipArg, (caddr_t) NULL},
{"%", "*tekGeometry", XrmoptionStickyArg, (caddr_t) NULL},
{"#", ".iconGeometry",XrmoptionStickyArg, (caddr_t) NULL},
{"-T", ".title", XrmoptionSepArg, (caddr_t) NULL},
{"-n", "*iconName", XrmoptionSepArg, (caddr_t) NULL},
{"-r", "*reverseVideo",XrmoptionNoArg, (caddr_t) "on"},
{"+r", "*reverseVideo",XrmoptionNoArg, (caddr_t) "off"},
{"-rv", "*reverseVideo",XrmoptionNoArg, (caddr_t) "on"},
{"+rv", "*reverseVideo",XrmoptionNoArg, (caddr_t) "off"},
{"-w", ".borderWidth", XrmoptionSepArg, (caddr_t) NULL},
};
static OptionHelp xtermOptions[] = {
{ "-version", "print the version number" },
{ "-help", "print out this message" },
{ "-display displayname", "X server to contact" },
{ "-geometry geom", "size (in characters) and position" },
{ "-/+rv", "turn on/off reverse video" },
{ "-bg color", "background color" },
{ "-fg color", "foreground color" },
{ "-bd color", "border color" },
{ "-bw number", "border width in pixels" },
{ "-fn fontname", "normal text font" },
{ "-fb fontname", "bold text font" },
{ "-/+fbb", "turn on/off normal/bold font comparison inhibit"},
{ "-/+fbx", "turn off/on linedrawing characters"},
#if OPT_RENDERFONT
{ "-fa pattern", "FreeType font-selection pattern" },
{ "-fd pattern", "FreeType Doublesize font-selection pattern" },
{ "-fs size", "FreeType font-size" },
#endif
#if OPT_WIDE_CHARS
{ "-fw fontname", "doublewidth text font" },
{ "-fwb fontname", "doublewidth bold text font" },
#endif
#if OPT_INPUT_METHOD
{ "-fx fontname", "XIM fontset" },
#endif
{ "-iconic", "start iconic" },
{ "-name string", "client instance, icon, and title strings" },
{ "-class string", "class string (XTerm)" },
{ "-title string", "title string" },
{ "-xrm resourcestring", "additional resource specifications" },
{ "-/+132", "turn on/off 80/132 column switching" },
{ "-/+ah", "turn on/off always highlight" },
#ifndef NO_ACTIVE_ICON
{ "-/+ai", "turn off/on active icon" },
{ "-fi fontname", "icon font for active icon" },
#endif
{ "-b number", "internal border in pixels" },
{ "-/+bc", "turn on/off text cursor blinking" },
{ "-bcf milliseconds", "time text cursor is off when blinking"},
{ "-bcn milliseconds", "time text cursor is on when blinking"},
{ "-/+bdc", "turn off/on display of bold as color"},
{ "-/+cb", "turn on/off cut-to-beginning-of-line inhibit" },
{ "-cc classrange", "specify additional character classes" },
{ "-/+cm", "turn off/on ANSI color mode" },
{ "-/+cn", "turn on/off cut newline inhibit" },
{ "-cr color", "text cursor color" },
{ "-/+cu", "turn on/off curses emulation" },
{ "-/+dc", "turn off/on dynamic color selection" },
#if OPT_HIGHLIGHT_COLOR
{ "-/+hm", "turn on/off selection-color override" },
{ "-selbg color", "selection background color" },
{ "-selfg color", "selection foreground color" },
#endif
#if OPT_HP_FUNC_KEYS
{ "-/+hf", "turn on/off HP Function Key escape codes" },
#endif
{ "-/+hold", "turn on/off logic that retains window after exit" },
#if OPT_INITIAL_ERASE
{ "-/+ie", "turn on/off initialization of 'erase' from pty" },
#endif
{ "-/+im", "use insert mode for TERMCAP" },
{ "-/+j", "turn on/off jump scroll" },
#if OPT_C1_PRINT
{ "-/+k8", "turn on/off C1-printable classification"},
#endif
{ "-kt keyboardtype", "set keyboard type:" KEYBOARD_TYPES },
#ifdef ALLOWLOGGING
{ "-/+l", "turn on/off logging" },
{ "-lf filename", "logging filename" },
#else
{ "-/+l", "turn on/off logging (not supported)" },
{ "-lf filename", "logging filename (not supported)" },
#endif
{ "-/+ls", "turn on/off login shell" },
{ "-/+mb", "turn on/off margin bell" },
{ "-mc milliseconds", "multiclick time in milliseconds" },
{ "-/+mesg", "forbid/allow messages" },
{ "-ms color", "pointer color" },
{ "-nb number", "margin bell in characters from right end" },
{ "-/+nul", "turn off/on display of underlining" },
{ "-/+aw", "turn on/off auto wraparound" },
{ "-/+pc", "turn on/off PC-style bold colors" },
{ "-/+rw", "turn on/off reverse wraparound" },
{ "-/+s", "turn on/off multiscroll" },
{ "-/+sb", "turn on/off scrollbar" },
#ifdef SCROLLBAR_RIGHT
{ "-rightbar", "force scrollbar right (default left)" },
{ "-leftbar", "force scrollbar left" },
#endif
{ "-/+rvc", "turn off/on display of reverse as color" },
{ "-/+sf", "turn on/off Sun Function Key escape codes" },
{ "-/+si", "turn on/off scroll-on-tty-output inhibit" },
{ "-/+sk", "turn on/off scroll-on-keypress" },
{ "-sl number", "number of scrolled lines to save" },
#if OPT_SUNPC_KBD
{ "-/+sp", "turn on/off Sun/PC Function/Keypad mapping" },
#endif
#if OPT_TEK4014
{ "-/+t", "turn on/off Tek emulation window" },
#endif
#if OPT_TOOLBAR
{ "-/+tb", "turn on/off toolbar" },
#endif
{ "-ti termid", "terminal identifier" },
{ "-tm string", "terminal mode keywords and characters" },
{ "-tn name", "TERM environment variable name" },
#if OPT_WIDE_CHARS
{ "-/+u8", "turn on/off UTF-8 mode (implies wide-characters)" },
#endif
#if OPT_LUIT_PROG
{ "-/+lc", "turn on/off locale mode using luit" },
{ "-lcc path", "filename of locale converter (" DEFLOCALEFILTER ")" },
#endif
{ "-/+uc", "turn on/off underline cursor" },
{ "-/+ulc", "turn off/on display of underline as color" },
{ "-/+ulit", "turn off/on display of underline as italics" },
#ifdef HAVE_UTMP
{ "-/+ut", "turn on/off utmp support" },
#else
{ "-/+ut", "turn on/off utmp support (not available)" },
#endif
{ "-/+vb", "turn on/off visual bell" },
{ "-/+pob", "turn on/off pop on bell" },
#if OPT_WIDE_CHARS
{ "-/+wc", "turn on/off wide-character mode" },
{ "-/+mk_width", "turn on/off simple width convention" },
{ "-/+cjk_width", "turn on/off legacy CJK width convention" },
#endif
{ "-/+wf", "turn on/off wait for map before command exec" },
{ "-e command args ...", "command to execute" },
#if OPT_TEK4014
{ "%geom", "Tek window geometry" },
#endif
{ "#geom", "icon window geometry" },
{ "-T string", "title name for window" },
{ "-n string", "icon name for window" },
#if defined(TIOCCONS) || defined(SRIOCSREDIR)
{ "-C", "intercept console messages" },
#else
{ "-C", "intercept console messages (not supported)" },
#endif
{ "-Sccn", "slave mode on \"ttycc\", file descriptor \"n\"" },
{ "-into windowId", "use the window id given to -into as the parent window rather than the default root window" },
#if OPT_ZICONBEEP
{ "-ziconbeep percent", "beep and flag icon of window having hidden output" },
#endif
#if OPT_SAME_NAME
{ "-/+samename", "turn on/off the no-flicker option for title and icon name" },
#endif
#if OPT_SESSION_MGT
{ "-/+sm", "turn on/off the session-management support" },
#endif
#if OPT_MAXIMIZE
{"-/+maximized", "turn on/off maxmize on startup" },
#endif
{ NULL, NULL }};
static char *message[] =
{
"Fonts should be fixed width and, if both normal and bold are specified, should",
"have the same size. If only a normal font is specified, it will be used for",
"both normal and bold text (by doing overstriking). The -e option, if given,",
"must appear at the end of the command line, otherwise the user's default shell",
"will be started. Options that start with a plus sign (+) restore the default.",
NULL};
static int
decode_keyvalue(char **ptr, int termcap)
{
char *string = *ptr;
int value = -1;
TRACE(("...decode '%s'\n", string));
if (*string == '^') {
switch (*++string) {
case '?':
value = A2E(ANSI_DEL);
break;
case '-':
if (!termcap) {
errno = 0;
#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
value = _POSIX_VDISABLE;
#endif
#if defined(_PC_VDISABLE)
if (value == -1) {
value = fpathconf(0, _PC_VDISABLE);
if (value == -1) {
if (errno != 0)
break;
value = 0377;
}
}
#elif defined(VDISABLE)
if (value == -1)
value = VDISABLE;
#endif
break;
}
default:
value = CONTROL(*string);
break;
}
++string;
} else if (termcap && (*string == '\\')) {
char *d;
int temp = strtol(string + 1, &d, 8);
if (temp > 0 && d != string) {
value = temp;
string = d;
}
} else {
value = CharOf(*string);
++string;
}
*ptr = string;
return value;
}
static int
abbrev(char *tst, char *cmp, size_t need)
{
size_t len = strlen(tst);
return ((len >= need) && (!strncmp(tst, cmp, len)));
}
static void
Syntax(char *badOption)
{
OptionHelp *opt;
OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
int col;
fprintf(stderr, "%s: bad command line option \"%s\"\r\n\n",
ProgramName, badOption);
fprintf(stderr, "usage: %s", ProgramName);
col = 8 + strlen(ProgramName);
for (opt = list; opt->opt; opt++) {
int len = 3 + strlen(opt->opt);
if (col + len > 79) {
fprintf(stderr, "\r\n ");
col = 3;
}
fprintf(stderr, " [%s]", opt->opt);
col += len;
}
fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
ProgramName);
exit(1);
}
static void
Version(void)
{
printf("%s\n", xtermVersion());
fflush(stdout);
}
static void
Help(void)
{
OptionHelp *opt;
OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
char **cpp;
printf("%s usage:\n %s [-options ...] [-e command args]\n\n",
xtermVersion(), ProgramName);
printf("where options include:\n");
for (opt = list; opt->opt; opt++) {
printf(" %-28s %s\n", opt->opt, opt->desc);
}
putchar('\n');
for (cpp = message; *cpp; cpp++)
puts(*cpp);
putchar('\n');
fflush(stdout);
}
#if defined(TIOCCONS) || defined(SRIOCSREDIR)
static Boolean
ConvertConsoleSelection(Widget w GCC_UNUSED,
Atom * selection GCC_UNUSED,
Atom * target GCC_UNUSED,
Atom * type GCC_UNUSED,
XtPointer *value GCC_UNUSED,
unsigned long *length GCC_UNUSED,
int *format GCC_UNUSED)
{
return False;
}
#endif
#if OPT_SESSION_MGT
static void
die_callback(Widget w GCC_UNUSED,
XtPointer client_data GCC_UNUSED,
XtPointer call_data GCC_UNUSED)
{
Cleanup(0);
}
static void
save_callback(Widget w GCC_UNUSED,
XtPointer client_data GCC_UNUSED,
XtPointer call_data)
{
XtCheckpointToken token = (XtCheckpointToken) call_data;
token->save_success = True;
}
static void
icewatch(IceConn iceConn,
IcePointer clientData GCC_UNUSED,
Bool opening,
IcePointer * watchData GCC_UNUSED)
{
if (opening) {
ice_fd = IceConnectionNumber(iceConn);
TRACE(("got IceConnectionNumber %d\n", ice_fd));
} else {
ice_fd = -1;
TRACE(("reset IceConnectionNumber\n"));
}
}
#endif
static void
DeleteWindow(Widget w,
XEvent * event GCC_UNUSED,
String * params GCC_UNUSED,
Cardinal *num_params GCC_UNUSED)
{
#if OPT_TEK4014
if (w == toplevel) {
if (TEK4014_SHOWN(term))
hide_vt_window();
else
do_hangup(w, (XtPointer) 0, (XtPointer) 0);
} else if (term->screen.Vshow)
hide_tek_window();
else
#endif
do_hangup(w, (XtPointer) 0, (XtPointer) 0);
}
static void
KeyboardMapping(Widget w GCC_UNUSED,
XEvent * event,
String * params GCC_UNUSED,
Cardinal *num_params GCC_UNUSED)
{
switch (event->type) {
case MappingNotify:
XRefreshKeyboardMapping(&event->xmapping);
break;
}
}
static XtActionsRec actionProcs[] =
{
{"DeleteWindow", DeleteWindow},
{"KeyboardMapping", KeyboardMapping},
};
static char *
my_pty_name(char *device)
{
size_t len = strlen(device);
Bool name = False;
while (len != 0) {
int ch = device[len - 1];
if (isdigit(ch)) {
len--;
} else if (ch == '/') {
if (name)
break;
len--;
} else if (isalpha(ch)) {
name = True;
len--;
} else {
break;
}
}
TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
return device + len;
}
static char *
my_pty_id(char *device)
{
char *name = my_pty_name(device);
char *leaf = x_basename(name);
if (name == leaf) {
int len = strlen(leaf);
if (PTYCHARLEN < len)
leaf = leaf + (len - PTYCHARLEN);
}
TRACE(("my_pty_id (%s) -> '%s'\n", device, leaf));
return leaf;
}
static void
set_pty_id(char *device, char *id)
{
char *name = my_pty_name(device);
char *leaf = x_basename(name);
if (name == leaf) {
strcpy(my_pty_id(device), id);
} else {
strcpy(leaf, id);
}
TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
}
static Bool
ParseSccn(char *option)
{
char *leaf = x_basename(option);
Bool code = False;
if (leaf != option) {
if (leaf - option > 0
&& isdigit(CharOf(*leaf))
&& sscanf(leaf, "%d", &am_slave) == 1) {
size_t len = leaf - option - 1;
strncpy(passedPty, option, len);
passedPty[len] = 0;
code = True;
}
} else {
code = (sscanf(option, "%c%c%d",
passedPty, passedPty + 1, &am_slave) == 3);
}
TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
passedPty, am_slave, code ? "OK" : "ERR"));
return code;
}
#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
static char *
my_utmp_id(char *device)
{
typedef struct UTMP_STR UTMP_STRUCT;
#define UTIDSIZE (sizeof(((UTMP_STRUCT *)NULL)->ut_id))
static char result[UTIDSIZE + 1];
#if defined(__SCO__) || defined(__UNIXWARE__)
int len, n;
len = strlen(device);
n = UTIDSIZE;
result[n] = '\0';
while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
result[--n] = device[--len];
while (n > 0)
result[--n] = '0';
result[0] = 'x';
#else
char *name = my_pty_name(device);
char *leaf = x_basename(name);
size_t len = strlen(leaf);
if ((UTIDSIZE - 1) < len)
leaf = leaf + (len - (UTIDSIZE - 1));
sprintf(result, "p%s", leaf);
#endif
TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
return result;
}
#endif
#ifdef USE_POSIX_SIGNALS
typedef void (*sigfunc) (int);
static sigfunc
posix_signal(int signo, sigfunc func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
#ifdef SA_RESTART
act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
#else
act.sa_flags = SA_NOCLDSTOP;
#endif
if (sigaction(signo, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
#endif
#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
static void
disableSetUid(void)
{
TRACE(("process %d disableSetUid\n", (int) getpid()));
if (setuid(save_ruid) == -1) {
fprintf(stderr, "%s: unable to reset uid\n", ProgramName);
exit(1);
}
TRACE_IDS;
}
#else
#define disableSetUid()
#endif
#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
static void
disableSetGid(void)
{
TRACE(("process %d disableSetGid\n", (int) getpid()));
if (setegid(save_rgid) == -1) {
fprintf(stderr, "%s: unable to reset effective gid\n", ProgramName);
exit(1);
}
TRACE_IDS;
}
#else
#define disableSetGid()
#endif
#if defined(HAVE_POSIX_SAVED_IDS)
#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
static void
setEffectiveGroup(gid_t group)
{
TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
if (setegid(group) == -1) {
#ifdef __MVS__
if (!(errno == EMVSERR))
#endif
{
(void) fprintf(stderr, "setegid(%d): %s\n",
(int) group, strerror(errno));
}
}
TRACE_IDS;
}
#endif
#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
static void
setEffectiveUser(uid_t user)
{
TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
if (seteuid(user) == -1) {
#ifdef __MVS__
if (!(errno == EMVSERR))
#endif
{
(void) fprintf(stderr, "seteuid(%d): %s\n",
(int) user, strerror(errno));
}
}
TRACE_IDS;
}
#endif
#endif
int
main(int argc, char *argv[]ENVP_ARG)
{
Widget form_top, menu_top;
Dimension menu_high;
TScreen *screen;
int mode;
char *my_class = DEFCLASS;
Window winToEmbedInto = None;
#if OPT_COLOR_RES
Bool reversed = False;
#endif
ProgramName = argv[0];
#ifdef HAVE_POSIX_SAVED_IDS
save_euid = geteuid();
save_egid = getegid();
#endif
save_ruid = getuid();
save_rgid = getgid();
#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
#if defined(DISABLE_SETUID)
disableSetUid();
#endif
#if defined(DISABLE_SETGID)
disableSetGid();
#endif
TRACE_IDS;
#endif
ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
#ifdef USE_PTY_DEVICE
ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
if (!ttydev || !ptydev)
#else
if (!ttydev)
#endif
{
fprintf(stderr,
"%s: unable to allocate memory for ttydev or ptydev\n",
ProgramName);
exit(1);
}
strcpy(ttydev, TTYDEV);
#ifdef USE_PTY_DEVICE
strcpy(ptydev, PTYDEV);
#endif
#if defined(USE_UTMP_SETGID)
get_pty(NULL, NULL);
disableSetUid();
disableSetGid();
TRACE_IDS;
#define get_pty(pty, from) really_get_pty(pty, from)
#endif
TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
TRACE_ARGV("Before XtOpenApplication", argv);
if (argc > 1) {
int n;
unsigned unique = 2;
Bool quit = True;
for (n = 1; n < argc; n++) {
TRACE(("parsing %s\n", argv[n]));
if (abbrev(argv[n], "-version", unique)) {
Version();
} else if (abbrev(argv[n], "-help", unique)) {
Help();
} else if (abbrev(argv[n], "-class", 3)) {
if ((my_class = argv[++n]) == 0) {
Help();
} else {
quit = False;
}
unique = 3;
} else {
#if OPT_COLOR_RES
if (abbrev(argv[n], "-reverse", 2)
|| !strcmp("-rv", argv[n])) {
reversed = True;
} else if (!strcmp("+rv", argv[n])) {
reversed = False;
}
#endif
quit = False;
unique = 3;
}
}
if (quit)
exit(0);
}
#if OPT_I18N_SUPPORT
XtSetLanguageProc(NULL, NULL, NULL);
#endif
#ifdef TERMIO_STRUCT
memset(&d_tio, 0, sizeof(d_tio));
d_tio.c_iflag = ICRNL | IXON;
#ifdef TAB3
d_tio.c_oflag = OPOST | ONLCR | TAB3;
#else
#ifdef ONLCR
d_tio.c_oflag = OPOST | ONLCR;
#else
d_tio.c_oflag = OPOST;
#endif
#endif
{
Cardinal nn;
for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
if (validTtyChar(d_tio, nn)) {
d_tio.c_cc[known_ttyChars[nn].sysMode] =
known_ttyChars[nn].myDefault;
}
}
}
#if defined(macII) || defined(ATT) || defined(CRAY)
d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
#ifdef ECHOKE
d_tio.c_lflag |= ECHOKE | IEXTEN;
#endif
#ifdef ECHOCTL
d_tio.c_lflag |= ECHOCTL | IEXTEN;
#endif
#ifndef USE_TERMIOS
d_tio.c_line = 0;
#endif
#ifdef HAS_LTCHARS
d_ltc.t_suspc = CSUSP;
d_ltc.t_dsuspc = CDSUSP;
d_ltc.t_rprntc = CRPRNT;
d_ltc.t_flushc = CFLUSH;
d_ltc.t_werasc = CWERASE;
d_ltc.t_lnextc = CLNEXT;
#endif
#ifdef TIOCLSET
d_lmode = 0;
#endif
#else
#ifndef USE_POSIX_TERMIOS
#ifdef BAUD_0
d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
#else
d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
#endif
#else
d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
cfsetispeed(&d_tio, VAL_LINE_SPEED);
cfsetospeed(&d_tio, VAL_LINE_SPEED);
#endif
d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
#ifdef ECHOKE
d_tio.c_lflag |= ECHOKE | IEXTEN;
#endif
#ifdef ECHOCTL
d_tio.c_lflag |= ECHOCTL | IEXTEN;
#endif
#ifndef USE_POSIX_TERMIOS
#ifdef NTTYDISC
d_tio.c_line = NTTYDISC;
#else
d_tio.c_line = 0;
#endif
#endif
#ifdef __sgi
d_tio.c_cflag &= ~(HUPCL | PARENB);
d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
#endif
#ifdef __MVS__
d_tio.c_cflag &= ~(HUPCL | PARENB);
#endif
{
Cardinal nn;
int i;
for (i = 0; i <= 2; i++) {
TERMIO_STRUCT deftio;
if (ttyGetAttr(i, &deftio) == 0) {
for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
if (validTtyChar(d_tio, nn)) {
d_tio.c_cc[known_ttyChars[nn].sysMode] =
deftio.c_cc[known_ttyChars[nn].sysMode];
}
}
break;
}
}
}
#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)
d_tio.c_cc[VMIN] = 1;
d_tio.c_cc[VTIME] = 0;
#endif
#ifdef HAS_LTCHARS
d_ltc.t_suspc = CharOf('\000');
d_ltc.t_dsuspc = CharOf('\000');
d_ltc.t_rprntc = CharOf('\377');
d_ltc.t_flushc = CharOf('\377');
d_ltc.t_werasc = CharOf('\377');
d_ltc.t_lnextc = CharOf('\377');
#endif
#ifdef TIOCLSET
d_lmode = 0;
#endif
#endif
#endif
{
#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
setEffectiveGroup(save_rgid);
setEffectiveUser(save_ruid);
TRACE_IDS;
#endif
XtSetErrorHandler(xt_error);
#if OPT_SESSION_MGT
toplevel = XtOpenApplication(&app_con, my_class,
optionDescList,
XtNumber(optionDescList),
&argc, argv, fallback_resources,
sessionShellWidgetClass,
NULL, 0);
IceAddConnectionWatch(icewatch, NULL);
#else
toplevel = XtAppInitialize(&app_con, my_class,
optionDescList,
XtNumber(optionDescList),
&argc, argv, fallback_resources,
NULL, 0);
#endif
XtSetErrorHandler((XtErrorHandler) 0);
XtGetApplicationResources(toplevel, (XtPointer) &resource,
application_resources,
XtNumber(application_resources), NULL, 0);
TRACE_XRES();
#if OPT_PTY_HANDSHAKE
resource.wait_for_map0 = resource.wait_for_map;
#endif
#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
#if !defined(DISABLE_SETUID)
setEffectiveUser(save_euid);
#endif
#if !defined(DISABLE_SETGID)
setEffectiveGroup(save_egid);
#endif
TRACE_IDS;
#endif
#endif
}
XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
if (resource.tty_modes) {
int n = parse_tty_modes(resource.tty_modes, ttymodelist);
if (n < 0) {
fprintf(stderr, "%s: bad tty modes \"%s\"\n",
ProgramName, resource.tty_modes);
} else if (n > 0) {
override_tty_modes = True;
}
}
#if OPT_ZICONBEEP
if (resource.zIconBeep > 100 || resource.zIconBeep < -100) {
resource.zIconBeep = 0;
fprintf(stderr,
"a number between -100 and 100 is required for zIconBeep. 0 used by default\n");
}
#endif
hold_screen = resource.hold_screen ? 1 : 0;
xterm_name = resource.xterm_name;
if (strcmp(xterm_name, "-") == 0)
xterm_name = DFT_TERMTYPE;
if (resource.icon_geometry != NULL) {
int scr, junk;
int ix, iy;
Arg args[2];
for (scr = 0;
XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
scr++) ;
args[0].name = XtNiconX;
args[1].name = XtNiconY;
XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
args[0].value = (XtArgVal) ix;
args[1].value = (XtArgVal) iy;
XtSetValues(toplevel, args, 2);
}
XtSetValues(toplevel, ourTopLevelShellArgs,
number_ourTopLevelShellArgs);
#if OPT_WIDE_CHARS
init_classtab();
#endif
TRACE_ARGV("After XtOpenApplication", argv);
for (argc--, argv++; argc > 0; argc--, argv++) {
#ifdef VMS
if (**argv != '-')
Syntax(*argv);
#else
if (**argv != '-') {
if (argc > 1)
Syntax(*argv);
if (command_to_exec == 0)
explicit_shname = xtermFindShell(*argv, True);
continue;
}
#endif
TRACE(("parsing %s\n", argv[0]));
switch (argv[0][1]) {
case 'h':
Help();
continue;
case 'v':
Version();
continue;
case 'C':
#if defined(TIOCCONS) || defined(SRIOCSREDIR)
#ifndef __sgi
{
struct stat sbuf;
if (!stat("/dev/console", &sbuf) &&
(sbuf.st_uid == save_ruid) &&
!access("/dev/console", R_OK | W_OK)) {
Console = True;
} else
Console = False;
}
#else
Console = True;
#endif
#endif
continue;
case 'S':
if (!ParseSccn(*argv + 2))
Syntax(*argv);
continue;
#ifdef DEBUG
case 'D':
debug = True;
continue;
#endif
case 'c':
if (strcmp(argv[0] + 1, "class") == 0)
argc--, argv++;
else
Syntax(*argv);
continue;
case 'e':
if (argc <= 1)
Syntax(*argv);
command_to_exec = ++argv;
break;
case 'i':
if (argc <= 1) {
Syntax(*argv);
} else {
char *endPtr;
--argc;
++argv;
winToEmbedInto = (Window) strtol(argv[0], &endPtr, 10);
}
continue;
default:
Syntax(*argv);
}
break;
}
SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
form_top,
#if OPT_TOOLBAR
XtNmenuBar, menu_top,
XtNresizable, True,
XtNfromVert, menu_top,
XtNleft, XawChainLeft,
XtNright, XawChainRight,
XtNtop, XawChainTop,
XtNbottom, XawChainBottom,
XtNmenuHeight, menu_high,
#endif
(XtPointer) 0);
decode_keyboard_type(term, &resource);
screen = TScreenOf(term);
screen->inhibit = 0;
#ifdef ALLOWLOGGING
if (term->misc.logInhibit)
screen->inhibit |= I_LOG;
#endif
if (term->misc.signalInhibit)
screen->inhibit |= I_SIGNAL;
#if OPT_TEK4014
if (term->misc.tekInhibit)
screen->inhibit |= I_TEK;
#endif
#if OPT_TEK4014
if (screen->inhibit & I_TEK)
TEK4014_ACTIVE(term) = False;
if (TEK4014_ACTIVE(term) && !TekInit())
SysError(ERROR_INIT);
#endif
#if OPT_TOOLBAR
ShowToolbar(resource.toolBar);
#endif
#if OPT_SESSION_MGT
if (resource.sessionMgt) {
TRACE(("Enabling session-management callbacks\n"));
XtAddCallback(toplevel, XtNdieCallback, die_callback, NULL);
XtAddCallback(toplevel, XtNsaveCallback, save_callback, NULL);
}
#endif
if (command_to_exec) {
Arg args[2];
if (!resource.title) {
if (command_to_exec) {
resource.title = x_basename(command_to_exec[0]);
}
}
if (!resource.icon_name)
resource.icon_name = resource.title;
XtSetArg(args[0], XtNtitle, resource.title);
XtSetArg(args[1], XtNiconName, resource.icon_name);
TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\tbased on command \"%s\"\n",
resource.title,
resource.icon_name,
*command_to_exec));
XtSetValues(toplevel, args, 2);
}
#if OPT_LUIT_PROG
if (term->misc.callfilter) {
int u = (term->misc.use_encoding ? 2 : 0);
if (command_to_exec) {
int n;
char **c;
for (n = 0, c = command_to_exec; *c; n++, c++) ;
c = TypeMallocN(char *, n + 3 + u);
if (c == NULL)
SysError(ERROR_LUMALLOC);
memcpy(c + 2 + u, command_to_exec, (n + 1) * sizeof(char *));
c[0] = term->misc.localefilter;
if (u) {
c[1] = "-encoding";
c[2] = term->misc.locale_str;
}
c[1 + u] = "--";
command_to_exec_with_luit = c;
} else {
static char *luit[6];
luit[0] = term->misc.localefilter;
if (u) {
luit[1] = "-encoding";
luit[2] = term->misc.locale_str;
luit[3] = NULL;
} else
luit[1] = NULL;
command_to_exec_with_luit = luit;
}
}
#endif
#ifdef DEBUG
{
char dbglogfile[45];
int i = -1;
if (debug) {
timestamp_filename(dbglogfile, "xterm.debug.log.");
if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0666) > 0) {
i = open(dbglogfile, O_WRONLY | O_TRUNC);
}
}
if (i >= 0) {
dup2(i, 2);
(void) fcntl(i, F_SETFD, 1);
}
}
#endif
spawnXTerm(term);
#ifndef VMS
#ifdef USE_POSIX_SIGNALS
(void) posix_signal(SIGCHLD, reapchild);
#else
(void) signal(SIGCHLD, reapchild);
#endif
if (am_slave >= 0) {
char buf[80];
buf[0] = '\0';
sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
write(screen->respond, buf, strlen(buf));
}
#ifdef AIXV3
#if (OSMAJORVERSION < 4)
{
TERMIO_STRUCT tio;
if (ttyGetAttr(screen->respond, &tio) == -1)
SysError(ERROR_TIOCGETP);
tio.c_cflag &= ~(CLOCAL);
if (ttySetAttr(screen->respond, &tio) == -1)
SysError(ERROR_TIOCSETP);
}
#endif
#endif
#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__)
if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
SysError(ERROR_F_GETFL);
#ifdef O_NDELAY
mode |= O_NDELAY;
#else
mode |= O_NONBLOCK;
#endif
if (fcntl(screen->respond, F_SETFL, mode))
SysError(ERROR_F_SETFL);
#else
mode = 1;
if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
SysError(ERROR_FIONBIO);
#endif
#if OPT_DABBREV
#ifdef TERMIO_STRUCT
screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
#else
screen->dabbrev_erase_char = d_sg.sg_erase;
#endif
TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
#endif
FD_ZERO(&pty_mask);
FD_ZERO(&X_mask);
FD_ZERO(&Select_mask);
FD_SET(screen->respond, &pty_mask);
FD_SET(ConnectionNumber(screen->display), &X_mask);
FD_SET(screen->respond, &Select_mask);
FD_SET(ConnectionNumber(screen->display), &Select_mask);
max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
? (1 + ConnectionNumber(screen->display))
: (1 + screen->respond));
#endif
#ifdef DEBUG
if (debug)
printf("debugging on\n");
#endif
XSetErrorHandler(xerror);
XSetIOErrorHandler(xioerror);
initPtyData(&VTbuffer);
#ifdef ALLOWLOGGING
if (term->misc.log_on) {
StartLog(screen);
}
#endif
if (winToEmbedInto != None) {
XtRealizeWidget(toplevel);
XReparentWindow(XtDisplay(toplevel),
XtWindow(toplevel),
winToEmbedInto, 0, 0);
}
#if OPT_COLOR_RES
TRACE(("checking resource values rv %s fg %s, bg %s\n",
BtoS(term->misc.re_verse0),
NonNull(term->screen.Tcolors[TEXT_FG].resource),
NonNull(term->screen.Tcolors[TEXT_BG].resource)));
if ((reversed && term->misc.re_verse0)
&& ((term->screen.Tcolors[TEXT_FG].resource
&& !isDefaultForeground(term->screen.Tcolors[TEXT_FG].resource))
|| (term->screen.Tcolors[TEXT_BG].resource
&& !isDefaultBackground(term->screen.Tcolors[TEXT_BG].resource))
))
ReverseVideo(term);
#endif
#if OPT_MAXIMIZE
if (resource.maximized)
RequestMaximize(term, True);
#endif
for (;;) {
#if OPT_TEK4014
if (TEK4014_ACTIVE(term))
TekRun();
else
#endif
VTRun();
}
}
#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
#define USE_OPENPTY 1
static int opened_tty = -1;
#endif
static int
get_pty(int *pty, char *from GCC_UNUSED)
{
int result = 1;
#if defined(PUCC_PTYD)
result = ((*pty = openrpty(ttydev, ptydev,
(resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
save_ruid, from)) < 0);
#elif defined(USE_OPENPTY)
result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
#elif defined(__QNXNTO__)
result = pty_search(pty);
#else
#if defined(USE_ISPTS_FLAG)
result = pty_search(pty);
if (!result)
IsPts = 0;
#endif
#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
#ifdef __GLIBC__
if ((*pty = getpt()) >= 0) {
char *name = ptsname(*pty);
if (name != 0) {
strcpy(ttydev, name);
result = 0;
}
}
#elif defined(__MVS__)
result = pty_search(pty);
#else
#if defined(USE_ISPTS_FLAG)
if (result) {
#endif
result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
#endif
#if defined(SVR4) || defined(__SCO__) || defined(USE_ISPTS_FLAG)
if (!result)
strcpy(ttydev, ptsname(*pty));
#ifdef USE_ISPTS_FLAG
IsPts = !result;
}
#endif
#endif
#elif defined(AIXV3)
if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
strcpy(ttydev, ttyname(*pty));
result = 0;
}
#elif defined(__convex__)
char *pty_name;
extern char *getpty(void);
while ((pty_name = getpty()) != NULL) {
if ((*pty = open(pty_name, O_RDWR)) >= 0) {
strcpy(ptydev, pty_name);
strcpy(ttydev, pty_name);
*x_basename(ttydev) = 't';
result = 0;
break;
}
}
#elif defined(sequent)
result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
#elif defined(__sgi) && (OSMAJORVERSION >= 4)
char *tty_name;
tty_name = _getpty(pty, O_RDWR, 0622, 0);
if (tty_name != 0) {
strcpy(ttydev, tty_name);
result = 0;
}
#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
struct stat fstat_buf;
*pty = open("/dev/ptc", O_RDWR);
if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
result = 0;
sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
}
#elif defined(__hpux)
if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
char *name = ptsname(*pty);
if (name != 0) {
strcpy(ttydev, name);
result = 0;
} else {
close(*pty);
*pty = -1;
result = pty_search(pty);
}
} else {
result = pty_search(pty);
}
#else
result = pty_search(pty);
#endif
#endif
TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
ttydev != 0 ? ttydev : "?",
ptydev != 0 ? ptydev : "?",
result ? "FAIL" : "OK",
pty != 0 ? *pty : -1));
return result;
}
static void
set_pty_permissions(uid_t uid, gid_t gid, mode_t mode)
{
#ifdef USE_TTY_GROUP
struct group *ttygrp;
if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
gid = ttygrp->gr_gid;
mode &= 0660U;
}
endgrent();
#endif
TRACE_IDS;
set_owner(ttydev, uid, gid, mode);
}
#ifdef get_pty
#undef get_pty
static int
get_pty(int *pty, char *from)
{
static int m_pty = -1;
int result = -1;
if (pty == NULL) {
result = really_get_pty(&m_pty, from);
seteuid(0);
set_pty_permissions(save_ruid, save_rgid, 0600U);
seteuid(save_ruid);
TRACE_IDS;
#ifdef USE_OPENPTY
if (opened_tty >= 0) {
close(opened_tty);
opened_tty = -1;
}
#endif
} else if (m_pty != -1) {
*pty = m_pty;
result = 0;
} else {
result = -1;
}
return result;
}
#endif
#ifdef USE_PTY_SEARCH
static int
pty_search(int *pty)
{
static int devindex = 0, letter = 0;
#if defined(CRAY) || defined(__MVS__)
while (devindex < MAXPTTYS) {
sprintf(ttydev, TTYFORMAT, devindex);
sprintf(ptydev, PTYFORMAT, devindex);
devindex++;
TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
if ((*pty = open(ptydev, O_RDWR)) >= 0) {
return 0;
}
}
#else
while (PTYCHAR1[letter]) {
ttydev[strlen(ttydev) - 2] =
ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
while (PTYCHAR2[devindex]) {
ttydev[strlen(ttydev) - 1] =
ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
devindex++;
TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
if ((*pty = open(ptydev, O_RDWR)) >= 0) {
#ifdef sun
int pgrp_rtn;
if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
close(*pty);
continue;
}
#endif
return 0;
}
}
devindex = 0;
letter++;
}
#endif
return 1;
}
#endif
#if OPT_TEK4014
static char *tekterm[] =
{
"tek4014",
"tek4015",
"tek4012",
"tek4013",
"tek4010",
"dumb",
0
};
#endif
static char *vtterm[] =
{
#ifdef USE_X11TERM
"x11term",
#endif
DFT_TERMTYPE,
"xterm",
"vt102",
"vt100",
"ansi",
"dumb",
0
};
static SIGNAL_T
hungtty(int i GCC_UNUSED)
{
siglongjmp(env, 1);
SIGNAL_RETURN;
}
#if OPT_PTY_HANDSHAKE
#define NO_FDS {-1, -1}
static int cp_pipe[2] = NO_FDS;
static int pc_pipe[2] = NO_FDS;
typedef enum {
PTY_BAD,
PTY_FATALERROR,
PTY_GOOD,
PTY_NEW,
PTY_NOMORE,
UTMP_ADDED,
UTMP_TTYSLOT,
PTY_EXEC
} status_t;
typedef struct {
status_t status;
int error;
int fatal_error;
int tty_slot;
int rows;
int cols;
char buffer[1024];
} handshake_t;
#if OPT_TRACE
static void
trace_handshake(const char *tag, handshake_t * data)
{
const char *status = "?";
switch (data->status) {
case PTY_BAD:
status = "PTY_BAD";
break;
case PTY_FATALERROR:
status = "PTY_FATALERROR";
break;
case PTY_GOOD:
status = "PTY_GOOD";
break;
case PTY_NEW:
status = "PTY_NEW";
break;
case PTY_NOMORE:
status = "PTY_NOMORE";
break;
case UTMP_ADDED:
status = "UTMP_ADDED";
break;
case UTMP_TTYSLOT:
status = "UTMP_TTYSLOT";
break;
case PTY_EXEC:
status = "PTY_EXEC";
break;
}
TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
tag,
status,
data->error,
data->fatal_error,
data->buffer));
}
#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
#else
#define TRACE_HANDSHAKE(tag, data)
#endif
static void
HsSysError(int error)
{
handshake_t handshake;
memset(&handshake, 0, sizeof(handshake));
handshake.status = PTY_FATALERROR;
handshake.error = errno;
handshake.fatal_error = error;
strcpy(handshake.buffer, ttydev);
if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
handshake.error,
handshake.fatal_error,
handshake.buffer));
TRACE_HANDSHAKE("writing", &handshake);
write(cp_pipe[1], (char *) &handshake, sizeof(handshake));
} else {
fprintf(stderr,
"%s: fatal pty error errno=%d, error=%d device \"%s\"\n",
ProgramName,
handshake.error,
handshake.fatal_error,
handshake.buffer);
fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
}
exit(error);
}
void
first_map_occurred(void)
{
if (resource.wait_for_map) {
handshake_t handshake;
TScreen *screen = TScreenOf(term);
memset(&handshake, 0, sizeof(handshake));
handshake.status = PTY_EXEC;
handshake.rows = screen->max_row;
handshake.cols = screen->max_col;
if (pc_pipe[1] >= 0) {
TRACE(("first_map_occurred: %dx%d\n", handshake.rows, handshake.cols));
TRACE_HANDSHAKE("writing", &handshake);
write(pc_pipe[1], (char *) &handshake, sizeof(handshake));
close(cp_pipe[0]);
close(pc_pipe[1]);
}
resource.wait_for_map = False;
}
}
#else
static void
HsSysError(int error)
{
fprintf(stderr, "%s: fatal pty error %d (errno=%d) on tty %s\n",
ProgramName, error, errno, ttydev);
exit(error);
}
#endif
#ifndef VMS
static void
set_owner(char *device, uid_t uid, gid_t gid, mode_t mode)
{
int why;
TRACE_IDS;
TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n", device, uid, gid, mode));
if (chown(device, uid, gid) < 0) {
why = errno;
if (why != ENOENT
&& save_ruid == 0) {
fprintf(stderr, "Cannot chown %s to %ld,%ld: %s\n",
device, (long) uid, (long) gid,
strerror(why));
}
TRACE(("...chown failed: %s\n", strerror(why)));
}
if (chmod(device, mode) < 0) {
why = errno;
if (why != ENOENT) {
struct stat sb;
if (stat(device, &sb) < 0) {
fprintf(stderr, "Cannot chmod %s to %03o: %s\n",
device, (unsigned) mode,
strerror(why));
} else if (mode != (sb.st_mode & 0777U)) {
fprintf(stderr,
"Cannot chmod %s to %03lo currently %03lo: %s\n",
device,
(unsigned long) mode,
(unsigned long) (sb.st_mode & 0777U),
strerror(why));
TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
sb.st_uid, sb.st_gid, sb.st_mode));
}
}
TRACE(("...chmod failed: %s\n", strerror(why)));
}
}
#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
static void
init_utmp(int type, struct UTMP_STR *tofind)
{
memset(tofind, 0, sizeof(*tofind));
tofind->ut_type = type;
(void) strncpy(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
(void) strncpy(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
}
static struct UTMP_STR *
find_utmp(struct UTMP_STR *tofind)
{
struct UTMP_STR *result;
struct UTMP_STR working;
for (;;) {
memset(&working, 0, sizeof(working));
working.ut_type = tofind->ut_type;
memcpy(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
working.ut_type = 0;
#endif
if ((result = call_getutid(&working)) == 0)
break;
if (!strcmp(result->ut_line, tofind->ut_line))
break;
memset(result, 0, sizeof(*result));
}
return result;
}
#endif
#define close_fd(fd) close(fd), fd = -1
static int
spawnXTerm(XtermWidget xw)
{
TScreen *screen = TScreenOf(xw);
Cardinal nn;
#if OPT_PTY_HANDSHAKE
Bool got_handshake_size = False;
handshake_t handshake;
int done;
#endif
#if OPT_INITIAL_ERASE
int initial_erase = VAL_INITIAL_ERASE;
Bool setInitialErase;
#endif
int rc = 0;
int ttyfd = -1;
Bool ok_termcap;
char *newtc;
#ifdef TERMIO_STRUCT
TERMIO_STRUCT tio;
#ifdef __MVS__
TERMIO_STRUCT gio;
#endif
#ifdef TIOCLSET
unsigned lmode;
#endif
#ifdef HAS_LTCHARS
struct ltchars ltc;
#endif
#else
int ldisc = 0;
int discipline;
unsigned lmode;
struct tchars tc;
struct ltchars ltc;
struct sgttyb sg;
#ifdef sony
int jmode;
struct jtchars jtc;
#endif
#endif
char *ptr, *shname, *shname_minus;
int i, no_dev_tty = False;
char **envnew;
char buf[64];
char *TermName = NULL;
#ifdef TTYSIZE_STRUCT
TTYSIZE_STRUCT ts;
#endif
struct passwd *pw = NULL;
char *login_name = NULL;
#ifndef USE_UTEMPTER
#ifdef HAVE_UTMP
struct UTMP_STR utmp;
#ifdef USE_SYSV_UTMP
struct UTMP_STR *utret = NULL;
#endif
#ifdef USE_LASTLOG
struct lastlog lastlog;
#endif
#ifdef USE_LASTLOGX
struct lastlogx lastlogx;
#endif
#endif
#endif
(void) rc;
#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
(void) utret;
#endif
screen->uid = save_ruid;
screen->gid = save_rgid;
#ifdef SIGTTOU
signal(SIGTTOU, SIG_IGN);
#endif
#if OPT_PTY_HANDSHAKE
memset(&handshake, 0, sizeof(handshake));
#endif
if (am_slave >= 0) {
screen->respond = am_slave;
set_pty_id(ttydev, passedPty);
#ifdef USE_PTY_DEVICE
set_pty_id(ptydev, passedPty);
#endif
if (xtermResetIds(screen) < 0)
exit(1);
} else {
Bool tty_got_hung;
signal(SIGALRM, hungtty);
alarm(2);
if (!sigsetjmp(env, 1)) {
ttyfd = open("/dev/tty", O_RDWR);
alarm(0);
tty_got_hung = False;
} else {
tty_got_hung = True;
ttyfd = -1;
errno = ENXIO;
}
pw = NULL;
#if OPT_PTY_HANDSHAKE
got_handshake_size = False;
#endif
#if OPT_INITIAL_ERASE
initial_erase = VAL_INITIAL_ERASE;
#endif
signal(SIGALRM, SIG_DFL);
no_dev_tty = False;
if (ttyfd < 0) {
if (tty_got_hung || errno == ENXIO || errno == EIO ||
#ifdef ENODEV
errno == ENODEV ||
#endif
#ifdef __CYGWIN__
errno == ENOENT ||
#endif
errno == EINVAL || errno == ENOTTY || errno == EACCES) {
no_dev_tty = True;
#ifdef HAS_LTCHARS
ltc = d_ltc;
#endif
#ifdef TIOCLSET
lmode = d_lmode;
#endif
#ifdef TERMIO_STRUCT
tio = d_tio;
#else
sg = d_sg;
tc = d_tc;
discipline = d_disipline;
#ifdef sony
jmode = d_jmode;
jtc = d_jtc;
#endif
#endif
} else {
SysError(ERROR_OPDEVTTY);
}
} else {
#ifdef HAS_LTCHARS
if (ioctl(ttyfd, TIOCGLTC, <c) == -1)
ltc = d_ltc;
#endif
#ifdef TIOCLSET
if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
lmode = d_lmode;
#endif
#ifdef TERMIO_STRUCT
if ((rc = ttyGetAttr(ttyfd, &tio)) == -1)
tio = d_tio;
#else
if ((rc = ioctl(ttyfd, TIOCGETP, (char *) &sg)) == -1)
sg = d_sg;
if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
tc = d_tc;
if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
discipline = d_disipline;
#ifdef sony
if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
jmode = d_jmode;
if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
jtc = d_jtc;
#endif
#endif
#if OPT_INITIAL_ERASE
if (resource.ptyInitialErase) {
#ifdef TERMIO_STRUCT
initial_erase = tio.c_cc[VERASE];
#else
initial_erase = sg.sg_erase;
#endif
TRACE(("%s initial_erase:%d (from /dev/tty)\n",
rc == 0 ? "OK" : "FAIL",
initial_erase));
}
#endif
#ifdef __MVS__
if (ttyGetAttr(ttyfd, &gio) == 0) {
gio.c_cflag &= ~(HUPCL | PARENB);
ttySetAttr(ttyfd, &gio);
}
#endif
close_fd(ttyfd);
}
if (get_pty(&screen->respond, XDisplayString(screen->display))) {
SysError(ERROR_PTYS);
}
#if OPT_INITIAL_ERASE
if (resource.ptyInitialErase) {
#ifdef TERMIO_STRUCT
TERMIO_STRUCT my_tio;
if ((rc = ttyGetAttr(screen->respond, &my_tio)) == 0)
initial_erase = my_tio.c_cc[VERASE];
#else
struct sgttyb my_sg;
if ((rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg)) == 0)
initial_erase = my_sg.sg_erase;
#endif
TRACE(("%s initial_erase:%d (from pty)\n",
(rc == 0) ? "OK" : "FAIL",
initial_erase));
}
#endif
}
XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
False);
if (!TEK4014_ACTIVE(xw))
VTInit();
#if defined(TIOCCONS) || defined(SRIOCSREDIR)
if (Console) {
XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
mit_console = XInternAtom(screen->display, mit_console_name, False);
XtOwnSelection(SHELL_OF(CURRENT_EMU()),
mit_console, CurrentTime,
ConvertConsoleSelection, NULL, NULL);
}
#endif
#if OPT_TEK4014
if (TEK4014_ACTIVE(xw)) {
envnew = tekterm;
newtc = TekScreenOf(tekWidget)->tcapbuf;
} else
#endif
{
envnew = vtterm;
newtc = screen->tcapbuf;
}
ok_termcap = True;
if (!get_termcap(TermName = resource.term_name, newtc)) {
char *last = NULL;
TermName = *envnew;
ok_termcap = False;
while (*envnew != NULL) {
if ((last == NULL || strcmp(last, *envnew))
&& get_termcap(*envnew, newtc)) {
TermName = *envnew;
ok_termcap = True;
break;
}
last = *envnew;
envnew++;
}
}
if (ok_termcap) {
resize_termcap(xw, newtc);
}
#if OPT_INITIAL_ERASE
TRACE(("resource ptyInitialErase is %sset\n",
resource.ptyInitialErase ? "" : "not "));
setInitialErase = False;
if (override_tty_modes && ttymodelist[XTTYMODE_erase].set) {
initial_erase = ttymodelist[XTTYMODE_erase].value;
setInitialErase = True;
} else if (resource.ptyInitialErase) {
;
} else if (ok_termcap) {
char temp[1024], *p = temp;
char *s = tgetstr(TERMCAP_ERASE, &p);
TRACE(("...extracting initial_erase value from termcap\n"));
if (s != 0) {
initial_erase = decode_keyvalue(&s, True);
setInitialErase = True;
}
}
TRACE(("...initial_erase:%d\n", initial_erase));
TRACE(("resource backarrowKeyIsErase is %sset\n",
resource.backarrow_is_erase ? "" : "not "));
if (resource.backarrow_is_erase) {
if (initial_erase == ANSI_DEL) {
xw->keyboard.flags &= ~MODE_DECBKM;
} else {
xw->keyboard.flags |= MODE_DECBKM;
xw->keyboard.reset_DECBKM = 1;
}
TRACE(("...sets DECBKM %s\n",
(xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
} else {
xw->keyboard.reset_DECBKM = 2;
}
#endif
#ifdef TTYSIZE_STRUCT
#if OPT_TEK4014
if (TEK4014_ACTIVE(xw)) {
TTYSIZE_ROWS(ts) = 38;
TTYSIZE_COLS(ts) = 81;
#if defined(USE_STRUCT_WINSIZE)
ts.ws_xpixel = TFullWidth(&(tekWidget->screen));
ts.ws_ypixel = TFullHeight(&(tekWidget->screen));
#endif
} else
#endif
{
TTYSIZE_ROWS(ts) = MaxRows(screen);
TTYSIZE_COLS(ts) = MaxCols(screen);
#if defined(USE_STRUCT_WINSIZE)
ts.ws_xpixel = FullWidth(screen);
ts.ws_ypixel = FullHeight(screen);
#endif
}
i = SET_TTYSIZE(screen->respond, ts);
TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
TTYSIZE_ROWS(ts),
TTYSIZE_COLS(ts), i));
#endif
added_utmp_entry = False;
#if defined(USE_UTEMPTER)
#undef UTMP
if (!resource.utmpInhibit) {
struct UTMP_STR dummy;
SetUtmpHost(dummy.ut_host, screen);
addToUtmp(ttydev, dummy.ut_host, screen->respond);
added_utmp_entry = True;
}
#endif
if (am_slave < 0) {
#if OPT_PTY_HANDSHAKE
if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
SysError(ERROR_FORK);
#endif
TRACE(("Forking...\n"));
if ((screen->pid = fork()) == -1)
SysError(ERROR_FORK);
if (screen->pid == 0) {
#ifdef USE_USG_PTYS
int ptyfd;
char *pty_name;
#endif
#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
int pgrp = setsid();
#else
int pgrp = getpid();
#endif
TRACE_CHILD
#ifdef USE_USG_PTYS
#ifdef USE_ISPTS_FLAG
if (IsPts) {
#endif
ptyfd = 0;
pty_name = 0;
setpgrp();
grantpt(screen->respond);
unlockpt(screen->respond);
if ((pty_name = ptsname(screen->respond)) == 0) {
SysError(ERROR_PTSNAME);
}
if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
SysError(ERROR_OPPTSNAME);
}
#ifdef I_PUSH
if (ioctl(ptyfd, I_PUSH, "ptem") < 0) {
SysError(ERROR_PTEM);
}
#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
if (!x_getenv("CONSEM") && ioctl(ptyfd, I_PUSH, "consem") < 0) {
SysError(ERROR_CONSEM);
}
#endif
if (ioctl(ptyfd, I_PUSH, "ldterm") < 0) {
SysError(ERROR_LDTERM);
}
#ifdef SVR4
if (ioctl(ptyfd, I_PUSH, "ttcompat") < 0) {
SysError(ERROR_TTCOMPAT);
}
#endif
#endif
ttyfd = ptyfd;
#ifndef __MVS__
close_fd(screen->respond);
#endif
#ifdef TTYSIZE_STRUCT
#if OPT_TEK4014
if (TEK4014_ACTIVE(xw)) {
TTYSIZE_ROWS(ts) = 24;
TTYSIZE_COLS(ts) = 80;
#ifdef USE_STRUCT_WINSIZE
ts.ws_xpixel = TFullWidth(&(tekWidget->screen));
ts.ws_ypixel = TFullHeight(&(tekWidget->screen));
#endif
} else
#endif
{
TTYSIZE_ROWS(ts) = MaxRows(screen);
TTYSIZE_COLS(ts) = MaxCols(screen);
#ifdef USE_STRUCT_WINSIZE
ts.ws_xpixel = FullWidth(screen);
ts.ws_ypixel = FullHeight(screen);
#endif
}
#endif
#ifdef USE_ISPTS_FLAG
} else {
#endif
#endif
(void) pgrp;
#if OPT_PTY_HANDSHAKE
if (resource.ptyHandshake) {
close(cp_pipe[0]);
close(pc_pipe[1]);
if (cp_pipe[1] <= 2) {
if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
(void) close(cp_pipe[1]);
cp_pipe[1] = i;
}
}
if (pc_pipe[0] <= 2) {
if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
(void) close(pc_pipe[0]);
pc_pipe[0] = i;
}
}
close(ConnectionNumber(screen->display));
#ifndef __MVS__
close(screen->respond);
#endif
#ifdef USE_SYSV_PGRP
#if defined(CRAY) && (OSMAJORVERSION > 5)
(void) setsid();
#else
(void) setpgrp();
#endif
#endif
#if defined(__QNX__) && !defined(__QNXNTO__)
qsetlogin(getlogin(), ttydev);
#endif
if (ttyfd >= 0) {
#ifdef __MVS__
if (ttyGetAttr(ttyfd, &gio) == 0) {
gio.c_cflag &= ~(HUPCL | PARENB);
ttySetAttr(ttyfd, &gio);
}
#else
close_fd(ttyfd);
#endif
}
while (1) {
#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
if (!no_dev_tty
&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
close_fd(ttyfd);
}
#endif
#ifdef CSRG_BASED
(void) revoke(ttydev);
#endif
if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
#if defined(CRAY) && defined(TCSETCTTY)
ioctl(ttyfd, TCSETCTTY, 0);
#endif
#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
ioctl(ttyfd, TIOCSCTTY, 0);
#endif
#ifdef USE_SYSV_PGRP
if ((i = open("/dev/tty", O_RDWR)) >= 0) {
close(i);
break;
}
#else
break;
#endif
}
perror("open ttydev");
#ifdef TIOCSCTTY
ioctl(ttyfd, TIOCSCTTY, 0);
#endif
handshake.status = PTY_BAD;
handshake.error = errno;
strcpy(handshake.buffer, ttydev);
TRACE_HANDSHAKE("writing", &handshake);
write(cp_pipe[1], (char *) &handshake,
sizeof(handshake));
i = read(pc_pipe[0], (char *) &handshake,
sizeof(handshake));
if (i <= 0) {
exit(1);
}
if (handshake.status == PTY_NOMORE) {
exit(1);
}
free(ttydev);
ttydev = CastMallocN(char, strlen(handshake.buffer));
if (ttydev == NULL) {
SysError(ERROR_SPREALLOC);
}
strcpy(ttydev, handshake.buffer);
}
if ((ptr = ttyname(ttyfd)) != 0) {
ttydev = TypeRealloc(char, strlen(ptr) + 1, ttydev);
if (ttydev == NULL) {
SysError(ERROR_SPREALLOC);
}
(void) strcpy(ttydev, ptr);
}
}
#endif
#ifdef USE_ISPTS_FLAG
}
#endif
set_pty_permissions(screen->uid,
screen->gid,
(resource.messages
? 0622U
: 0600U));
{
#ifdef TERMIO_STRUCT
#if defined(umips) || defined(CRAY) || defined(linux)
if (ttyGetAttr(ttyfd, &tio) == -1)
SysError(ERROR_TIOCGETP);
tio.c_lflag |= ECHOE;
#endif
tio.c_iflag &= ~(INLCR | IGNCR);
tio.c_iflag |= ICRNL;
#if OPT_WIDE_CHARS && defined(linux) && defined(IUTF8)
#if OPT_LUIT_PROG
if (command_to_exec_with_luit == 0)
#endif
if (screen->utf8_mode)
tio.c_iflag |= IUTF8;
#endif
#ifndef USE_POSIX_TERMIOS
tio.c_oflag &=
~(OCRNL
| ONLRET
| NLDLY
| CRDLY
| TABDLY
| BSDLY
| VTDLY
| FFDLY);
#endif
#ifdef ONLCR
tio.c_oflag |= ONLCR;
#endif
#ifdef OPOST
tio.c_oflag |= OPOST;
#endif
#ifndef USE_POSIX_TERMIOS
# if defined(Lynx) && !defined(CBAUD)
# define CBAUD V_CBAUD
# endif
tio.c_cflag &= ~(CBAUD);
#ifdef BAUD_0
#elif defined(HAVE_TERMIO_C_ISPEED)
tio.c_ispeed = tio.c_ospeed = VAL_LINE_SPEED;
#else
tio.c_cflag |= VAL_LINE_SPEED;
#endif
#else
cfsetispeed(&tio, VAL_LINE_SPEED);
cfsetospeed(&tio, VAL_LINE_SPEED);
#ifdef __MVS__
tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
#endif
tio.c_cflag &= ~CLOCAL;
#endif
tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
#ifdef ECHOKE
tio.c_lflag |= ECHOKE | IEXTEN;
#endif
#ifdef ECHOCTL
tio.c_lflag |= ECHOCTL | IEXTEN;
#endif
for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
if (validTtyChar(tio, nn)) {
int sysMode = known_ttyChars[nn].sysMode;
#ifdef __MVS__
if (tio.c_cc[sysMode] != 0) {
switch (sysMode) {
case VEOL:
case VEOF:
continue;
}
}
#endif
tio.c_cc[sysMode] = known_ttyChars[nn].myDefault;
}
}
if (override_tty_modes) {
for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
if (validTtyChar(tio, nn)) {
TMODE(known_ttyChars[nn].myMode,
tio.c_cc[known_ttyChars[nn].sysMode]);
}
}
#ifdef HAS_LTCHARS
TMODE(XTTYMODE_susp, ltc.t_suspc);
TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
TMODE(XTTYMODE_flush, ltc.t_flushc);
TMODE(XTTYMODE_weras, ltc.t_werasc);
TMODE(XTTYMODE_lnext, ltc.t_lnextc);
#endif
}
#ifdef HAS_LTCHARS
#ifdef __hpux
ltc.t_rprntc = ltc.t_rprntc = ltc.t_flushc =
ltc.t_werasc = ltc.t_lnextc = _POSIX_VDISABLE;
#endif
if (ioctl(ttyfd, TIOCSLTC, <c) == -1)
HsSysError(ERROR_TIOCSETC);
#endif
#ifdef TIOCLSET
if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
HsSysError(ERROR_TIOCLSET);
#endif
if (ttySetAttr(ttyfd, &tio) == -1)
HsSysError(ERROR_TIOCSETP);
tio.c_cflag &= ~CSIZE;
if (screen->input_eight_bits)
tio.c_cflag |= CS8;
else
tio.c_cflag |= CS7;
(void) ttySetAttr(ttyfd, &tio);
#else
sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
sg.sg_flags |= ECHO | CRMOD;
sg.sg_ispeed = VAL_LINE_SPEED;
sg.sg_ospeed = VAL_LINE_SPEED;
tc.t_brkc = -1;
#ifdef LPASS8
if (screen->input_eight_bits)
lmode |= LPASS8;
else
lmode &= ~(LPASS8);
#endif
#ifdef sony
jmode &= ~KM_KANJI;
#endif
ltc = d_ltc;
if (override_tty_modes) {
TMODE(XTTYMODE_intr, tc.t_intrc);
TMODE(XTTYMODE_quit, tc.t_quitc);
TMODE(XTTYMODE_erase, sg.sg_erase);
TMODE(XTTYMODE_kill, sg.sg_kill);
TMODE(XTTYMODE_eof, tc.t_eofc);
TMODE(XTTYMODE_start, tc.t_startc);
TMODE(XTTYMODE_stop, tc.t_stopc);
TMODE(XTTYMODE_brk, tc.t_brkc);
TMODE(XTTYMODE_susp, ltc.t_suspc);
TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
TMODE(XTTYMODE_flush, ltc.t_flushc);
TMODE(XTTYMODE_weras, ltc.t_werasc);
TMODE(XTTYMODE_lnext, ltc.t_lnextc);
}
if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
HsSysError(ERROR_TIOCSETP);
if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
HsSysError(ERROR_TIOCSETC);
if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
HsSysError(ERROR_TIOCSETD);
if (ioctl(ttyfd, TIOCSLTC, (char *) <c) == -1)
HsSysError(ERROR_TIOCSLTC);
if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
HsSysError(ERROR_TIOCLSET);
#ifdef sony
if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
HsSysError(ERROR_TIOCKSET);
if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
HsSysError(ERROR_TIOCKSETC);
#endif
#endif
#if defined(TIOCCONS) || defined(SRIOCSREDIR)
if (Console) {
#ifdef TIOCCONS
int on = 1;
if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
fprintf(stderr, "%s: cannot open console: %s\n",
ProgramName, strerror(errno));
#endif
#ifdef SRIOCSREDIR
int fd = open("/dev/console", O_RDWR);
if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
fprintf(stderr, "%s: cannot open console: %s\n",
ProgramName, strerror(errno));
(void) close(fd);
#endif
}
#endif
}
signal(SIGCHLD, SIG_DFL);
#ifdef USE_SYSV_SIGHUP
signal(SIGHUP, SIG_DFL);
#else
signal(SIGHUP, SIG_IGN);
#endif
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
#if OPT_INITIAL_ERASE
TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
initial_erase,
setInitialErase ? "YES" : "NO",
resource.ptyInitialErase,
override_tty_modes,
ttymodelist[XTTYMODE_erase].set));
if (setInitialErase) {
#if OPT_TRACE
int old_erase;
#endif
#ifdef TERMIO_STRUCT
if (ttyGetAttr(ttyfd, &tio) == -1)
tio = d_tio;
#if OPT_TRACE
old_erase = tio.c_cc[VERASE];
#endif
tio.c_cc[VERASE] = initial_erase;
rc = ttySetAttr(ttyfd, &tio);
#else
if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
sg = d_sg;
#if OPT_TRACE
old_erase = sg.sg_erase;
#endif
sg.sg_erase = initial_erase;
rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
#endif
TRACE(("%s setting erase to %d (was %d)\n",
rc ? "FAIL" : "OK", initial_erase, old_erase));
}
#endif
xtermCopyEnv(environ);
xtermSetenv("TERM", TermName);
if (!TermName)
*newtc = 0;
sprintf(buf, "%lu",
((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
xtermSetenv("WINDOWID", buf);
xtermSetenv("DISPLAY", XDisplayString(screen->display));
xtermSetenv("XTERM_VERSION", xtermVersion());
xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
signal(SIGTERM, SIG_DFL);
{
#if defined(CRAY) && (OSMAJORVERSION >= 6)
close_fd(ttyfd);
(void) close(0);
if (open("/dev/tty", O_RDWR)) {
SysError(ERROR_OPDEVTTY);
}
(void) close(1);
(void) close(2);
dup(0);
dup(0);
#else
for (i = 0; i <= 2; i++)
if (i != ttyfd) {
(void) close(i);
(void) dup(ttyfd);
}
#ifndef ATT
if (ttyfd > 2)
close_fd(ttyfd);
#endif
#endif
}
#if !defined(USE_SYSV_PGRP)
#ifdef TIOCSCTTY
setsid();
ioctl(0, TIOCSCTTY, 0);
#endif
ioctl(0, TIOCSPGRP, (char *) &pgrp);
setpgrp(0, 0);
close(open(ttydev, O_WRONLY));
setpgrp(0, pgrp);
#if defined(__QNX__)
tcsetpgrp(0, pgrp );
#endif
#endif
#ifdef Lynx
{
TERMIO_STRUCT t;
if (ttyGetAttr(0, &t) >= 0) {
t.c_oflag |= OPOST;
ttySetAttr(0, &t);
}
}
#endif
#ifdef HAVE_UTMP
pw = getpwuid(screen->uid);
login_name = NULL;
if (pw && pw->pw_name) {
#ifdef HAVE_GETLOGIN
if (((login_name = getlogin()) != NULL
|| (login_name = x_getenv("LOGNAME")) != NULL
|| (login_name = x_getenv("USER")) != NULL)
&& strcmp(login_name, pw->pw_name)) {
struct passwd *pw2 = getpwnam(login_name);
if (pw2 != 0) {
uid_t uid2 = pw2->pw_uid;
pw = getpwuid(screen->uid);
if ((uid_t) pw->pw_uid != uid2)
login_name = NULL;
} else {
pw = getpwuid(screen->uid);
}
}
#endif
if (login_name == NULL)
login_name = pw->pw_name;
if (login_name != NULL)
login_name = x_strdup(login_name);
}
if (login_name != NULL) {
xtermSetenv("LOGNAME", login_name);
}
#ifndef USE_UTEMPTER
#ifdef USE_UTMP_SETGID
setEffectiveGroup(save_egid);
TRACE_IDS;
#endif
#ifdef USE_SYSV_UTMP
(void) call_setutent();
init_utmp(DEAD_PROCESS, &utmp);
if (!(utret = find_utmp(&utmp))) {
(void) call_setutent();
init_utmp(USER_PROCESS, &utmp);
if (!(utret = find_utmp(&utmp))) {
(void) call_setutent();
}
}
#if OPT_TRACE
if (!utret)
TRACE(("getutid: NULL\n"));
else
TRACE(("getutid: pid=%d type=%d user=%s line=%s id=%s\n",
utret->ut_pid, utret->ut_type, utret->ut_user,
utret->ut_line, utret->ut_id));
#endif
utmp.ut_type = USER_PROCESS;
#ifdef HAVE_UTMP_UT_XSTATUS
utmp.ut_xstatus = 2;
#endif
(void) strncpy(utmp.ut_user,
(login_name != NULL) ? login_name : "????",
sizeof(utmp.ut_user));
(void) strncpy(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
(void) strncpy(utmp.ut_line,
my_pty_name(ttydev), sizeof(utmp.ut_line));
#ifdef HAVE_UTMP_UT_HOST
SetUtmpHost(utmp.ut_host, screen);
#endif
#ifdef HAVE_UTMP_UT_SYSLEN
SetUtmpSysLen(utmp);
#endif
(void) strncpy(utmp.ut_name,
(login_name) ? login_name : "????",
sizeof(utmp.ut_name));
utmp.ut_pid = getpid();
#if defined(HAVE_UTMP_UT_XTIME)
#if defined(HAVE_UTMP_UT_SESSION)
utmp.ut_session = getsid(0);
#endif
utmp.ut_xtime = time((time_t *) 0);
utmp.ut_tv.tv_usec = 0;
#else
utmp.ut_time = time((time_t *) 0);
#endif
if (!resource.utmpInhibit) {
errno = 0;
call_pututline(&utmp);
TRACE(("pututline: id %s, line %s, pid %ld, errno %d %s\n",
utmp.ut_id,
utmp.ut_line,
(long) utmp.ut_pid,
errno, (errno != 0) ? strerror(errno) : ""));
}
#ifdef WTMP
#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
if (xw->misc.login_shell)
updwtmpx(WTMPX_FILE, &utmp);
#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
if (xw->misc.login_shell)
call_updwtmp(etc_wtmp, &utmp);
#else
if (xw->misc.login_shell &&
(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
write(i, (char *) &utmp, sizeof(utmp));
close(i);
}
#endif
#endif
(void) call_endutent();
#else
tslot = ttyslot();
added_utmp_entry = False;
{
if (tslot > 0 && pw && !resource.utmpInhibit &&
(i = open(etc_utmp, O_WRONLY)) >= 0) {
bzero((char *) &utmp, sizeof(utmp));
(void) strncpy(utmp.ut_line,
my_pty_name(ttydev),
sizeof(utmp.ut_line));
(void) strncpy(utmp.ut_name, login_name,
sizeof(utmp.ut_name));
#ifdef HAVE_UTMP_UT_HOST
SetUtmpHost(utmp.ut_host, screen);
#endif
#ifdef HAVE_UTMP_UT_SYSLEN
SetUtmpSysLen(utmp);
#endif
utmp.ut_time = time((time_t *) 0);
lseek(i, (long) (tslot * sizeof(utmp)), 0);
write(i, (char *) &utmp, sizeof(utmp));
close(i);
added_utmp_entry = True;
#if defined(WTMP)
if (xw->misc.login_shell &&
(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
int status;
status = write(i, (char *) &utmp, sizeof(utmp));
status = close(i);
}
#elif defined(MNX_LASTLOG)
if (xw->misc.login_shell &&
(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
lseek(i, (long) (screen->uid *
sizeof(utmp)), 0);
write(i, (char *) &utmp, sizeof(utmp));
close(i);
}
#endif
} else
tslot = -tslot;
}
#if OPT_PTY_HANDSHAKE
if (resource.ptyHandshake) {
handshake.tty_slot = tslot;
}
#endif
#endif
#ifdef USE_LASTLOGX
if (xw->misc.login_shell) {
bzero((char *) &lastlogx, sizeof(lastlogx));
(void) strncpy(lastlogx.ll_line,
my_pty_name(ttydev),
sizeof(lastlogx.ll_line));
X_GETTIMEOFDAY(&lastlogx.ll_tv);
SetUtmpHost(lastlogx.ll_host, screen);
updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
}
#endif
#ifdef USE_LASTLOG
if (xw->misc.login_shell &&
(i = open(etc_lastlog, O_WRONLY)) >= 0) {
size_t size = sizeof(struct lastlog);
off_t offset = (screen->uid * size);
bzero((char *) &lastlog, size);
(void) strncpy(lastlog.ll_line,
my_pty_name(ttydev),
sizeof(lastlog.ll_line));
SetUtmpHost(lastlog.ll_host, screen);
lastlog.ll_time = time((time_t *) 0);
if (lseek(i, offset, 0) != (off_t) (-1)) {
write(i, (char *) &lastlog, size);
}
close(i);
}
#endif
#if defined(USE_UTMP_SETGID)
disableSetGid();
TRACE_IDS;
#endif
#if OPT_PTY_HANDSHAKE
if (resource.ptyHandshake) {
handshake.status = UTMP_ADDED;
handshake.error = 0;
strcpy(handshake.buffer, ttydev);
TRACE_HANDSHAKE("writing", &handshake);
(void) write(cp_pipe[1], (char *) &handshake, sizeof(handshake));
}
#endif
#endif
#endif
(void) setgid(screen->gid);
TRACE_IDS;
#ifdef HAS_BSD_GROUPS
if (geteuid() == 0 && pw) {
if (initgroups(login_name, pw->pw_gid)) {
perror("initgroups failed");
SysError(ERROR_INIGROUPS);
}
}
#endif
if (setuid(screen->uid)) {
SysError(ERROR_SETUID);
}
TRACE_IDS;
#if OPT_PTY_HANDSHAKE
if (resource.ptyHandshake) {
fcntl(cp_pipe[1], F_SETFD, 1);
fcntl(pc_pipe[0], F_SETFD, 1);
handshake.status = PTY_GOOD;
handshake.error = 0;
(void) strcpy(handshake.buffer, ttydev);
TRACE_HANDSHAKE("writing", &handshake);
(void) write(cp_pipe[1], (char *) &handshake, sizeof(handshake));
if (resource.wait_for_map) {
i = read(pc_pipe[0], (char *) &handshake,
sizeof(handshake));
if (i != sizeof(handshake) ||
handshake.status != PTY_EXEC) {
exit(ERROR_PTY_EXEC);
}
if (handshake.rows > 0 && handshake.cols > 0) {
TRACE(("handshake ttysize: %dx%d\n",
handshake.rows, handshake.cols));
set_max_row(screen, handshake.rows);
set_max_col(screen, handshake.cols);
#ifdef TTYSIZE_STRUCT
got_handshake_size = True;
TTYSIZE_ROWS(ts) = MaxRows(screen);
TTYSIZE_COLS(ts) = MaxCols(screen);
#if defined(USE_STRUCT_WINSIZE)
ts.ws_xpixel = FullWidth(screen);
ts.ws_ypixel = FullHeight(screen);
#endif
#endif
}
}
}
#endif
#ifdef USE_SYSV_ENVVARS
{
char numbuf[12];
sprintf(numbuf, "%d", MaxCols(screen));
xtermSetenv("COLUMNS", numbuf);
sprintf(numbuf, "%d", MaxRows(screen));
xtermSetenv("LINES", numbuf);
}
#ifdef HAVE_UTMP
if (pw) {
if (!x_getenv("HOME"))
xtermSetenv("HOME", pw->pw_dir);
if (!x_getenv("SHELL"))
xtermSetenv("SHELL", pw->pw_shell);
}
#endif
#ifdef OWN_TERMINFO_DIR
xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
#endif
#else
resize_termcap(xw, newtc);
if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
remove_termcap_entry(newtc, "ti=");
remove_termcap_entry(newtc, "te=");
}
if (resource.useInsertMode) {
remove_termcap_entry(newtc, "ic=");
remove_termcap_entry(newtc, "im=");
remove_termcap_entry(newtc, "ei=");
remove_termcap_entry(newtc, "mi");
if (*newtc)
strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
}
if (*newtc) {
#if OPT_INITIAL_ERASE
unsigned len;
remove_termcap_entry(newtc, TERMCAP_ERASE "=");
len = strlen(newtc);
if (len != 0 && newtc[len - 1] == ':')
len--;
sprintf(newtc + len, ":%s=\\%03o:",
TERMCAP_ERASE,
CharOf(initial_erase));
#endif
xtermSetenv("TERMCAP", newtc);
}
#endif
#if OPT_PTY_HANDSHAKE
if (resource.ptyHandshake
&& resource.ptySttySize
&& (got_handshake_size || !resource.wait_for_map0)) {
#ifdef TTYSIZE_STRUCT
i = SET_TTYSIZE(0, ts);
TRACE(("ptyHandshake SET_TTYSIZE %dx%d return %d\n",
TTYSIZE_ROWS(ts),
TTYSIZE_COLS(ts), i));
#endif
}
#endif
signal(SIGHUP, SIG_DFL);
if ((ptr = explicit_shname) == NULL) {
if (((ptr = x_getenv("SHELL")) == NULL) &&
((pw == NULL && (pw = getpwuid(screen->uid)) == NULL) ||
*(ptr = pw->pw_shell) == 0)) {
ptr = "/bin/sh";
}
} else {
xtermSetenv("SHELL", explicit_shname);
}
xtermSetenv("XTERM_SHELL", ptr);
shname = x_basename(ptr);
TRACE(("shell path '%s' leaf '%s'\n", ptr, shname));
#if OPT_LUIT_PROG
if (command_to_exec_with_luit && command_to_exec) {
xtermSetenv("XTERM_SHELL",
xtermFindShell(*command_to_exec_with_luit, False));
TRACE(("spawning command \"%s\"\n", *command_to_exec_with_luit));
execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
fprintf(stderr, "%s: Can't execvp %s: %s\n",
ProgramName, *command_to_exec_with_luit, strerror(errno));
fprintf(stderr, "%s: cannot support your locale.\n",
ProgramName);
}
#endif
if (command_to_exec) {
xtermSetenv("XTERM_SHELL",
xtermFindShell(*command_to_exec, False));
TRACE(("spawning command \"%s\"\n", *command_to_exec));
execvp(*command_to_exec, command_to_exec);
if (command_to_exec[1] == 0)
execlp(ptr, shname, "-c", command_to_exec[0], (void *) 0);
fprintf(stderr, "%s: Can't execvp %s: %s\n",
ProgramName, *command_to_exec, strerror(errno));
}
#ifdef USE_SYSV_SIGHUP
signal(SIGHUP, SIG_DFL);
#endif
shname_minus = CastMallocN(char, strlen(shname) + 2);
(void) strcpy(shname_minus, "-");
(void) strcat(shname_minus, shname);
#ifndef TERMIO_STRUCT
ldisc = XStrCmp("csh", shname + strlen(shname) - 3) == 0 ?
NTTYDISC : 0;
ioctl(0, TIOCSETD, (char *) &ldisc);
#endif
#ifdef USE_LOGIN_DASH_P
if (xw->misc.login_shell && pw && added_utmp_entry)
execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
#endif
#if OPT_LUIT_PROG
if (command_to_exec_with_luit) {
if (xw->misc.login_shell) {
int u;
u = (term->misc.use_encoding ? 2 : 0);
command_to_exec_with_luit[u + 1] = "-argv0";
command_to_exec_with_luit[u + 2] = shname_minus;
command_to_exec_with_luit[u + 3] = NULL;
}
execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
fprintf(stderr, "%s: Can't execvp %s: %s\n", ProgramName,
*command_to_exec_with_luit, strerror(errno));
}
#endif
execlp(ptr,
(xw->misc.login_shell ? shname_minus : shname),
(void *) 0);
fprintf(stderr, "%s: Could not exec %s: %s\n", ProgramName,
ptr, strerror(errno));
(void) sleep(5);
exit(ERROR_EXEC);
}
#if OPT_PTY_HANDSHAKE
if (resource.ptyHandshake) {
close(cp_pipe[1]);
close(pc_pipe[0]);
for (done = 0; !done;) {
if (read(cp_pipe[0],
(char *) &handshake,
sizeof(handshake)) <= 0) {
break;
}
TRACE_HANDSHAKE("read", &handshake);
switch (handshake.status) {
case PTY_GOOD:
done = 1;
break;
case PTY_BAD:
(void) close(screen->respond);
if (get_pty(&screen->respond, XDisplayString(screen->display))) {
fprintf(stderr,
"%s: child process can find no available ptys: %s\n",
ProgramName, strerror(errno));
handshake.status = PTY_NOMORE;
TRACE_HANDSHAKE("writing", &handshake);
write(pc_pipe[1], (char *) &handshake, sizeof(handshake));
exit(ERROR_PTYS);
}
handshake.status = PTY_NEW;
(void) strcpy(handshake.buffer, ttydev);
TRACE_HANDSHAKE("writing", &handshake);
write(pc_pipe[1], (char *) &handshake, sizeof(handshake));
break;
case PTY_FATALERROR:
errno = handshake.error;
close(cp_pipe[0]);
close(pc_pipe[1]);
SysError(handshake.fatal_error);
case UTMP_ADDED:
added_utmp_entry = True;
#ifndef USE_SYSV_UTMP
tslot = handshake.tty_slot;
#endif
free(ttydev);
ttydev = x_strdup(handshake.buffer);
break;
case PTY_NEW:
case PTY_NOMORE:
case UTMP_TTYSLOT:
case PTY_EXEC:
default:
fprintf(stderr, "%s: unexpected handshake status %d\n",
ProgramName,
(int) handshake.status);
}
}
if (!resource.wait_for_map) {
close(cp_pipe[0]);
close(pc_pipe[1]);
}
}
#endif
}
#ifdef USE_SYSV_SIGHUP
signal(SIGHUP, SIG_DFL);
#else
signal(SIGHUP, SIG_IGN);
#endif
#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
signal(SIGINT, SIG_IGN);
#ifndef SYSV
signal(SIGQUIT, SIG_IGN);
#endif
signal(SIGTERM, SIG_IGN);
#elif defined(SYSV) || defined(__osf__)
if (getpid() == getpgrp()) {
(void) signal(SIGINT, Exit);
(void) signal(SIGQUIT, Exit);
(void) signal(SIGTERM, Exit);
} else {
(void) signal(SIGINT, SIG_IGN);
(void) signal(SIGQUIT, SIG_IGN);
(void) signal(SIGTERM, SIG_IGN);
}
(void) signal(SIGPIPE, Exit);
#else
signal(SIGINT, Exit);
signal(SIGQUIT, Exit);
signal(SIGTERM, Exit);
signal(SIGPIPE, Exit);
#endif
return 0;
}
SIGNAL_T
Exit(int n)
{
TScreen *screen = TScreenOf(term);
#ifdef USE_UTEMPTER
if (!resource.utmpInhibit && added_utmp_entry)
removeFromUtmp();
#elif defined(HAVE_UTMP)
#ifdef USE_SYSV_UTMP
struct UTMP_STR utmp;
struct UTMP_STR *utptr;
if (xterm_exiting)
SIGNAL_RETURN;
xterm_exiting = True;
#ifdef PUCC_PTYD
closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
#endif
if (!resource.utmpInhibit
#if OPT_PTY_HANDSHAKE
&& (resource.ptyHandshake && added_utmp_entry)
#endif
) {
#if defined(USE_UTMP_SETGID)
setEffectiveGroup(save_egid);
TRACE_IDS;
#endif
init_utmp(USER_PROCESS, &utmp);
(void) call_setutent();
while ((utptr = find_utmp(&utmp)) != 0) {
if (utptr->ut_pid == screen->pid) {
utptr->ut_type = DEAD_PROCESS;
#if defined(HAVE_UTMP_UT_XTIME)
#if defined(HAVE_UTMP_UT_SESSION)
utptr->ut_session = getsid(0);
#endif
utptr->ut_xtime = time((time_t *) 0);
utptr->ut_tv.tv_usec = 0;
#else
*utptr->ut_user = 0;
utptr->ut_time = time((time_t *) 0);
#endif
(void) call_pututline(utptr);
#ifdef WTMP
#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
if (term->misc.login_shell)
updwtmpx(WTMPX_FILE, utptr);
#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
strncpy(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
if (term->misc.login_shell)
call_updwtmp(etc_wtmp, utptr);
#else
if (term->misc.login_shell) {
int fd;
if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
write(fd, utptr, sizeof(*utptr));
close(fd);
}
}
#endif
#endif
break;
}
memset(utptr, 0, sizeof(*utptr));
}
(void) call_endutent();
#ifdef USE_UTMP_SETGID
disableSetGid();
TRACE_IDS;
#endif
}
#else
int wfd;
struct utmp utmp;
if (!resource.utmpInhibit && added_utmp_entry &&
(am_slave < 0 && tslot > 0)) {
#if defined(USE_UTMP_SETGID)
setEffectiveGroup(save_egid);
TRACE_IDS;
#endif
if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
bzero((char *) &utmp, sizeof(utmp));
lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
write(wfd, (char *) &utmp, sizeof(utmp));
close(wfd);
}
#ifdef WTMP
if (term->misc.login_shell &&
(wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
(void) strncpy(utmp.ut_line,
my_pty_name(ttydev),
sizeof(utmp.ut_line));
utmp.ut_time = time((time_t *) 0);
write(wfd, (char *) &utmp, sizeof(utmp));
close(wfd);
}
#endif
#ifdef USE_UTMP_SETGID
disableSetGid();
TRACE_IDS;
#endif
}
#endif
#endif
ttyFlush(screen->respond);
if (am_slave < 0) {
TRACE_IDS;
set_owner(ttydev, 0, 0, 0666U);
#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
set_owner(ptydev, 0, 0, 0666U);
#endif
}
close(screen->respond);
#ifdef ALLOWLOGGING
if (screen->logging)
CloseLog(screen);
#endif
#ifdef NO_LEAKS
if (n == 0) {
TRACE(("Freeing memory leaks\n"));
if (term != 0) {
Display *dpy = term->screen.display;
if (toplevel) {
XtDestroyWidget(toplevel);
TRACE(("destroyed top-level widget\n"));
}
sortedOpts(0, 0, 0);
noleaks_charproc();
noleaks_ptydata();
#if OPT_WIDE_CHARS
noleaks_CharacterClass();
#endif
XtCloseDisplay(dpy);
XtDestroyApplicationContext(app_con);
#if OPT_SESSION_MGT
IceRemoveConnectionWatch(icewatch, NULL);
#endif
TRACE(("closed display\n"));
}
TRACE((0));
}
#endif
exit(n);
SIGNAL_RETURN;
}
static void
resize_termcap(XtermWidget xw, char *newtc)
{
#ifndef USE_SYSV_ENVVARS
if (!TEK4014_ACTIVE(xw) && *newtc) {
TScreen *screen = TScreenOf(xw);
char *ptr1, *ptr2;
size_t i;
int li_first = 0;
char *temp;
char oldtc[TERMCAP_SIZE];
strcpy(oldtc, newtc);
TRACE(("resize %s\n", oldtc));
if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
strcat(oldtc, "co#80:");
ptr1 = x_strindex(oldtc, "co#");
}
if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
strcat(oldtc, "li#24:");
ptr2 = x_strindex(oldtc, "li#");
}
if (ptr1 > ptr2) {
li_first++;
temp = ptr1;
ptr1 = ptr2;
ptr2 = temp;
}
ptr1 += 3;
ptr2 += 3;
strncpy(newtc, oldtc, i = ptr1 - oldtc);
temp = newtc + i;
sprintf(temp, "%d", (li_first
? MaxRows(screen)
: MaxCols(screen)));
temp += strlen(temp);
ptr1 = strchr(ptr1, ':');
strncpy(temp, ptr1, i = ptr2 - ptr1);
temp += i;
sprintf(temp, "%d", (li_first
? MaxCols(screen)
: MaxRows(screen)));
ptr2 = strchr(ptr2, ':');
strcat(temp, ptr2);
TRACE((" ==> %s\n", newtc));
TRACE((" new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
}
#endif
}
#endif
int
nonblocking_wait(void)
{
#ifdef USE_POSIX_WAIT
pid_t pid;
pid = waitpid(-1, NULL, WNOHANG);
#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
int pid = 0;
#else
#if defined(Lynx)
int status;
#else
union wait status;
#endif
int pid;
pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
#endif
return pid;
}
#ifndef VMS
static SIGNAL_T
reapchild(int n GCC_UNUSED)
{
int olderrno = errno;
int pid;
pid = wait(NULL);
#ifdef USE_SYSV_SIGNALS
(void) signal(SIGCHLD, reapchild);
#endif
do {
if (pid == term->screen.pid) {
#ifdef DEBUG
if (debug)
fputs("Exiting\n", stderr);
#endif
if (!hold_screen)
need_cleanup = True;
}
} while ((pid = nonblocking_wait()) > 0);
errno = olderrno;
SIGNAL_RETURN;
}
#endif
static void
remove_termcap_entry(char *buf, char *str)
{
char *base = buf;
char *first = base;
int count = 0;
size_t len = strlen(str);
TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
while (*buf != 0) {
if (!count && !strncmp(buf, str, len)) {
while (*buf != 0) {
if (*buf == '\\')
buf++;
else if (*buf == ':')
break;
if (*buf != 0)
buf++;
}
while ((*first++ = *buf++) != 0) ;
TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
return;
} else if (*buf == '\\') {
buf++;
} else if (*buf == ':') {
first = buf;
count = 0;
} else if (!isspace(CharOf(*buf))) {
count++;
}
if (*buf != 0)
buf++;
}
TRACE(("...cannot remove\n"));
}
static int
parse_tty_modes(char *s, struct _xttymodes *modelist)
{
struct _xttymodes *mp;
int c;
int count = 0;
TRACE(("parse_tty_modes\n"));
while (1) {
size_t len;
while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
s++;
if (!*s)
return count;
for (len = 0; isalnum(CharOf(s[len])); ++len) ;
for (mp = modelist; mp->name; mp++) {
if (len == mp->len
&& strncmp(s, mp->name, mp->len) == 0)
break;
}
if (!mp->name)
return -1;
s += mp->len;
while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
s++;
if (!*s)
return -1;
if ((c = decode_keyvalue(&s, False)) != -1) {
mp->value = c;
mp->set = 1;
count++;
TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
}
}
}
#ifndef VMS
int
GetBytesAvailable(int fd)
{
#if defined(FIONREAD)
int arg;
ioctl(fd, FIONREAD, (char *) &arg);
return (int) arg;
#elif defined(__CYGWIN__)
fd_set set;
struct timeval timeout =
{0, 0};
FD_ZERO(&set);
FD_SET(fd, &set);
if (Select(fd + 1, &set, NULL, NULL, &timeout) > 0)
return 1;
else
return 0;
#elif defined(FIORDCK)
return (ioctl(fd, FIORDCHK, NULL));
#else
struct pollfd pollfds[1];
pollfds[0].fd = fd;
pollfds[0].events = POLLIN;
return poll(pollfds, 1, 0);
#endif
}
#endif
int
kill_process_group(int pid, int sig)
{
TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
return kill(-pid, sig);
#else
return killpg(pid, sig);
#endif
}
#if OPT_EBCDIC
int
A2E(int x)
{
char c;
c = x;
__atoe_l(&c, 1);
return c;
}
int
E2A(int x)
{
char c;
c = x;
__etoa_l(&c, 1);
return c;
}
#endif
#if defined(__QNX__) && !defined(__QNXNTO__)
#include <sys/types.h>
#include <sys/proc_msg.h>
#include <sys/kernel.h>
#include <string.h>
#include <errno.h>
struct _proc_session ps;
struct _proc_session_reply rps;
int
qsetlogin(char *login, char *ttyname)
{
int v = getsid(getpid());
memset(&ps, 0, sizeof(ps));
memset(&rps, 0, sizeof(rps));
ps.type = _PROC_SESSION;
ps.subtype = _PROC_SUB_ACTION1;
ps.sid = v;
strcpy(ps.name, login);
Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
if (rps.status < 0)
return (rps.status);
ps.type = _PROC_SESSION;
ps.subtype = _PROC_SUB_ACTION2;
ps.sid = v;
sprintf(ps.name, "//%d%s", getnid(), ttyname);
Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
return (rps.status);
}
#endif