diff options
Diffstat (limited to 'vendor/x11iraf/xgterm/main.c')
-rw-r--r-- | vendor/x11iraf/xgterm/main.c | 5300 |
1 files changed, 5300 insertions, 0 deletions
diff --git a/vendor/x11iraf/xgterm/main.c b/vendor/x11iraf/xgterm/main.c new file mode 100644 index 00000000..01937cc7 --- /dev/null +++ b/vendor/x11iraf/xgterm/main.c @@ -0,0 +1,5300 @@ +#ifndef lint +static char *rid="$XConsortium: main.c,v 1.222 94/04/17 20:23:28 gildea Exp $"; +#endif /* lint */ + +/* + * W A R N I N G + * + * If you think you know what all of this code is doing, you are + * probably very mistaken. There be serious and nasty dragons here. + * + * This client is *not* to be taken as an example of how to write X + * Toolkit applications. It is in need of a substantial rewrite, + * ideally to create a generic tty widget with several different parsing + * widgets so that you can plug 'em together any way you want. Don't + * hold your breath, though.... + */ + +/*********************************************************** + + +Copyright (c) 1987, 1988 X Consortium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the X Consortium shall not be +used in advertising or otherwise to promote the sale, use or other dealings +in this Software without prior written authorization from the X Consortium. + + +Copyright 1987, 1988 by Digital Equipment Corporation, Maynard. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Digital not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. + +DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +******************************************************************/ + + +/* main.c */ + +#include "ptyx.h" +#include "data.h" +#include "error.h" +#include "menu.h" +#include <ObmW/Gterm.h> +#include <X11/StringDefs.h> +#include <X11/Shell.h> +#ifdef I18N +#include <X11/Xlocale.h> +#endif + +#define TERMCAP_SIZE 1500 + + +/* choose a nice default value for speed - if we make it too low, users who + * mistakenly use $TERM set to vt100 will get padding delays + */ +#define B38400 /* everyone should define this */ +#ifdef B38400 /* everyone should define this */ +#define VAL_LINE_SPEED B38400 +#else /* ...but xterm's used this for a long time */ +#define VAL_LINE_SPEED B9600 +#endif + + +#include <X11/Xos.h> +#include <X11/cursorfont.h> +#include <X11/Xaw/SimpleMenu.h> +#include <pwd.h> +#include <ctype.h> + +#ifdef USE_TTY_GROUP +#include <grp.h> +#endif + +#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30) +/* older SYSV systems cannot ignore SIGHUP. + Shell hangs, or you get extra shells, or something like that */ +#define USE_SYSV_SIGHUP +#endif + +#ifdef __DARWIN__ +#define NEW_GET_PTY +#define NEW_SPAWN +#define USE_HANDSHAKE +#define USE_USG_PTYS +#define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value +#define USE_STRUCT_WINSIZE 1 +#define TTYSIZE_STRUCT struct winsize + +#define TTYSIZE_STRUCT struct winsize +#define SET_TTYSIZE(fd, data) ioctl(fd, TIOCSWINSZ, (char *) &data) +#define TTYSIZE_COLS(data) data.ws_col +#define TTYSIZE_ROWS(data) data.ws_row +/* +*/ +#endif + +/* +#ifdef linux +*/ +#if defined(linux) +#define USE_ANY_SYSV_TERMIO +#define USE_SYSV_TERMIO +#define USE_SYSV_PGRP +#define USE_SYSV_UTMP +#define USE_SYSV_SIGNALS + +#define FEDORA +#define NEW_GET_PTY +#define NEW_SPAWN +#define USE_USG_PTYS +/* +#define USE_STRUCT_WINSIZE +*/ +#define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value + +#define USE_STRUCT_WINSIZE 1 +#define TTYSIZE_STRUCT struct winsize + +#define TTYSIZE_STRUCT struct winsize +#define SET_TTYSIZE(fd, data) ioctl(fd, TIOCSWINSZ, (char *) &data) +#define TTYSIZE_COLS(data) data.ws_col +#define TTYSIZE_ROWS(data) data.ws_row + +/* +#ifndef SYSV +#define SYSV +#endif +*/ +#endif /* linux */ + + +#ifdef att +#define ATT +#endif + +#ifdef linux +#define USE_SYSV_UTMP +#define USE_SYSV_PGRP +#define USE_TERMIOS +#define USE_HANDSHAKE +#define HAS_UTMP_UT_HOST +/* +#define HAS_BSD_GROUPS +*/ +#undef TIOCCONS +#define CONSLOG "/proc/kmsg" +#endif + +#ifdef SVR4 +#ifndef SYSV +#define SYSV /* SVR4 is (approx) superset of SVR3 */ +#endif +#define ATT +#define USE_SYSV_UTMP +#define USE_TERMIOS +#define HAS_UTMP_UT_HOST +#endif + +#if defined(sgi) && OSMAJORVERSION >= 5 +#ifndef SVR4 +#define SVR4 /* close enough for xterm */ +#endif +#define USE_SYSV_UTMP +#define USE_TERMIOS +#define HAS_UTMP_UT_HOST +#endif + +#ifdef SYSV386 +#define USE_SYSV_UTMP +#define ATT +#define USE_HANDSHAKE +static Bool IsPts = False; +#endif + +#ifdef ATT +#define USE_USG_PTYS +#else +#define USE_HANDSHAKE +#endif + +#if defined(SYSV) && !defined(SVR4) && !defined(AUX) && !defined(ISC22) && !defined(ISC30) +/* older SYSV systems cannot ignore SIGHUP. + Shell hangs, or you get extra shells, or something like that */ +#define USE_SYSV_SIGHUP +#endif + +/* Some local additions to get things to build. (DCT) */ +#ifdef AUX +#include <utmp.h> +struct utmp *getutid(); +extern char *ttyname(); +void *memmove(a,b,n) void *a; const void *b; size_t n; { bcopy(b,a,n); } +#endif +#if defined(sun) && OSMAJORVERSION < 5 +#undef memmove +void *memmove(a,b,n) void *a, *b; int n; { bcopy(b,a,n); } +#endif + +#if defined(sony) && defined(bsd43) && !defined(KANJI) +#define KANJI +#endif + +#include <sys/ioctl.h> +#include <sys/stat.h> + + +#ifdef USE_TERMIOS +#include <termios.h> +/* this hacked termios support only works on SYSV */ +#define USE_SYSV_TERMIO +#define termio termios +#undef TCGETA +#define TCGETA TCGETS +#undef TCSETA +#define TCSETA TCSETS +#else /* USE_TERMIOS */ +#ifdef SYSV +#include <sys/termio.h> +#ifdef SCO /* broken TIOCSWINSZ ioctl so disable it */ +#undef TIOCSWINSZ +#endif +#endif /* SYSV */ +#endif /* USE_TERMIOS else */ + +#if defined(SVR4) || defined(__linux__) +#undef TIOCSLTC /* defined, but not useable */ +#endif +#define USE_TERMCAP_ENVVARS /* every one uses this except SYSV maybe */ + +#if defined(sgi) && OSMAJORVERSION >= 5 +#undef TIOCLSET /* defined, but not useable */ +#endif + +#ifdef SYSV /* { */ +#ifdef USE_USG_PTYS /* AT&T SYSV has no ptyio.h */ +#include <sys/stream.h> /* get typedef used in ptem.h */ +#include <sys/stropts.h> /* for I_PUSH */ +#ifndef SVR4 +#include <sys/ptem.h> /* get struct winsize */ +#endif +#include <poll.h> /* for POLLIN */ +#endif /* USE_USG_PTYS */ +#ifdef FEDORA +#define USE_USG_PTYS +#endif +#define USE_SYSV_TERMIO +#define USE_SYSV_SIGNALS +#define USE_SYSV_PGRP + +#if !defined(TIOCSWINSZ) +#define USE_SYSV_ENVVARS /* COLUMNS/LINES vs. TERMCAP */ +#endif + +#ifndef SCO +#undef USE_TERMCAP_ENVVARS /* SCO wants both TERMCAP and TERMINFO env */ +#endif +/* + * now get system-specific includes + */ +#ifdef CRAY +#define USE_SYSV_UTMP +#define HAS_UTMP_UT_HOST +#define HAS_BSD_GROUPS +#endif +#ifdef _IBMR2 +#define HAS_UTMP_UT_HOST +#define HAS_BSD_GROUPS +#define USE_SYSV_UTMP +#endif +#ifdef macII +#define USE_SYSV_UTMP +#define HAS_UTMP_UT_HOST +#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 +#if defined(hpux) || defined (__hpux) +#define HAS_BSD_GROUPS +#define USE_SYSV_UTMP +#define HAS_UTMP_UT_HOST +#include <sys/ptyio.h> +#endif /* __hpux */ +#ifdef sgi +#include <sys/sysmacros.h> +#endif /* sgi */ +#ifdef sun +#include <sys/strredir.h> +#endif +#ifdef AIXV3 +#define USE_SYSV_UTMP +#define HAS_UTMP_UT_HOST +#endif +#else /* } !SYSV { */ /* BSD systems */ +#ifndef linux +#include <sgtty.h> +#include <sys/resource.h> +#define HAS_UTMP_UT_HOST +#define HAS_BSD_GROUPS +#ifdef __osf__ +#define USE_SYSV_UTMP +#define setpgrp setpgid +#endif +#endif /* !linux */ +#endif /* } !SYSV */ + +#ifdef _POSIX_SOURCE +#define USE_POSIXSYSV_WAIT +#endif +#ifdef SVR4 +#define USE_POSIX_WAIT +#endif + +#include <stdio.h> +#include <errno.h> +#include <setjmp.h> + +#ifdef X_NOT_STDC_ENV +extern int errno; +#define Time_t long +extern Time_t time (); +#else +#include <time.h> +#define Time_t time_t +#endif + +#if defined(hpux) || defined(__hpux) +#include <sys/utsname.h> +#endif /* __hpux */ + +#if defined(apollo) && OSMAJORVERSION == 10 && OSMINORVERSION < 4 +#define ttyslot() 1 +#endif /* apollo */ + +#ifdef SVR4 +#include <utmpx.h> +#define setutent setutxent +#define getutent getutxent +#define getutid getutxid +#define endutent endutxent +#define pututline pututxline +#else +#include <utmp.h> +#if defined(_CRAY) && OSMAJORVERSION < 8 +extern struct utmp *getutid __((struct utmp *_Id)); +#endif +#endif + +#ifdef LASTLOG +#include <lastlog.h> +#endif +#include <sys/param.h> /* for NOFILE */ + +#ifdef PUCC_PTYD +#include <local/openpty.h> +int Ptyfd; +#endif /* PUCC_PTYD */ + +#ifdef sequent +#define USE_GET_PSEUDOTTY +#endif + +#ifndef UTMP_FILENAME +#ifdef UTMP_FILE +#define UTMP_FILENAME UTMP_FILE +#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" /* only on BSD systems */ +#endif +#endif + +#ifndef WTMP_FILENAME +#ifdef WTMP_FILE +#define WTMP_FILENAME WTMP_FILE +#else +#if defined(_PATH_WTMP) /* R6 update */ +#define WTMP_FILENAME _PATH_WTMP +#else +#if defined(SYSV) +#define WTMP_FILENAME "/etc/wtmp" +#else +#define WTMP_FILENAME "/usr/adm/wtmp" +#endif +#endif +#endif +#endif + +#include <signal.h> + +#if defined(SCO) || defined(ISC) +#undef SIGTSTP /* defined, but not the BSD way */ +#endif + +#ifdef SIGTSTP +#include <sys/wait.h> +#if defined(hpux) || defined(__hpux) +#include <sys/bsdtty.h> +#endif +#endif + +#ifdef SIGNALRETURNSINT +#define SIGNAL_T int +#define SIGNAL_RETURN return 0 +#else +#define SIGNAL_T void +#define SIGNAL_RETURN return +#endif + +SIGNAL_T Exit(); + +#ifndef X_NOT_POSIX +#include <unistd.h> +#else +extern long lseek(); +#if defined(USG) || defined(SCO324) +extern unsigned sleep(); +#else +extern void sleep(); +#endif +#endif + +#ifndef X_NOT_STDC_ENV +#include <stdlib.h> +#else +extern char *malloc(); +extern char *calloc(); +extern char *realloc(); +extern char *getenv(); +extern void exit(); +#endif +#ifdef X_NOT_POSIX +extern char *ttyname(); +#endif + +#ifdef SYSV +extern char *ptsname(); +#endif + +extern char *strindex (); +extern void HandlePopupMenu(); +extern void gtermio_connect(); + +int switchfb[] = {0, 2, 1, 3}; + +static SIGNAL_T reapchild (); + +static Bool added_utmp_entry = False; + +static char **command_to_exec; + +#ifdef USE_SYSV_TERMIO +/* The following structures are initialized in main() in order +** to eliminate any assumptions about the internal order of their +** contents. +*/ +static struct termio d_tio; +#ifdef TIOCSLTC +static struct ltchars d_ltc; +#endif /* TIOCSLTC */ +#ifdef TIOCLSET +static unsigned int d_lmode; +#endif /* TIOCLSET */ +#else /* not USE_SYSV_TERMIO */ +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 /* sony */ +#endif /* USE_SYSV_TERMIO */ + +static int parse_tty_modes (); +/* + * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars; + * SVR4 has only termio.c_cc, but it includes everything from ltchars. + */ +#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 } + +static int override_tty_modes = 0; +struct _xttymodes { + char *name; + int len; + int set; + char value; +} ttymodelist[] = { +{ "intr", 4, 0, '\0' }, /* tchars.t_intrc ; VINTR */ +#define XTTYMODE_intr 0 +{ "quit", 4, 0, '\0' }, /* tchars.t_quitc ; VQUIT */ +#define XTTYMODE_quit 1 +{ "erase", 5, 0, '\0' }, /* sgttyb.sg_erase ; VERASE */ +#define XTTYMODE_erase 2 +{ "kill", 4, 0, '\0' }, /* sgttyb.sg_kill ; VKILL */ +#define XTTYMODE_kill 3 +{ "eof", 3, 0, '\0' }, /* tchars.t_eofc ; VEOF */ +#define XTTYMODE_eof 4 +{ "eol", 3, 0, '\0' }, /* VEOL */ +#define XTTYMODE_eol 5 +{ "swtch", 5, 0, '\0' }, /* VSWTCH */ +#define XTTYMODE_swtch 6 +{ "start", 5, 0, '\0' }, /* tchars.t_startc */ +#define XTTYMODE_start 7 +{ "stop", 4, 0, '\0' }, /* tchars.t_stopc */ +#define XTTYMODE_stop 8 +{ "brk", 3, 0, '\0' }, /* tchars.t_brkc */ +#define XTTYMODE_brk 9 +{ "susp", 4, 0, '\0' }, /* ltchars.t_suspc ; VSUSP */ +#define XTTYMODE_susp 10 +{ "dsusp", 5, 0, '\0' }, /* ltchars.t_dsuspc ; VDSUSP */ +#define XTTYMODE_dsusp 11 +{ "rprnt", 5, 0, '\0' }, /* ltchars.t_rprntc ; VREPRINT */ +#define XTTYMODE_rprnt 12 +{ "flush", 5, 0, '\0' }, /* ltchars.t_flushc ; VDISCARD */ +#define XTTYMODE_flush 13 +{ "weras", 5, 0, '\0' }, /* ltchars.t_werasc ; VWERASE */ +#define XTTYMODE_weras 14 +{ "lnext", 5, 0, '\0' }, /* ltchars.t_lnextc ; VLNEXT */ +#define XTTYMODE_lnext 15 + TTYMODE("status"), /* VSTATUS */ +#define XTTYMODE_status 16 + TTYMODE("erase2"), /* VERASE2 */ +#define XTTYMODE_erase2 17 + TTYMODE("eol2"), /* VEOL2 */ +#define XTTYMODE_eol2 18 +{ NULL, 0, 0, '\0' }, /* end of data */ +}; + +#ifdef USE_SYSV_UTMP +#if defined(X_NOT_STDC_ENV) || defined(AIXV3) +extern struct utmp *getutent(); +extern struct utmp *getutid(); +extern struct utmp *getutline(); +extern void setutent(); +extern void endutent(); +#ifdef AIXV3 +extern struct utmp* pututline(); +extern int utmpname(); +#else +extern void pututline(); +extern void utmpname(); +#endif +#endif /* !SVR4 */ + +/*#ifndef SYSV386 /* could remove paragraph unconditionally? */ +#ifdef X_NOT_STDC_ENV /* could remove paragraph unconditionally? */ +extern struct passwd *getpwent(); +extern struct passwd *getpwuid(); +extern struct passwd *getpwnam(); +extern void setpwent(); +extern void endpwent(); +#endif + +extern struct passwd *fgetpwent(); +#else /* not USE_SYSV_UTMP */ +static char etc_utmp[] = UTMP_FILENAME; +#ifdef LASTLOG +static char etc_lastlog[] = LASTLOG_FILENAME; +#endif +#endif /* USE_SYSV_UTMP */ + +#ifdef WTMP +static char etc_wtmp[] = WTMP_FILENAME; +#endif + +/* + * Some people with 4.3bsd /bin/login seem to like to use login -p -f user + * to implement xgterm -ls. They can turn on USE_LOGIN_DASH_P and turn off + * WTMP and LASTLOG. + */ +#ifdef USE_LOGIN_DASH_P +#ifndef LOGIN_FILENAME +#define LOGIN_FILENAME "/bin/login" +#endif +static char bin_login[] = LOGIN_FILENAME; +#endif + +static int inhibit; +static char passedPty[2]; /* name if pty if slave */ + +#if defined(TIOCCONS) || defined(SRIOCSREDIR) +static int Console; +#include <X11/Xmu/SysUtil.h> /* XmuGetHostname */ +#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 /* TIOCCONS */ + +#ifndef USE_SYSV_UTMP +static int tslot; +#endif /* USE_SYSV_UTMP */ +static jmp_buf env; + +char *ProgramName; +Boolean sunFunctionKeys; + +static struct _resource { + char *xgterm_name; + char *icon_geometry; + char *title; + char *icon_name; + char *term_name; + char *tty_modes; + Boolean utmpInhibit; + Boolean sunFunctionKeys; /* %%% should be widget resource? */ + Boolean wait_for_map; + Boolean useInsertMode; +} resource; + +/* used by VT (charproc.c) */ + +#define offset(field) XtOffsetOf(struct _resource, field) + +static XtResource application_resources[] = { + {"name", "Name", XtRString, sizeof(char *), + offset(xgterm_name), XtRString, "xgterm"}, + {"iconGeometry", "IconGeometry", XtRString, sizeof(char *), + offset(icon_geometry), XtRString, (caddr_t) NULL}, + {XtNtitle, XtCTitle, XtRString, sizeof(char *), + offset(title), XtRString, (caddr_t) NULL}, + {XtNiconName, XtCIconName, XtRString, sizeof(char *), + offset(icon_name), XtRString, (caddr_t) NULL}, + {"termName", "TermName", XtRString, sizeof(char *), + offset(term_name), XtRString, (caddr_t) NULL}, + {"ttyModes", "TtyModes", XtRString, sizeof(char *), + offset(tty_modes), XtRString, (caddr_t) NULL}, + {"utmpInhibit", "UtmpInhibit", XtRBoolean, sizeof (Boolean), + offset(utmpInhibit), XtRString, "false"}, + {"sunFunctionKeys", "SunFunctionKeys", XtRBoolean, sizeof (Boolean), + offset(sunFunctionKeys), XtRString, "false"}, + {"waitForMap", "WaitForMap", XtRBoolean, sizeof (Boolean), + offset(wait_for_map), XtRString, "false"}, + {"useInsertMode", "UseInsertMode", XtRBoolean, sizeof (Boolean), + offset(useInsertMode), XtRString, "false"}, +}; +#undef offset + +static char *fallback_resources[] = { + "XGterm*SimpleMenu*menuLabel.vertSpace: 100", + "XGterm*SimpleMenu*HorizontalMargins: 16", + "XGterm*SimpleMenu*Sme.height: 16", + "XGterm*SimpleMenu*Cursor: left_ptr", + "XGterm*mainMenu.Label: Main Options (no app-defaults)", + "XGterm*vtMenu.Label: VT Options (no app-defaults)", + "XGterm*fontMenu.Label: VT Fonts (no app-defaults)", + NULL +}; + +/* Command line options table. Only resources are entered here...there is a + pass over the remaining options after XrmParseCommand is let loose. */ + +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"}, +{"-b", "*internalBorder", XrmoptionSepArg, (caddr_t) NULL}, +{"-cb", "*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "off"}, +{"+cb", "*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "on"}, +{"-cc", "*charClass", XrmoptionSepArg, (caddr_t) NULL}, +{"-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) "on"}, +{"+dc", "*dynamicColors", XrmoptionNoArg, (caddr_t) "off"}, +{"-e", NULL, XrmoptionSkipLine, (caddr_t) NULL}, +{"-fb", "*boldFont", XrmoptionSepArg, (caddr_t) NULL}, +{"-im", "*useInsertMode", XrmoptionNoArg, (caddr_t) "on"}, +{"+im", "*useInsertMode", XrmoptionNoArg, (caddr_t) "off"}, +{"-j", "*jumpScroll", XrmoptionNoArg, (caddr_t) "on"}, +{"+j", "*jumpScroll", XrmoptionNoArg, (caddr_t) "off"}, +/* parse logging options anyway for compatibility */ +{"-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}, +{"-ms", "*pointerColor", XrmoptionSepArg, (caddr_t) NULL}, +{"-nb", "*nMarginBell", XrmoptionSepArg, (caddr_t) NULL}, +{"-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"}, +{"-sbr", "*scrollBarRight", XrmoptionNoArg, (caddr_t) "on"}, +{"+sbr", "*scrollBarRight", XrmoptionNoArg, (caddr_t) "off"}, +{"-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}, +{"-t", "*tekStartup", XrmoptionNoArg, (caddr_t) "on"}, +{"+t", "*tekStartup", XrmoptionNoArg, (caddr_t) "off"}, +{"-tm", "*ttyModes", XrmoptionSepArg, (caddr_t) NULL}, +{"-tn", "*termName", XrmoptionSepArg, (caddr_t) NULL}, +{"-ut", "*utmpInhibit", XrmoptionNoArg, (caddr_t) "on"}, +{"+ut", "*utmpInhibit", XrmoptionNoArg, (caddr_t) "off"}, +{"-vb", "*visualBell", XrmoptionNoArg, (caddr_t) "on"}, +{"+vb", "*visualBell", XrmoptionNoArg, (caddr_t) "off"}, +{"-wf", "*waitForMap", XrmoptionNoArg, (caddr_t) "on"}, +{"+wf", "*waitForMap", XrmoptionNoArg, (caddr_t) "off"}, +/* bogus old compatibility stuff for which there are + standard XtAppInitialize options now */ +{"-G", "*tekGeometry", XrmoptionSepArg, (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 struct _options { + char *opt; + char *desc; +} options[] = { +{ "-help", "print out this message" }, +{ "-display displayname", "X server to contact" }, +{ "-geometry geom", "size (in characters) and position" }, +{ "-G geom", "geometry of toplevel graphics window" }, +{ "-/+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" }, +{ "-iconic", "start iconic" }, +{ "-name string", "client instance, icon, and title strings" }, +{ "-title string", "title string" }, +{ "-xrm resourcestring", "additional resource specifications" }, +{ "-/+132", "turn on/off column switch inhibiting" }, +{ "-/+ah", "turn on/off always highlight" }, +{ "-b number", "internal border in pixels" }, +{ "-/+cb", "turn on/off cut-to-beginning-of-line inhibit" }, +{ "-cc classrange", "specify additional character classes" }, +{ "-/+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" }, +{ "-/+sbr", "turn off/on rightside scrollbar option" }, +{ "-fb fontname", "bold text font" }, +{ "-/+im", "use insert mode for TERMCAP" }, +{ "-/+j", "turn on/off jump scroll" }, +#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" }, +{ "-ms color", "pointer color" }, +{ "-nb number", "margin bell in characters from right end" }, +{ "-/+aw", "turn on/off auto wraparound" }, +{ "-/+rw", "turn on/off reverse wraparound" }, +{ "-/+s", "turn on/off multiscroll" }, +{ "-/+sb", "turn on/off scrollbar" }, +{ "-/+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" }, +{ "-tm string", "terminal mode keywords and characters" }, +{ "-tn name", "TERM environment variable name" }, +#ifdef UTMP +{ "-/+ut", "turn on/off utmp inhibit" }, +#else +{ "-/+ut", "turn on/off utmp inhibit (not supported)" }, +#endif +{ "-/+vb", "turn on/off visual bell" }, +{ "-/+wf", "turn on/off wait for map before command exec" }, +{ "-e command args ...", "command to execute" }, +{ "%geom", "Tek window geometry" }, +{ "#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 +{ "-Sxxd", "slave mode on \"ttyxx\", file descriptor \"d\"" }, +{ NULL, NULL }}; + +static char *message[] = { +"Fonts must be fixed width and, if both normal and bold are specified, must", +"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 be 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}; + + +/* The X11IRAF version. */ +char *xgterm_version[] = { +# include "../version.h" + NULL +}; + + +/* + * If we're linked to terminfo, tgetent() will return an empty buffer. We + * cannot use that to adjust the $TERMCAP variable. + */ +static Boolean +get_termcap(char *name, char *buffer, char *resized) +{ + register TScreen *screen = &term->screen; + + *buffer = 0; /* initialize, in case we're using terminfo's tgetent */ + + if (name != 0) { + if (tgetent(buffer, name) == 1) { + if (*buffer) { + if (!screen->TekEmu) { + resize(screen, buffer, resized); + } + } + return True; + } else { + *buffer = 0; /* just in case */ + } + } + return False; +} + + +static void Syntax (badOption) + char *badOption; +{ + struct _options *opt; + 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 = options; opt->opt; opt++) { + int len = 3 + strlen(opt->opt); /* space [ string ] */ + if (col + len > 79) { + fprintf (stderr, "\r\n "); /* 3 spaces */ + 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 Help () +{ + struct _options *opt; + char **cpp; + + fprintf (stderr, "usage:\n %s [-options ...] [-e command args]\n\n", + ProgramName); + fprintf (stderr, "where options include:\n"); + for (opt = options; opt->opt; opt++) { + fprintf (stderr, " %-28s %s\n", opt->opt, opt->desc); + } + + putc ('\n', stderr); + for (cpp = message; *cpp; cpp++) { + fputs (*cpp, stderr); + putc ('\n', stderr); + } + putc ('\n', stderr); + + exit (0); +} + +#if defined(TIOCCONS) || defined(SRIOCSREDIR) +/* ARGSUSED */ +static Boolean +ConvertConsoleSelection(w, selection, target, type, value, length, format) + Widget w; + Atom *selection, *target, *type; + XtPointer *value; + unsigned long *length; + int *format; +{ + /* we don't save console output, so can't offer it */ + return False; +} +#endif /* TIOCCONS */ + + +extern WidgetClass xgtermWidgetClass; + +Arg ourTopLevelShellArgs[] = { + { XtNallowShellResize, (XtArgVal) TRUE }, + { XtNinput, (XtArgVal) TRUE }, +}; +int number_ourTopLevelShellArgs = 2; + +XtAppContext app_con; +Widget toplevel; +Bool waiting_for_initial_map; + +extern void do_hangup(); +extern void xt_error(); + +/* + * DeleteWindow(): Action proc to implement ICCCM delete_window. + */ +/* ARGSUSED */ +void +DeleteWindow(w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + if (w == toplevel) + if (term->screen.Tshow) + hide_vt_window(); + else + do_hangup(w); + else + if (term->screen.Vshow) + hide_tek_window(); + else + do_hangup(w); +} + +/* ARGSUSED */ +void +KeyboardMapping(w, event, params, num_params) + Widget w; + XEvent *event; + String *params; + Cardinal *num_params; +{ + switch (event->type) { + case MappingNotify: + XRefreshKeyboardMapping(&event->xmapping); + break; + } +} + +XtActionsRec actionProcs[] = { + "DeleteWindow", DeleteWindow, + "KeyboardMapping", KeyboardMapping, +}; + +Atom wm_delete_window; + + +main (argc, argv) +int argc; +char **argv; +{ + register TScreen *screen; + register int pty; + int Xsocket, mode; + char *base_name(); + int xerror(), xioerror(); + +#ifdef I18N + setlocale(LC_ALL, NULL); +#endif + + ProgramName = argv[0]; + + ttydev = (char *) malloc (strlen (TTYDEV) + 1); + ptydev = (char *) malloc (strlen (PTYDEV) + 1); + if (!ttydev || !ptydev) { + fprintf (stderr, + "%s: unable to allocate memory for ttydev or ptydev\n", + ProgramName); + exit (1); + } + strcpy (ttydev, TTYDEV); + strcpy (ptydev, PTYDEV); + +#ifdef USE_SYSV_TERMIO + /* Initialization is done here rather than above in order + ** to prevent any assumptions about the order of the contents + ** of the various terminal structures (which may change from + ** implementation to implementation). + */ +#if defined(macII) || defined(ATT) || defined(CRAY) + d_tio.c_iflag = ICRNL|IXON; + d_tio.c_oflag = OPOST|ONLCR|TAB3; + d_tio.c_cflag = B9600|CS8|CREAD|PARENB|HUPCL; + d_tio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; + +#ifndef USE_TERMIOS + d_tio.c_line = 0; +#endif + + d_tio.c_cc[VINTR] = CINTR; + d_tio.c_cc[VQUIT] = CQUIT; + d_tio.c_cc[VERASE] = CERASE; + d_tio.c_cc[VKILL] = CKILL; + d_tio.c_cc[VEOF] = CEOF; + d_tio.c_cc[VEOL] = CNUL; + d_tio.c_cc[VEOL2] = CNUL; + d_tio.c_cc[VSWTCH] = CNUL; + +#ifdef USE_TERMIOS + d_tio.c_cc[VSUSP] = CSUSP; +#ifdef VDSUSP /* R6 update */ + d_tio.c_cc[VDSUSP] = CDSUSP; +#endif + d_tio.c_cc[VREPRINT] = CNUL; + d_tio.c_cc[VDISCARD] = CNUL; + d_tio.c_cc[VWERASE] = CNUL; + d_tio.c_cc[VLNEXT] = CNUL; +#endif +#ifdef TIOCSLTC + d_ltc.t_suspc = CSUSP; /* t_suspc */ + d_ltc.t_dsuspc = CDSUSP; /* t_dsuspc */ + d_ltc.t_rprntc = 0; /* reserved...*/ + d_ltc.t_flushc = 0; + d_ltc.t_werasc = 0; + d_ltc.t_lnextc = 0; +#endif /* TIOCSLTC */ +#ifdef TIOCLSET + d_lmode = 0; +#endif /* TIOCLSET */ +#else /* else !macII */ + d_tio.c_iflag = ICRNL|IXON; + d_tio.c_oflag = OPOST|ONLCR|TAB3; +#ifdef BAUD_0 + d_tio.c_cflag = CS8|CREAD|PARENB|HUPCL; +#else /* !BAUD_0 */ + d_tio.c_cflag = B9600|CS8|CREAD|PARENB|HUPCL; +#endif /* !BAUD_0 */ + d_tio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; +#ifndef sgi + d_tio.c_line = 0; +#endif +#ifdef linux + d_tio.c_cc[VINTR] = 'C' & 0x3f; + d_tio.c_cc[VQUIT] = '\\' & 0x3f; + d_tio.c_cc[VERASE] = 0x7f; + d_tio.c_cc[VKILL] = 'U' & 0x3f; + d_tio.c_cc[VEOF] = 'D' & 0x3f; + d_tio.c_cc[VEOL] = '@' & 0x3f; +#else + d_tio.c_cc[VINTR] = 0x7f; /* DEL */ + d_tio.c_cc[VQUIT] = '\\' & 0x3f; /* '^\' */ + d_tio.c_cc[VERASE] = '#'; /* '#' */ + d_tio.c_cc[VKILL] = '@'; /* '@' */ + d_tio.c_cc[VEOF] = 'D' & 0x3f; /* '^D' */ + d_tio.c_cc[VEOL] = '@' & 0x3f; /* '^@' */ +#endif +#ifdef VSWTCH + d_tio.c_cc[VSWTCH] = '@' & 0x3f; /* '^@' */ +#endif /* VSWTCH */ + /* now, try to inherit tty settings */ + { + int i; + + for (i = 0; i <= 2; i++) { + struct termio deftio; + if (ioctl (i, TCGETA, &deftio) == 0) { + d_tio.c_cc[VINTR] = deftio.c_cc[VINTR]; + d_tio.c_cc[VQUIT] = deftio.c_cc[VQUIT]; + d_tio.c_cc[VERASE] = deftio.c_cc[VERASE]; + d_tio.c_cc[VKILL] = deftio.c_cc[VKILL]; + d_tio.c_cc[VEOF] = deftio.c_cc[VEOF]; + d_tio.c_cc[VEOL] = deftio.c_cc[VEOL]; +#ifdef VSWTCH + d_tio.c_cc[VSWTCH] = deftio.c_cc[VSWTCH]; +#endif /* VSWTCH */ + break; + } + } + } +#ifdef TIOCSLTC + d_ltc.t_suspc = '\000'; /* t_suspc */ + d_ltc.t_dsuspc = '\000'; /* t_dsuspc */ + d_ltc.t_rprntc = '\377'; /* reserved...*/ + d_ltc.t_flushc = '\377'; + d_ltc.t_werasc = '\377'; + d_ltc.t_lnextc = '\377'; +#endif /* TIOCSLTC */ +#ifdef USE_TERMIOS +#ifdef linux + d_tio.c_cc[VSUSP] = 'Z' & 0x3f; +#else + d_tio.c_cc[VSUSP] = '\000'; +#endif +#ifdef VDSUSP + d_tio.c_cc[VDSUSP] = '\000'; +#endif + d_tio.c_cc[VREPRINT] = '\377'; + d_tio.c_cc[VDISCARD] = '\377'; + d_tio.c_cc[VWERASE] = '\377'; + d_tio.c_cc[VLNEXT] = '\377'; +#endif +#ifdef TIOCLSET + d_lmode = 0; +#endif /* TIOCLSET */ +#endif /* macII */ +#endif /* USE_SYSV_TERMIO */ + + /* Init the Toolkit. */ + { +#ifdef HAS_POSIX_SAVED_IDS + uid_t euid = geteuid(); + gid_t egid = getegid(); + uid_t ruid = getuid(); + gid_t rgid = getgid(); + + if (setegid(ruid) == -1) + (void) fprintf(stderr, "setegid(%d): %s\n", + rgid, strerror(errno)); + + if (seteuid(ruid) == -1) + (void) fprintf(stderr, "seteuid(%d): %s\n", + ruid, strerror(errno)); +#endif + + XtSetErrorHandler(xt_error); + toplevel = XtAppInitialize (&app_con, "XGterm", + optionDescList, XtNumber(optionDescList), + &argc, argv, fallback_resources, NULL, 0); + + XtGetApplicationResources(toplevel, (XtPointer) &resource, + application_resources, + XtNumber(application_resources), NULL, 0); + +#ifdef HAS_POSIX_SAVED_IDS + if (seteuid(euid) == -1) + (void) fprintf(stderr, "seteuid(%d): %s\n", + euid, strerror(errno)); + + if (setegid(egid) == -1) + (void) fprintf(stderr, "setegid(%d): %s\n", + egid, strerror(errno)); +#endif + } + + + waiting_for_initial_map = resource.wait_for_map; + + /* + * ICCCM delete_window. + */ + XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs)); + + /* + * fill in terminal modes + */ + 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 = 1; + } + } + + xgterm_name = resource.xgterm_name; + sunFunctionKeys = resource.sunFunctionKeys; + if (strcmp(xgterm_name, "-") == 0) xgterm_name = "xgterm"; + if (resource.icon_geometry != NULL) { + int scr, junk; + int ix, iy; + Arg args[2]; + + for(scr = 0; /* yyuucchh */ + 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); + + + /* Parse the rest of the command line */ + for (argc--, argv++ ; argc > 0 ; argc--, argv++) { + if(**argv != '-') Syntax (*argv); + + switch(argv[0][1]) { + case 'h': + Help (); + /* NOTREACHED */ + case 'C': +#if defined(TIOCCONS) || defined(SRIOCSREDIR) + { + struct stat sbuf; + + /* Must be owner and have read/write permission. + xdm cooperates to give the console the right user. */ + if ( !stat("/dev/console", &sbuf) && + (sbuf.st_uid == getuid()) && + !access("/dev/console", R_OK|W_OK)) + { + Console = TRUE; + } else + Console = FALSE; + } +#endif /* TIOCCONS */ + continue; + case 'S': + if (sscanf(*argv + 2, "%c%c%d", passedPty, passedPty+1, + &am_slave) != 3) + Syntax(*argv); + continue; +#ifdef DEBUG + case 'D': + debug = TRUE; + continue; +#endif /* DEBUG */ + case 'e': + if (argc <= 1) Syntax (*argv); + command_to_exec = ++argv; + argc = 0; + break; + case 'v': + if (strcmp (*argv, "-version") == 0) { + printf ("Version: %s\n", xgterm_version[0]); + exit (1); + } + break; + default: + Syntax (*argv); + } + break; + } + + XawSimpleMenuAddGlobalActions (app_con); + XtRegisterGrabAction (HandlePopupMenu, True, + (ButtonPressMask|ButtonReleaseMask), + GrabModeAsync, GrabModeAsync); + + /* Create the vt100 terminal emulator widget. */ + term = (XgtermWidget) XtCreateManagedWidget ("vt100", + xgtermWidgetClass, toplevel, NULL, 0); + screen = &term->screen; + + if (screen->savelines < 0) screen->savelines = 0; + + term->flags = 0; + if (!screen->jumpscroll) { + term->flags |= SMOOTHSCROLL; + update_jumpscroll(); + } + if (term->misc.reverseWrap) { + term->flags |= REVERSEWRAP; + update_reversewrap(); + } + if (term->misc.autoWrap) { + term->flags |= WRAPAROUND; + update_autowrap(); + } + if (term->misc.re_verse) { + term->flags |= REVERSE_VIDEO; + update_reversevideo(); + } + + inhibit = 0; +#ifdef ALLOWLOGGING + if (term->misc.logInhibit) inhibit |= I_LOG; +#endif + if (term->misc.signalInhibit) inhibit |= I_SIGNAL; + if (term->misc.tekInhibit) inhibit |= I_TEK; + + term->initflags = term->flags; + + if (term->misc.appcursorDefault) { + term->keyboard.flags |= CURSOR_APL; + update_appcursor(); + } + + if (term->misc.appkeypadDefault) { + term->keyboard.flags |= KYPD_APL; + update_appkeypad(); + } + +/* + * Set title and icon name if not specified + */ + + if (command_to_exec) { + Arg args[2]; + + if (!resource.title) { + if (command_to_exec) { + resource.title = base_name (command_to_exec[0]); + } /* else not reached */ + } + + if (!resource.icon_name) + resource.icon_name = resource.title; + XtSetArg (args[0], XtNtitle, resource.title); + XtSetArg (args[1], XtNiconName, resource.icon_name); + + XtSetValues (toplevel, args, 2); + } + +#ifdef DEBUG + { + /* Set up stderr properly. Opening this log file cannot be + done securely by a privileged xgterm process (although we try), + so the debug feature is disabled by default. */ + int i = -1; + if(debug) { + creat_as (getuid(), getgid(), "xgterm.debug.log", 0666); + i = open ("xgterm.debug.log", O_WRONLY | O_TRUNC, 0666); + } + if(i >= 0) { +#if defined(USE_SYSV_TERMIO) && !defined(SVR4) && !defined(linux) + /* SYSV has another pointer which should be part of the + ** FILE structure but is actually a seperate array. + */ + unsigned char *old_bufend; + + old_bufend = (unsigned char *) _bufend(stderr); +#if defined(hpux) || defined(__hpux) + stderr->__fileH = (i >> 8); + stderr->__fileL = i; +#else + stderr->_file = i; +#endif + _bufend(stderr) = old_bufend; +#else /* USE_SYSV_TERMIO */ +#ifdef linux + setfileno(stderr, i); +#else + stderr->_file = i; +#endif +#endif /* USE_SYSV_TERMIO */ + + /* mark this file as close on exec */ + (void) fcntl(i, F_SETFD, 1); + } + } +#endif /* DEBUG */ + + /* open a terminal for client */ + get_terminal (); + spawn (); + + + /* Child process is out there, let's catch its termination */ +#ifdef USE_POSIX_SIGNALS + (void) posix_signal(SIGCHLD, reapchild); +#else + (void) signal(SIGCHLD, reapchild); +#endif + + + /* Realize procs have now been executed */ + + Xsocket = ConnectionNumber(screen->display); + pty = screen->respond; + init_ttyio (pty); + + /* Connect gtermio to the pty. */ + if (!term->misc.tekInhibit) { + gio_setup (app_con, argc, argv, pty); + gio_postconnectcallback (gtermio_connect, NULL); + } + + /* Start up graphics window? */ + if (inhibit & I_TEK) + screen->TekEmu = FALSE; + if (screen->TekEmu) + hide_vt_window(); + + /* Write window id so master end can read and use */ + if (am_slave >= 0) { + char buf[80]; + + buf[0] = '\0'; + sprintf (buf, "%lx\n", XtWindow (XtParent (term))); + write (pty, buf, strlen (buf)); + } + +#ifdef ALLOWLOGGING + if (term->misc.log_on) { + StartLog(screen); + } +#endif + screen->inhibit = inhibit; + +#ifdef AIXV3 + /* In AIXV3, xterms started from /dev/console have CLOCAL set. + * This means we need to clear CLOCAL so that SIGHUP gets sent + * to the slave-pty process when xterm exits. + */ + + { + struct termio tio; + + if(ioctl(pty, TCGETA, &tio) == -1) + SysError(ERROR_TIOCGETP); + + tio.c_cflag &= ~(CLOCAL); + + if (ioctl (pty, TCSETA, &tio) == -1) + SysError(ERROR_TIOCSETP); + } +#endif +#ifdef USE_SYSV_TERMIO + if (0 > (mode = fcntl(pty, F_GETFL, 0))) + Error(); +#ifdef O_NDELAY + mode |= O_NDELAY; +#else + mode |= O_NONBLOCK; +#endif /* O_NDELAY */ + if (fcntl(pty, F_SETFL, mode)) + Error(); +#else /* USE_SYSV_TERMIO */ + mode = 1; + if (ioctl (pty, FIONBIO, (char *)&mode) == -1) SysError (ERROR_FIONBIO); +#endif /* USE_SYSV_TERMIO */ + + pty_mask = 1 << pty; + X_mask = 1 << Xsocket; + Select_mask = pty_mask | X_mask; + max_plus1 = (pty < Xsocket) ? (1 + Xsocket) : (1 + pty); + +#ifdef DEBUG + if (debug) printf ("debugging on\n"); +#endif /* DEBUG */ + XSetErrorHandler(xerror); + XSetIOErrorHandler(xioerror); + for( ; ; ) + VTRun(); +} + +char *base_name(name) +char *name; +{ + register char *cp; + + cp = strrchr(name, '/'); + return(cp ? cp + 1 : name); +} + + + + +#ifdef NEW_GET_PTY + + +#ifdef __DARWIN__ +#define USE_OPENPTY 1 +static int opened_tty = -1; +#endif + +/* + * This function opens up a pty master and stuffs its value into pty. + * + * If it finds one, it returns a value of 0. If it does not find one, + * it returns a value of !0. This routine is designed to be re-entrant, + * so that if a pty master is found and later, we find that the slave + * has problems, we can re-enter this function and get another one. + */ +static int +get_pty(int *pty, char *from) +{ + int result = 1; + + +#if defined(USE_OPENPTY) + result = openpty(pty, &opened_tty, ttydev, NULL, NULL); + +#elif defined(__OpenBSD__) + static int m_tty = -1; + static int m_pty = -1; + struct group *ttygrp; + + + if (pty == NULL) { + result = openpty(&m_pty, &m_tty, ttydev, NULL, NULL); + + seteuid(0); + if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) { + set_owner(ttydev, getuid(), ttygrp->gr_gid, 0600); + } else { + set_owner(ttydev, getuid(), getgid(), 0600); + } + seteuid(getuid()); + } else if (m_pty != -1) { + *pty = m_pty; + result = 0; + } else { + result = -1; + } +#elif defined(PUCC_PTYD) + + result = ((*pty = openrpty(ttydev, ptydev, + (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), + getuid(), from)) < 0); + +/* +#elif defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__NetBSD__) + + int tty; + result = openpty(pty, &tty, ttydev, NULL, NULL); +*/ +#elif defined(__QNXNTO__) + + result = pty_search(pty); + +#else +#if defined(USE_ISPTS_FLAG) + + /* + The order of this code is *important*. On SYSV/386 we want to open + a /dev/ttyp? first if at all possible. If none are available, then + we'll try to open a /dev/pts??? device. + + The reason for this is because /dev/ttyp? works correctly, where + as /dev/pts??? devices have a number of bugs, (won't update + screen correcly, will hang -- it more or less works, but you + really don't want to use it). + + Most importantly, for boxes of this nature, one of the major + "features" is that you can emulate a 8086 by spawning off a UNIX + program on 80386/80486 in v86 mode. In other words, you can spawn + off multiple MS-DOS environments. On ISC the program that does + this is named "vpix." The catcher is that "vpix" will *not* work + with a /dev/pts??? device, will only work with a /dev/ttyp? device. + + Since we can open either a /dev/ttyp? or a /dev/pts??? device, + the flag "IsPts" is set here so that we know which type of + device we're dealing with in routine spawn(). That's the reason + for the "if (IsPts)" statement in spawn(); we have two different + device types which need to be handled differently. + */ + result = pty_search(pty); + if (!result) + IsPts = 0; + +#endif +#if defined(USE_USG_PTYS) || defined(__CYGWIN__) || defined(FEDORA) +#ifdef __GLIBC__ /* if __GLIBC__ and USE_USG_PTYS, we know glibc >= 2.1 */ + /* GNU libc 2 allows us to abstract away from having to know the + master pty device name. */ + if ((*pty = getpt()) >= 0) { + char *name = ptsname(*pty); + if (name != 0) { /* if filesystem is trashed, this may be null */ + 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; /* true if we're successful */ + } +#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) + + /* + * Use the clone device if it works, otherwise use pty_search logic. + */ + if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) { + char *name = ptsname(*pty); + if (name != 0) { + strcpy(ttydev, name); + result = 0; + } else { /* permissions, or other unexpected problem */ + close(*pty); + *pty = -1; + result = pty_search(pty); + } + } else { + result = pty_search(pty); + } + +#else + + result = pty_search(pty); + +#endif +#endif + + return result; +} +#else + + + +/* This function opens up a pty master and stuffs its value into pty. + * If it finds one, it returns a value of 0. If it does not find one, + * it returns a value of !0. This routine is designed to be re-entrant, + * so that if a pty master is found and later, we find that the slave + * has problems, we can re-enter this function and get another one. + */ + +get_pty (pty) + int *pty; +{ +#if defined(SYSV) && defined(SYSV386) + /* + The order of this code is *important*. On SYSV/386 we want to open + a /dev/ttyp? first if at all possible. If none are available, then + we'll try to open a /dev/pts??? device. + + The reason for this is because /dev/ttyp? works correctly, where + as /dev/pts??? devices have a number of bugs, (won't update + screen correcly, will hang -- it more or less works, but you + really don't want to use it). + + Most importantly, for boxes of this nature, one of the major + "features" is that you can emulate a 8086 by spawning off a UNIX + program on 80386/80486 in v86 mode. In other words, you can spawn + off multiple MS-DOS environments. On ISC the program that does + this is named "vpix." The catcher is that "vpix" will *not* work + with a /dev/pts??? device, will only work with a /dev/ttyp? device. + + Since we can open either a /dev/ttyp? or a /dev/pts??? device, + the flag "IsPts" is set here so that we know which type of + device we're dealing with in routine spawn(). That's the reason + for the "if (IsPts)" statement in spawn(); we have two different + device types which need to be handled differently. + */ + if (pty_search(pty) == 0) + return 0; +#endif /* SYSV && SYSV386 */ + +/* Need to move this block of code up a bit on IRIX 6.5 systems to avoid + * a segvio when running out of ptys. + */ +#if defined(sgi) && OSMAJORVERSION >= 6 && OSMINORVERSION >= 5 + { + char *tty_name; + + tty_name = _getpty (pty, O_RDWR, 0622, 0); + if (tty_name == 0) + return 1; + strcpy (ttydev, tty_name); + return 0; + } +#endif +#ifdef ATT + if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0) { + return 1; + } +#if defined(SVR4) || defined(SYSV386) + strcpy(ttydev, ptsname(*pty)); +#if defined (SYSV) && defined(SYSV386) + IsPts = True; +#endif +#endif + return 0; +#else /* ATT else */ +#ifdef AIXV3 + if ((*pty = open ("/dev/ptc", O_RDWR)) < 0) { + return 1; + } + strcpy(ttydev, ttyname(*pty)); + return 0; +#endif + +/* Original code for systems below IRIX 6.5 */ +#if defined(sgi) && OSMAJORVERSION >= 4 && (OSMAJORVERSION <= 6 && OSMINORVERSION < 5) + { + char *tty_name; + + tty_name = _getpty (pty, O_RDWR, 0622, 0); + if (tty_name == 0) + return 1; + strcpy (ttydev, tty_name); + return 0; + } +#endif +#ifdef __convex__ + { + char *pty_name, *getpty(); + + while ((pty_name = getpty()) != NULL) { + if ((*pty = open (pty_name, O_RDWR)) >= 0) { + strcpy(ptydev, pty_name); + strcpy(ttydev, pty_name); + ttydev[5] = 't'; + return 0; + } + } + return 1; + } +#endif /* __convex__ */ +#ifdef USE_GET_PSEUDOTTY + return ((*pty = getpseudotty (&ttydev, &ptydev)) >= 0 ? 0 : 1); +#else +#if (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) { + return(1); + } + sprintf (ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev)); +#ifndef sgi + sprintf (ptydev, "/dev/ptyq%d", minor(fstat_buf.st_rdev)); + if ((*tty = open (ttydev, O_RDWR)) < 0) { + close (*pty); + return(1); + } +#endif /* !sgi */ + /* got one! */ + return(0); +#else /* sgi or umips */ + + return pty_search(pty); + +#endif /* sgi or umips else */ +#endif /* USE_GET_PSEUDOTTY else */ +#endif /* ATT else */ +} +#endif + + +/* + * Called from get_pty to iterate over likely pseudo terminals + * we might allocate. Used on those systems that do not have + * a functional interface for allocating a pty. + * Returns 0 if found a pty, 1 if fails. + */ +int pty_search(pty) + int *pty; +{ + static int devindex, letter = 0; + +#ifdef CRAY + for (; devindex < 256; devindex++) { + sprintf (ttydev, "/dev/ttyp%03d", devindex); + sprintf (ptydev, "/dev/pty/%03d", devindex); + + if ((*pty = open (ptydev, O_RDWR)) >= 0) { + /* We need to set things up for our next entry + * into this function! + */ + (void) devindex++; + return 0; + } + } +#else /* CRAY */ + 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]; + /* for next time around loop or next entry to this function */ + devindex++; + if ((*pty = open (ptydev, O_RDWR)) >= 0) { +#ifdef sun + /* Need to check the process group of the pty. + * If it exists, then the slave pty is in use, + * and we need to get another one. + */ + int pgrp_rtn; + if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) { + close(*pty); + continue; + } +#endif /* sun */ + return 0; + } + } + devindex = 0; + (void) letter++; + } +#endif /* CRAY else */ + /* + * We were unable to allocate a pty master! Return an error + * condition and let our caller terminate cleanly. + */ + return 1; +} + +get_terminal () +/* + * sets up X and initializes the terminal structure except for term.buf.fildes. + */ +{ + register TScreen *screen = &term->screen; + + screen->arrow = make_colored_cursor (XC_left_ptr, + screen->mousecolor, + screen->mousecolorback); +} + +/* + * The only difference in /etc/termcap between 4014 and 4015 is that + * the latter has support for switching character sets. We support the + * 4015 protocol, but ignore the character switches. Therefore, we + * choose 4014 over 4015. + * + * Features of the 4014 over the 4012: larger (19") screen, 12-bit + * graphics addressing (compatible with 4012 10-bit addressing), + * special point plot mode, incremental plot mode (not implemented in + * later Tektronix terminals), and 4 character sizes. + * All of these are supported by xterm. + */ + +static char *tekterm[] = { + "tek4014", + "tek4015", /* 4014 with APL character set support */ + "tek4012", /* 4010 with lower case */ + "tek4013", /* 4012 with APL character set support */ + "tek4010", /* small screen, upper-case only */ + "dumb", + 0 +}; + +/* The VT102 is a VT100 with the Advanced Video Option included standard. + * It also adds Escape sequences for insert/delete character/line. + * The VT220 adds 8-bit character sets, selective erase. + * The VT320 adds a 25th status line, terminal state interrogation. + * The VT420 has up to 48 lines on the screen. + */ + +static char *vtterm[] = { +#ifdef USE_X11TERM + "x11term", /* for people who want special term name */ +#endif + "xgterm", /* technically correct name */ + "xterm", /* more likely to be found */ + "vt102", + "vt100", + "ansi", + "dumb", + 0 +}; + +/* ARGSUSED */ +SIGNAL_T hungtty(i) + int i; +{ + longjmp(env, 1); + SIGNAL_RETURN; +} + +#ifdef USE_HANDSHAKE +typedef enum { /* c == child, p == parent */ + PTY_BAD, /* c->p: can't open pty slave for some reason */ + PTY_FATALERROR, /* c->p: we had a fatal error with the pty */ + PTY_GOOD, /* c->p: we have a good pty, let's go on */ + PTY_NEW, /* p->c: here is a new pty slave, try this */ + PTY_NOMORE, /* p->c; no more pty's, terminate */ + UTMP_ADDED, /* c->p: utmp entry has been added */ + UTMP_TTYSLOT, /* c->p: here is my ttyslot */ + PTY_EXEC /* p->c: window has been mapped the first time */ +} status_t; + +typedef struct { + status_t status; + int error; + int fatal_error; + int tty_slot; + int rows; + int cols; + char buffer[1024]; +} handshake_t; + +/* HsSysError() + * + * This routine does the equivalent of a SysError but it handshakes + * over the errno and error exit to the master process so that it can + * display our error message and exit with our exit code so that the + * user can see it. + */ + +void +HsSysError(pf, error) +int pf; +int error; +{ + handshake_t handshake; + + handshake.status = PTY_FATALERROR; + handshake.error = errno; + handshake.fatal_error = error; + strcpy(handshake.buffer, ttydev); + write(pf, (char *) &handshake, sizeof(handshake)); + exit(error); +} + +static int pc_pipe[2]; /* this pipe is used for parent to child transfer */ +static int cp_pipe[2]; /* this pipe is used for child to parent transfer */ + +void first_map_occurred () +{ + handshake_t handshake; + register TScreen *screen = &term->screen; + + handshake.status = PTY_EXEC; + handshake.rows = screen->max_row; + handshake.cols = screen->max_col; + write (pc_pipe[1], (char *) &handshake, sizeof(handshake)); + close (cp_pipe[0]); + close (pc_pipe[1]); + waiting_for_initial_map = False; +} +#else +/* + * temporary hack to get xgterm working on att ptys + */ +void first_map_occurred () +{ + return; +} +#define HsSysError(a,b) +#endif /* USE_HANDSHAKE else !USE_HANDSHAKE */ + + +#ifdef NEW_SPAWN + +extern char **environ; + +char * +x_basename(char *name) +{ + char *cp; + + cp = strrchr(name, '/'); +#ifdef __UNIXOS2__ + if (cp == 0) + cp = strrchr(name, '\\'); +#endif + return (cp ? cp + 1 : name); +} + + +static void +set_owner(char *device, int uid, int gid, int mode) +{ + if (chown(device, uid, gid) < 0) { + if (errno != ENOENT + && getuid() == 0) { + fprintf(stderr, "Cannot chown %s to %d,%d: %s\n", + device, uid, gid, strerror(errno)); + } + } + chmod(device, mode); +} + + +/* + * sets the value of var to be arg in the Unix 4.2 BSD environment env. + * Var should end with '=' (bindings are of the form "var=value"). + * This procedure assumes the memory for the first level of environ + * was allocated using calloc, with enough extra room at the end so not + * to have to do a realloc(). + */ +void +xtermSetenv(register char *var, register char *value) +{ + register int envindex = 0; + register size_t len = strlen(var); + + while (environ[envindex] != NULL) { + if (strncmp(environ[envindex], var, len) == 0) { + /* found it */ + environ[envindex] = (char *) malloc((unsigned) len + + strlen(value) + 1); + strcpy(environ[envindex], var); + strcat(environ[envindex], value); + return; + } + envindex++; + } + + environ[envindex] = (char *) malloc((unsigned) len + strlen(value) + 1); + (void) strcpy(environ[envindex], var); + strcat(environ[envindex], value); + environ[++envindex] = NULL; +} + + +/* + * Some platforms use names such as /dev/tty01, others /dev/pts/1. Parse off + * the "tty01" or "pts/1" portion, and return that for use as an identifier for + * utmp. + */ +static char * +my_pty_name(char *device) +{ + size_t len = strlen(device); + Boolean 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; + } + } + return device + len; +} + +/* + * If the name contains a '/', it is a "pts/1" case. Otherwise, return the + * last few characters for a utmp identifier. + */ +static char * +my_pty_id(char *device) +{ + char *name = my_pty_name(device); + char *leaf = x_basename(name); + + if (name == leaf) { /* no '/' in the name */ + int len = strlen(leaf); + if (PTYCHARLEN < len) + leaf = leaf + (len - PTYCHARLEN); + } + return leaf; +} + + +/* + * Set the tty/pty identifier + */ +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); + } +} + + + + +spawn(void) +/* + * Inits pty and tty and forks a login process. + * Does not close fd Xsocket. + * If slave, the pty named in passedPty is already open for use + */ +{ + register TScreen *screen = &term->screen; +#if OPT_PTY_HANDSHAKE + handshake_t handshake; + int done; +#endif +#if OPT_INITIAL_ERASE + int initial_erase = VAL_INITIAL_ERASE; +#endif + int rc = 0; + int tty = -1; +#ifdef USE_ANY_SYSV_TERMIO + struct termio tio; +#ifdef TIOCLSET + unsigned lmode; +#endif /* TIOCLSET */ +#ifdef HAS_LTCHARS + struct ltchars ltc; +#endif /* HAS_LTCHARS */ +#elif defined(USE_POSIX_TERMIOS) + struct termios tio; +#else /* !USE_ANY_SYSV_TERMIO && !USE_POSIX_TERMIOS */ + int ldisc = 0; + int discipline; + unsigned lmode; + struct tchars tc; + struct ltchars ltc; + struct sgttyb sg; +#ifdef sony + int jmode; + struct jtchars jtc; +#endif /* sony */ +#endif /* USE_ANY_SYSV_TERMIO */ + + char termcap[TERMCAP_SIZE]; + char newtc[TERMCAP_SIZE]; + char *ptr, *shname, *shname_minus; + int i, no_dev_tty = FALSE; + char **envnew; /* new environment */ + int envsize; /* elements in new environment */ + 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 lastlog; +#endif /* USE_LASTLOG */ +#endif /* HAVE_UTMP */ +#endif /* !USE_UTEMPTER */ + char *x_basename(); + + /* Noisy compilers (suppress some unused-variable warnings) */ + (void) rc; +#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER) + (void) utret; +#endif + + screen->uid = getuid(); + screen->gid = getgid(); + + termcap[0] = '\0'; + newtc[0] = '\0'; + +#ifdef SIGTTOU + /* so that TIOCSWINSZ || TIOCSIZE doesn't block */ + signal(SIGTTOU, SIG_IGN); +#endif + + if (am_slave >= 0) { + screen->respond = am_slave; + set_pty_id(ttydev, passedPty); +#ifdef USE_PTY_DEVICE + set_pty_id(ptydev, passedPty); +#endif + setgid(screen->gid); + setuid(screen->uid); + } else { + Bool tty_got_hung; + + /* + * Sometimes /dev/tty hangs on open (as in the case of a pty + * that has gone away). Simply make up some reasonable + * defaults. + */ + + signal(SIGALRM, hungtty); + alarm(2); /* alarm(1) might return too soon */ + if (!sigsetjmp(env, 1)) { + tty = open("/dev/tty", O_RDWR); + alarm(0); + tty_got_hung = False; + } else { + tty_got_hung = True; + tty = -1; + errno = ENXIO; + } +#if OPT_INITIAL_ERASE + initial_erase = VAL_INITIAL_ERASE; +#endif + signal(SIGALRM, SIG_DFL); + + /* + * Check results and ignore current control terminal if + * necessary. ENXIO is what is normally returned if there is + * no controlling terminal, but some systems (e.g. SunOS 4.0) + * seem to return EIO. Solaris 2.3 is said to return EINVAL. + * Cygwin returns ENOENT. + */ + no_dev_tty = FALSE; + if (tty < 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 /* HAS_LTCHARS */ +#ifdef TIOCLSET + lmode = d_lmode; +#endif /* TIOCLSET */ +#if defined(USE_ANY_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS) + tio = d_tio; +#else /* not USE_ANY_SYSV_TERMIO and not USE_POSIX_TERMIOS */ + sg = d_sg; + tc = d_tc; + discipline = d_disipline; +#ifdef sony + jmode = d_jmode; + jtc = d_jtc; +#endif /* sony */ +#endif /* USE_ANY_SYSV_TERMIO or USE_POSIX_TERMIOS */ + } else { + SysError(ERROR_OPDEVTTY); + } + } else { + + /* Get a copy of the current terminal's state, + * if we can. Some systems (e.g., SVR4 and MacII) + * may not have a controlling terminal at this point + * if started directly from xdm or xinit, + * in which case we just use the defaults as above. + */ +#ifdef HAS_LTCHARS + if (ioctl(tty, TIOCGLTC, <c) == -1) + ltc = d_ltc; +#endif /* HAS_LTCHARS */ +#ifdef TIOCLSET + if (ioctl(tty, TIOCLGET, &lmode) == -1) + lmode = d_lmode; +#endif /* TIOCLSET */ +#ifdef USE_ANY_SYSV_TERMIO + if ((rc = ioctl(tty, TCGETA, &tio)) == -1) + tio = d_tio; +#elif defined(USE_POSIX_TERMIOS) + if ((rc = tcgetattr(tty, &tio)) == -1) + tio = d_tio; +#else /* !USE_ANY_SYSV_TERMIO && !USE_POSIX_TERMIOS */ + if ((rc = ioctl(tty, TIOCGETP, (char *) &sg)) == -1) + sg = d_sg; + if (ioctl(tty, TIOCGETC, (char *) &tc) == -1) + tc = d_tc; + if (ioctl(tty, TIOCGETD, (char *) &discipline) == -1) + discipline = d_disipline; +#ifdef sony + if (ioctl(tty, TIOCKGET, (char *) &jmode) == -1) + jmode = d_jmode; + if (ioctl(tty, TIOCKGETC, (char *) &jtc) == -1) + jtc = d_jtc; +#endif /* sony */ +#endif /* USE_ANY_SYSV_TERMIO */ + + /* + * If ptyInitialErase is set, we want to get the pty's + * erase value. Just in case that will fail, first get + * the value from /dev/tty, so we will have something + * at least. + */ +#if OPT_INITIAL_ERASE + if (resource.ptyInitialErase) { +#ifdef USE_ANY_SYSV_TERMIO + initial_erase = tio.c_cc[VERASE]; +#elif defined(USE_POSIX_TERMIOS) + initial_erase = tio.c_cc[VERASE]; +#else /* !USE_ANY_SYSV_TERMIO && !USE_POSIX_TERMIOS */ + initial_erase = sg.sg_erase; +#endif /* USE_ANY_SYSV_TERMIO */ + } +#endif + + close(tty); + /* tty is no longer an open fd! */ + tty = -1; + } + +#ifdef NEW_GET_PTY + if (get_pty(&screen->respond, XDisplayString(screen->display))) { + SysError(ERROR_PTYS); + } +#else + if (get_pty(&screen->respond))) { + SysError(ERROR_PTYS); + } +#endif +#if OPT_INITIAL_ERASE + if (resource.ptyInitialErase) { +#ifdef USE_ANY_SYSV_TERMIO + struct termio my_tio; + if ((rc = ioctl(screen->respond, TCGETA, &my_tio)) == 0) + initial_erase = my_tio.c_cc[VERASE]; +#elif defined(USE_POSIX_TERMIOS) + struct termios my_tio; + if ((rc = tcgetattr(screen->respond, &my_tio)) == 0) + initial_erase = my_tio.c_cc[VERASE]; +#else /* !USE_ANY_SYSV_TERMIO && !USE_POSIX_TERMIOS */ + struct sgttyb my_sg; + if ((rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg)) == 0) + initial_erase = my_sg.sg_erase; +#endif /* USE_ANY_SYSV_TERMIO */ + } +#endif /* OPT_INITIAL_ERASE */ + } + + /* avoid double MapWindow requests + */ + XtSetMappedWhenManaged( XtParent(term), False ); + + wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", + False); + + VTInit(); /* realize now so know window size for tty driver */ +#if defined(TIOCCONS) || defined(SRIOCSREDIR) + if (Console) { + /* + * Inform any running xconsole program + * that we are going to steal the console. + */ + XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255); + mit_console = XInternAtom(screen->display, mit_console_name, False); + /* the user told us to be the console, so we can use CurrentTime */ + XtOwnSelection(XtParent(term), + mit_console, CurrentTime, + ConvertConsoleSelection, NULL, NULL); + + } +#endif + + if (screen->TekEmu) { + envnew = tekterm; + ptr = newtc; + } else { + envnew = vtterm; + ptr = termcap; + } + + /* + * This used to exit if no termcap entry was found for the specified + * terminal name. That's a little unfriendly, so instead we'll allow + * the program to proceed (but not to set $TERMCAP) if the termcap + * entry is not found. + */ + if (!get_termcap(TermName = resource.term_name, ptr, newtc)) { + char *last = NULL; + TermName = *envnew; + while (*envnew != NULL) { + if ((last == NULL || strcmp(last, *envnew)) + && get_termcap(*envnew, ptr, newtc)) { + TermName = *envnew; + break; + } + last = *envnew; + envnew++; + } + } + + /* + * Check if ptyInitialErase is not set. If so, we rely on the termcap + * (or terminfo) to tell us what the erase mode should be set to. + */ +#if OPT_INITIAL_ERASE + if (!resource.ptyInitialErase) { + char temp[1024], *p = temp; + char *s = tgetstr(TERMCAP_ERASE, &p); + if (s != 0) { + initial_erase = decode_keyvalue(&s, True); + } + } + + if (resource.backarrow_is_erase) { /* see input.c */ + if (initial_erase == 127) { + term->keyboard.flags &= ~MODE_DECBKM; + } else { + term->keyboard.flags |= MODE_DECBKM; + term->keyboard.reset_DECBKM = 1; + } + } else { + term->keyboard.reset_DECBKM = 2; + } +#endif /* OPT_INITIAL_ERASE */ + +#ifdef TTYSIZE_STRUCT + /* tell tty how big window is */ + +/* + if (screen->TekEmu) { + TTYSIZE_ROWS(ts) = 38; + TTYSIZE_COLS(ts) = 81; +#if defined(USE_STRUCT_WINSIZE) + ts.ws_xpixel = TFullWidth(screen); + ts.ws_ypixel = TFullHeight(screen); +#endif + } else +*/ + + { + TTYSIZE_ROWS(ts) = screen->max_row + 1; + TTYSIZE_COLS(ts) = screen->max_col + 1; +#if defined(USE_STRUCT_WINSIZE) + ts.ws_xpixel = FullWidth(screen); + ts.ws_ypixel = FullHeight(screen); +#endif + } + i = SET_TTYSIZE(screen->respond, ts); +#endif /* TTYSIZE_STRUCT */ + + added_utmp_entry = False; +#if defined(USE_UTEMPTER) +#undef UTMP + if (!resource.utmpInhibit) { + struct UTMP_STR dummy; + char host[sizeof(dummy.ut_host) + 1], *endptr; + + (void) strncpy(host, DisplayString(screen->display), sizeof host); + host[sizeof(host) - 1] = '\0'; + endptr = strrchr(host, ':'); + if (endptr) { + *endptr = '\0'; + } + addToUtmp(ttydev, 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 + if ((screen->pid = fork()) == -1) + SysError(ERROR_FORK); + + if (screen->pid == 0) { + /* + * now in child process + */ +#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__) + int pgrp = setsid(); /* variable may not be used... */ +#else + int pgrp = getpid(); +#endif + +#ifdef USE_USG_PTYS +#ifdef USE_ISPTS_FLAG + if (IsPts) { /* SYSV386 supports both, which did we open? */ +#endif + int ptyfd = 0; + char *pty_name = 0; + +#ifdef __DARWIN__ + ; +#else + setpgrp(); +#endif + 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 (!getenv("CONSEM") && ioctl(ptyfd, I_PUSH, "consem") < 0) { + SysError(ERROR_CONSEM); + } +#endif /* !SVR4 */ + if (ioctl(ptyfd, I_PUSH, "ldterm") < 0) { + SysError(ERROR_LDTERM); + } +#ifdef SVR4 /* from Sony */ + if (ioctl(ptyfd, I_PUSH, "ttcompat") < 0) { + SysError(ERROR_TTCOMPAT); + } +#endif /* SVR4 */ +#endif /* I_PUSH */ + tty = ptyfd; + close(screen->respond); + +#ifdef TTYSIZE_STRUCT + /* tell tty how big window is */ + + if (screen->TekEmu) { + TTYSIZE_ROWS(ts) = 24; + TTYSIZE_COLS(ts) = 80; +/* +#ifdef USE_STRUCT_WINSIZE + ts.ws_xpixel = TFullWidth(screen); + ts.ws_ypixel = TFullHeight(screen); +#endif +*/ + } else + + { + TTYSIZE_ROWS(ts) = screen->max_row + 1; + TTYSIZE_COLS(ts) = screen->max_col + 1; +/* +#ifdef USE_STRUCT_WINSIZE + ts.ws_xpixel = FullWidth(screen); + ts.ws_ypixel = FullHeight(screen); +#endif +*/ + } +#endif /* TTYSIZE_STRUCT */ + +#ifdef USE_ISPTS_FLAG + } else { /* else pty, not pts */ +#endif +#endif /* USE_USG_PTYS */ + + (void) pgrp; /* not all branches use this variable */ + +#if OPT_PTY_HANDSHAKE /* warning, goes for a long ways */ + if (resource.ptyHandshake) { + /* close parent's sides of the pipes */ + close(cp_pipe[0]); + close(pc_pipe[1]); + + /* Make sure that our sides of the pipes are not in the + * 0, 1, 2 range so that we don't fight with stdin, out + * or err. + */ + 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; + } + } + + /* we don't need the socket, or the pty master anymore */ + close(ConnectionNumber(screen->display)); + close(screen->respond); + + /* Now is the time to set up our process group and + * open up the pty slave. + */ +#ifdef USE_SYSV_PGRP +#if defined(CRAY) && (OSMAJORVERSION > 5) + (void) setsid(); +#else + (void) setpgrp(); +#endif +#endif /* USE_SYSV_PGRP */ + +#if defined(__QNX__) && !defined(__QNXNTO__) + qsetlogin(getlogin(), ttydev); +#endif + while (1) { +#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) + if (!no_dev_tty + && (tty = open("/dev/tty", O_RDWR)) >= 0) { + ioctl(tty, TIOCNOTTY, (char *) NULL); + close(tty); + } +#endif /* TIOCNOTTY && !glibc >= 2.1 */ +#ifdef CSRG_BASED + (void) revoke(ttydev); +#endif + if ((tty = open(ttydev, O_RDWR)) >= 0) { +#if defined(CRAY) && defined(TCSETCTTY) + /* make /dev/tty work */ + ioctl(tty, TCSETCTTY, 0); +#endif +#ifdef USE_SYSV_PGRP + /* We need to make sure that we are actually + * the process group leader for the pty. If + * we are, then we should now be able to open + * /dev/tty. + */ + if ((i = open("/dev/tty", O_RDWR)) >= 0) { + /* success! */ + close(i); + break; + } +#else /* USE_SYSV_PGRP */ + break; +#endif /* USE_SYSV_PGRP */ + } + perror("open ttydev"); +#ifdef TIOCSCTTY + ioctl(tty, TIOCSCTTY, 0); +#endif + /* let our master know that the open failed */ + handshake.status = PTY_BAD; + handshake.error = errno; + strcpy(handshake.buffer, ttydev); + write(cp_pipe[1], (char *) &handshake, + sizeof(handshake)); + + /* get reply from parent */ + i = read(pc_pipe[0], (char *) &handshake, + sizeof(handshake)); + if (i <= 0) { + /* parent terminated */ + exit(1); + } + + if (handshake.status == PTY_NOMORE) { + /* No more ptys, let's shutdown. */ + exit(1); + } + + /* We have a new pty to try */ + free(ttydev); + ttydev = (char *) malloc((unsigned) + (strlen(handshake.buffer) + 1)); + if (ttydev == NULL) { + SysError(ERROR_SPREALLOC); + } + strcpy(ttydev, handshake.buffer); + } + + /* use the same tty name that everyone else will use + * (from ttyname) + */ + if ((ptr = ttyname(tty)) != 0) { + /* it may be bigger */ + ttydev = (char *) realloc(ttydev, + (unsigned) (strlen(ptr) + 1)); + if (ttydev == NULL) { + SysError(ERROR_SPREALLOC); + } + (void) strcpy(ttydev, ptr); + } + } +#endif /* OPT_PTY_HANDSHAKE -- from near fork */ + +#ifdef USE_ISPTS_FLAG + } /* end of IsPts else clause */ +#endif + +#ifdef USE_TTY_GROUP + { + struct group *ttygrp; + if ((ttygrp = getgrnam("tty")) != 0) { + /* change ownership of tty to real uid, "tty" gid */ + set_owner(ttydev, screen->uid, ttygrp->gr_gid, 0620); + } else { + /* change ownership of tty to real group and user id */ + set_owner(ttydev, screen->uid, screen->gid, 0622); + } + endgrent(); + } +#else /* else !USE_TTY_GROUP */ + /* change ownership of tty to real group and user id */ + set_owner(ttydev, screen->uid, screen->gid, 0622); +#endif /* USE_TTY_GROUP */ + + /* + * set up the tty modes + */ + { +#if defined(USE_ANY_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS) +#if defined(umips) || defined(CRAY) || defined(linux) + /* If the control tty had its modes screwed around with, + eg. by lineedit in the shell, or emacs, etc. then tio + will have bad values. Let's just get termio from the + new tty and tailor it. */ + if (ioctl(tty, TCGETA, &tio) == -1) + SysError(ERROR_TIOCGETP); + tio.c_lflag |= ECHOE; +#endif /* umips */ + /* Now is also the time to change the modes of the + * child pty. + */ + /* input: nl->nl, don't ignore cr, cr->nl */ + tio.c_iflag &= ~(INLCR | IGNCR); + tio.c_iflag |= ICRNL; + /* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */ +#ifndef USE_POSIX_TERMIOS + tio.c_oflag &= + ~(OCRNL + | ONLRET + | NLDLY + | CRDLY + | TABDLY + | BSDLY + | VTDLY + | FFDLY); +#endif /* USE_POSIX_TERMIOS */ +#ifdef ONLCR + tio.c_oflag |= ONLCR; +#endif /* ONLCR */ +#ifdef OPOST + tio.c_oflag |= OPOST; +#endif /* OPOST */ +#ifndef USE_POSIX_TERMIOS +# if defined(Lynx) && !defined(CBAUD) +# define CBAUD V_CBAUD +# endif + tio.c_cflag &= ~(CBAUD); +#ifdef BAUD_0 + /* baud rate is 0 (don't care) */ +#elif defined(HAVE_TERMIO_C_ISPEED) + tio.c_ispeed = tio.c_ospeed = VAL_LINE_SPEED; +#else /* !BAUD_0 */ + tio.c_cflag |= VAL_LINE_SPEED; +#endif /* !BAUD_0 */ +#else /* USE_POSIX_TERMIOS */ + cfsetispeed(&tio, VAL_LINE_SPEED); + cfsetospeed(&tio, VAL_LINE_SPEED); +#ifdef __MVS__ + /* turn off bits that can't be set from the slave side */ + tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND); +#endif /* __MVS__ */ + /* Clear CLOCAL so that SIGHUP is sent to us + when the xterm ends */ + tio.c_cflag &= ~CLOCAL; +#endif /* USE_POSIX_TERMIOS */ + tio.c_cflag &= ~CSIZE; + if (screen->input_eight_bits) + tio.c_cflag |= CS8; + else + tio.c_cflag |= CS7; + /* enable signals, canonical processing (erase, kill, etc), + * echo + */ + tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK; +#ifdef ECHOKE + tio.c_lflag |= ECHOKE | IEXTEN; +#endif +#ifdef ECHOCTL + tio.c_lflag |= ECHOCTL | IEXTEN; +#endif +#ifndef __MVS__ + /* reset EOL to default value */ + tio.c_cc[VEOL] = CEOL; /* '^@' */ + /* certain shells (ksh & csh) change EOF as well */ + tio.c_cc[VEOF] = CEOF; /* '^D' */ +#else + if (tio.c_cc[VEOL] == 0) + tio.c_cc[VEOL] = CEOL; /* '^@' */ + if (tio.c_cc[VEOF] == 0) + tio.c_cc[VEOF] = CEOF; /* '^D' */ +#endif +#ifdef VLNEXT + tio.c_cc[VLNEXT] = CLNEXT; +#endif +#ifdef VWERASE + tio.c_cc[VWERASE] = CWERASE; +#endif +#ifdef VREPRINT + tio.c_cc[VREPRINT] = CRPRNT; +#endif +#ifdef VRPRNT + tio.c_cc[VRPRNT] = CRPRNT; +#endif +#ifdef VDISCARD + tio.c_cc[VDISCARD] = CFLUSH; +#endif +#ifdef VFLUSHO + tio.c_cc[VFLUSHO] = CFLUSH; +#endif +#ifdef VSTOP + tio.c_cc[VSTOP] = CSTOP; +#endif +#ifdef VSTART + tio.c_cc[VSTART] = CSTART; +#endif +#ifdef VSUSP + tio.c_cc[VSUSP] = CSUSP; +#endif +#ifdef VDSUSP + tio.c_cc[VDSUSP] = CDSUSP; +#endif + if (override_tty_modes) { + /* sysv-specific */ + TMODE(XTTYMODE_intr, tio.c_cc[VINTR]); + TMODE(XTTYMODE_quit, tio.c_cc[VQUIT]); + TMODE(XTTYMODE_erase, tio.c_cc[VERASE]); + TMODE(XTTYMODE_kill, tio.c_cc[VKILL]); + TMODE(XTTYMODE_eof, tio.c_cc[VEOF]); + TMODE(XTTYMODE_eol, tio.c_cc[VEOL]); +#ifdef VSWTCH + TMODE(XTTYMODE_swtch, tio.c_cc[VSWTCH]); +#endif +#ifdef VSUSP + TMODE(XTTYMODE_susp, tio.c_cc[VSUSP]); +#endif +#ifdef VDSUSP + TMODE(XTTYMODE_dsusp, tio.c_cc[VDSUSP]); +#endif +#ifdef VREPRINT + TMODE(XTTYMODE_rprnt, tio.c_cc[VREPRINT]); +#endif +#ifdef VRPRNT + TMODE(XTTYMODE_rprnt, tio.c_cc[VRPRNT]); +#endif +#ifdef VDISCARD + TMODE(XTTYMODE_flush, tio.c_cc[VDISCARD]); +#endif +#ifdef VFLUSHO + TMODE(XTTYMODE_flush, tio.c_cc[VFLUSHO]); +#endif +#ifdef VWERASE + TMODE(XTTYMODE_weras, tio.c_cc[VWERASE]); +#endif +#ifdef VLNEXT + TMODE(XTTYMODE_lnext, tio.c_cc[VLNEXT]); +#endif +#ifdef VSTART + TMODE(XTTYMODE_start, tio.c_cc[VSTART]); +#endif +#ifdef VSTOP + TMODE(XTTYMODE_stop, tio.c_cc[VSTOP]); +#endif +#ifdef VSTATUS + TMODE(XTTYMODE_status, tio.c_cc[VSTATUS]); +#endif +#ifdef VERASE2 + TMODE(XTTYMODE_erase2, tio.c_cc[VERASE2]); +#endif +#ifdef VEOL2 + TMODE(XTTYMODE_eol2, tio.c_cc[VEOL2]); +#endif +#ifdef HAS_LTCHARS + /* both SYSV and BSD have 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 + /* ioctl chokes when the "reserved" process group controls + * are not set to _POSIX_VDISABLE */ + ltc.t_rprntc = ltc.t_rprntc = ltc.t_flushc = + ltc.t_werasc = ltc.t_lnextc = _POSIX_VDISABLE; +#endif /* __hpux */ + if (ioctl(tty, TIOCSLTC, <c) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETC); +#endif /* HAS_LTCHARS */ +#ifdef TIOCLSET + if (ioctl(tty, TIOCLSET, (char *) &lmode) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCLSET); +#endif /* TIOCLSET */ +#ifndef USE_POSIX_TERMIOS + if (ioctl(tty, TCSETA, &tio) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETP); +#else /* USE_POSIX_TERMIOS */ + if (tcsetattr(tty, TCSANOW, &tio) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETP); +#endif /* USE_POSIX_TERMIOS */ +#else /* USE_ANY_SYSV_TERMIO or USE_POSIX_TERMIOS */ + sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW); + sg.sg_flags |= (ECHO | CRMOD); + /* make sure speed is set on pty so that editors work right */ +/* + sg.sg_ispeed = VAL_LINE_SPEED; + sg.sg_ospeed = VAL_LINE_SPEED; +*/ + /* reset t_brkc to default value */ + tc.t_brkc = -1; +#ifdef LPASS8 + if (screen->input_eight_bits) + lmode |= LPASS8; + else + lmode &= ~(LPASS8); +#endif +#ifdef sony + jmode &= ~KM_KANJI; +#endif /* sony */ + + 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); + /* both SYSV and BSD have 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); + } + + if (ioctl(tty, TIOCSETP, (char *) &sg) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETP); + if (ioctl(tty, TIOCSETC, (char *) &tc) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETC); + if (ioctl(tty, TIOCSETD, (char *) &discipline) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETD); + if (ioctl(tty, TIOCSLTC, (char *) <c) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSLTC); + if (ioctl(tty, TIOCLSET, (char *) &lmode) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCLSET); +#ifdef sony + if (ioctl(tty, TIOCKSET, (char *) &jmode) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCKSET); + if (ioctl(tty, TIOCKSETC, (char *) &jtc) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCKSETC); +#endif /* sony */ +#endif /* !USE_ANY_SYSV_TERMIO */ +#if defined(TIOCCONS) || defined(SRIOCSREDIR) + if (Console) { +#ifdef TIOCCONS + int on = 1; + if (ioctl(tty, TIOCCONS, (char *) &on) == -1) + fprintf(stderr, "%s: cannot open console: %s\n", + "xgterm", strerror(errno)); +#endif +#ifdef SRIOCSREDIR + int fd = open("/dev/console", O_RDWR); + if (fd == -1 || ioctl(fd, SRIOCSREDIR, tty) == -1) + fprintf(stderr, "%s: cannot open console: %s\n", + "xgterm", strerror(errno)); + (void) close(fd); +#endif + } +#endif /* TIOCCONS */ + } + + signal(SIGCHLD, SIG_DFL); +#ifdef USE_SYSV_SIGHUP + /* watch out for extra shells (I don't understand either) */ + signal(SIGHUP, SIG_DFL); +#else + signal(SIGHUP, SIG_IGN); +#endif + /* restore various signals to their defaults */ + signal(SIGINT, SIG_DFL); + signal(SIGQUIT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + + /* + * If we're not asked to make the parent process set the + * terminal's erase mode, and if we had no ttyModes resource, + * then set the terminal's erase mode from our best guess. + */ +#if OPT_INITIAL_ERASE + if (!resource.ptyInitialErase + && !override_tty_modes + && !ttymodelist[XTTYMODE_erase].set) { +#ifdef USE_ANY_SYSV_TERMIO + if (ioctl(tty, TCGETA, &tio) == -1) + tio = d_tio; + tio.c_cc[VERASE] = initial_erase; + rc = ioctl(tty, TCSETA, &tio); +#elif defined(USE_POSIX_TERMIOS) + if (tcgetattr(tty, &tio) == -1) + tio = d_tio; + tio.c_cc[VERASE] = initial_erase; + rc = tcsetattr(tty, TCSANOW, &tio); +#else /* !USE_ANY_SYSV_TERMIO && !USE_POSIX_TERMIOS */ + if (ioctl(tty, TIOCGETP, (char *) &sg) == -1) + sg = d_sg; + sg.sg_erase = initial_erase; + rc = ioctl(tty, TIOCSETP, (char *) &sg); +#endif /* USE_ANY_SYSV_TERMIO */ + } +#endif + + /* copy the environment before Setenving */ + for (i = 0; environ[i] != NULL; i++) ; + /* compute number of xtermSetenv() calls below */ + envsize = 1; /* (NULL terminating entry) */ + envsize += 3; /* TERM, WINDOWID, DISPLAY */ +#ifdef HAVE_UTMP + envsize += 1; /* LOGNAME */ +#endif /* HAVE_UTMP */ +#ifdef USE_SYSV_ENVVARS + envsize += 2; /* COLUMNS, LINES */ +#ifdef HAVE_UTMP + envsize += 2; /* HOME, SHELL */ +#endif /* HAVE_UTMP */ +#ifdef OWN_TERMINFO_DIR + envsize += 1; /* TERMINFO */ +#endif +#else /* USE_SYSV_ENVVARS */ + envsize += 1; /* TERMCAP */ +#endif /* USE_SYSV_ENVVARS */ + envnew = (char **) calloc((unsigned) i + envsize, sizeof(char *)); + memmove((char *) envnew, (char *) environ, i * sizeof(char *)); + environ = envnew; + xtermSetenv("TERM=", TermName); + if (!TermName) + *newtc = 0; + + sprintf(buf, "%lu", + ((unsigned long) XtWindow(XtParent(term)))); + xtermSetenv("WINDOWID=", buf); + + /* put the display into the environment of the shell */ + xtermSetenv("DISPLAY=", XDisplayString(screen->display)); + + signal(SIGTERM, SIG_DFL); + + /* this is the time to go and set up stdin, out, and err + */ + { +#if defined(CRAY) && (OSMAJORVERSION >= 6) + (void) close(tty); + (void) close(0); + + if (open("/dev/tty", O_RDWR)) { + SysError(ERROR_OPDEVTTY); + } + (void) close(1); + (void) close(2); + dup(0); + dup(0); +#else + /* dup the tty */ + for (i = 0; i <= 2; i++) + if (i != tty) { + (void) close(i); + (void) dup(tty); + } +#ifndef ATT + /* and close the tty */ + if (tty > 2) + (void) close(tty); +#endif +#endif /* CRAY */ + } + +#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 /*setsid() */ ); +#endif +#endif /* !USE_SYSV_PGRP */ + +#ifdef Lynx + { + struct termio t; + if (ioctl(0, TCGETA, &t) >= 0) { + /* this gets lost somewhere on our way... */ + t.c_oflag |= OPOST; + ioctl(0, TCSETA, &t); + } + } +#endif + +#ifdef HAVE_UTMP + pw = getpwuid(screen->uid); + login_name = NULL; + if (pw && pw->pw_name) { +#ifdef HAVE_GETLOGIN + /* + * If the value from getlogin() differs from the value we + * get by looking in the password file, check if it does + * correspond to the same uid. If so, allow that as an + * alias for the uid. + * + * Of course getlogin() will fail if we're started from + * a window-manager, since there's no controlling terminal + * to fuss with. In that case, try to get something useful + * from the user's $LOGNAME or $USER environment variables. + */ + if (((login_name = getlogin()) != NULL + || (login_name = getenv("LOGNAME")) != NULL + || (login_name = getenv("USER")) != NULL) + && strcmp(login_name, pw->pw_name)) { + struct passwd *pw2 = getpwnam(login_name); + if (pw2 != 0 + && pw->pw_uid != pw2->pw_uid) { + login_name = NULL; + } + } +#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); /* for POSIX */ + } +#ifndef USE_UTEMPTER +#ifdef USE_SYSV_UTMP + /* Set up our utmp entry now. We need to do it here + * for the following reasons: + * - It needs to have our correct process id (for + * login). + * - If our parent was to set it after the fork(), + * it might make it out before we need it. + * - We need to do it before we go and change our + * user and group id's. + */ + (void) setutent(); + /* set up entry to search for */ + bzero((char *) &utmp, sizeof(utmp)); + (void) strncpy(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id)); + + utmp.ut_type = DEAD_PROCESS; + + /* position to entry in utmp file */ + /* Test return value: beware of entries left behind: PSz 9 Mar 00 */ + if (!(utret = getutid(&utmp))) { + (void) setutent(); + utmp.ut_type = USER_PROCESS; + if (!(utret = getutid(&utmp))) { + (void) setutent(); + } + } + + /* set up the new entry */ + 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)); + /* why are we copying this string again? (see above) */ + (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 + (void) strncpy(buf, DisplayString(screen->display), sizeof(buf)); +#ifndef linux + { + char *disfin = strrchr(buf, ':'); + if (disfin) + *disfin = '\0'; + } +#endif + (void) strncpy(utmp.ut_host, buf, sizeof(utmp.ut_host)); +#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 + + /* write out the entry */ + if (!resource.utmpInhibit) { + errno = 0; + pututline(&utmp); + } +#ifdef WTMP +#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__)) + if (term->misc.login_shell) + updwtmpx(WTMPX_FILE, &utmp); +#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) + if (term->misc.login_shell) + updwtmp(etc_wtmp, &utmp); +#else + if (term->misc.login_shell && + (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { + write(i, (char *) &utmp, sizeof(utmp)); + close(i); + } +#endif +#endif + /* close the file */ + (void) endutent(); + +#else /* USE_SYSV_UTMP */ + /* We can now get our ttyslot! We can also set the initial + * utmp entry. + */ + 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 + (void) strncpy(utmp.ut_host, + XDisplayString(screen->display), + sizeof(utmp.ut_host)); +#endif + /* cast needed on Ultrix 4.4 */ + time((time_t *) & utmp.ut_time); + lseek(i, (long) (tslot * sizeof(utmp)), 0); + write(i, (char *) &utmp, sizeof(utmp)); + close(i); + added_utmp_entry = True; +#if defined(WTMP) + if (term->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 (term->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 /* WTMP or MNX_LASTLOG */ + } else + tslot = -tslot; + } + + /* Let's pass our ttyslot to our parent so that it can + * clean up after us. + */ +#if OPT_PTY_HANDSHAKE + if (resource.ptyHandshake) { + handshake.tty_slot = tslot; + } +#endif /* OPT_PTY_HANDSHAKE */ +#endif /* USE_SYSV_UTMP */ + +#ifdef USE_LASTLOGX + if (term->misc.login_shell) { + bzero((char *) &lastlog, sizeof(lastlog)); + (void) strncpy(lastlog.ll_line, + my_pty_name(ttydev), + sizeof(lastlog.ll_line)); + X_GETTIMEOFDAY(&lastlog.ll_tv); + (void) strncpy(lastlog.ll_host, + XDisplayString(screen->display), + sizeof(lastlog.ll_host)); + updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlog); + } +#endif + +#ifdef USE_LASTLOG + if (term->misc.login_shell && + (i = open(etc_lastlog, O_WRONLY)) >= 0) { + bzero((char *) &lastlog, sizeof(struct lastlog)); + (void) strncpy(lastlog.ll_line, + my_pty_name(ttydev), + sizeof(lastlog.ll_line)); + (void) strncpy(lastlog.ll_host, + XDisplayString(screen->display), + sizeof(lastlog.ll_host)); + time(&lastlog.ll_time); + lseek(i, (long) (screen->uid * sizeof(struct lastlog)), 0); + write(i, (char *) &lastlog, sizeof(struct lastlog)); + close(i); + } +#endif /* USE_LASTLOG */ + +#ifdef __OpenBSD__ + /* Switch to real gid after writing utmp entry */ + utmpGid = getegid(); + if (getgid() != getegid()) { + utmpGid = getegid(); + setegid(getgid()); + } +#endif + +#if OPT_PTY_HANDSHAKE + /* Let our parent know that we set up our utmp entry + * so that it can clean up after us. + */ + if (resource.ptyHandshake) { + handshake.status = UTMP_ADDED; + handshake.error = 0; + strcpy(handshake.buffer, ttydev); + (void) write(cp_pipe[1], (char *) &handshake, sizeof(handshake)); + } +#endif /* OPT_PTY_HANDSHAKE */ +#endif /* USE_UTEMPTER */ +#endif /* HAVE_UTMP */ + + (void) setgid(screen->gid); +#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); + } +#if OPT_PTY_HANDSHAKE + if (resource.ptyHandshake) { + /* mark the pipes as close on exec */ + fcntl(cp_pipe[1], F_SETFD, 1); + fcntl(pc_pipe[0], F_SETFD, 1); + + /* We are at the point where we are going to + * exec our shell (or whatever). Let our parent + * know we arrived safely. + */ + handshake.status = PTY_GOOD; + handshake.error = 0; + (void) strcpy(handshake.buffer, ttydev); + (void) write(cp_pipe[1], (char *) &handshake, sizeof(handshake)); + + if (waiting_for_initial_map) { + i = read(pc_pipe[0], (char *) &handshake, + sizeof(handshake)); + if (i != sizeof(handshake) || + handshake.status != PTY_EXEC) { + /* some very bad problem occurred */ + exit(ERROR_PTY_EXEC); + } + if (handshake.rows > 0 && handshake.cols > 0) { + screen->max_row = handshake.rows; + screen->max_col = handshake.cols; +#ifdef TTYSIZE_STRUCT + TTYSIZE_ROWS(ts) = screen->max_row + 1; + TTYSIZE_COLS(ts) = screen->max_col + 1; +#if defined(USE_STRUCT_WINSIZE) + ts.ws_xpixel = FullWidth(screen); + ts.ws_ypixel = FullHeight(screen); +#endif +#endif /* TTYSIZE_STRUCT */ + } + } + } +#endif /* OPT_PTY_HANDSHAKE */ + +#ifdef USE_SYSV_ENVVARS + { + char numbuf[12]; + sprintf(numbuf, "%d", screen->max_col + 1); + xtermSetenv("COLUMNS=", numbuf); + sprintf(numbuf, "%d", screen->max_row + 1); + xtermSetenv("LINES=", numbuf); + } +#ifdef HAVE_UTMP + if (pw) { /* SVR4 doesn't provide these */ + if (!getenv("HOME")) + xtermSetenv("HOME=", pw->pw_dir); + if (!getenv("SHELL")) + xtermSetenv("SHELL=", pw->pw_shell); + } +#endif /* HAVE_UTMP */ +#ifdef OWN_TERMINFO_DIR + xtermSetenv("TERMINFO=", OWN_TERMINFO_DIR); +#endif +#else /* USE_SYSV_ENVVARS */ + if (!screen->TekEmu && *newtc) { + strcpy(termcap, newtc); + resize(screen, termcap, newtc); + } +/* + if (term->misc.titeInhibit && !term->misc.tiXtraScroll) { +*/ + if (term->misc.titeInhibit) { + remove_termcap_entry(newtc, "ti="); + remove_termcap_entry(newtc, "te="); + } + /* + * work around broken termcap entries */ + if (resource.useInsertMode) { + remove_termcap_entry(newtc, "ic="); + /* don't get duplicates */ + 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, + initial_erase & 0377); +#endif + xtermSetenv("TERMCAP=", newtc); + } +#endif /* USE_SYSV_ENVVARS */ + + /* need to reset after all the ioctl bashing we did above */ +#if OPT_PTY_HANDSHAKE + if (resource.ptyHandshake) { +#ifdef TTYSIZE_STRUCT + i = SET_TTYSIZE(0, ts); +#endif /* TTYSIZE_STRUCT */ + } +#endif /* OPT_PTY_HANDSHAKE */ + signal(SIGHUP, SIG_DFL); + +#ifdef HAVE_UTMP + if (((ptr = getenv("SHELL")) == NULL || *ptr == 0) && + ((pw == NULL && (pw = getpwuid(screen->uid)) == NULL) || + *(ptr = pw->pw_shell) == 0)) +#else /* HAVE_UTMP */ + if (((ptr = getenv("SHELL")) == NULL || *ptr == 0) && + ((pw = getpwuid(screen->uid)) == NULL || + *(ptr = pw->pw_shell) == 0)) +#endif /* HAVE_UTMP */ + ptr = "/bin/sh"; + shname = x_basename(ptr); + +#if OPT_LUIT_PROG + /* + * Use two copies of command_to_exec, in case luit is not actually + * there, or refuses to run. In that case we will fall-through to + * to command that the user gave anyway. + */ + if (command_to_exec_with_luit) { + execvp(*command_to_exec_with_luit, command_to_exec_with_luit); + /* print error message on screen */ + fprintf(stderr, "%s: Can't execvp %s: %s\n", + "xgterm", *command_to_exec_with_luit, strerror(errno)); + fprintf(stderr, "%s: cannot support your locale.\n", + "xgterm"); + } +#endif + if (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); + /* print error message on screen */ + fprintf(stderr, "%s: Can't execvp %s: %s\n", + "xgterm", *command_to_exec, strerror(errno)); + } +#ifdef USE_SYSV_SIGHUP + /* fix pts sh hanging around + signal(SIGHUP, SIG_DFL); + */ +#endif + + shname_minus = (char *) malloc(strlen(shname) + 2); + (void) strcpy(shname_minus, "-"); + (void) strcat(shname_minus, shname); +#if !defined(USE_ANY_SYSV_TERMIO) && !defined(USE_POSIX_TERMIOS) + ldisc = XStrCmp("csh", shname + strlen(shname) - 3) == 0 ? + NTTYDISC : 0; + ioctl(0, TIOCSETD, (char *) &ldisc); +#endif /* !USE_ANY_SYSV_TERMIO && !USE_POSIX_TERMIOS */ + +#ifdef USE_LOGIN_DASH_P + if (term->misc.login_shell && pw && added_utmp_entry) + execl(bin_login, "login", "-p", "-f", login_name, (void *) 0); +#endif + execlp(ptr, + (term->misc.login_shell ? shname_minus : shname), + (void *) 0); + + /* Exec failed. */ + fprintf(stderr, "%s: Could not exec %s: %s\n", "xgterm", + ptr, strerror(errno)); + (void) sleep(5); + exit(ERROR_EXEC); + } + /* end if in child after fork */ +#if OPT_PTY_HANDSHAKE + if (resource.ptyHandshake) { + /* Parent process. Let's handle handshaked requests to our + * child process. + */ + + /* close childs's sides of the pipes */ + close(cp_pipe[1]); + close(pc_pipe[0]); + + for (done = 0; !done;) { + if (read(cp_pipe[0], + (char *) &handshake, + sizeof(handshake)) <= 0) { + /* Our child is done talking to us. If it terminated + * due to an error, we will catch the death of child + * and clean up. + */ + break; + } + + switch (handshake.status) { + case PTY_GOOD: + /* Success! Let's free up resources and + * continue. + */ + done = 1; + break; + + case PTY_BAD: + /* The open of the pty failed! Let's get + * another one. + */ + (void) close(screen->respond); +#ifdef NEW_GET_PTY + if (get_pty(&screen->respond, XDisplayString(screen->display))) { +#else + if (get_pty(&screen->respond)) { +#endif + /* no more ptys! */ + fprintf(stderr, + "%s: child process can find no available ptys: %s\n", + "xgterm", strerror(errno)); + handshake.status = PTY_NOMORE; + write(pc_pipe[1], (char *) &handshake, sizeof(handshake)); + exit(ERROR_PTYS); + } + handshake.status = PTY_NEW; + (void) strcpy(handshake.buffer, ttydev); + 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); + /*NOTREACHED */ + + case UTMP_ADDED: + /* The utmp entry was set by our slave. Remember + * this so that we can reset it later. + */ + added_utmp_entry = True; +#ifndef USE_SYSV_UTMP + tslot = handshake.tty_slot; +#endif /* USE_SYSV_UTMP */ + free(ttydev); + ttydev = x_strdup(handshake.buffer); + break; + default: + fprintf(stderr, "%s: unexpected handshake status %d\n", + "xgterm", handshake.status); + } + } + /* close our sides of the pipes */ + if (!waiting_for_initial_map) { + close(cp_pipe[0]); + close(pc_pipe[1]); + } + } +#endif /* OPT_PTY_HANDSHAKE */ + } + + /* end if no slave */ + /* + * still in parent (xterm process) + */ +#ifdef USE_SYSV_SIGHUP + /* hung sh problem? (Fedora) + signal(SIGHUP, SIG_DFL); + */ + signal(SIGHUP, SIG_IGN); +#else + signal(SIGHUP, SIG_IGN); +#endif + +/* + * Unfortunately, System V seems to have trouble divorcing the child process + * from the process group of xterm. This is a problem because hitting the + * INTR or QUIT characters on the keyboard will cause xterm to go away if we + * don't ignore the signals. This is annoying. + */ + +#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) + signal(SIGINT, SIG_IGN); + +#ifndef SYSV + /* hung shell problem */ + signal(SIGQUIT, SIG_IGN); +#endif + signal(SIGTERM, SIG_IGN); +#elif defined(SYSV) || defined(__osf__) + /* if we were spawned by a jobcontrol smart shell (like ksh or csh), + * then our pgrp and pid will be the same. If we were spawned by + * a jobcontrol dumb shell (like /bin/sh), then we will be in our + * parent's pgrp, and we must ignore keyboard signals, or we will + * tank on everything. + */ + 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 /* SYSV */ + signal(SIGINT, Exit); + signal(SIGQUIT, Exit); + signal(SIGTERM, Exit); + signal(SIGPIPE, Exit); +#endif /* USE_SYSV_SIGNALS and not SIGTSTP */ + + return 0; +} /* end spawn */ + +#else + + +spawn () +/* + * Inits pty and tty and forks a login process. + * Does not close fd Xsocket. + * If slave, the pty named in passedPty is already open for use + */ +{ + extern char *SysErrorMsg(); + register TScreen *screen = &term->screen; + int Xsocket = ConnectionNumber(screen->display); +#ifdef USE_HANDSHAKE + handshake_t handshake; +#else + int fds[2]; +#endif + int tty = -1; + int discipline; + int done; +#ifdef USE_SYSV_TERMIO + struct termio tio; + struct termio dummy_tio; +#ifdef TIOCLSET + unsigned lmode; +#endif /* TIOCLSET */ +#ifdef TIOCSLTC + struct ltchars ltc; +#endif /* TIOCSLTC */ + int one = 1; + int zero = 0; + int status; +#else /* else not USE_SYSV_TERMIO */ + unsigned lmode; + struct tchars tc; + struct ltchars ltc; + struct sgttyb sg; +#ifdef sony + int jmode; + struct jtchars jtc; +#endif /* sony */ +#endif /* USE_SYSV_TERMIO */ + + char termcap [1024]; + char newtc [1024]; + char *ptr, *shname, *shname_minus; + int i, no_dev_tty = FALSE; +#ifdef USE_SYSV_TERMIO + char *dev_tty_name = (char *) 0; + int fd; /* for /etc/wtmp */ +#endif /* USE_SYSV_TERMIO */ + char **envnew; /* new environment */ + int envsize; /* elements in new environment */ + char buf[64]; + char *TermName = NULL; + int ldisc = 0; +#if defined(sun) && !defined(SVR4) +#ifdef TIOCSSIZE + struct ttysize ts; +#endif /* TIOCSSIZE */ +#else /* not sun */ +#ifdef TIOCSWINSZ + struct winsize ws; +#endif /* TIOCSWINSZ */ +#endif /* sun */ + struct passwd *pw = NULL; +#ifdef UTMP +#ifdef SVR4 + struct utmpx utmp; +#else + struct utmp utmp; +#endif +#ifdef LASTLOG + struct lastlog lastlog; +#endif /* LASTLOG */ +#endif /* UTMP */ + + screen->uid = getuid(); + screen->gid = getgid(); + +#ifdef linux + memset(termcap, 0, sizeof(termcap)); + memset(newtc, 0, sizeof(newtc)); +#endif + +#ifdef SIGTTOU + /* so that TIOCSWINSZ || TIOCSIZE doesn't block */ + signal(SIGTTOU,SIG_IGN); +#endif + + if (am_slave) { + screen->respond = am_slave; + ptydev[strlen(ptydev) - 2] = ttydev[strlen(ttydev) - 2] = + passedPty[0]; + ptydev[strlen(ptydev) - 1] = ttydev[strlen(ttydev) - 1] = + passedPty[1]; + + setgid (screen->gid); + setuid (screen->uid); + } else { + Bool tty_got_hung = False; + + /* + * Sometimes /dev/tty hangs on open (as in the case of a pty + * that has gone away). Simply make up some reasonable + * defaults. + */ + signal(SIGALRM, hungtty); + alarm(2); /* alarm(1) might return too soon */ + if (! setjmp(env)) { + tty = open ("/dev/tty", O_RDWR, 0); + alarm(0); + } else { + tty_got_hung = True; + tty = -1; + errno = ENXIO; + } + signal(SIGALRM, SIG_DFL); + + /* + * Check results and ignore current control terminal if + * necessary. ENXIO is what is normally returned if there is + * no controlling terminal, but some systems (e.g. SunOS 4.0) + * seem to return EIO. + */ + if (tty < 0) { + if (tty_got_hung || errno == ENXIO || errno == EIO || + errno == ENOTTY) { + no_dev_tty = TRUE; +#ifdef TIOCSLTC + ltc = d_ltc; +#endif /* TIOCSLTC */ +#ifdef TIOCLSET + lmode = d_lmode; +#endif /* TIOCLSET */ +#ifdef USE_SYSV_TERMIO + tio = d_tio; +#else /* not USE_SYSV_TERMIO */ + sg = d_sg; + tc = d_tc; + discipline = d_disipline; +#ifdef sony + jmode = d_jmode; + jtc = d_jtc; +#endif /* sony */ +#endif /* USE_SYSV_TERMIO */ + } else { + SysError(ERROR_OPDEVTTY); + } + } else { + /* Get a copy of the current terminal's state, + * if we can. Some systems (e.g., SVR4 and MacII) + * may not have a controlling terminal at this point + * if started directly from xdm or xinit, + * in which case we just use the defaults as above. + */ +#ifdef TIOCSLTC + if(ioctl(tty, TIOCGLTC, <c) == -1) + ltc = d_ltc; +#endif /* TIOCSLTC */ +#ifdef TIOCLSET + if(ioctl(tty, TIOCLGET, &lmode) == -1) + lmode = d_lmode; +#endif /* TIOCLSET */ +#ifdef USE_SYSV_TERMIO + if(ioctl(tty, TCGETA, &tio) == -1) + tio = d_tio; + +#else /* not USE_SYSV_TERMIO */ + if(ioctl(tty, TIOCGETP, (char *)&sg) == -1) + sg = d_sg; + if(ioctl(tty, TIOCGETC, (char *)&tc) == -1) + tc = d_tc; + if(ioctl(tty, TIOCGETD, (char *)&discipline) == -1) + discipline = d_disipline; +#ifdef sony + if(ioctl(tty, TIOCKGET, (char *)&jmode) == -1) + jmode = d_jmode; + if(ioctl(tty, TIOCKGETC, (char *)&jtc) == -1) + jtc = d_jtc; +#endif /* sony */ +#endif /* USE_SYSV_TERMIO */ + close (tty); + /* tty is no longer an open fd! */ + tty = -1; + } + +#ifdef PUCC_PTYD + if(-1 == (screen->respond = openrpty(ttydev, ptydev, + (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), + getuid(), XDisplayString(screen->display)))) { +#else /* not PUCC_PTYD */ +#ifdef NEW_GET_PTY + if (get_pty(&screen->respond,XDisplayString(screen->display))) { +#else + if (get_pty(&screen->respond)) { +#endif +#endif /* PUCC_PTYD */ + /* no ptys! */ + (void) fprintf(stderr, "%s: no available ptys\n", + xgterm_name); + exit (ERROR_PTYS); +#ifdef PUCC_PTYD + } +#else + } /* keep braces balanced for emacs */ +#endif +#ifdef PUCC_PTYD + else { + /* + * set the fd of the master in a global var so + * we can undo all this on exit + * + */ + Ptyfd = screen->respond; + } +#endif /* PUCC_PTYD */ + } + + /* avoid double MapWindow requests */ + XtSetMappedWhenManaged( XtParent(term), False ); + wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", + False); + VTInit(); /* realize now so know window size for tty driver */ +#if defined(TIOCCONS) || defined(SRIOCSREDIR) + if (Console) { + /* + * Inform any running xconsole program + * that we are going to steal the console. + */ + XmuGetHostname (mit_console_name + MIT_CONSOLE_LEN, 255); + mit_console = XInternAtom(screen->display, mit_console_name, False); + /* the user told us to be the console, so we can use CurrentTime */ + XtOwnSelection (XtParent(term), + mit_console, CurrentTime, + ConvertConsoleSelection, NULL, NULL); + } +#endif + if(screen->TekEmu) { + envnew = tekterm; + ptr = newtc; + } else { + envnew = vtterm; + ptr = termcap; + } + TermName = NULL; + if (resource.term_name) { + if (tgetent (ptr, resource.term_name) == 1) { + TermName = resource.term_name; + if (!screen->TekEmu) + resize (screen, TermName, termcap, newtc); + } else { + fprintf (stderr, "%s: invalid termcap entry \"%s\".\n", + ProgramName, resource.term_name); + } + } + if (!TermName) { + while (*envnew != NULL) { + if(tgetent(ptr, *envnew) == 1) { + TermName = *envnew; + if(!screen->TekEmu) + resize(screen, TermName, termcap, newtc); + break; + } + envnew++; + } + if (TermName == NULL) { + fprintf (stderr, "%s: unable to find usable termcap entry.\n", + ProgramName); + Exit (1); + } + } + +#if defined(sun) && !defined(SVR4) +#ifdef TIOCSSIZE + /* tell tty how big window is */ + if(screen->TekEmu) { + ts.ts_lines = 35; + ts.ts_cols = 80; + } else { + ts.ts_lines = screen->max_row + 1; + ts.ts_cols = screen->max_col + 1; + } +#endif /* TIOCSSIZE */ +#else /* not sun */ +#ifdef TIOCSWINSZ + /* tell tty how big window is */ + if(screen->TekEmu) { + /* We can only guess at the size at this point. */ + ws.ws_row = 35; + ws.ws_col = 80; + ws.ws_xpixel = 640; + ws.ws_ypixel = 480; + } else { + ws.ws_row = screen->max_row + 1; + ws.ws_col = screen->max_col + 1; + ws.ws_xpixel = FullWidth(screen); + ws.ws_ypixel = FullHeight(screen); + } +#endif /* TIOCSWINSZ */ +#endif /* sun */ + + if (!am_slave) { +#ifdef USE_HANDSHAKE + if (pipe(pc_pipe) || pipe(cp_pipe)) + SysError (ERROR_FORK); +#endif + if ((screen->pid = fork ()) == -1) + SysError (ERROR_FORK); + + if (screen->pid == 0) { + /* + * now in child process + */ + extern char **environ; +#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) + int pgrp = setsid(); +#else + int pgrp = getpid(); +#endif +#ifdef USE_SYSV_TERMIO + char numbuf[12]; +#endif /* USE_SYSV_TERMIO */ +#if defined(UTMP) && defined(USE_SYSV_UTMP) + char *ptyname; +#endif + +#ifdef USE_USG_PTYS +#if defined(SYSV) && defined(SYSV386) + if (IsPts) { /* SYSV386 supports both, which did we open? */ +#endif /* SYSV && SYSV386 */ + int ptyfd; + + setpgrp(); + grantpt (screen->respond); + unlockpt (screen->respond); + if ((ptyfd = open (ptsname(screen->respond), O_RDWR)) < 0) { + SysError (1); + } +#ifdef I_PUSH + if (ioctl (ptyfd, I_PUSH, "ptem") < 0) { + SysError (2); + } +#if !defined(SVR4) && !defined(SYSV386) + if (!getenv("CONSEM") && ioctl (ptyfd, I_PUSH, "consem") < 0) { + SysError (3); + } +#endif /* !SVR4 */ + if (ioctl (ptyfd, I_PUSH, "ldterm") < 0) { + SysError (4); + } +#ifdef SVR4 /* from Sony */ +#if !defined(sgi) && !defined(ibm) + if (ioctl (ptyfd, I_PUSH, "ttcompat") < 0) { + SysError (5); + } +#endif /* !defined(sgi) */ +#endif /* SVR4 */ +#endif /* I_PUSH */ + tty = ptyfd; + close (screen->respond); +#ifdef TIOCSWINSZ + /* tell tty how big window is */ + if(screen->TekEmu) { + ws.ws_row = 35; + ws.ws_col = 80; + ws.ws_xpixel = 640; + ws.ws_ypixel = 480; + } else { + ws.ws_row = screen->max_row + 1; + ws.ws_col = screen->max_col + 1; + ws.ws_xpixel = FullWidth(screen); + ws.ws_ypixel = FullHeight(screen); + } +#endif +#if defined(SYSV) && defined(SYSV386) + } else { /* else pty, not pts */ +#endif /* SYSV && SYSV386 */ +#endif /* USE_USG_PTYS */ + +#ifdef USE_HANDSHAKE /* warning, goes for a long ways */ + /* close parent's sides of the pipes */ + close (cp_pipe[0]); + close (pc_pipe[1]); + + /* Make sure that our sides of the pipes are not in the + * 0, 1, 2 range so that we don't fight with stdin, out + * or err. + */ + 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; + } + } + + /* we don't need the socket, or the pty master anymore */ + close (Xsocket); + close (screen->respond); + + /* Now is the time to set up our process group and + * open up the pty slave. + */ +#ifdef USE_SYSV_PGRP +#if defined(CRAY) && (OSMAJORVERSION > 5) + (void) setsid(); +#else + (void) setpgrp(); +#endif +#endif /* USE_SYSV_PGRP */ + while (1) { + +#ifdef TIOCNOTTY + if (!no_dev_tty && (tty = open ("/dev/tty", O_RDWR)) >= 0) { + ioctl (tty, TIOCNOTTY, (char *) NULL); + close (tty); + } +#endif /* TIOCNOTTY */ + if ((tty = open(ttydev, O_RDWR, 0)) >= 0) { +#if defined(CRAY) && defined(TCSETCTTY) + /* make /dev/tty work */ + ioctl(tty, TCSETCTTY, 0); +#endif +#ifdef USE_SYSV_PGRP + /* We need to make sure that we are acutally + * the process group leader for the pty. If + * we are, then we should now be able to open + * /dev/tty. + */ + if ((i = open("/dev/tty", O_RDWR, 0)) >= 0) { + /* success! */ + close(i); + break; + } +#else /* USE_SYSV_PGRP */ + break; +#endif /* USE_SYSV_PGRP */ + } + +#ifdef TIOCSCTTY + ioctl(tty, TIOCSCTTY, 0); +#endif + /* let our master know that the open failed */ + handshake.status = PTY_BAD; + handshake.error = errno; + strcpy(handshake.buffer, ttydev); + write(cp_pipe[1], (char *) &handshake, + sizeof(handshake)); + + /* get reply from parent */ + i = read(pc_pipe[0], (char *) &handshake, + sizeof(handshake)); + if (i <= 0) { + /* parent terminated */ + exit(1); + } + + if (handshake.status == PTY_NOMORE) { + /* No more ptys, let's shutdown. */ + exit(1); + } + + /* We have a new pty to try */ + free(ttydev); + ttydev = malloc((unsigned) + (strlen(handshake.buffer) + 1)); + strcpy(ttydev, handshake.buffer); + } + + /* use the same tty name that everyone else will use + ** (from ttyname) + */ + if (ptr = ttyname(tty)) + { + /* it may be bigger */ + ttydev = realloc (ttydev, (unsigned) (strlen(ptr) + 1)); + (void) strcpy(ttydev, ptr); + } +#if defined(SYSV) && defined(SYSV386) + } /* end of IsPts else clause */ +#endif /* SYSV && SYSV386 */ + +#endif /* USE_HANDSHAKE -- from near fork */ + +#ifdef USE_TTY_GROUP + { +#include <grp.h> /* R6 update */ + struct group *ttygrp; + if (ttygrp = getgrnam("tty")) { + /* change ownership of tty to real uid, "tty" gid */ + chown (ttydev, screen->uid, ttygrp->gr_gid); + chmod (ttydev, 0620); + } + else { + /* change ownership of tty to real group and user id */ + chown (ttydev, screen->uid, screen->gid); + chmod (ttydev, 0622); + } + endgrent(); + } +#else /* else !USE_TTY_GROUP */ + /* change ownership of tty to real group and user id */ + chown (ttydev, screen->uid, screen->gid); + + /* change protection of tty */ + chmod (ttydev, 0622); +#endif /* USE_TTY_GROUP */ + + /* + * set up the tty modes + */ + { +/* +#ifdef USE_SYSV_TERMIO +*/ +#if defined(USE_ANY_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS) +#if defined(umips) || defined(CRAY) || defined(linux) + /* If the control tty had its modes screwed around with, + eg. by lineedit in the shell, or emacs, etc. then tio + will have bad values. Let's just get termio from the + new tty and tailor it. */ + if (ioctl (tty, TCGETA, &tio) == -1) + SysError (ERROR_TIOCGETP); + tio.c_lflag |= ECHOE; +#endif /* umips */ + /* Now is also the time to change the modes of the + * child pty. + */ + /* input: nl->nl, don't ignore cr, cr->nl */ + tio.c_iflag &= ~(INLCR|IGNCR); + tio.c_iflag |= ICRNL; + /* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */ + tio.c_oflag &= + ~(OCRNL|ONLRET|NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY); + tio.c_oflag |= ONLCR; +#ifdef OPOST + tio.c_oflag |= OPOST; +#endif /* OPOST */ +#ifdef BAUD_0 + /* baud rate is 0 (don't care) */ + tio.c_cflag &= ~(CBAUD); +#else /* !BAUD_0 */ + /* baud rate is 9600 (nice default) */ + tio.c_cflag &= ~(CBAUD); + tio.c_cflag |= B9600; +#endif /* !BAUD_0 */ + /* enable signals, canonical processing (erase, kill, etc), + ** echo + */ + tio.c_lflag |= ISIG|ICANON|ECHO; + /* reset EOL to defalult value */ + tio.c_cc[VEOL] = '@' & 0x3f; /* '^@' */ + /* certain shells (ksh & csh) change EOF as well */ + tio.c_cc[VEOF] = 'D' & 0x3f; /* '^D' */ + +#define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value; + if (override_tty_modes) { + /* sysv-specific */ + TMODE (XTTYMODE_intr, tio.c_cc[VINTR]); + TMODE (XTTYMODE_quit, tio.c_cc[VQUIT]); + TMODE (XTTYMODE_erase, tio.c_cc[VERASE]); + TMODE (XTTYMODE_kill, tio.c_cc[VKILL]); + TMODE (XTTYMODE_eof, tio.c_cc[VEOF]); + TMODE (XTTYMODE_eol, tio.c_cc[VEOL]); +#ifdef VSWTCH + TMODE (XTTYMODE_swtch, d_tio.c_cc[VSWTCH]); +#endif +#ifdef TIOCSLTC + /* both SYSV and BSD have 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 + } +#undef TMODE + + if (ioctl (tty, TCSETA, &tio) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETP); +#ifdef TIOCSLTC +#ifndef hpux + if (ioctl (tty, TIOCSLTC, <c) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCSETC); +#endif +#endif /* TIOCSLTC */ +#ifdef TIOCLSET + if (ioctl (tty, TIOCLSET, (char *)&lmode) == -1) + HsSysError(cp_pipe[1], ERROR_TIOCLSET); +#endif /* TIOCLSET */ +#else /* USE_SYSV_TERMIO */ + sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW); + sg.sg_flags |= ECHO | CRMOD; + /* make sure speed is set on pty so that editors work right*/ + sg.sg_ispeed = B9600; + sg.sg_ospeed = B9600; + /* reset t_brkc to default value */ + tc.t_brkc = -1; +#ifdef sony + if (screen->input_eight_bits) + lmode |= LPASS8; + else + lmode &= ~(LPASS8); + jmode &= ~KM_KANJI; +#endif /* sony */ + +#define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value; + 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); + /* both SYSV and BSD have 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); + } +#undef TMODE + + if (ioctl (tty, TIOCSETP, (char *)&sg) == -1) + HsSysError (cp_pipe[1], ERROR_TIOCSETP); +#ifndef hpux + if (ioctl (tty, TIOCSETC, (char *)&tc) == -1) + HsSysError (cp_pipe[1], ERROR_TIOCSETC); +#endif + if (ioctl (tty, TIOCSETD, (char *)&discipline) == -1) + HsSysError (cp_pipe[1], ERROR_TIOCSETD); + if (ioctl (tty, TIOCSLTC, (char *)<c) == -1) + HsSysError (cp_pipe[1], ERROR_TIOCSLTC); + if (ioctl (tty, TIOCLSET, (char *)&lmode) == -1) + HsSysError (cp_pipe[1], ERROR_TIOCLSET); +#ifdef sony + if (ioctl (tty, TIOCKSET, (char *)&jmode) == -1) + HsSysError (cp_pipe[1], ERROR_TIOCKSET); + if (ioctl (tty, TIOCKSETC, (char *)&jtc) == -1) + HsSysError (cp_pipe[1], ERROR_TIOCKSETC); +#endif /* sony */ +#endif /* !USE_SYSV_TERMIO */ +#if defined(TIOCCONS) || defined(SRIOCSREDIR) + if (Console) { +#ifdef TIOCCONS + int on = 1; + if (ioctl (tty, TIOCCONS, (char *)&on) == -1) + fprintf(stderr, "%s: cannot open console\n", + xgterm_name); +#endif +#ifdef SRIOCSREDIR + int fd = open("/dev/console",O_RDWR); + if (fd == -1 || ioctl (fd, SRIOCSREDIR, tty) == -1) + fprintf(stderr, "%s: cannot open console\n", + xgterm_name); + (void) close (fd); +#endif + } +#endif /* TIOCCONS */ + } + + signal (SIGCHLD, SIG_DFL); +#ifdef USE_SYSV_SIGHUP + /* watch out for extra shells (I don't understand either) */ + signal (SIGHUP, SIG_DFL); +#else + signal (SIGHUP, SIG_IGN); +#endif + /* restore various signals to their defaults */ + signal (SIGINT, SIG_DFL); + signal (SIGQUIT, SIG_DFL); + signal (SIGTERM, SIG_DFL); + + /* copy the environment before Setenving */ + for (i = 0 ; environ [i] != NULL ; i++) + ; + /* compute number of Setenv() calls below */ + envsize = 1; /* (NULL terminating entry) */ + envsize += 3; /* TERM, WINDOWID, DISPLAY */ +#ifdef UTMP + envsize += 1; /* LOGNAME */ +#endif /* UTMP */ +#ifdef USE_SYSV_ENVVARS +#ifndef TIOCSWINSZ /* window size not stored in driver? */ + envsize += 2; /* COLUMNS, LINES */ +#endif /* TIOCSWINSZ */ +#ifdef UTMP + envsize += 2; /* HOME, SHELL */ +#endif /* UTMP */ +#else /* USE_SYSV_ENVVARS */ + envsize += 1; /* TERMCAP */ +#endif /* USE_SYSV_ENVVARS */ + envnew = (char **) calloc ((unsigned) i + envsize, sizeof(char *)); + memmove( (char *)envnew, (char *)environ, i * sizeof(char *)); + environ = envnew; + Setenv ("TERM=", TermName); + if(!TermName) + *newtc = 0; + + sprintf (buf, "%lu", + ((unsigned long) XtWindow (XtParent(term)))); + Setenv ("WINDOWID=", buf); + /* put the display into the environment of the shell*/ + Setenv ("DISPLAY=", XDisplayString (screen->display)); + + signal(SIGTERM, SIG_DFL); + + /* this is the time to go and set up stdin, out, and err + */ + { +#if defined(CRAY) && (OSMAJORVERSION >= 6) + (void) close(tty); + (void) close(0); + + if (open ("/dev/tty", O_RDWR)) { + fprintf(stderr, "cannot open /dev/tty\n"); + exit(1); + } + (void) close(1); + (void) close(2); + dup(0); + dup(0); +#else + /* dup the tty */ + for (i = 0; i <= 2; i++) + if (i != tty) { + (void) close(i); + (void) dup(tty); + } + +#ifndef ATT + /* and close the tty */ + if (tty > 2) + (void) close(tty); +#endif +#endif /* CRAY */ + } + +#ifndef USE_SYSV_PGRP +#ifdef TIOCSCTTY + setsid(); + ioctl(0, TIOCSCTTY, 0); +#endif + ioctl(0, TIOCSPGRP, (char *)&pgrp); + setpgrp(0,0); + close(open(ttydev, O_WRONLY, 0)); + setpgrp (0, pgrp); +#endif /* !USE_SYSV_PGRP */ + +#ifdef UTMP + pw = getpwuid(screen->uid); + if (pw && pw->pw_name) + Setenv ("LOGNAME=", pw->pw_name); /* for POSIX */ +#ifdef USE_SYSV_UTMP + /* Set up our utmp entry now. We need to do it here + ** for the following reasons: + ** - It needs to have our correct process id (for + ** login). + ** - If our parent was to set it after the fork(), + ** it might make it out before we need it. + ** - We need to do it before we go and change our + ** user and group id's. + */ +#ifdef CRAY +#define PTYCHARLEN 4 +#else +#define PTYCHARLEN 2 +#endif + + (void) setutent (); + /* set up entry to search for */ + ptyname = ttydev; + (void) strncpy(utmp.ut_id,ptyname + strlen(ptyname)-PTYCHARLEN, + sizeof (utmp.ut_id)); + utmp.ut_type = DEAD_PROCESS; + + /* position to entry in utmp file */ + (void) getutid(&utmp); + + /* set up the new entry */ + utmp.ut_type = USER_PROCESS; +#ifndef linux + utmp.ut_exit.e_exit = 2; +#endif + (void) strncpy(utmp.ut_user, + (pw && pw->pw_name) ? pw->pw_name : "????", + sizeof(utmp.ut_user)); + + (void)strncpy(utmp.ut_id, ptyname + strlen(ptyname)-PTYCHARLEN, + sizeof(utmp.ut_id)); + (void) strncpy (utmp.ut_line, + ptyname + strlen("/dev/"), sizeof (utmp.ut_line)); + +#ifdef HAS_UTMP_UT_HOST + (void) strncpy(buf, DisplayString(screen->display), + sizeof(buf)); +#ifndef linux /* R6 update */ + { + char *disfin = strrchr(buf, ':'); + if (disfin) + *disfin = '\0'; + } +#endif /* R6 update */ + (void) strncpy(utmp.ut_host, buf, sizeof(utmp.ut_host)); +#endif + (void) strncpy(utmp.ut_name, pw->pw_name, + sizeof(utmp.ut_name)); + + utmp.ut_pid = getpid(); +#ifdef SVR4 + utmp.ut_session = getsid(0); + utmp.ut_xtime = time ((Time_t *) 0); + utmp.ut_tv.tv_usec = 0; +#else + utmp.ut_time = time ((Time_t *) 0); +#endif + + /* write out the entry */ + if (!resource.utmpInhibit) + (void) pututline(&utmp); +#ifdef WTMP +#ifdef SVR4 + if (term->misc.login_shell) + updwtmpx(WTMPX_FILE, &utmp); +#else + if (term->misc.login_shell && + (i = open(etc_wtmp, O_WRONLY|O_APPEND)) >= 0) { + write(i, (char *)&utmp, sizeof(struct utmp)); + close(i); + } +#endif +#endif + /* close the file */ + (void) endutent(); + +#else /* USE_SYSV_UTMP */ + /* We can now get our ttyslot! We can also set the initial + * UTMP entry. + */ + tslot = ttyslot(); + added_utmp_entry = False; + { + if (pw && !resource.utmpInhibit && + (i = open(etc_utmp, O_WRONLY)) >= 0) { + memset((char *)&utmp, 0, sizeof(struct utmp)); + (void) strncpy(utmp.ut_line, + ttydev + strlen("/dev/"), + sizeof(utmp.ut_line)); + (void) strncpy(utmp.ut_name, pw->pw_name, + sizeof(utmp.ut_name)); +#ifdef HAS_UTMP_UT_HOST + (void) strncpy(utmp.ut_host, + XDisplayString (screen->display), + sizeof(utmp.ut_host)); +#endif + time(&utmp.ut_time); + lseek(i, (long)(tslot * sizeof(struct utmp)), 0); + write(i, (char *)&utmp, sizeof(struct utmp)); + close(i); + added_utmp_entry = True; +#ifdef WTMP + if (term->misc.login_shell && + (i = open(etc_wtmp, O_WRONLY|O_APPEND)) >= 0) { + int status; + status = write(i, (char *)&utmp, + sizeof(struct utmp)); + status = close(i); + } +#endif /* WTMP */ +#ifdef MNX_LASTLOG + if (term->misc.login_shell && + (i = open(_U_LASTLOG, O_WRONLY)) >= 0) { + lseek(i, (long)(screen->uid * + sizeof (struct utmp)), 0); + write(i, (char *)&utmp, + sizeof (struct utmp)); + close(i); + } +#endif /* MNX_LASTLOG */ +#ifdef LASTLOG + if (term->misc.login_shell && + (i = open(etc_lastlog, O_WRONLY)) >= 0) { + memset((char *)&lastlog, 0, + sizeof (struct lastlog)); + (void) strncpy(lastlog.ll_line, ttydev + + sizeof("/dev"), + sizeof (lastlog.ll_line)); + (void) strncpy(lastlog.ll_host, + XDisplayString (screen->display), + sizeof (lastlog.ll_host)); + time(&lastlog.ll_time); + lseek(i, (long)(screen->uid * + sizeof (struct lastlog)), 0); + write(i, (char *)&lastlog, + sizeof (struct lastlog)); + close(i); + } +#endif /* LASTLOG */ + } else + tslot = -tslot; + } + + /* Let's pass our ttyslot to our parent so that it can + * clean up after us. + */ +#ifdef USE_HANDSHAKE + handshake.tty_slot = tslot; +#endif /* USE_HANDSHAKE */ +#endif /* USE_SYSV_UTMP */ + +#ifdef USE_HANDSHAKE + /* Let our parent know that we set up our utmp entry + * so that it can clean up after us. + */ + handshake.status = UTMP_ADDED; + handshake.error = 0; + strcpy(handshake.buffer, ttydev); + (void)write(cp_pipe[1], (char *)&handshake, sizeof(handshake)); +#endif /* USE_HANDSHAKE */ +#endif/* UTMP */ + + (void) setgid (screen->gid); +#ifdef HAS_BSD_GROUPS + if (geteuid() == 0 && pw) + initgroups (pw->pw_name, pw->pw_gid); +#endif + (void) setuid (screen->uid); + +#ifdef USE_HANDSHAKE + /* mark the pipes as close on exec */ + fcntl(cp_pipe[1], F_SETFD, 1); + fcntl(pc_pipe[0], F_SETFD, 1); + + /* We are at the point where we are going to + * exec our shell (or whatever). Let our parent + * know we arrived safely. + */ + handshake.status = PTY_GOOD; + handshake.error = 0; + (void)strcpy(handshake.buffer, ttydev); + (void)write(cp_pipe[1], (char *)&handshake, sizeof(handshake)); + + if (waiting_for_initial_map) { + i = read (pc_pipe[0], (char *) &handshake, + sizeof(handshake)); + if (i != sizeof(handshake) || + handshake.status != PTY_EXEC) { + /* some very bad problem occurred */ + exit (ERROR_PTY_EXEC); + } + if(handshake.rows > 0 && handshake.cols > 0) { + screen->max_row = handshake.rows; + screen->max_col = handshake.cols; +#if defined(sun) && !defined(SVR4) +#ifdef TIOCSSIZE + ts.ts_lines = screen->max_row + 1; + ts.ts_cols = screen->max_col + 1; +#endif /* TIOCSSIZE */ +#else /* !sun */ +#ifdef TIOCSWINSZ + ws.ws_row = screen->max_row + 1; + ws.ws_col = screen->max_col + 1; + ws.ws_xpixel = FullWidth(screen); + ws.ws_ypixel = FullHeight(screen); +#endif /* TIOCSWINSZ */ +#endif /* sun else !sun */ + } + } +#endif /* USE_HANDSHAKE */ + +#ifdef USE_SYSV_ENVVARS + sprintf (numbuf, "%d", screen->max_col + 1); + Setenv("COLUMNS=", numbuf); + sprintf (numbuf, "%d", screen->max_row + 1); + Setenv("LINES=", numbuf); +#ifdef UTMP + if (pw) { /* SVR4 doesn't provide these */ + if (!getenv("HOME")) + Setenv("HOME=", pw->pw_dir); + if (!getenv("SHELL")) + Setenv("SHELL=", pw->pw_shell); + } +#endif /* UTMP */ +#else /* USE_SYSV_ENVVAR */ + if(!screen->TekEmu) { + strcpy (termcap, newtc); + resize (screen, TermName, termcap, newtc); + } + if (term->misc.titeInhibit) { + remove_termcap_entry (newtc, ":ti="); + remove_termcap_entry (newtc, ":te="); + } + /* + * work around broken termcap entries */ + if (resource.useInsertMode) { + remove_termcap_entry (newtc, ":ic="); + /* don't get duplicates */ + remove_termcap_entry (newtc, ":im="); + remove_termcap_entry (newtc, ":ei="); + remove_termcap_entry (newtc, ":mi"); + strcat (newtc, ":im=\\E[4h:ei=\\E[4l:mi:"); + } + Setenv ("TERMCAP=", newtc); +#endif /* USE_SYSV_ENVVAR */ + + + /* need to reset after all the ioctl bashing we did above */ +#if defined(sun) && !defined(SVR4) +#ifdef TIOCSSIZE + ioctl (0, TIOCSSIZE, &ts); +#endif /* TIOCSSIZE */ +#else /* not sun */ +#ifdef TIOCSWINSZ + ioctl (0, TIOCSWINSZ, (char *)&ws); +#endif /* TIOCSWINSZ */ +#endif /* sun */ + + signal(SIGHUP, SIG_DFL); + if (command_to_exec) { + execvp(*command_to_exec, command_to_exec); + /* print error message on screen */ + fprintf(stderr, "%s: Can't execvp %s\n", xgterm_name, + *command_to_exec); + } + +#ifdef USE_SYSV_SIGHUP + /* fix pts sh hanging around */ + signal (SIGHUP, SIG_DFL); +#endif +#ifdef _IBMR2 + /* The AIX 3.1 "rsh" command turns off INTR in sigmask. We + must turn it back on. No you cannot solve this by calling + signal(SIGINT,SIG_DFL). Tried. + -- Dan Greening dgreen@ibm.com */ + { + extern int sigprocmask(); + int mask; + sigset_t set, oset; + + sigemptyset(&set); + sigprocmask(SIG_SETMASK,&set,&oset); + } +#endif /* _IBMR2 */ + +#ifdef UTMP + if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) && + ((pw == NULL && (pw = getpwuid(screen->uid)) == NULL) || + *(ptr = pw->pw_shell) == 0)) +#else /* UTMP */ + if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) && + ((pw = getpwuid(screen->uid)) == NULL || + *(ptr = pw->pw_shell) == 0)) +#endif /* UTMP */ + ptr = "/bin/sh"; + if(shname = strrchr(ptr, '/')) + shname++; + else + shname = ptr; + shname_minus = malloc(strlen(shname) + 2); + (void) strcpy(shname_minus, "-"); + (void) strcat(shname_minus, shname); +#ifndef USE_SYSV_TERMIO + ldisc = XStrCmp("csh", shname + strlen(shname) - 3) == 0 ? + NTTYDISC : 0; + ioctl(0, TIOCSETD, (char *)&ldisc); +#endif /* !USE_SYSV_TERMIO */ + +#ifdef USE_LOGIN_DASH_P + if (term->misc.login_shell && pw && added_utmp_entry) + execl (bin_login, "login", "-p", "-f", pw->pw_name, 0); +#endif + execlp (ptr, (term->misc.login_shell ? shname_minus : shname), + 0); + + /* Exec failed. */ + fprintf (stderr, "%s: Could not exec %s!\n", xgterm_name, ptr); + (void) sleep(5); + exit(ERROR_EXEC); + } /* end if in child after fork */ + +#ifdef USE_HANDSHAKE + /* Parent process. Let's handle handshaked requests to our + * child process. + */ + + /* close childs's sides of the pipes */ + close (cp_pipe[1]); + close (pc_pipe[0]); + + for (done = 0; !done; ) { + if (read(cp_pipe[0], (char *) &handshake, sizeof(handshake)) <= 0) { + /* Our child is done talking to us. If it terminated + * due to an error, we will catch the death of child + * and clean up. + */ + break; + } + + switch(handshake.status) { + case PTY_GOOD: + /* Success! Let's free up resources and + * continue. + */ + done = 1; + break; + + case PTY_BAD: + /* The open of the pty failed! Let's get + * another one. + */ + (void) close(screen->respond); +#ifdef NEW_GET_PTY + if (get_pty(&screen->respond, XDisplayString(screen->display))) { +#else + if (get_pty(&screen->respond)) { +#endif + /* no more ptys! */ + (void) fprintf(stderr, + "%s: child process can find no available ptys\n", + xgterm_name); + handshake.status = PTY_NOMORE; + write(pc_pipe[1], (char *) &handshake, sizeof(handshake)); + exit (ERROR_PTYS); + } + handshake.status = PTY_NEW; + (void) strcpy(handshake.buffer, ttydev); + 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: + /* The utmp entry was set by our slave. Remember + * this so that we can reset it later. + */ + added_utmp_entry = True; +#ifndef USE_SYSV_UTMP + tslot = handshake.tty_slot; +#endif /* USE_SYSV_UTMP */ + free(ttydev); + ttydev = malloc((unsigned) strlen(handshake.buffer) + 1); + strcpy(ttydev, handshake.buffer); + break; + default: + fprintf(stderr, "%s: unexpected handshake status %d\n", + xgterm_name, handshake.status); + } + } + /* close our sides of the pipes */ + if (!waiting_for_initial_map) { + close (cp_pipe[0]); + close (pc_pipe[1]); + } +#endif /* USE_HANDSHAKE */ + } /* end if no slave */ + + /* + * still in parent (xgterm process) + */ + +#ifdef USE_SYSV_SIGHUP + /* hung sh problem? */ + signal (SIGHUP, SIG_DFL); +#else + signal (SIGHUP,SIG_IGN); +#endif + +/* + * Unfortunately, System V seems to have trouble divorcing the child process + * from the process group of xgterm. This is a problem because hitting the + * INTR or QUIT characters on the keyboard will cause xgterm to go away if we + * don't ignore the signals. This is annoying. + */ + +#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) + signal (SIGINT, SIG_IGN); + +#ifndef SYSV + /* hung shell problem */ + signal (SIGQUIT, SIG_IGN); +#endif + signal (SIGTERM, SIG_IGN); +#else /* else is bsd or has job control */ +#ifdef SYSV + /* if we were spawned by a jobcontrol smart shell (like ksh or csh), + * then our pgrp and pid will be the same. If we were spawned by + * a jobcontrol dumb shell (like /bin/sh), then we will be in our + * parent's pgrp, and we must ignore keyboard signals, or we will + * tank on everything. + */ + 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 /* SYSV */ + signal (SIGINT, Exit); + signal (SIGQUIT, Exit); + signal (SIGTERM, Exit); + signal (SIGPIPE, Exit); +#endif /* SYSV */ +#endif /* USE_SYSV_SIGNALS and not SIGTSTP */ + + return 0; +} /* end spawn */ +#endif + + + +SIGNAL_T +Exit(n) + int n; +{ + register TScreen *screen = &term->screen; + int pty = term->screen.respond; /* file descriptor of pty */ +#ifdef UTMP +#ifdef USE_SYSV_UTMP +#ifdef SVR4 + struct utmpx utmp; + struct utmpx *utptr; +#else + struct utmp utmp; + struct utmp *utptr; +#endif + char *ptyname; +#if defined(WTMP) && !defined(SVR4) + int fd; /* for /etc/wtmp */ + int i; +#endif + +#ifdef PUCC_PTYD + closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), Ptyfd); +#endif /* PUCC_PTYD */ + + /* cleanup the utmp entry we forged earlier */ + if (!resource.utmpInhibit +#ifdef USE_HANDSHAKE /* without handshake, no way to know */ + && added_utmp_entry +#endif /* USE_HANDSHAKE */ + ) { + ptyname = ttydev; + utmp.ut_type = USER_PROCESS; + (void) strncpy(utmp.ut_id, ptyname + strlen(ptyname) - PTYCHARLEN, + sizeof(utmp.ut_id)); + (void) setutent(); + utptr = getutid(&utmp); + /* write it out only if it exists, and the pid's match */ + if (utptr && (utptr->ut_pid == screen->pid)) { + utptr->ut_type = DEAD_PROCESS; +#ifdef SVR4 + utmp.ut_session = getsid(0); + utmp.ut_xtime = time ((Time_t *) 0); + utmp.ut_tv.tv_usec = 0; +#else + utptr->ut_time = time((Time_t *) 0); +#endif + (void) pututline(utptr); +#ifdef WTMP +#ifdef SVR4 + updwtmpx(WTMPX_FILE, &utmp); +#else + /* set wtmp entry if wtmp file exists */ + if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { + i = write(fd, utptr, sizeof(utmp)); + i = close(fd); + } +#endif +#endif + + } + (void) endutent(); + } +#else /* not USE_SYSV_UTMP */ + register int wfd; + register int i; + struct utmp utmp; + + if (!resource.utmpInhibit && added_utmp_entry && + (!am_slave && tslot > 0 && (wfd = open(etc_utmp, O_WRONLY)) >= 0)){ + memset((char *)&utmp, 0, sizeof(struct utmp)); + lseek(wfd, (long)(tslot * sizeof(struct utmp)), 0); + write(wfd, (char *)&utmp, sizeof(struct utmp)); + close(wfd); +#ifdef WTMP + if (term->misc.login_shell && + (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { + (void) strncpy(utmp.ut_line, ttydev + + sizeof("/dev"), sizeof (utmp.ut_line)); + time(&utmp.ut_time); + i = write(wfd, (char *)&utmp, sizeof(struct utmp)); + i = close(wfd); + } +#endif /* WTMP */ + } +#endif /* USE_SYSV_UTMP */ +#endif /* UTMP */ + close(pty); /* close explicitly to avoid race with slave side */ +#ifdef ALLOWLOGGING + if(screen->logging) + CloseLog(screen); +#endif + + if (!am_slave) { + /* restore ownership of tty and pty */ + chown (ttydev, 0, 0); +#ifndef sgi + chown (ptydev, 0, 0); +#endif /* !sgi */ + + /* restore modes of tty and pty */ + chmod (ttydev, 0666); +#ifndef sgi + chmod (ptydev, 0666); +#endif /* !sgi */ + } + exit(n); + SIGNAL_RETURN; +} + +/* ARGSUSED */ +resize(screen, TermName, oldtc, newtc) +TScreen *screen; +char *TermName; +register char *oldtc, *newtc; +{ +#ifndef USE_SYSV_ENVVARS + register char *ptr1, *ptr2; + register int i; + register int li_first = 0; + register char *temp; + + if ((ptr1 = strindex (oldtc, "co#")) == NULL){ + strcat (oldtc, "co#80:"); + ptr1 = strindex (oldtc, "co#"); + } + if ((ptr2 = strindex (oldtc, "li#")) == NULL){ + strcat (oldtc, "li#24:"); + ptr2 = strindex (oldtc, "li#"); + } + if(ptr1 > ptr2) { + li_first++; + temp = ptr1; + ptr1 = ptr2; + ptr2 = temp; + } + ptr1 += 3; + ptr2 += 3; + strncpy (newtc, oldtc, i = ptr1 - oldtc); + newtc += i; + sprintf (newtc, "%d", li_first ? screen->max_row + 1 : + screen->max_col + 1); + newtc += strlen(newtc); + ptr1 = strchr(ptr1, ':'); + strncpy (newtc, ptr1, i = ptr2 - ptr1); + newtc += i; + sprintf (newtc, "%d", li_first ? screen->max_col + 1 : + screen->max_row + 1); + ptr2 = strchr(ptr2, ':'); + strcat (newtc, ptr2); +#endif /* USE_SYSV_ENVVARS */ +} + +/* + * Does a non-blocking wait for a child process. If the system + * doesn't support non-blocking wait, do nothing. + * Returns the pid of the child, or 0 or -1 if none or error. + */ +int +nonblocking_wait() +{ +#ifdef USE_POSIX_WAIT + pid_t pid; + + pid = waitpid(-1, NULL, WNOHANG); +#else /* USE_POSIX_WAIT */ +#if defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) + /* cannot do non-blocking wait */ + int pid = 0; +#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */ + /* union wait status; */ int status; + register int pid; + + pid = wait3 (&status, WNOHANG, (struct rusage *)NULL); +#endif /* defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) */ +#endif /* USE_POSIX_WAIT else */ + + return pid; +} + +/* ARGSUSED */ +static SIGNAL_T reapchild (n) + int n; +{ + int pid; + + pid = wait(NULL); + +#ifdef USE_SYSV_SIGNALS + /* cannot re-enable signal before waiting for child + because then SVR4 loops. Sigh. HP-UX 9.01 too. */ + (void) signal(SIGCHLD, reapchild); +#endif + + do { + if (pid == term->screen.pid) { +#ifdef DEBUG + if (debug) fputs ("Exiting\n", stderr); +#endif + Cleanup (0); + } + } while ( (pid=nonblocking_wait()) > 0); + + SIGNAL_RETURN; +} + +/* VARARGS1 */ +consolepr(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9) +char *fmt; +{ + extern char *SysErrorMsg(); + int oerrno; + int f; + char buf[ BUFSIZ ]; + + oerrno = errno; + strcpy(buf, "new-xgterm: "); + sprintf(buf+strlen(buf), fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9); + strcat(buf, ": "); + strcat(buf, SysErrorMsg (oerrno)); + strcat(buf, "\n"); + f = open("/dev/console",O_WRONLY); + write(f, buf, strlen(buf)); + close(f); +#ifdef TIOCNOTTY + if ((f = open("/dev/tty", 2)) >= 0) { + ioctl(f, TIOCNOTTY, (char *)NULL); + close(f); + } +#endif /* TIOCNOTTY */ +} + + +remove_termcap_entry (buf, str) + char *buf; + char *str; +{ + register char *strinbuf; + + strinbuf = strindex (buf, str); + if (strinbuf) { + register char *colonPtr = strchr(strinbuf+1, ':'); + if (colonPtr) { + while (*colonPtr) { + *strinbuf++ = *colonPtr++; /* copy down */ + } + *strinbuf = '\0'; + } else { + strinbuf[1] = '\0'; + } + } + return 0; +} + +/* + * parse_tty_modes accepts lines of the following form: + * + * [SETTING] ... + * + * where setting consists of the words in the modelist followed by a character + * or ^char. + */ +static int parse_tty_modes (s, modelist) + char *s; + struct _xttymodes *modelist; +{ + struct _xttymodes *mp; + int c; + int count = 0; + + while (1) { + while (*s && isascii(*s) && isspace(*s)) s++; + if (!*s) return count; + + for (mp = modelist; mp->name; mp++) { + if (strncmp (s, mp->name, mp->len) == 0) break; + } + if (!mp->name) return -1; + + s += mp->len; + while (*s && isascii(*s) && isspace(*s)) s++; + if (!*s) return -1; + + if (*s == '^') { + s++; + c = ((*s == '?') ? 0177 : *s & 31); /* keep control bits */ + } else { + c = *s; + } + mp->value = c; + mp->set = 1; + count++; + s++; + } +} + + +int GetBytesAvailable (fd) + int fd; +{ +#ifdef FIONREAD + static long arg; + ioctl (fd, FIONREAD, (char *) &arg); + return (int) arg; +#else +#ifdef 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 +} + +/* Utility function to try to hide system differences from + everybody who used to call killpg() */ + +int +kill_process_group(pid, sig) + int pid; + int sig; +{ +#ifndef X_NOT_POSIX + return kill (-pid, sig); +#else +#if defined(SVR4) || defined(SYSV) + return kill (-pid, sig); +#else + return killpg (pid, sig); +#endif +#endif +} |