home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / m / mxterm.zip / mxterm / main.c < prev    next >
C/C++ Source or Header  |  1992-10-18  |  67KB  |  2,476 lines

  1. #ifndef lint
  2. static char rcs_id[] = "$XConsortium: main.c,v 1.144 89/12/20 21:39:07 jim Exp $";
  3. #endif    /* lint */
  4.  
  5. /*
  6.  *                  W A R N I N G
  7.  * 
  8.  * If you think you know what all of this code is doing, you are probably
  9.  * very mistaken.  There be serious and nasty dragons here.
  10.  *
  11.  * This client is *not* to be taken as an example of how to write X Toolkit
  12.  * applications.  It is in need of a substantial rewrite, ideally to create
  13.  * a generic tty widget with several different parsing widgets so that you 
  14.  * can plug 'em together any way you want.  Don't hold your breath, though....
  15.  */
  16.  
  17. #include <X11/copyright.h>
  18.  
  19. /***********************************************************
  20. Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
  21. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  22.  
  23.                         All Rights Reserved
  24.  
  25. Permission to use, copy, modify, and distribute this software and its 
  26. documentation for any purpose and without fee is hereby granted, 
  27. provided that the above copyright notice appear in all copies and that
  28. both that copyright notice and this permission notice appear in 
  29. supporting documentation, and that the names of Digital or MIT not be
  30. used in advertising or publicity pertaining to distribution of the
  31. software without specific, written prior permission.  
  32.  
  33. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  34. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  35. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  36. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  37. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  38. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  39. SOFTWARE.
  40.  
  41. ******************************************************************/
  42.  
  43.  
  44. /* main.c */
  45.  
  46. #include <X11/Xos.h>
  47. #include <X11/Xlib.h>
  48. #include <X11/cursorfont.h>
  49. #include <pwd.h>
  50. #include <ctype.h>
  51.  
  52. #ifdef att
  53. #define USE_USG_PTYS
  54. #endif
  55.  
  56. #ifndef att
  57. #define USE_HANDSHAKE
  58. #endif
  59.  
  60. #include <sys/ioctl.h>
  61.  
  62. #ifdef SYSV
  63. #include <sys/termio.h>
  64. #ifdef USE_USG_PTYS            /* AT&T SYSV has no ptyio.h */
  65. #include <sys/stream.h>            /* get typedef used in ptem.h */
  66. #include <sys/ptem.h>            /* get struct winsize */
  67. #include <sys/stropts.h>        /* for I_PUSH */
  68. #include <poll.h>            /* for POLLIN */
  69. #endif
  70. #include <sys/stat.h>
  71. #define USE_SYSV_TERMIO
  72. #define USE_SYSV_SIGNALS
  73. #define    USE_SYSV_PGRP
  74. #define USE_SYSV_ENVVARS        /* COLUMNS/LINES vs. TERMCAP */
  75. /*
  76.  * now get system-specific includes
  77.  */
  78. #ifdef CRAY
  79. #define HAS_UTMP_UT_HOST
  80. #define HAS_BSD_GROUPS
  81. #endif
  82. #ifdef macII
  83. #define HAS_UTMP_UT_HOST
  84. #define HAS_BSD_GROUPS
  85. #include <sys/ttychars.h>
  86. #undef USE_SYSV_ENVVARS
  87. #undef FIOCLEX
  88. #undef FIONCLEX
  89. #define setpgrp2 setpgrp
  90. #include <sgtty.h>
  91. #include <sys/resource.h>
  92. #endif
  93. #ifdef hpux
  94. #define HAS_BSD_GROUPS
  95. #include <sys/ptyio.h>
  96. #endif
  97. #endif /* SYSV */
  98.  
  99. #ifndef SYSV                /* BSD systems */
  100. #include <sgtty.h>
  101. #include <sys/resource.h>
  102. #define HAS_UTMP_UT_HOST
  103. #define HAS_BSD_GROUPS
  104. #endif    /* !SYSV */
  105.  
  106. #include <stdio.h>
  107. #include <errno.h>
  108. #include <setjmp.h>
  109.  
  110. #ifdef hpux
  111. #include <sys/utsname.h>
  112. #endif /* hpux */
  113.  
  114. #ifdef apollo
  115. #define ttyslot() 1
  116. #endif /* apollo */
  117.  
  118. #include <utmp.h>
  119. #ifdef LASTLOG
  120. #include <lastlog.h>
  121. #endif
  122. #include <sys/param.h>    /* for NOFILE */
  123.  
  124. #ifdef  PUCC_PTYD
  125. #include <local/openpty.h>
  126. int    Ptyfd;
  127. #endif /* PUCC_PTYD */
  128.  
  129. #ifndef UTMP_FILENAME
  130. #define UTMP_FILENAME "/etc/utmp"
  131. #endif
  132. #ifndef LASTLOG_FILENAME
  133. #define LASTLOG_FILENAME "/usr/adm/lastlog"  /* only on BSD systems */
  134. #endif
  135. #ifndef WTMP_FILENAME
  136. #if defined(SYSV)
  137. #define WTMP_FILENAME "/etc/wtmp"
  138. #else
  139. #define WTMP_FILENAME "/usr/adm/wtmp"
  140. #endif
  141. #endif
  142.  
  143. #include "ptyx.h"
  144. #include "data.h"
  145. #include "error.h"
  146. #include "main.h"
  147. #include "menu.h"
  148. #include <X11/StringDefs.h>
  149. #include <X11/Shell.h>
  150. #ifdef SIGTSTP
  151. #include <sys/wait.h>
  152. #ifdef hpux
  153. #include <sys/bsdtty.h>
  154. #endif
  155. #endif
  156.  
  157. #ifdef SIGNALRETURNSINT
  158. #define SIGNAL_T int
  159. #define SIGNAL_RETURN return 0
  160. #else
  161. #define SIGNAL_T void
  162. #define SIGNAL_RETURN return
  163. #endif
  164.  
  165. SIGNAL_T Exit();
  166. extern char *malloc();
  167. extern char *calloc();
  168. extern char *realloc();
  169. extern char *ttyname();
  170. extern char *getenv();
  171. extern char *strindex ();
  172. extern void exit();
  173. extern void bcopy();
  174. extern long lseek();
  175. extern void HandlePopupMenu();
  176.  
  177. int switchfb[] = {0, 2, 1, 3};
  178.  
  179. static SIGNAL_T reapchild ();
  180.  
  181. static Bool added_utmp_entry = False;
  182.  
  183. static char **command_to_exec;
  184.  
  185. Atom wm_delete_window;
  186.  
  187. static void DeleteWindow();
  188.  
  189. static void KeyboardMapping();
  190.  
  191.  
  192. XtActionsRec actionProcs[] = {
  193.     "DeleteWindow", DeleteWindow,
  194.     "KeyboardMapping", KeyboardMapping,
  195. };
  196.  
  197. #ifdef USE_SYSV_TERMIO
  198. /* The following structures are initialized in main() in order
  199. ** to eliminate any assumptions about the internal order of their
  200. ** contents.
  201. */
  202. static struct termio d_tio;
  203. #ifdef TIOCSLTC
  204. static struct ltchars d_ltc;
  205. #endif    /* TIOCSLTC */
  206. #ifdef TIOCLSET
  207. static unsigned int d_lmode;
  208. #endif    /* TIOCLSET */
  209. #else /* not USE_SYSV_TERMIO */
  210. static struct  sgttyb d_sg = {
  211.         0, 0, 0177, CKILL, EVENP|ODDP|ECHO|XTABS|CRMOD
  212. };
  213. static struct  tchars d_tc = {
  214.         CINTR, CQUIT, CSTART,
  215.         CSTOP, CEOF, CBRK,
  216. };
  217. static struct  ltchars d_ltc = {
  218.         CSUSP, CDSUSP, CRPRNT,
  219.         CFLUSH, CWERASE, CLNEXT
  220. };
  221. static int d_disipline = NTTYDISC;
  222. static long int d_lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
  223. #endif /* USE_SYSV_TERMIO */
  224.  
  225. static int parse_tty_modes ();
  226. /*
  227.  * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars
  228.  */
  229. static int override_tty_modes = 0;
  230. struct _xttymodes {
  231.     char *name;
  232.     int len;
  233.     int set;
  234.     char value;
  235. } ttymodelist[] = {
  236. { "intr", 4, 0, '\0' },            /* tchars.t_intrc ; VINTR */
  237. #define XTTYMODE_intr 0
  238. { "quit", 4, 0, '\0' },            /* tchars.t_quitc ; VQUIT */
  239. #define XTTYMODE_quit 1
  240. { "erase", 5, 0, '\0' },        /* sgttyb.sg_erase ; VERASE */
  241. #define XTTYMODE_erase 2
  242. { "kill", 4, 0, '\0' },            /* sgttyb.sg_kill ; VKILL */
  243. #define XTTYMODE_kill 3
  244. { "eof", 3, 0, '\0' },            /* tchars.t_eofc ; VEOF */
  245. #define XTTYMODE_eof 4
  246. { "eol", 3, 0, '\0' },            /* VEOL */
  247. #define XTTYMODE_eol 5
  248. { "swtch", 5, 0, '\0' },        /* VSWTCH */
  249. #define XTTYMODE_swtch 6
  250. { "start", 5, 0, '\0' },        /* tchars.t_startc */
  251. #define XTTYMODE_start 7
  252. { "stop", 4, 0, '\0' },            /* tchars.t_stopc */
  253. #define XTTYMODE_stop 8
  254. { "brk", 3, 0, '\0' },            /* tchars.t_brkc */
  255. #define XTTYMODE_brk 9
  256. { "susp", 4, 0, '\0' },            /* ltchars.t_suspc */
  257. #define XTTYMODE_susp 10
  258. { "dsusp", 5, 0, '\0' },        /* ltchars.t_dsuspc */
  259. #define XTTYMODE_dsusp 11
  260. { "rprnt", 5, 0, '\0' },        /* ltchars.t_rprntc */
  261. #define XTTYMODE_rprnt 12
  262. { "flush", 5, 0, '\0' },        /* ltchars.t_flushc */
  263. #define XTTYMODE_flush 13
  264. { "weras", 5, 0, '\0' },        /* ltchars.t_werasc */
  265. #define XTTYMODE_weras 14
  266. { "lnext", 5, 0, '\0' },        /* ltchars.t_lnextc */
  267. #define XTTYMODE_lnext 15
  268. #define NXTTYMODES 16
  269. };
  270.  
  271. #ifdef USE_SYSV_UTMP
  272. extern struct utmp *getutent();
  273. extern struct utmp *getutid();
  274. extern struct utmp *getutline();
  275. extern void pututline();
  276. extern void setutent();
  277. extern void endutent();
  278. extern void utmpname();
  279.  
  280. extern struct passwd *getpwent();
  281. extern struct passwd *getpwuid();
  282. extern struct passwd *getpwnam();
  283. extern void setpwent();
  284. extern void endpwent();
  285. extern struct passwd *fgetpwent();
  286. #else    /* not USE_SYSV_UTMP */
  287. static char etc_utmp[] = UTMP_FILENAME;
  288. #ifdef LASTLOG
  289. static char etc_lastlog[] = LASTLOG_FILENAME;
  290. #endif 
  291. #ifdef WTMP
  292. static char etc_wtmp[] = WTMP_FILENAME;
  293. #endif
  294. #endif    /* USE_SYSV_UTMP */
  295.  
  296. /*
  297.  * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
  298.  * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
  299.  * WTMP and LASTLOG.
  300.  */
  301. #ifdef USE_LOGIN_DASH_P
  302. #ifndef LOGIN_FILENAME
  303. #define LOGIN_FILENAME "/bin/login"
  304. #endif
  305. static char bin_login[] = LOGIN_FILENAME;
  306. #endif
  307.  
  308. static int inhibit;
  309. static char passedPty[2];    /* name if pty if slave */
  310.  
  311. #ifdef TIOCCONS
  312. static int Console;
  313. #endif    /* TIOCCONS */
  314. #ifndef USE_SYSV_UTMP
  315. static int tslot;
  316. #endif    /* USE_SYSV_UTMP */
  317. static jmp_buf env;
  318.  
  319. char *ProgramName;
  320. Boolean sunFunctionKeys;
  321.  
  322. static struct _resource {
  323.     char *xterm_name;
  324.     char *icon_geometry;
  325.     char *title;
  326.     char *icon_name;
  327.     char *term_name;
  328.     char *tty_modes;
  329.     Boolean utmpInhibit;
  330.     Boolean sunFunctionKeys;    /* %%% should be widget resource? */
  331.     Boolean wait_for_map;
  332. } resource;
  333.  
  334. /* used by VT (charproc.c) */
  335.  
  336. #define offset(field)    XtOffset(struct _resource *, field)
  337.  
  338. static XtResource application_resources[] = {
  339.     {"name", "Name", XtRString, sizeof(char *),
  340.     offset(xterm_name), XtRString, "xterm"},
  341.     {"iconGeometry", "IconGeometry", XtRString, sizeof(char *),
  342.     offset(icon_geometry), XtRString, (caddr_t) NULL},
  343.     {XtNtitle, XtCTitle, XtRString, sizeof(char *),
  344.     offset(title), XtRString, (caddr_t) NULL},
  345.     {XtNiconName, XtCIconName, XtRString, sizeof(char *),
  346.     offset(icon_name), XtRString, (caddr_t) NULL},
  347.     {"termName", "TermName", XtRString, sizeof(char *),
  348.     offset(term_name), XtRString, (caddr_t) NULL},
  349.     {"ttyModes", "TtyModes", XtRString, sizeof(char *),
  350.     offset(tty_modes), XtRString, (caddr_t) NULL},
  351.     {"utmpInhibit", "UtmpInhibit", XtRBoolean, sizeof (Boolean),
  352.     offset(utmpInhibit), XtRString, "false"},
  353.     {"sunFunctionKeys", "SunFunctionKeys", XtRBoolean, sizeof (Boolean),
  354.     offset(sunFunctionKeys), XtRString, "false"},
  355.     {"waitForMap", "WaitForMap", XtRBoolean, sizeof (Boolean),
  356.         offset(wait_for_map), XtRString, "false"},
  357. };
  358. #undef offset
  359.  
  360. /* Command line options table.  Only resources are entered here...there is a
  361.    pass over the remaining options after XtParseCommand is let loose. */
  362.  
  363. #ifdef MOTIF
  364. static char *fallback_resources[] = {
  365.     "MXTerm*mainMenu.labelString:  Main Options (no app-defaults)",
  366.     "MXTerm*vtMenu.labelString:  VT Options (no app-defaults)",
  367.     "MXTerm*fontMenu.labelString:  VT Fonts (no app-defaults)",
  368.     "MXTerm*tekMenu.labelString:  Tek Options (no app-defaults)",
  369.     NULL
  370. };
  371. #else
  372. static char *fallback_resources[] = {
  373.     "XTerm*SimpleMenu*menuLabel.vertSpace: 100",
  374.     "XTerm*SimpleMenu*HorizontalMargins: 16",
  375.     "XTerm*SimpleMenu*Sme.height: 16",
  376.     "XTerm*SimpleMenu*Cursor: left_ptr",
  377.     "XTerm*mainMenu.Label:  Main Options (no app-defaults)",
  378.     "XTerm*vtMenu.Label:  VT Options (no app-defaults)",
  379.     "XTerm*fontMenu.Label:  VT Fonts (no app-defaults)",
  380.     "XTerm*tekMenu.Label:  Tek Options (no app-defaults)",
  381.     NULL
  382. };
  383. #endif /* MOTIF */
  384.  
  385. static XrmOptionDescRec optionDescList[] = {
  386. {"-geometry",    "*vt100.geometry",XrmoptionSepArg,    (caddr_t) NULL},
  387. {"-132",    "*c132",    XrmoptionNoArg,        (caddr_t) "on"},
  388. {"+132",    "*c132",    XrmoptionNoArg,        (caddr_t) "off"},
  389. {"-ah",        "*alwaysHighlight", XrmoptionNoArg,    (caddr_t) "on"},
  390. {"+ah",        "*alwaysHighlight", XrmoptionNoArg,    (caddr_t) "off"},
  391. {"-b",        "*internalBorder",XrmoptionSepArg,    (caddr_t) NULL},
  392. {"-cb",        "*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "off"},
  393. {"+cb",        "*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "on"},
  394. {"-cc",        "*charClass",    XrmoptionSepArg,    (caddr_t) NULL},
  395. {"-cn",        "*cutNewline",    XrmoptionNoArg,        (caddr_t) "off"},
  396. {"+cn",        "*cutNewline",    XrmoptionNoArg,        (caddr_t) "on"},
  397. {"-cr",        "*cursorColor",    XrmoptionSepArg,    (caddr_t) NULL},
  398. {"-cu",        "*curses",    XrmoptionNoArg,        (caddr_t) "on"},
  399. {"+cu",        "*curses",    XrmoptionNoArg,        (caddr_t) "off"},
  400. {"-e",        NULL,        XrmoptionSkipLine,    (caddr_t) NULL},
  401. {"-fb",        "*boldFont",    XrmoptionSepArg,    (caddr_t) NULL},
  402. {"-j",        "*jumpScroll",    XrmoptionNoArg,        (caddr_t) "on"},
  403. {"+j",        "*jumpScroll",    XrmoptionNoArg,        (caddr_t) "off"},
  404. {"-l",        "*logging",    XrmoptionNoArg,        (caddr_t) "on"},
  405. {"+l",        "*logging",    XrmoptionNoArg,        (caddr_t) "off"},
  406. {"-lf",        "*logFile",    XrmoptionSepArg,    (caddr_t) NULL},
  407. {"-ls",        "*loginShell",    XrmoptionNoArg,        (caddr_t) "on"},
  408. {"+ls",        "*loginShell",    XrmoptionNoArg,        (caddr_t) "off"},
  409. {"-mb",        "*marginBell",    XrmoptionNoArg,        (caddr_t) "on"},
  410. {"+mb",        "*marginBell",    XrmoptionNoArg,        (caddr_t) "off"},
  411. {"-mc",        "*multiClickTime", XrmoptionSepArg,    (caddr_t) NULL},
  412. {"-ms",        "*pointerColor",XrmoptionSepArg,    (caddr_t) NULL},
  413. {"-nb",        "*nMarginBell",    XrmoptionSepArg,    (caddr_t) NULL},
  414. {"-rw",        "*reverseWrap",    XrmoptionNoArg,        (caddr_t) "on"},
  415. {"+rw",        "*reverseWrap",    XrmoptionNoArg,        (caddr_t) "off"},
  416. {"-s",        "*multiScroll",    XrmoptionNoArg,        (caddr_t) "on"},
  417. {"+s",        "*multiScroll",    XrmoptionNoArg,        (caddr_t) "off"},
  418. {"-sb",        "*scrollBar",    XrmoptionNoArg,        (caddr_t) "on"},
  419. {"+sb",        "*scrollBar",    XrmoptionNoArg,        (caddr_t) "off"},
  420. {"-sf",        "*sunFunctionKeys", XrmoptionNoArg,    (caddr_t) "on"},
  421. {"+sf",        "*sunFunctionKeys", XrmoptionNoArg,    (caddr_t) "off"},
  422. {"-si",        "*scrollTtyOutput",    XrmoptionNoArg,        (caddr_t) "off"},
  423. {"+si",        "*scrollTtyOutput",    XrmoptionNoArg,        (caddr_t) "on"},
  424. {"-sk",        "*scrollKey",    XrmoptionNoArg,        (caddr_t) "on"},
  425. {"+sk",        "*scrollKey",    XrmoptionNoArg,        (caddr_t) "off"},
  426. {"-sl",        "*saveLines",    XrmoptionSepArg,    (caddr_t) NULL},
  427. {"-t",        "*tekStartup",    XrmoptionNoArg,        (caddr_t) "on"},
  428. {"+t",        "*tekStartup",    XrmoptionNoArg,        (caddr_t) "off"},
  429. {"-tm",        "*ttyModes",    XrmoptionSepArg,    (caddr_t) NULL},
  430. {"-tn",        "*termName",    XrmoptionSepArg,    (caddr_t) NULL},
  431. {"-ut",        "*utmpInhibit",    XrmoptionNoArg,        (caddr_t) "on"},
  432. {"+ut",        "*utmpInhibit",    XrmoptionNoArg,        (caddr_t) "off"},
  433. {"-vb",        "*visualBell",    XrmoptionNoArg,        (caddr_t) "on"},
  434. {"+vb",        "*visualBell",    XrmoptionNoArg,        (caddr_t) "off"},
  435. {"-wf",        "*waitForMap",    XrmoptionNoArg,        (caddr_t) "on"},
  436. {"+wf",        "*waitForMap",    XrmoptionNoArg,        (caddr_t) "off"},
  437. /* bogus old compatibility stuff for which there are
  438.    standard XtInitialize options now */
  439. {"%",        "*tekGeometry",    XrmoptionStickyArg,    (caddr_t) NULL},
  440. {"#",        ".iconGeometry",XrmoptionStickyArg,    (caddr_t) NULL},
  441. {"-T",        "*title",    XrmoptionSepArg,    (caddr_t) NULL},
  442. {"-n",        "*iconName",    XrmoptionSepArg,    (caddr_t) NULL},
  443. {"-r",        "*reverseVideo",XrmoptionNoArg,        (caddr_t) "on"},
  444. {"+r",        "*reverseVideo",XrmoptionNoArg,        (caddr_t) "off"},
  445. {"-rv",        "*reverseVideo",XrmoptionNoArg,        (caddr_t) "on"},
  446. {"+rv",        "*reverseVideo",XrmoptionNoArg,        (caddr_t) "off"},
  447. {"-w",        ".borderWidth", XrmoptionSepArg,    (caddr_t) NULL},
  448. };
  449.  
  450. static struct _options {
  451.   char *opt;
  452.   char *desc;
  453. } options[] = {
  454. { "-help",                 "print out this message" },
  455. { "-display displayname",  "X server to contact" },
  456. { "-geometry geom",        "size (in characters) and position" },
  457. { "-/+rv",                 "turn on/off reverse video" },
  458. { "-bg color",             "background color" },
  459. { "-fg color",             "foreground color" },
  460. { "-bd color",             "border color" },
  461. { "-bw number",            "border width in pixels" },
  462. { "-fn fontname",          "normal text font" },
  463. { "-iconic",               "start iconic" },
  464. { "-name string",          "client instance, icon, and title strings" },
  465. { "-title string",         "title string" },
  466. { "-xrm resourcestring",   "additional resource specifications" },
  467. { "-/+132",                "turn on/off column switch inhibiting" },
  468. { "-/+ah",                 "turn on/off always highlight" },
  469. { "-b number",             "internal border in pixels" },
  470. { "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
  471. { "-cc classrange",        "specify additional character classes" },
  472. { "-/+cn",                 "turn on/off cut newline inhibit" },
  473. { "-cr color",             "text cursor color" },
  474. { "-/+cu",                 "turn on/off curses emulation" },
  475. { "-fb fontname",          "bold text font" },
  476. { "-/+j",                  "turn on/off jump scroll" },
  477. { "-/+l",                  "turn on/off logging" },
  478. { "-lf filename",          "logging filename" },
  479. { "-/+ls",                 "turn on/off login shell" },
  480. { "-/+mb",                 "turn on/off margin bell" },
  481. { "-mc milliseconds",      "multiclick time in milliseconds" },
  482. { "-ms color",             "pointer color" },
  483. { "-nb number",            "margin bell in characters from right end" },
  484. { "-/+rw",                 "turn on/off reverse wraparound" },
  485. { "-/+s",                  "turn on/off multiscroll" },
  486. { "-/+sb",                 "turn on/off scrollbar" },
  487. { "-/+sf",                 "turn on/off Sun Function Key escape codes" },
  488. { "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
  489. { "-/+sk",                 "turn on/off scroll-on-keypress" },
  490. { "-sl number",            "number of scrolled lines to save" },
  491. { "-/+t",                  "turn on/off Tek emulation window" },
  492. { "-tm string",            "terminal mode keywords and characters" },
  493. { "-tn name",              "TERM environment variable name" },
  494. { "-/+ut",                 "turn on/off utmp inhibit" },
  495. { "-/+vb",                 "turn on/off visual bell" },
  496. { "-e command args",       "command to execute" },
  497. { "%geom",                 "Tek window geometry" },
  498. { "#geom",                 "icon window geometry" },
  499. { "-T string",             "title name for window" },
  500. { "-n string",             "icon name for window" },
  501. { "-C",                    "intercept console messages, if supported" },
  502. { "-Sxxd",                 "slave mode on \"ttyxx\", file descriptor \"d\"" },
  503. { NULL, NULL }};
  504.  
  505. static char *message[] = {
  506. "Fonts must be fixed width and, if both normal and bold are specified, must",
  507. "have the same size.  If only a normal font is specified, it will be used for",
  508. "both normal and bold text (by doing overstriking).  The -e option, if given,",
  509. "must be appear at the end of the command line, otherwise the user's default",
  510. "shell will be started.  Options that start with a plus sign (+) restore the",
  511. "default.",
  512. NULL};
  513.  
  514. static void Syntax (badOption)
  515.     char *badOption;
  516. {
  517.     struct _options *opt;
  518.     int col;
  519.  
  520.     fprintf (stderr, "%s:  bad command line option \"%s\"\r\n\n",
  521.          ProgramName, badOption);
  522.  
  523.     fprintf (stderr, "usage:  %s", ProgramName);
  524.     col = 8 + strlen(ProgramName);
  525.     for (opt = options; opt->opt; opt++) {
  526.     int len = 3 + strlen(opt->opt);     /* space [ string ] */
  527.     if (col + len > 79) {
  528.         fprintf (stderr, "\r\n   ");  /* 3 spaces */
  529.         col = 3;
  530.     }
  531.     fprintf (stderr, " [%s]", opt->opt);
  532.     col += len;
  533.     }
  534.  
  535.     fprintf (stderr, "\r\n\nType %s -help for a full description.\r\n\n",
  536.          ProgramName);
  537.     exit (1);
  538. }
  539.  
  540. static void Help ()
  541. {
  542.     struct _options *opt;
  543.     char **cpp;
  544.  
  545.     fprintf (stderr, "usage:\n        %s [-options ...] [-e command args]\n\n",
  546.          ProgramName);
  547.     fprintf (stderr, "where options include:\n");
  548.     for (opt = options; opt->opt; opt++) {
  549.     fprintf (stderr, "    %-28s %s\n", opt->opt, opt->desc);
  550.     }
  551.  
  552.     putc ('\n', stderr);
  553.     for (cpp = message; *cpp; cpp++) {
  554.     fputs (*cpp, stderr);
  555.     putc ('\n', stderr);
  556.     }
  557.     putc ('\n', stderr);
  558.  
  559.     exit (0);
  560. }
  561.  
  562.  
  563. extern WidgetClass xtermWidgetClass;
  564.  
  565. Arg ourTopLevelShellArgs[] = {
  566.     { XtNallowShellResize, (XtArgVal) TRUE },    
  567.     { XtNinput, (XtArgVal) TRUE },
  568. };
  569. int number_ourTopLevelShellArgs = 2;
  570.     
  571. XtAppContext app_con;
  572. Widget toplevel;
  573. Bool waiting_for_initial_map;
  574.  
  575. main (argc, argv)
  576. int argc;
  577. char **argv;
  578. {
  579.     register TScreen *screen;
  580.     register int i, pty;
  581.     int Xsocket, mode;
  582.     char *basename();
  583.     int xerror(), xioerror();
  584.  
  585.     ProgramName = argv[0];
  586.  
  587.     ttydev = (char *) malloc (strlen (TTYDEV) + 1);
  588.     ptydev = (char *) malloc (strlen (PTYDEV) + 1);
  589.     if (!ttydev || !ptydev) {
  590.         fprintf (stderr, 
  591.                  "%s:  unable to allocate memory for ttydev or ptydev\n",
  592.              ProgramName);
  593.         exit (1);
  594.     }
  595.     strcpy (ttydev, TTYDEV);
  596.     strcpy (ptydev, PTYDEV);
  597.  
  598. #ifdef USE_SYSV_TERMIO
  599.     /* Initialization is done here rather than above in order
  600.     ** to prevent any assumptions about the order of the contents
  601.     ** of the various terminal structures (which may change from
  602.     ** implementation to implementation).
  603.     */
  604. #if defined(macII) || defined(att)
  605.     d_tio.c_iflag = ICRNL|IXON;
  606.     d_tio.c_oflag = OPOST|ONLCR|TAB3;
  607.         d_tio.c_cflag = B9600|CS8|CREAD|PARENB|HUPCL;
  608.         d_tio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
  609.  
  610.     d_tio.c_line = 0;
  611.  
  612.     d_tio.c_cc[VINTR] = CINTR;
  613.     d_tio.c_cc[VQUIT] = CQUIT;
  614.     d_tio.c_cc[VERASE] = CERASE;
  615.     d_tio.c_cc[VKILL] = CKILL;
  616.         d_tio.c_cc[VEOF] = CEOF;
  617.     d_tio.c_cc[VEOL] = CNUL;
  618.     d_tio.c_cc[VEOL2] = CNUL;
  619.     d_tio.c_cc[VSWTCH] = CNUL;
  620.  
  621. #ifdef TIOCSLTC
  622.         d_ltc.t_suspc = CSUSP;        /* t_suspc */
  623.         d_ltc.t_dsuspc = CDSUSP;    /* t_dsuspc */
  624.         d_ltc.t_rprntc = 0;        /* reserved...*/
  625.         d_ltc.t_flushc = 0;
  626.         d_ltc.t_werasc = 0;
  627.         d_ltc.t_lnextc = 0;
  628. #endif /* TIOCSLTC */
  629. #else  /* else !macII */
  630.     d_tio.c_iflag = ICRNL|IXON;
  631.     d_tio.c_oflag = OPOST|ONLCR|TAB3;
  632. #ifdef BAUD_0
  633.         d_tio.c_cflag = CS8|CREAD|PARENB|HUPCL;
  634. #else    /* !BAUD_0 */
  635.         d_tio.c_cflag = B9600|CS8|CREAD|PARENB|HUPCL;
  636. #endif    /* !BAUD_0 */
  637.         d_tio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
  638.     d_tio.c_line = 0;
  639.     d_tio.c_cc[VINTR] = 0x7f;        /* DEL  */
  640.     d_tio.c_cc[VQUIT] = '\\' & 0x3f;    /* '^\'    */
  641.     d_tio.c_cc[VERASE] = '#';        /* '#'    */
  642.     d_tio.c_cc[VKILL] = '@';        /* '@'    */
  643.         d_tio.c_cc[VEOF] = 'D' & 0x3f;        /* '^D'    */
  644.     d_tio.c_cc[VEOL] = '@' & 0x3f;        /* '^@'    */
  645. #ifdef VSWTCH
  646.     d_tio.c_cc[VSWTCH] = '@' & 0x3f;    /* '^@'    */
  647. #endif    /* VSWTCH */
  648.     /* now, try to inherit tty settings */
  649.     {
  650.         int i;
  651.  
  652.         for (i = 0; i <= 2; i++) {
  653.         struct termio deftio;
  654.         if (ioctl (i, TCGETA, &deftio) == 0) {
  655.             d_tio.c_cc[VINTR] = deftio.c_cc[VINTR];
  656.             d_tio.c_cc[VQUIT] = deftio.c_cc[VQUIT];
  657.             d_tio.c_cc[VERASE] = deftio.c_cc[VERASE];
  658.             d_tio.c_cc[VKILL] = deftio.c_cc[VKILL];
  659.             d_tio.c_cc[VEOF] = deftio.c_cc[VEOF];
  660.             d_tio.c_cc[VEOL] = deftio.c_cc[VEOL];
  661. #ifdef VSWTCH
  662.             d_tio.c_cc[VSWTCH] = deftio.c_cc[VSWTCH];
  663. #endif /* VSWTCH */
  664.             break;
  665.         }
  666.         }
  667.     }
  668. #ifdef TIOCSLTC
  669.         d_ltc.t_suspc = '\000';        /* t_suspc */
  670.         d_ltc.t_dsuspc = '\000';    /* t_dsuspc */
  671.         d_ltc.t_rprntc = '\377';    /* reserved...*/
  672.         d_ltc.t_flushc = '\377';
  673.         d_ltc.t_werasc = '\377';
  674.         d_ltc.t_lnextc = '\377';
  675. #endif    /* TIOCSLTC */
  676. #ifdef TIOCLSET
  677.     d_lmode = 0;
  678. #endif    /* TIOCLSET */
  679. #endif  /* macII */
  680. #endif    /* USE_SYSV_TERMIO */
  681.  
  682.     /* Init the Toolkit. */
  683. #ifdef MOTIF
  684.     toplevel = XtAppInitialize (&app_con, "MXTerm", 
  685.                     optionDescList, XtNumber(optionDescList), 
  686.                     &argc, argv, fallback_resources, 
  687.                     NULL, 0);
  688. #else
  689.     toplevel = XtAppInitialize (&app_con, "XTerm", 
  690.                     optionDescList, XtNumber(optionDescList), 
  691.                     &argc, argv, fallback_resources, 
  692.                     NULL, 0);
  693. #endif /* MOTIF */
  694.  
  695.     XtGetApplicationResources( toplevel, &resource, application_resources,
  696.                    XtNumber(application_resources), NULL, 0 );
  697.  
  698.     waiting_for_initial_map = resource.wait_for_map;
  699.  
  700.   XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
  701.  
  702.     /*
  703.      * fill in terminal modes
  704.      */
  705.     if (resource.tty_modes) {
  706.         int n = parse_tty_modes (resource.tty_modes,
  707.                      ttymodelist, NXTTYMODES);
  708.         if (n < 0) {
  709.         fprintf (stderr, "%s:  bad tty modes \"%s\"\n",
  710.              ProgramName, resource.tty_modes);
  711.         } else if (n > 0) {
  712.         override_tty_modes = 1;
  713.         }
  714.     }
  715.  
  716.     xterm_name = resource.xterm_name;
  717.     sunFunctionKeys = resource.sunFunctionKeys;
  718.     if (strcmp(xterm_name, "-") == 0) xterm_name = "xterm";
  719.     if (resource.icon_geometry != NULL) {
  720.         int scr, junk;
  721.         int ix, iy;
  722.         Arg args[2];
  723.  
  724.         for(scr = 0;    /* yyuucchh */
  725.         XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel),scr);
  726.         scr++);
  727.  
  728.         args[0].name = XtNiconX;
  729.         args[1].name = XtNiconY;
  730.         XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
  731.               0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
  732.         args[0].value = (XtArgVal) ix;
  733.         args[1].value = (XtArgVal) iy;
  734.         XtSetValues( toplevel, args, 2);
  735.     }
  736.  
  737.     XtSetValues (toplevel, ourTopLevelShellArgs, 
  738.              number_ourTopLevelShellArgs);
  739.  
  740.  
  741.     /* Parse the rest of the command line */
  742.     for (argc--, argv++ ; argc > 0 ; argc--, argv++) {
  743.         if(**argv != '-') Syntax (*argv);
  744.  
  745.         switch(argv[0][1]) {
  746.          case 'h':
  747.         Help ();
  748.         /* NOTREACHED */
  749.          case 'C':
  750. #ifdef TIOCCONS
  751.         Console = TRUE;
  752. #endif    /* TIOCCONS */
  753.         continue;
  754.          case 'S':
  755.         sscanf(*argv + 2, "%c%c%d", passedPty, passedPty+1,
  756.          &am_slave);
  757.         if (am_slave <= 0) Syntax(*argv);
  758.         continue;
  759. #ifdef DEBUG
  760.          case 'D':
  761.         debug = TRUE;
  762.         continue;
  763. #endif    /* DEBUG */
  764.          case 'e':
  765.         if (argc <= 1) Syntax (*argv);
  766.         command_to_exec = ++argv;
  767.         break;
  768.          default:
  769.         Syntax (*argv);
  770.         }
  771.         break;
  772.     }
  773.  
  774. #ifndef MOTIF    
  775.     XawSimpleMenuAddGlobalActions (XtWidgetToApplicationContext(toplevel));
  776. #endif /* MOTIF */    
  777.  
  778. #if 0
  779.     XtRegisterGrabAction (HandlePopupMenu, True,
  780.                   (ButtonPressMask|ButtonReleaseMask),
  781.                   GrabModeAsync, GrabModeAsync);
  782. #endif
  783.  
  784.         term = (XtermWidget) XtCreateManagedWidget(
  785.         "vt100", xtermWidgetClass, toplevel, NULL, 0);
  786.             /* this causes the initialize method to be called */
  787.  
  788.         screen = &term->screen;
  789.  
  790.     term->flags = WRAPAROUND;
  791.     update_autowrap();
  792.     if (!screen->jumpscroll) {
  793.         term->flags |= SMOOTHSCROLL;
  794.         update_jumpscroll();
  795.     }
  796.     if (term->misc.reverseWrap) {
  797.         term->flags |= REVERSEWRAP;
  798.         update_reversewrap();
  799.     }
  800.     if (term->misc.re_verse) {
  801.         term->flags |= REVERSE_VIDEO;
  802.         update_reversevideo();
  803.     }
  804.  
  805.     inhibit = 0;
  806.     if (term->misc.logInhibit)         inhibit |= I_LOG;
  807.     if (term->misc.signalInhibit)        inhibit |= I_SIGNAL;
  808.     if (term->misc.tekInhibit)            inhibit |= I_TEK;
  809.  
  810.     term->initflags = term->flags;
  811.  
  812. /*
  813.  * Set title and icon name if not specified
  814.  */
  815.  
  816.     if (command_to_exec) {
  817.         Arg args[2];
  818.  
  819.         if (!resource.title) {
  820.         if (command_to_exec) {
  821.             resource.title = basename (command_to_exec[0]);
  822.         } /* else not reached */
  823.         }
  824.  
  825.         if (!resource.icon_name) 
  826.           resource.icon_name = resource.title;
  827.         XtSetArg (args[0], XtNtitle, resource.title);
  828.         XtSetArg (args[1], XtNiconName, resource.icon_name);        
  829.  
  830.         XtSetValues (toplevel, args, 2);
  831.     }
  832.  
  833.  
  834.     if(inhibit & I_TEK)
  835.         screen->TekEmu = FALSE;
  836.  
  837.     if(screen->TekEmu && !TekInit())
  838.         exit(ERROR_INIT);
  839.  
  840.     /* set up stderr properly */
  841.     i = -1;
  842. #ifdef DEBUG
  843.     if(debug)
  844.         i = open ("xterm.debug.log", O_WRONLY | O_CREAT | O_TRUNC,
  845.          0666);
  846. #endif    /* DEBUG */
  847.     if(i >= 0) {
  848. #ifdef USE_SYSV_TERMIO
  849.         /* SYSV has another pointer which should be part of the
  850.         ** FILE structure but is actually a seperate array.
  851.         */
  852.         unsigned char *old_bufend;
  853.  
  854.         old_bufend = (unsigned char *) _bufend(stderr);
  855.         fileno(stderr) = i;
  856.         _bufend(stderr) = old_bufend;
  857. #else    /* USE_SYSV_TERMIO */
  858.         fileno(stderr) = i;
  859. #endif    /* USE_SYSV_TERMIO */
  860.  
  861.         /* mark this file as close on exec */
  862.         (void) fcntl(i, F_SETFD, 1);
  863.     }
  864.  
  865.     /* open a terminal for client */
  866.     get_terminal ();
  867.     spawn ();
  868.     /* Child process is out there, let's catch it's termination */
  869.     signal (SIGCHLD, reapchild);
  870.  
  871.     /* Realize procs have now been executed */
  872.  
  873.     Xsocket = screen->display->fd;
  874.     pty = screen->respond;
  875.  
  876.     if (am_slave) { /* Write window id so master end can read and use */
  877.         char buf[80];
  878.  
  879.         buf[0] = '\0';
  880.         sprintf (buf, "%lx\n", 
  881.                  screen->TekEmu ? XtWindow (XtParent (tekWidget)) :
  882.                       XtWindow (XtParent (term)));
  883.         write (pty, buf, strlen (buf));
  884.     }
  885.  
  886.     if (term->misc.log_on) {
  887.         StartLog(screen);
  888.     }
  889.     screen->inhibit = inhibit;
  890.  
  891. #ifdef USE_SYSV_TERMIO
  892.     if (0 > (mode = fcntl(pty, F_GETFL, 0)))
  893.         Error();
  894.     mode |= O_NDELAY;
  895.     if (fcntl(pty, F_SETFL, mode))
  896.         Error();
  897. #else    /* USE_SYSV_TERMIO */
  898.     mode = 1;
  899.     if (ioctl (pty, FIONBIO, (char *)&mode) == -1) SysError (ERROR_FIONBIO);
  900. #endif    /* USE_SYSV_TERMIO */
  901.     
  902.     pty_mask = 1 << pty;
  903.     X_mask = 1 << Xsocket;
  904.     Select_mask = pty_mask | X_mask;
  905.     max_plus1 = (pty < Xsocket) ? (1 + Xsocket) : (1 + pty);
  906.  
  907. #ifdef DEBUG
  908.     if (debug) printf ("debugging on\n");
  909. #endif    /* DEBUG */
  910.     XSetErrorHandler(xerror);
  911.     XSetIOErrorHandler(xioerror);
  912.     for( ; ; ) {
  913.         if(screen->TekEmu) {
  914.             TekRun();
  915.         } else
  916.             VTRun();
  917.     }
  918. }
  919.  
  920. char *basename(name)
  921. char *name;
  922. {
  923.     register char *cp;
  924.     char *rindex();
  925.  
  926.     return((cp = rindex(name, '/')) ? cp + 1 : name);
  927. }
  928.  
  929. /* This function opens up a pty master and stuffs it's value into pty.
  930.  * If it finds one, it returns a value of 0.  If it does not find one,
  931.  * it returns a value of !0.  This routine is designed to be re-entrant,
  932.  * so that if a pty master is found and later, we find that the slave
  933.  * has problems, we can re-enter this function and get another one.
  934.  */
  935.  
  936. get_pty (pty)
  937. int *pty;
  938. {
  939.     static int devindex, letter = 0;
  940.  
  941. #ifdef att
  942.     if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0) {
  943.         return 1;
  944.     }
  945.     return 0;
  946. #else /* !att, need lots of code */
  947.  
  948. #if defined(umips) && defined (SYSTYPE_SYSV)
  949.     struct stat fstat_buf;
  950.  
  951.     *pty = open ("/dev/ptc", O_RDWR);
  952.     if (*pty < 0 || (fstat (*pty, &fstat_buf)) < 0) {
  953.       return(1);
  954.     }
  955.     sprintf (ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
  956.     sprintf (ptydev, "/dev/ptyq%d", minor(fstat_buf.st_rdev));
  957.     if ((*tty = open (ttydev, O_RDWR)) < 0) {
  958.       close (*pty);
  959.       return(1);
  960.     }
  961.     /* got one! */
  962.     return(0);
  963. #else /* not (umips && SYSTYPE_SYSV) */
  964. #ifdef CRAY
  965.     for (; devindex < 256; devindex++) {
  966.         sprintf (ttydev, "/dev/ttyp%03d", devindex);
  967.         sprintf (ptydev, "/dev/pty/%03d", devindex);
  968.  
  969.         if ((*pty = open (ptydev, O_RDWR)) >= 0) {
  970.         /* We need to set things up for our next entry
  971.          * into this function!
  972.          */
  973.         (void) devindex++;
  974.         return(0);
  975.         }
  976.     }
  977. #else /* !CRAY */
  978.     while (PTYCHAR1[letter]) {
  979.         ttydev [strlen(ttydev) - 2]  = ptydev [strlen(ptydev) - 2] =
  980.             PTYCHAR1 [letter];
  981.  
  982.         while (PTYCHAR2[devindex]) {
  983.         ttydev [strlen(ttydev) - 1] = ptydev [strlen(ptydev) - 1] =
  984.             PTYCHAR2 [devindex];
  985.         if ((*pty = open (ptydev, O_RDWR)) >= 0) {
  986.             /* We need to set things up for our next entry
  987.              * into this function!
  988.              */
  989.             (void) devindex++;
  990.             return(0);
  991.         }
  992.         devindex++;
  993.         }
  994.         devindex = 0;
  995.         (void) letter++;
  996.     }
  997. #endif /* CRAY else not CRAY */
  998.     /* We were unable to allocate a pty master!  Return an error
  999.      * condition and let our caller terminate cleanly.
  1000.      */
  1001.     return(1);
  1002. #endif /* umips && SYSTYPE_SYSV */
  1003. #endif /* att */
  1004. }
  1005.  
  1006. get_terminal ()
  1007. /* 
  1008.  * sets up X and initializes the terminal structure except for term.buf.fildes.
  1009.  */
  1010. {
  1011.     register TScreen *screen = &term->screen;
  1012.     
  1013.     screen->arrow = make_colored_cursor (XC_left_ptr, 
  1014.                          screen->mousecolor,
  1015.                          screen->mousecolorback);
  1016. }
  1017.  
  1018. /*
  1019.  * The only difference in /etc/termcap between 4014 and 4015 is that 
  1020.  * the latter has support for switching character sets.  We support the
  1021.  * 4015 protocol, but ignore the character switches.  Therefore, we should
  1022.  * probably choose 4014 over 4015.
  1023.  */
  1024.  
  1025. static char *tekterm[] = {
  1026.     "tek4014",
  1027.     "tek4015",        /* has alternate character set switching */
  1028.     "tek4013",
  1029.     "tek4010",
  1030.     "dumb",
  1031.     0
  1032. };
  1033.  
  1034. static char *vtterm[] = {
  1035. #ifdef USE_X11TERM
  1036.     "x11term",        /* for people who want special term name */
  1037. #endif
  1038.     "xterm",        /* the prefered name, should be fastest */
  1039.     "vt102",
  1040.     "vt100",
  1041.     "ansi",
  1042.     "dumb",
  1043.     0
  1044. };
  1045.  
  1046. /* ARGSUSED */
  1047. SIGNAL_T hungtty(i)
  1048.     int i;
  1049. {
  1050.     longjmp(env, 1);
  1051.     SIGNAL_RETURN;
  1052. }
  1053.  
  1054. #ifdef USE_HANDSHAKE
  1055. typedef enum {        /* c == child, p == parent                        */
  1056.     PTY_BAD,    /* c->p: can't open pty slave for some reason     */
  1057.     PTY_FATALERROR,    /* c->p: we had a fatal error with the pty        */
  1058.     PTY_GOOD,    /* c->p: we have a good pty, let's go on          */
  1059.     PTY_NEW,    /* p->c: here is a new pty slave, try this        */
  1060.     PTY_NOMORE,    /* p->c; no more pty's, terminate                 */
  1061.     UTMP_ADDED,    /* c->p: utmp entry has been added                */
  1062.     UTMP_TTYSLOT,    /* c->p: here is my ttyslot                       */
  1063.     PTY_EXEC    /* p->c: window has been mapped the first time    */
  1064. } status_t;
  1065.  
  1066. typedef struct {
  1067.     status_t status;
  1068.     int error;
  1069.     int fatal_error;
  1070.     int tty_slot;
  1071.     int rows;
  1072.     int cols;
  1073.     char buffer[1024];
  1074. } handshake_t;
  1075.  
  1076. /* HsSysError()
  1077.  *
  1078.  * This routine does the equivalent of a SysError but it handshakes
  1079.  * over the errno and error exit to the master process so that it can
  1080.  * display our error message and exit with our exit code so that the
  1081.  * user can see it.
  1082.  */
  1083.  
  1084. void
  1085. HsSysError(pf, error)
  1086. int pf;
  1087. int error;
  1088. {
  1089.     handshake_t handshake;
  1090.  
  1091.     handshake.status = PTY_FATALERROR;
  1092.     handshake.error = errno;
  1093.     handshake.fatal_error = error;
  1094.     strcpy(handshake.buffer, ttydev);
  1095.     write(pf, &handshake, sizeof(handshake));
  1096.     exit(error);
  1097. }
  1098.  
  1099. static int pc_pipe[2];    /* this pipe is used for parent to child transfer */
  1100. static int cp_pipe[2];    /* this pipe is used for child to parent transfer */
  1101.  
  1102. void first_map_occurred ()
  1103. {
  1104.     handshake_t handshake;
  1105.     register TScreen *screen = &term->screen;
  1106.  
  1107.     if (screen->max_row > 0 && screen->max_col > 0) {
  1108.     handshake.status = PTY_EXEC;
  1109.     handshake.rows = screen->max_row;
  1110.     handshake.cols = screen->max_col;
  1111.     write (pc_pipe[1], (char *) &handshake, sizeof(handshake));
  1112.     close (cp_pipe[0]);
  1113.     close (pc_pipe[1]);
  1114.     waiting_for_initial_map = False;
  1115.     }
  1116. }
  1117. #else
  1118. /*
  1119.  * temporary hack to get xterm working on att ptys
  1120.  */
  1121. first_map_occurred ()
  1122. {
  1123.     return;
  1124. }
  1125. #define HsSysError(a,b)
  1126. #endif /* USE_HANDSHAKE else !USE_HANDSHAKE */
  1127.  
  1128.  
  1129. spawn ()
  1130. /* 
  1131.  *  Inits pty and tty and forks a login process.
  1132.  *  Does not close fd Xsocket.
  1133.  *  If slave, the pty named in passedPty is already open for use
  1134.  */
  1135. {
  1136.     extern char *SysErrorMsg();
  1137.     register TScreen *screen = &term->screen;
  1138.     int Xsocket = screen->display->fd;
  1139. #ifdef USE_HANDSHAKE
  1140.     handshake_t handshake;
  1141. #else
  1142.     int fds[2];
  1143. #endif
  1144.     int tty = -1;
  1145.     int discipline;
  1146.     int done;
  1147. #ifdef USE_SYSV_TERMIO
  1148.     struct termio tio;
  1149.     struct termio dummy_tio;
  1150. #ifdef TIOCLSET
  1151.     unsigned lmode;
  1152. #endif    /* TIOCLSET */
  1153. #ifdef TIOCSLTC
  1154.     struct ltchars ltc;
  1155. #endif    /* TIOCSLTC */
  1156.     int one = 1;
  1157.     int zero = 0;
  1158.     int status;
  1159. #else    /* else not USE_SYSV_TERMIO */
  1160.     unsigned lmode;
  1161.     struct tchars tc;
  1162.     struct ltchars ltc;
  1163.     struct sgttyb sg;
  1164. #endif    /* USE_SYSV_TERMIO */
  1165.  
  1166.     char termcap [1024];
  1167.     char newtc [1024];
  1168.     char *ptr, *shname, *shname_minus;
  1169.     int i, no_dev_tty = FALSE;
  1170. #ifdef USE_SYSV_TERMIO
  1171.     char *dev_tty_name = (char *) 0;
  1172.     int fd;            /* for /etc/wtmp */
  1173. #endif    /* USE_SYSV_TERMIO */
  1174.     char **envnew;        /* new environment */
  1175.     char buf[32];
  1176.     char *TermName = NULL;
  1177.     int ldisc = 0;
  1178. #ifdef sun
  1179. #ifdef TIOCSSIZE
  1180.     struct ttysize ts;
  1181. #endif    /* TIOCSSIZE */
  1182. #else    /* not sun */
  1183. #ifdef TIOCSWINSZ
  1184.     struct winsize ws;
  1185. #endif    /* TIOCSWINSZ */
  1186. #endif    /* sun */
  1187.     struct passwd *pw = NULL;
  1188. #ifdef UTMP
  1189.     struct utmp utmp;
  1190. #ifdef LASTLOG
  1191.     struct lastlog lastlog;
  1192. #endif    /* LASTLOG */
  1193. #endif    /* UTMP */
  1194.  
  1195.     screen->uid = getuid();
  1196.     screen->gid = getgid();
  1197.  
  1198. #ifdef SIGTTOU
  1199.     /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
  1200.     signal(SIGTTOU,SIG_IGN);
  1201. #endif
  1202.  
  1203.     if (am_slave) {
  1204.         screen->respond = am_slave;
  1205.         ptydev[strlen(ptydev) - 2] = ttydev[strlen(ttydev) - 2] =
  1206.             passedPty[0];
  1207.         ptydev[strlen(ptydev) - 1] = ttydev[strlen(ttydev) - 1] =
  1208.             passedPty[1];
  1209.  
  1210.         setgid (screen->gid);
  1211.         setuid (screen->uid);
  1212.     } else {
  1213.         Bool tty_got_hung = False;
  1214.  
  1215.          /*
  1216.           * Sometimes /dev/tty hangs on open (as in the case of a pty
  1217.           * that has gone away).  Simply make up some reasonable
  1218.           * defaults.
  1219.           */
  1220.          signal(SIGALRM, hungtty);
  1221.          alarm(2);        /* alarm(1) might return too soon */
  1222.          if (! setjmp(env)) {
  1223.              tty = open ("/dev/tty", O_RDWR, 0);
  1224.              alarm(0);
  1225.          } else {
  1226.             tty_got_hung = True;
  1227.              tty = -1;
  1228.              errno = ENXIO;
  1229.          }
  1230.          signal(SIGALRM, SIG_DFL);
  1231.  
  1232.         /*
  1233.          * Check results and ignore current control terminal if
  1234.          * necessary.  ENXIO is what is normally returned if there is
  1235.          * no controlling terminal, but some systems (e.g. SunOS 4.0)
  1236.          * seem to return EIO.
  1237.          */
  1238.          if (tty < 0) {
  1239.             if (tty_got_hung || errno == ENXIO || errno == EIO) {
  1240.                 no_dev_tty = TRUE;
  1241. #ifdef USE_SYSV_TERMIO
  1242.                 tio = d_tio;
  1243. #ifdef TIOCSLTC
  1244.                 ltc = d_ltc;
  1245. #endif    /* TIOCSLTC */
  1246. #ifdef TIOCLSET
  1247.                 lmode = d_lmode;
  1248. #endif    /* TIOCLSET */
  1249. #else    /* not USE_SYSV_TERMIO */
  1250.                 sg = d_sg;
  1251.                 tc = d_tc;
  1252.                 discipline = d_disipline;
  1253.                 ltc = d_ltc;
  1254.                 lmode = d_lmode;
  1255. #endif    /* USE_SYSV_TERMIO */
  1256.             } else {
  1257.                 SysError(ERROR_OPDEVTTY);
  1258.             }
  1259.         } else {
  1260.             /* get a copy of the current terminal's state */
  1261.  
  1262. #ifdef USE_SYSV_TERMIO
  1263.             if(ioctl(tty, TCGETA, &tio) == -1)
  1264.                 SysError(ERROR_TIOCGETP);
  1265. #ifdef TIOCSLTC
  1266.             if(ioctl(tty, TIOCGLTC, <c) == -1)
  1267.                 SysError(ERROR_TIOCGLTC);
  1268. #endif    /* TIOCSLTC */
  1269. #ifdef TIOCLSET
  1270.             if(ioctl(tty, TIOCLGET, &lmode) == -1)
  1271.                 SysError(ERROR_TIOCLGET);
  1272. #endif    /* TIOCLSET */
  1273. #else    /* not USE_SYSV_TERMIO */
  1274.             if(ioctl(tty, TIOCGETP, (char *)&sg) == -1)
  1275.                 SysError (ERROR_TIOCGETP);
  1276.             if(ioctl(tty, TIOCGETC, (char *)&tc) == -1)
  1277.                 SysError (ERROR_TIOCGETC);
  1278.             if(ioctl(tty, TIOCGETD, (char *)&discipline) == -1)
  1279.                 SysError (ERROR_TIOCGETD);
  1280.             if(ioctl(tty, TIOCGLTC, (char *)<c) == -1)
  1281.                 SysError (ERROR_TIOCGLTC);
  1282.             if(ioctl(tty, TIOCLGET, (char *)&lmode) == -1)
  1283.                 SysError (ERROR_TIOCLGET);
  1284. #endif    /* USE_SYSV_TERMIO */
  1285.             close (tty);
  1286.             /* tty is no longer an open fd! */
  1287.             tty = -1;
  1288.         }
  1289.  
  1290. #ifdef     PUCC_PTYD
  1291.         if(-1 == (screen->respond = openrpty(ttydev, ptydev,
  1292.                 (resource.utmpInhibit ?  OPTY_NOP : OPTY_LOGIN),
  1293.                 getuid(), XDisplayString(screen->display)))) {
  1294. #else /* not PUCC_PTYD */
  1295.         if (get_pty (&screen->respond)) {
  1296. #endif /* PUCC_PTYD */
  1297.             /*  no ptys! */
  1298.             (void) fprintf(stderr, "%s: no available ptys\n",
  1299.                        xterm_name);
  1300.             exit (ERROR_PTYS);
  1301. #ifdef PUCC_PTYD
  1302.         }
  1303. #else
  1304.         }            /* keep braces balanced for emacs */
  1305. #endif
  1306. #ifdef PUCC_PTYD
  1307.           else {
  1308.             /*
  1309.              *  set the fd of the master in a global var so
  1310.              *  we can undo all this on exit
  1311.              *
  1312.              */
  1313.             Ptyfd = screen->respond;
  1314.           }
  1315. #endif /* PUCC_PTYD */
  1316.     }
  1317.  
  1318.     /* avoid double MapWindow requests */
  1319.     XtSetMappedWhenManaged( screen->TekEmu ? XtParent(tekWidget) :
  1320.                     XtParent(term), False );
  1321.         /* Realize the Tek or VT widget, depending on which mode we're in.
  1322.            If VT mode, this calls VTRealize (the widget's Realize proc) */
  1323.         XtRealizeWidget (screen->TekEmu ? XtParent(tekWidget) :
  1324.              XtParent(term));
  1325.  
  1326.     if(screen->TekEmu) {
  1327.         envnew = tekterm;
  1328.         ptr = newtc;
  1329.     } else {
  1330.         envnew = vtterm;
  1331.         ptr = termcap;
  1332.     }
  1333.     TermName = NULL;
  1334.     if (resource.term_name) {
  1335.         if (tgetent (ptr, resource.term_name) == 1) {
  1336.         TermName = resource.term_name;
  1337.         if (!screen->TekEmu)
  1338.             resize (screen, TermName, termcap, newtc);
  1339.         } else {
  1340.         fprintf (stderr, "%s:  invalid termcap entry \"%s\".\n",
  1341.              ProgramName, resource.term_name);
  1342.         }
  1343.     }
  1344.     if (!TermName) {
  1345.         while (*envnew != NULL) {
  1346.         if(tgetent(ptr, *envnew) == 1) {
  1347.             TermName = *envnew;
  1348.             if(!screen->TekEmu)
  1349.                 resize(screen, TermName, termcap, newtc);
  1350.             break;
  1351.         }
  1352.         envnew++;
  1353.         }
  1354.         if (TermName == NULL) {
  1355.         fprintf (stderr, "%s:  unable to find usable termcap entry.\n",
  1356.              ProgramName);
  1357.         Exit (1);
  1358.         }
  1359.     }
  1360.  
  1361. #ifdef sun
  1362. #ifdef TIOCSSIZE
  1363.     /* tell tty how big window is */
  1364.     if(screen->TekEmu) {
  1365.         ts.ts_lines = 38;
  1366.         ts.ts_cols = 81;
  1367.     } else {
  1368.         ts.ts_lines = screen->max_row + 1;
  1369.         ts.ts_cols = screen->max_col + 1;
  1370.     }
  1371. #endif    /* TIOCSSIZE */
  1372. #else    /* not sun */
  1373. #ifdef TIOCSWINSZ
  1374.     /* tell tty how big window is */
  1375.     if(screen->TekEmu) {
  1376.         ws.ws_row = 38;
  1377.         ws.ws_col = 81;
  1378.         ws.ws_xpixel = TFullWidth(screen);
  1379.         ws.ws_ypixel = TFullHeight(screen);
  1380.     } else {
  1381.         ws.ws_row = screen->max_row + 1;
  1382.         ws.ws_col = screen->max_col + 1;
  1383.         ws.ws_xpixel = FullWidth(screen);
  1384.         ws.ws_ypixel = FullHeight(screen);
  1385.     }
  1386. #endif    /* TIOCSWINSZ */
  1387. #endif    /* sun */
  1388.  
  1389.     if (!am_slave) {
  1390. #ifdef USE_HANDSHAKE
  1391.         if (pipe(pc_pipe) || pipe(cp_pipe))
  1392.         SysError (ERROR_FORK);
  1393. #endif
  1394.         if ((screen->pid = fork ()) == -1)
  1395.         SysError (ERROR_FORK);
  1396.         
  1397.         if (screen->pid == 0) {
  1398.         /*
  1399.          * now in child process
  1400.          */
  1401.         extern char **environ;
  1402.         int pgrp = getpid();
  1403. #ifdef USE_SYSV_TERMIO
  1404.         char numbuf[12];
  1405. #endif    /* USE_SYSV_TERMIO */
  1406.  
  1407. #ifndef USE_HANDSHAKE
  1408.         int ptyfd;
  1409.  
  1410.         setpgrp();
  1411.         grantpt (screen->respond);
  1412.         unlockpt (screen->respond);
  1413.         if ((ptyfd = open (ptsname(screen->respond), O_RDWR)) < 0) {
  1414.             SysError (1);
  1415.         }
  1416.         if (ioctl (ptyfd, I_PUSH, "ptem") < 0) {
  1417.             SysError (2);
  1418.         }
  1419.         if (!getenv("CONSEM") && ioctl (ptyfd, I_PUSH, "consem") < 0) {
  1420.             SysError (3);
  1421.         }
  1422.         if (ioctl (ptyfd, I_PUSH, "ldterm") < 0) {
  1423.             SysError (4);
  1424.         }
  1425.         tty = ptyfd;
  1426.         close (screen->respond);
  1427. #ifdef TIOCSWINSZ
  1428.                 /* tell tty how big window is */
  1429.                 if(screen->TekEmu) {
  1430.                         ws.ws_row = 24;
  1431.                         ws.ws_col = 80;
  1432.                         ws.ws_xpixel = TFullWidth(screen);
  1433.                         ws.ws_ypixel = TFullHeight(screen);
  1434.                 } else {
  1435.                         ws.ws_row = screen->max_row + 1;
  1436.                         ws.ws_col = screen->max_col + 1;
  1437.                         ws.ws_xpixel = FullWidth(screen);
  1438.                         ws.ws_ypixel = FullHeight(screen);
  1439.                 }
  1440. #endif
  1441.  
  1442.  
  1443. #else /* USE_HANDSHAKE:  warning, goes for a long ways */
  1444.         /* close parent's sides of the pipes */
  1445.         close (cp_pipe[0]);
  1446.         close (pc_pipe[1]);
  1447.  
  1448.         /* Make sure that our sides of the pipes are not in the
  1449.          * 0, 1, 2 range so that we don't fight with stdin, out
  1450.          * or err.
  1451.          */
  1452.         if (cp_pipe[1] <= 2) {
  1453.             if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
  1454.                 (void) close(cp_pipe[1]);
  1455.                 cp_pipe[1] = i;
  1456.             }
  1457.         }
  1458.         if (pc_pipe[0] <= 2) {
  1459.             if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
  1460.                 (void) close(pc_pipe[0]);
  1461.                 pc_pipe[0] = i;
  1462.             }
  1463.         }
  1464.  
  1465.         /* we don't need the socket, or the pty master anymore */
  1466.         close (Xsocket);
  1467.         close (screen->respond);
  1468.  
  1469.         /* Now is the time to set up our process group and
  1470.          * open up the pty slave.
  1471.          */
  1472. #ifdef    USE_SYSV_PGRP
  1473.         (void) setpgrp();
  1474. #endif    /* USE_SYSV_PGRP */
  1475.         while (1) {
  1476. #ifdef TIOCNOTTY
  1477.             if ((tty = open ("/dev/tty", 2)) >= 0) {
  1478.                 ioctl (tty, TIOCNOTTY, (char *) NULL);
  1479.                 close (tty);
  1480.             }
  1481. #endif    /* TIOCNOTTY */
  1482.             if ((tty = open(ttydev, O_RDWR, 0)) >= 0) {
  1483. #ifdef    USE_SYSV_PGRP
  1484.                 /* We need to make sure that we are acutally
  1485.                  * the process group leader for the pty.  If
  1486.                  * we are, then we should now be able to open
  1487.                  * /dev/tty.
  1488.                  */
  1489.                 if ((i = open("/dev/tty", O_RDWR, 0)) >= 0) {
  1490.                     /* success! */
  1491.                     close(i);
  1492.                     break;
  1493.                 }
  1494. #else    /* USE_SYSV_PGRP */
  1495.                 break;
  1496. #endif    /* USE_SYSV_PGRP */
  1497.             }
  1498.  
  1499. #ifdef TIOCSCTTY
  1500.             ioctl(tty, TIOCSCTTY, 0);
  1501. #endif
  1502.             /* let our master know that the open failed */
  1503.             handshake.status = PTY_BAD;
  1504.             handshake.error = errno;
  1505.             strcpy(handshake.buffer, ttydev);
  1506.             write(cp_pipe[1], (char *) &handshake,
  1507.                 sizeof(handshake));
  1508.  
  1509.             /* get reply from parent */
  1510.             i = read(pc_pipe[0], (char *) &handshake,
  1511.                 sizeof(handshake));
  1512.             if (i <= 0) {
  1513.                 /* parent terminated */
  1514.                 exit(1);
  1515.             }
  1516.  
  1517.             if (handshake.status == PTY_NOMORE) {
  1518.                 /* No more ptys, let's shutdown. */
  1519.                 exit(1);
  1520.             }
  1521.  
  1522.             /* We have a new pty to try */
  1523.             free(ttydev);
  1524.             ttydev = malloc((unsigned)
  1525.                 (strlen(handshake.buffer) + 1));
  1526.             strcpy(ttydev, handshake.buffer);
  1527.         }
  1528.  
  1529.         /* use the same tty name that everyone else will use
  1530.         ** (from ttyname)
  1531.         */
  1532.         if (ptr = ttyname(tty))
  1533.         {
  1534.             /* it may be bigger */
  1535.             ttydev = realloc (ttydev, (unsigned) (strlen(ptr) + 1));
  1536.             (void) strcpy(ttydev, ptr);
  1537.         }
  1538.  
  1539. #endif /* !USE_HANDSHAKE else USE_HANDSHAKE - from near fork */
  1540.  
  1541. #ifdef USE_TTY_GROUP
  1542.     { 
  1543. #include <grp.h>
  1544.         struct group *ttygrp;
  1545.         if (ttygrp = getgrnam("tty")) {
  1546.             /* change ownership of tty to real uid, "tty" gid */
  1547.             chown (ttydev, screen->uid, ttygrp->gr_gid);
  1548.             chmod (ttydev, 0620);
  1549.         }
  1550.         else {
  1551.             /* change ownership of tty to real group and user id */
  1552.             chown (ttydev, screen->uid, screen->gid);
  1553.             chmod (ttydev, 0622);
  1554.         }
  1555.         endgrent();
  1556.     }
  1557. #else /* else !USE_TTY_GROUP */
  1558.         /* change ownership of tty to real group and user id */
  1559.         chown (ttydev, screen->uid, screen->gid);
  1560.  
  1561.         /* change protection of tty */
  1562.         chmod (ttydev, 0622);
  1563. #endif /* USE_TTY_GROUP */
  1564.  
  1565.         /*
  1566.          * set up the tty modes
  1567.          */
  1568.         {
  1569. #ifdef USE_SYSV_TERMIO
  1570. #ifdef umips
  1571.             /* If the control tty had its modes screwed around with,
  1572.                eg. by lineedit in the shell, or emacs, etc. then tio
  1573.                will have bad values.  Let's just get termio from the
  1574.                new tty and tailor it.  */
  1575.             if (ioctl (tty, TCGETA, &tio) == -1)
  1576.               SysError (ERROR_TIOCGETP);
  1577.             tio.c_lflag |= ECHOE;
  1578. #endif /* umips */
  1579.             /* Now is also the time to change the modes of the
  1580.              * child pty.
  1581.              */
  1582.             /* input: nl->nl, don't ignore cr, cr->nl */
  1583.             tio.c_iflag &= ~(INLCR|IGNCR);
  1584.             tio.c_iflag |= ICRNL;
  1585.             /* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */
  1586.             tio.c_oflag &=
  1587.              ~(OCRNL|ONLRET|NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
  1588.             tio.c_oflag |= ONLCR;
  1589. #ifdef BAUD_0
  1590.             /* baud rate is 0 (don't care) */
  1591.             tio.c_cflag &= ~(CBAUD);
  1592. #else    /* !BAUD_0 */
  1593.             /* baud rate is 9600 (nice default) */
  1594.             tio.c_cflag &= ~(CBAUD);
  1595.             tio.c_cflag |= B9600;
  1596. #endif    /* !BAUD_0 */
  1597.             /* enable signals, canonical processing (erase, kill, etc),
  1598.             ** echo
  1599.             */
  1600.             tio.c_lflag |= ISIG|ICANON|ECHO;
  1601.             /* reset EOL to defalult value */
  1602.             tio.c_cc[VEOL] = '@' & 0x3f;        /* '^@'    */
  1603.             /* certain shells (ksh & csh) change EOF as well */
  1604.             tio.c_cc[VEOF] = 'D' & 0x3f;        /* '^D'    */
  1605.  
  1606. #define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value;
  1607.             if (override_tty_modes) {
  1608.             /* sysv-specific */
  1609.             TMODE (XTTYMODE_intr, tio.c_cc[VINTR]);
  1610.             TMODE (XTTYMODE_quit, tio.c_cc[VQUIT]);
  1611.             TMODE (XTTYMODE_erase, tio.c_cc[VERASE]);
  1612.             TMODE (XTTYMODE_kill, tio.c_cc[VKILL]);
  1613.             TMODE (XTTYMODE_eof, tio.c_cc[VEOF]);
  1614.             TMODE (XTTYMODE_eol, tio.c_cc[VEOL]);
  1615. #ifdef VSWTCH
  1616.             TMODE (XTTYMODE_swtch, d_tio.c_cc[VSWTCH]);
  1617. #endif
  1618. #ifdef TIOCSLTC
  1619.             /* both SYSV and BSD have ltchars */
  1620.             TMODE (XTTYMODE_susp, ltc.t_suspc);
  1621.             TMODE (XTTYMODE_dsusp, ltc.t_dsuspc);
  1622.             TMODE (XTTYMODE_rprnt, ltc.t_rprntc);
  1623.             TMODE (XTTYMODE_flush, ltc.t_flushc);
  1624.             TMODE (XTTYMODE_weras, ltc.t_werasc);
  1625.             TMODE (XTTYMODE_lnext, ltc.t_lnextc);
  1626. #endif
  1627.             }
  1628. #undef TMODE
  1629.  
  1630.             if (ioctl (tty, TCSETA, &tio) == -1)
  1631.                 HsSysError(cp_pipe[1], ERROR_TIOCSETP);
  1632. #ifdef TIOCSLTC
  1633.             if (ioctl (tty, TIOCSLTC, <c) == -1)
  1634.                 HsSysError(cp_pipe[1], ERROR_TIOCSETC);
  1635. #endif    /* TIOCSLTC */
  1636. #ifdef TIOCLSET
  1637.             if (ioctl (tty, TIOCLSET, (char *)&lmode) == -1)
  1638.                 HsSysError(cp_pipe[1], ERROR_TIOCLSET);
  1639. #endif    /* TIOCLSET */
  1640. #ifdef TIOCCONS
  1641.             if (Console) {
  1642.                 int on = 1;
  1643.                 if (ioctl (tty, TIOCCONS, (char *)&on) == -1)
  1644.                     HsSysError(cp_pipe[1], ERROR_TIOCCONS);
  1645.             }
  1646. #endif    /* TIOCCONS */
  1647. #else    /* USE_SYSV_TERMIO */
  1648.             sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
  1649.             sg.sg_flags |= ECHO | CRMOD;
  1650.             /* make sure speed is set on pty so that editors work right*/
  1651.             sg.sg_ispeed = B9600;
  1652.             sg.sg_ospeed = B9600;
  1653.             /* reset t_brkc to default value */
  1654.             tc.t_brkc = -1;
  1655.  
  1656. #define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value;
  1657.             if (override_tty_modes) {
  1658.             TMODE (XTTYMODE_intr, tc.t_intrc);
  1659.             TMODE (XTTYMODE_quit, tc.t_quitc);
  1660.             TMODE (XTTYMODE_erase, sg.sg_erase);
  1661.             TMODE (XTTYMODE_kill, sg.sg_kill);
  1662.             TMODE (XTTYMODE_eof, tc.t_eofc);
  1663.             TMODE (XTTYMODE_start, tc.t_startc);
  1664.             TMODE (XTTYMODE_stop, tc.t_stopc);
  1665.             TMODE (XTTYMODE_brk, tc.t_brkc);
  1666.             /* both SYSV and BSD have ltchars */
  1667.             TMODE (XTTYMODE_susp, ltc.t_suspc);
  1668.             TMODE (XTTYMODE_dsusp, ltc.t_dsuspc);
  1669.             TMODE (XTTYMODE_rprnt, ltc.t_rprntc);
  1670.             TMODE (XTTYMODE_flush, ltc.t_flushc);
  1671.             TMODE (XTTYMODE_weras, ltc.t_werasc);
  1672.             TMODE (XTTYMODE_lnext, ltc.t_lnextc);
  1673.             }
  1674. #undef TMODE
  1675.  
  1676.             if (ioctl (tty, TIOCSETP, (char *)&sg) == -1)
  1677.                 HsSysError (cp_pipe[1], ERROR_TIOCSETP);
  1678.             if (ioctl (tty, TIOCSETC, (char *)&tc) == -1)
  1679.                 HsSysError (cp_pipe[1], ERROR_TIOCSETC);
  1680.             if (ioctl (tty, TIOCSETD, (char *)&discipline) == -1)
  1681.                 HsSysError (cp_pipe[1], ERROR_TIOCSETD);
  1682.             if (ioctl (tty, TIOCSLTC, (char *)<c) == -1)
  1683.                 HsSysError (cp_pipe[1], ERROR_TIOCSLTC);
  1684.             if (ioctl (tty, TIOCLSET, (char *)&lmode) == -1)
  1685.                 HsSysError (cp_pipe[1], ERROR_TIOCLSET);
  1686. #ifdef TIOCCONS
  1687.             if (Console) {
  1688.                 int on = 1;
  1689.                 if (ioctl (tty, TIOCCONS, (char *)&on) == -1)
  1690.                     HsSysError(cp_pipe[1], ERROR_TIOCCONS);
  1691.             }
  1692. #endif    /* TIOCCONS */
  1693. #endif    /* !USE_SYSV_TERMIO */
  1694.         }
  1695.  
  1696.         signal (SIGCHLD, SIG_DFL);
  1697. #ifdef att
  1698.         /* watch out for extra shells (I don't understand either) */
  1699.         signal (SIGHUP, SIG_DFL);
  1700. #else
  1701.         signal (SIGHUP, SIG_IGN);
  1702. #endif
  1703.         /* restore various signals to their defaults */
  1704.         signal (SIGINT, SIG_DFL);
  1705.         signal (SIGQUIT, SIG_DFL);
  1706.         signal (SIGTERM, SIG_DFL);
  1707.  
  1708.         /* copy the environment before Setenving */
  1709.         for (i = 0 ; environ [i] != NULL ; i++) ;
  1710.         /*
  1711.          * The `4' (`5' for SYSV) is the number of Setenv()
  1712.          * calls which may add a new entry to the environment.
  1713.          * The `1' is for the NULL terminating entry.
  1714.          */
  1715. #ifdef USE_SYSV_ENVVARS
  1716.         envnew = (char **) calloc ((unsigned) i + (5 + 1), sizeof(char *));
  1717. #else
  1718.         envnew = (char **) calloc ((unsigned) i + (4 + 1), sizeof(char *));
  1719. #endif /* USE_SYSV_ENVVARS */
  1720.         bcopy((char *)environ, (char *)envnew, i * sizeof(char *));
  1721.         environ = envnew;
  1722.         Setenv ("TERM=", TermName);
  1723.         if(!TermName)
  1724.             *newtc = 0;
  1725.  
  1726.         sprintf (buf, "%lu", screen->TekEmu ? 
  1727.              ((unsigned long) XtWindow (XtParent(tekWidget))) :
  1728.              ((unsigned long) XtWindow (XtParent(term))));
  1729.         Setenv ("WINDOWID=", buf);
  1730.         /* put the display into the environment of the shell*/
  1731.         Setenv ("DISPLAY=", XDisplayString (screen->display));
  1732.  
  1733.         signal(SIGTERM, SIG_DFL);
  1734.  
  1735.         /* this is the time to go and set up stdin, out, and err
  1736.          */
  1737.         {
  1738.             /* dup the tty */
  1739.             for (i = 0; i <= 2; i++)
  1740.             if (i != tty) {
  1741.                 (void) close(i);
  1742.                 (void) dup(tty);
  1743.             }
  1744.  
  1745. #ifndef att
  1746.             /* and close the tty */
  1747.             if (tty > 2)
  1748.             (void) close(tty);
  1749. #endif
  1750.         }
  1751.  
  1752. #ifndef    USE_SYSV_PGRP
  1753. #ifdef TIOCSCTTY
  1754.         setsid();
  1755.         ioctl(0, TIOCSCTTY, 0);
  1756. #endif
  1757.         ioctl(0, TIOCSPGRP, (char *)&pgrp);
  1758.         setpgrp(0,0);
  1759.         close(open(ttydev, O_WRONLY, 0));
  1760.         setpgrp (0, pgrp);
  1761. #endif /* USE_SYSV_PGRP */
  1762.  
  1763. #ifdef UTMP
  1764. #ifdef USE_SYSV_UTMP
  1765.         /* Set up our utmp entry now.  We need to do it here
  1766.         ** for the following reasons:
  1767.         **   - It needs to have our correct process id (for
  1768.         **     login).
  1769.         **   - If our parent was to set it after the fork(),
  1770.         **     it might make it out before we need it.
  1771.         **   - We need to do it before we go and change our
  1772.         **     user and group id's.
  1773.         */
  1774.  
  1775.         (void) setutent ();
  1776.         /* set up entry to search for */
  1777.         (void) strncpy(utmp.ut_id,ttydev + strlen(ttydev) - 2,
  1778.          sizeof (utmp.ut_id));
  1779.         utmp.ut_type = DEAD_PROCESS;
  1780.  
  1781.         /* position to entry in utmp file */
  1782.         (void) getutid(&utmp);
  1783.  
  1784.         /* set up the new entry */
  1785.         pw = getpwuid(screen->uid);
  1786.         utmp.ut_type = USER_PROCESS;
  1787.         utmp.ut_exit.e_exit = 2;
  1788.         (void) strncpy(utmp.ut_user,
  1789.                    (pw && pw->pw_name) ? pw->pw_name : "????",
  1790.                    sizeof(utmp.ut_user));
  1791.             
  1792.         (void) strncpy(utmp.ut_id, ttydev + strlen(ttydev) - 2,
  1793.             sizeof(utmp.ut_id));
  1794.         (void) strncpy (utmp.ut_line,
  1795.             ttydev + strlen("/dev/"), sizeof (utmp.ut_line));
  1796. #ifdef HAS_UTMP_UT_HOST
  1797.         (void) strncpy(utmp.ut_host, DisplayString(screen->display),
  1798.                    sizeof(utmp.ut_host));
  1799. #endif
  1800.         (void) strncpy(utmp.ut_name, pw->pw_name, 
  1801.                    sizeof(utmp.ut_name));
  1802.  
  1803.         utmp.ut_pid = getpid();
  1804.         utmp.ut_time = time ((long *) 0);
  1805.  
  1806.         /* write out the entry */
  1807.         if (!resource.utmpInhibit) (void) pututline(&utmp);
  1808.  
  1809.         /* close the file */
  1810.         (void) endutent();
  1811.  
  1812. #else    /* USE_SYSV_UTMP */
  1813.         /* We can now get our ttyslot!  We can also set the initial
  1814.          * UTMP entry.
  1815.          */
  1816.         tslot = ttyslot();
  1817.         added_utmp_entry = False;
  1818.         {
  1819.             if (!resource.utmpInhibit &&
  1820.                 (pw = getpwuid(screen->uid)) &&
  1821.                 (i = open(etc_utmp, O_WRONLY)) >= 0) {
  1822.                 bzero((char *)&utmp, sizeof(struct utmp));
  1823.                 (void) strncpy(utmp.ut_line,
  1824.                            ttydev + strlen("/dev/"),
  1825.                            sizeof(utmp.ut_line));
  1826.                 (void) strncpy(utmp.ut_name, pw->pw_name,
  1827.                            sizeof(utmp.ut_name));
  1828. #ifdef HAS_UTMP_UT_HOST
  1829.                 (void) strncpy(utmp.ut_host, 
  1830.                            XDisplayString (screen->display),
  1831.                            sizeof(utmp.ut_host));
  1832. #endif
  1833.                 time(&utmp.ut_time);
  1834.                 lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
  1835.                 write(i, (char *)&utmp, sizeof(struct utmp));
  1836.                 close(i);
  1837.                 added_utmp_entry = True;
  1838. #ifdef WTMP
  1839.                 if (term->misc.login_shell &&
  1840.                 (i = open(etc_wtmp, O_WRONLY|O_APPEND)) >= 0) {
  1841.                     write(i, (char *)&utmp,
  1842.                     sizeof(struct utmp));
  1843.                 close(i);
  1844.                 }
  1845. #endif /* WTMP */
  1846. #ifdef LASTLOG
  1847.                 if (term->misc.login_shell &&
  1848.                 (i = open(etc_lastlog, O_WRONLY)) >= 0) {
  1849.                     bzero((char *)&lastlog,
  1850.                     sizeof (struct lastlog));
  1851.                     (void) strncpy(lastlog.ll_line, ttydev +
  1852.                     sizeof("/dev"),
  1853.                     sizeof (lastlog.ll_line));
  1854.                     (void) strncpy(lastlog.ll_host, 
  1855.                       XDisplayString (screen->display),
  1856.                       sizeof (lastlog.ll_host));
  1857.                     time(&lastlog.ll_time);
  1858.                     lseek(i, (long)(screen->uid *
  1859.                     sizeof (struct lastlog)), 0);
  1860.                     write(i, (char *)&lastlog,
  1861.                     sizeof (struct lastlog));
  1862.                     close(i);
  1863.                 }
  1864. #endif /* LASTLOG */
  1865.             } else
  1866.                 tslot = -tslot;
  1867.         }
  1868.  
  1869.         /* Let's pass our ttyslot to our parent so that it can
  1870.          * clean up after us.
  1871.          */
  1872. #ifdef USE_HANDSHAKE
  1873.         handshake.tty_slot = tslot;
  1874. #endif /* USE_HANDSHAKE */
  1875. #endif /* USE_SYSV_UTMP */
  1876.  
  1877. #ifdef USE_HANDSHAKE
  1878.         /* Let our parent know that we set up our utmp entry
  1879.          * so that it can clean up after us.
  1880.          */
  1881.         handshake.status = UTMP_ADDED;
  1882.         handshake.error = 0;
  1883.         strcpy(handshake.buffer, ttydev);
  1884.         (void) write(cp_pipe[1], &handshake, sizeof(handshake));
  1885. #endif /* USE_HANDSHAKE */
  1886. #endif/* UTMP */
  1887.  
  1888.         (void) setgid (screen->gid);
  1889. #ifdef HAS_BSD_GROUPS
  1890.         if (geteuid() == 0)
  1891.           initgroups (pw->pw_name, pw->pw_gid);
  1892. #endif
  1893.         (void) setuid (screen->uid);
  1894.  
  1895. #ifdef USE_HANDSHAKE
  1896.         /* mark the pipes as close on exec */
  1897.         fcntl(cp_pipe[1], F_SETFD, 1);
  1898.         fcntl(pc_pipe[0], F_SETFD, 1);
  1899.  
  1900.         /* We are at the point where we are going to
  1901.          * exec our shell (or whatever).  Let our parent
  1902.          * know we arrived safely.
  1903.          */
  1904.         handshake.status = PTY_GOOD;
  1905.         handshake.error = 0;
  1906.         (void) strcpy(handshake.buffer, ttydev);
  1907.         (void) write(cp_pipe[1], &handshake, sizeof(handshake));
  1908.  
  1909.         if (waiting_for_initial_map) {
  1910.             i = read (pc_pipe[0], (char *) &handshake,
  1911.                   sizeof(handshake));
  1912.             if (i != sizeof(handshake) ||
  1913.             handshake.status != PTY_EXEC) {
  1914.             /* some very bad problem occurred */
  1915.             exit (ERROR_PTY_EXEC);
  1916.             }
  1917.             screen->max_row = handshake.rows;
  1918.             screen->max_col = handshake.cols;
  1919. #ifdef sun
  1920. #ifdef TIOCSSIZE
  1921.             ts.ts_lines = screen->max_row + 1;
  1922.             ts.ts_cols = screen->max_col + 1;
  1923. #endif /* TIOCSSIZE */
  1924. #else /* !sun */
  1925. #ifdef TIOCSWINSZ
  1926.             ws.ws_row = screen->max_row + 1;
  1927.             ws.ws_col = screen->max_col + 1;
  1928.             ws.ws_xpixel = FullWidth(screen);
  1929.             ws.ws_ypixel = FullHeight(screen);
  1930. #endif /* TIOCSWINSZ */
  1931. #endif /* sun else !sun */
  1932.         }
  1933. #endif /* USE_HANDSHAKE */
  1934.  
  1935. #ifdef USE_SYSV_ENVVARS
  1936.         sprintf (numbuf, "%d", screen->max_col + 1);
  1937.         Setenv("COLUMNS=", numbuf);
  1938.         sprintf (numbuf, "%d", screen->max_row + 1);
  1939.         Setenv("LINES=", numbuf);
  1940. #else
  1941.         if(!screen->TekEmu) {
  1942.             strcpy (termcap, newtc);
  1943.             resize (screen, TermName, termcap, newtc);
  1944.         }
  1945.         if (term->misc.titeInhibit) {
  1946.             remove_termcap_entry (newtc, ":ti=");
  1947.             remove_termcap_entry (newtc, ":te=");
  1948.         }
  1949.         Setenv ("TERMCAP=", newtc);
  1950. #endif /* USE_SYSV_ENVVAR */
  1951.  
  1952.  
  1953.         /* need to reset after all the ioctl bashing we did above */
  1954. #ifdef sun
  1955. #ifdef TIOCSSIZE
  1956.         ioctl  (0, TIOCSSIZE, &ts);
  1957. #endif    /* TIOCSSIZE */
  1958. #else    /* not sun */
  1959. #ifdef TIOCSWINSZ
  1960.         ioctl (0, TIOCSWINSZ, (char *)&ws);
  1961. #endif    /* TIOCSWINSZ */
  1962. #endif    /* sun */
  1963.  
  1964.         signal(SIGHUP, SIG_DFL);
  1965.         if (command_to_exec) {
  1966.             execvp(*command_to_exec, command_to_exec);
  1967.             /* print error message on screen */
  1968.             fprintf(stderr, "%s: Can't execvp %s\n", xterm_name,
  1969.              *command_to_exec);
  1970.         } 
  1971.  
  1972. #ifdef att
  1973.         /* fix pts sh hanging around */
  1974.         signal (SIGHUP, SIG_DFL);
  1975. #endif
  1976.  
  1977. #ifdef UTMP
  1978.         if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
  1979.          ((pw == NULL && (pw = getpwuid(screen->uid)) == NULL) ||
  1980.          *(ptr = pw->pw_shell) == 0))
  1981. #else    /* UTMP */
  1982.         if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
  1983.          ((pw = getpwuid(screen->uid)) == NULL ||
  1984.          *(ptr = pw->pw_shell) == 0))
  1985. #endif    /* UTMP */
  1986.             ptr = "/bin/sh";
  1987.         if(shname = rindex(ptr, '/'))
  1988.             shname++;
  1989.         else
  1990.             shname = ptr;
  1991.         shname_minus = malloc(strlen(shname) + 2);
  1992.         (void) strcpy(shname_minus, "-");
  1993.         (void) strcat(shname_minus, shname);
  1994. #ifndef USE_SYSV_TERMIO
  1995.         ldisc = XStrCmp("csh", shname + strlen(shname) - 3) == 0 ?
  1996.          NTTYDISC : 0;
  1997.         ioctl(0, TIOCSETD, (char *)&ldisc);
  1998. #endif    /* !USE_SYSV_TERMIO */
  1999.  
  2000. #ifdef USE_LOGIN_DASH_P
  2001.         if (term->misc.login_shell && pw && added_utmp_entry)
  2002.           execl (bin_login, "login", "-p", "-f", pw->pw_name, 0);
  2003. #endif
  2004.         execlp (ptr, (term->misc.login_shell ? shname_minus : shname),
  2005.             0);
  2006.  
  2007.         /* Exec failed. */
  2008.         fprintf (stderr, "%s: Could not exec %s!\n", xterm_name, ptr);
  2009.         sleep(5);
  2010.         exit(ERROR_EXEC);
  2011.         }                /* end if in child after fork */
  2012.  
  2013. #ifdef USE_HANDSHAKE
  2014.         /* Parent process.  Let's handle handshaked requests to our
  2015.          * child process.
  2016.          */
  2017.  
  2018.         /* close childs's sides of the pipes */
  2019.         close (cp_pipe[1]);
  2020.         close (pc_pipe[0]);
  2021.  
  2022.         for (done = 0; !done; ) {
  2023.         if (read(cp_pipe[0], &handshake, sizeof(handshake)) <= 0) {
  2024.             /* Our child is done talking to us.  If it terminated
  2025.              * due to an error, we will catch the death of child
  2026.              * and clean up.
  2027.              */
  2028.             break;
  2029.         }
  2030.  
  2031.         switch(handshake.status) {
  2032.         case PTY_GOOD:
  2033.             /* Success!  Let's free up resources and
  2034.              * continue.
  2035.              */
  2036.             done = 1;
  2037.             break;
  2038.  
  2039.         case PTY_BAD:
  2040.             /* The open of the pty failed!  Let's get
  2041.              * another one.
  2042.              */
  2043.             (void) close(screen->respond);
  2044.             if (get_pty(&screen->respond)) {
  2045.                 /* no more ptys! */
  2046.                 (void) fprintf(stderr,
  2047.                    "%s: no available ptys\n", xterm_name);
  2048.                 handshake.status = PTY_NOMORE;
  2049.                 write(pc_pipe[1], &handshake, sizeof(handshake));
  2050.                 exit (ERROR_PTYS);
  2051.             }
  2052.             handshake.status = PTY_NEW;
  2053.             (void) strcpy(handshake.buffer, ttydev);
  2054.             write(pc_pipe[1], &handshake, sizeof(handshake));
  2055.             break;
  2056.  
  2057.         case PTY_FATALERROR:
  2058.             errno = handshake.error;
  2059.             close(cp_pipe[0]);
  2060.             close(pc_pipe[1]);
  2061.             SysError(handshake.fatal_error);
  2062.  
  2063.         case UTMP_ADDED:
  2064.             /* The utmp entry was set by our slave.  Remember
  2065.              * this so that we can reset it later.
  2066.              */
  2067.             added_utmp_entry = True;
  2068. #ifndef    USE_SYSV_UTMP
  2069.             tslot = handshake.tty_slot;
  2070. #endif    /* USE_SYSV_UTMP */
  2071.             free(ttydev);
  2072.             ttydev = malloc((unsigned) strlen(handshake.buffer) + 1);
  2073.             strcpy(ttydev, handshake.buffer);
  2074.             break;
  2075.         }
  2076.         }
  2077.         /* close our sides of the pipes */
  2078.         if (!waiting_for_initial_map) {
  2079.         close (cp_pipe[0]);
  2080.         close (pc_pipe[1]);
  2081.         }
  2082. #endif /* USE_HANDSHAKE */
  2083.     }                /* end if no slave */
  2084.  
  2085.     /*
  2086.      * still in parent (xterm process)
  2087.      */
  2088.  
  2089. #ifdef att
  2090.     /* hung sh problem? */
  2091.     signal (SIGHUP, SIG_DFL);
  2092. #else
  2093.     signal (SIGHUP,SIG_IGN);
  2094. #endif
  2095.  
  2096. /*
  2097.  * Unfortunately, System V seems to have trouble divorcing the child process
  2098.  * from the process group of xterm.  This is a problem because hitting the 
  2099.  * INTR or QUIT characters on the keyboard will cause xterm to go away if we
  2100.  * don't ignore the signals.  This is annoying.
  2101.  */
  2102.  
  2103. #if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
  2104.     signal (SIGINT, SIG_IGN);
  2105.  
  2106. #ifndef att
  2107.     /* hung shell problem */
  2108.     signal (SIGQUIT, SIG_IGN);
  2109. #endif
  2110.     signal (SIGTERM, SIG_IGN);
  2111. #else /* else is bsd or has job control */
  2112. #ifdef SYSV
  2113.     /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
  2114.      * then our pgrp and pid will be the same.  If we were spawned by
  2115.      * a jobcontrol dump shell (like /bin/sh), then we will be in out
  2116.      * parents pgrp, and we must ignore keyboard signals, or will will
  2117.      * tank on everything.
  2118.      */
  2119.     if (getpid() == getpgrp()) {
  2120.         (void) signal(SIGINT, Exit);
  2121.         (void) signal(SIGQUIT, Exit);
  2122.         (void) signal(SIGTERM, Exit);
  2123.     } else {
  2124.         (void) signal(SIGINT, SIG_IGN);
  2125.         (void) signal(SIGQUIT, SIG_IGN);
  2126.         (void) signal(SIGTERM, SIG_IGN);
  2127.     }
  2128. #else    /* SYSV */
  2129.     signal (SIGINT, Exit);
  2130.     signal (SIGQUIT, Exit);
  2131.     signal (SIGTERM, Exit);
  2132. #endif    /* SYSV */
  2133. #endif /* USE_SYSV_SIGNALS and not SIGTSTP */
  2134.  
  2135.     return;
  2136. }                            /* end spawn */
  2137.  
  2138. SIGNAL_T Exit(n)
  2139.     int n;
  2140. {
  2141.     register TScreen *screen = &term->screen;
  2142.         int pty = term->screen.respond;  /* file descriptor of pty */
  2143. #ifdef UTMP
  2144. #ifdef USE_SYSV_UTMP
  2145.     struct utmp utmp;
  2146.     struct utmp *utptr;
  2147. #ifdef WTMP
  2148.     int fd;            /* for /etc/wtmp */
  2149. #endif
  2150.     /* cleanup the utmp entry we forged earlier */
  2151.     if (!resource.utmpInhibit && added_utmp_entry) {
  2152. #ifdef CRAY
  2153. #define PTYCHARLEN 4
  2154. #else
  2155. #define PTYCHARLEN 2
  2156. #endif
  2157.         utmp.ut_type = USER_PROCESS;
  2158.         (void) strncpy(utmp.ut_id, ttydev + strlen(ttydev) - PTYCHARLEN,
  2159.             sizeof(utmp.ut_id));
  2160.         (void) setutent();
  2161.         utptr = getutid(&utmp);
  2162.         /* write it out only if it exists, and the pid's match */
  2163.         if (utptr && (utptr->ut_pid = screen->pid)) {
  2164.             utptr->ut_type = DEAD_PROCESS;
  2165.             utptr->ut_time = time((long *) 0);
  2166.             (void) pututline(utptr);
  2167. #ifdef WTMP
  2168.             /* set wtmp entry if wtmp file exists */
  2169.             if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
  2170.               (void) write(fd, utptr, sizeof(utmp));
  2171.               (void) close(fd);
  2172.             }
  2173. #endif
  2174.  
  2175.         }
  2176.         (void) endutent();
  2177.     }
  2178. #else    /* not USE_SYSV_UTMP */
  2179.     register int i;
  2180.     struct utmp utmp;
  2181.  
  2182.     if (!resource.utmpInhibit && added_utmp_entry &&
  2183.         (!am_slave && tslot > 0 && (i = open(etc_utmp, O_WRONLY)) >= 0)) {
  2184.         bzero((char *)&utmp, sizeof(struct utmp));
  2185.         lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
  2186.         write(i, (char *)&utmp, sizeof(struct utmp));
  2187.         close(i);
  2188. #ifdef WTMP
  2189.         if (term->misc.login_shell &&
  2190.             (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
  2191.             (void) strncpy(utmp.ut_line, ttydev +
  2192.                 sizeof("/dev"), sizeof (utmp.ut_line));
  2193.             time(&utmp.ut_time);
  2194.             write(i, (char *)&utmp, sizeof(struct utmp));
  2195.             close(i);
  2196.         }
  2197. #endif /* WTMP */
  2198.     }
  2199. #endif    /* USE_SYSV_UTMP */
  2200. #endif    /* UTMP */
  2201.         close(pty); /* close explicitly to avoid race with slave side */
  2202.     if(screen->logging)
  2203.         CloseLog(screen);
  2204.  
  2205.     if (!am_slave) {
  2206.         /* restore ownership of tty and pty */
  2207.         chown (ttydev, 0, 0);
  2208.         chown (ptydev, 0, 0);
  2209.  
  2210.         /* restore modes of tty and pty */
  2211.         chmod (ttydev, 0666);
  2212.         chmod (ptydev, 0666);
  2213.     }
  2214.     exit(n);
  2215.     SIGNAL_RETURN;
  2216. }
  2217.  
  2218. /* ARGSUSED */
  2219. resize(screen, TermName, oldtc, newtc)
  2220. TScreen *screen;
  2221. char *TermName;
  2222. register char *oldtc, *newtc;
  2223. {
  2224. #ifndef USE_SYSV_ENVVARS
  2225.     register char *ptr1, *ptr2;
  2226.     register int i;
  2227.     register int li_first = 0;
  2228.     register char *temp;
  2229.     char *index();
  2230.  
  2231.     if ((ptr1 = strindex (oldtc, "co#")) == NULL){
  2232.         strcat (oldtc, "co#80:");
  2233.         ptr1 = strindex (oldtc, "co#");
  2234.     }
  2235.     if ((ptr2 = strindex (oldtc, "li#")) == NULL){
  2236.         strcat (oldtc, "li#24:");
  2237.         ptr2 = strindex (oldtc, "li#");
  2238.     }
  2239.     if(ptr1 > ptr2) {
  2240.         li_first++;
  2241.         temp = ptr1;
  2242.         ptr1 = ptr2;
  2243.         ptr2 = temp;
  2244.     }
  2245.     ptr1 += 3;
  2246.     ptr2 += 3;
  2247.     strncpy (newtc, oldtc, i = ptr1 - oldtc);
  2248.     newtc += i;
  2249.     sprintf (newtc, "%d", li_first ? screen->max_row + 1 :
  2250.      screen->max_col + 1);
  2251.     newtc += strlen(newtc);
  2252.     ptr1 = index (ptr1, ':');
  2253.     strncpy (newtc, ptr1, i = ptr2 - ptr1);
  2254.     newtc += i;
  2255.     sprintf (newtc, "%d", li_first ? screen->max_col + 1 :
  2256.      screen->max_row + 1);
  2257.     ptr2 = index (ptr2, ':');
  2258.     strcat (newtc, ptr2);
  2259. #endif /* USE_SYSV_ENVVARS */
  2260. }
  2261.  
  2262. static SIGNAL_T reapchild ()
  2263. {
  2264. #if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
  2265.     int status, pid;
  2266.  
  2267.     pid = wait(&status);
  2268.     if (pid == -1) {
  2269.         (void) signal(SIGCHLD, reapchild);
  2270.         SIGNAL_RETURN;
  2271.     }
  2272. #else    /* defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) */
  2273.     union wait status;
  2274.     register int pid;
  2275.     
  2276. #ifdef DEBUG
  2277.     if (debug) fputs ("Exiting\n", stderr);
  2278. #endif    /* DEBUG */
  2279.     pid  = wait3 (&status, WNOHANG, (struct rusage *)NULL);
  2280.     if (!pid) {
  2281. #ifdef USE_SYSV_SIGNALS
  2282.         (void) signal(SIGCHLD, reapchild);
  2283. #endif /* USE_SYSV_SIGNALS */
  2284.         SIGNAL_RETURN;
  2285.     }
  2286. #endif    /* defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) */
  2287.  
  2288. #ifdef PUCC_PTYD
  2289.         closepty(ttydev, ptydev, (resource.utmpInhibit ?  OPTY_NOP : OPTY_LOGIN), Ptyfd);
  2290. #endif /* PUCC_PTYD */
  2291.  
  2292.     if (pid != term->screen.pid) {
  2293. #ifdef USE_SYSV_SIGNALS
  2294.         (void) signal(SIGCHLD, reapchild);
  2295. #endif    /* USE_SYSV_SIGNALS */
  2296.         SIGNAL_RETURN;
  2297.     }
  2298.     
  2299.     /*
  2300.      * Use pid instead of process group (which would have to get before
  2301.      * the wait call above) so that we don't accidentally hose other
  2302.      * applications.  Otherwise, somebody could write a program which put
  2303.      * itself in somebody else's process group.  Also, we call Exit instead
  2304.      * of Cleanup so that we don't do a killpg on -1 by accident.  Some
  2305.      * operating systems seem to do very nasty things with that.
  2306.      */
  2307.     if (pid > 1) {
  2308.         killpg (pid, SIGHUP);
  2309.     }
  2310.     Exit (0);
  2311.     SIGNAL_RETURN;
  2312. }
  2313.  
  2314. /* VARARGS1 */
  2315. consolepr(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
  2316. char *fmt;
  2317. {
  2318.     extern int errno;
  2319.     extern char *SysErrorMsg();
  2320.     int oerrno;
  2321.     int f;
  2322.      char buf[ BUFSIZ ];
  2323.  
  2324.     oerrno = errno;
  2325.      strcpy(buf, "xterm: ");
  2326.      sprintf(buf+strlen(buf), fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
  2327.      strcat(buf, ": ");
  2328.      strcat(buf, SysErrorMsg (oerrno));
  2329.      strcat(buf, "\n");    
  2330.     f = open("/dev/console",O_WRONLY);
  2331.     write(f, buf, strlen(buf));
  2332.     close(f);
  2333. #ifdef TIOCNOTTY
  2334.     if ((f = open("/dev/tty", 2)) >= 0) {
  2335.         ioctl(f, TIOCNOTTY, (char *)NULL);
  2336.         close(f);
  2337.     }
  2338. #endif    /* TIOCNOTTY */
  2339. }
  2340.  
  2341.  
  2342. remove_termcap_entry (buf, str)
  2343.     char *buf;
  2344.     char *str;
  2345. {
  2346.     register char *strinbuf;
  2347.  
  2348.     strinbuf = strindex (buf, str);
  2349.     if (strinbuf) {
  2350.         register char *colonPtr = index (strinbuf+1, ':');
  2351.         if (colonPtr) {
  2352.             while (*colonPtr) {
  2353.                 *strinbuf++ = *colonPtr++;      /* copy down */
  2354.             }
  2355.             *strinbuf = '\0';
  2356.         } else {
  2357.             strinbuf[1] = '\0';
  2358.         }
  2359.     }
  2360.     return;
  2361. }
  2362.  
  2363. /*
  2364.  * parse_tty_modes accepts lines of the following form:
  2365.  *
  2366.  *         [SETTING] ...
  2367.  *
  2368.  * where setting consists of the words in the modelist followed by a character
  2369.  * or ^char.
  2370.  */
  2371. static int parse_tty_modes (s, modelist, nmodes)
  2372.     char *s;
  2373.     struct _xttymodes *modelist;
  2374.     int nmodes;
  2375. {
  2376.     struct _xttymodes *mp;
  2377.     int c, i;
  2378.     int count = 0;
  2379.  
  2380.     while (1) {
  2381.     while (*s && isascii(*s) && isspace(*s)) s++;
  2382.     if (!*s) return count;
  2383.  
  2384.     for (mp = modelist, i = 0; mp->name; mp++, i++) {
  2385.         if (strncmp (s, mp->name, mp->len) == 0) break;
  2386.     }
  2387.     if (!mp->name) return -1;
  2388.  
  2389.     s += mp->len;
  2390.     while (*s && isascii(*s) && isspace(*s)) s++;
  2391.     if (!*s) return -1;
  2392.  
  2393.     if (*s == '^') {
  2394.         s++;
  2395.         c = ((*s == '?') ? 0177 : *s & 31);     /* keep control bits */
  2396.     } else {
  2397.         c = *s;
  2398.     }
  2399.     mp->value = c;
  2400.     mp->set = 1;
  2401.     count++;
  2402.     s++;
  2403.     }
  2404. }
  2405.  
  2406.  
  2407. int GetBytesAvailable (fd)
  2408.     int fd;
  2409. {
  2410. #ifdef FIONREAD
  2411.     static long arg;
  2412.     ioctl (fd, FIONREAD, (char *) &arg);
  2413.     return (int) arg;
  2414. #else
  2415.     struct pollfd pollfds[1];
  2416.  
  2417.     pollfds[0].fd = fd;
  2418.     pollfds[0].events = POLLIN;
  2419.     return poll (pollfds, 1, 0);
  2420. #endif
  2421. }
  2422.  
  2423. /* Utility function to try to hide system differences from
  2424.    everybody who used to call killpg() */
  2425. /* ARGSUSED */
  2426. int
  2427. kill_process_group(pid, sig)
  2428.     int pid;
  2429.     int sig;
  2430. {
  2431. #ifndef X_NOT_POSIX
  2432.     return kill (-pid, sig);
  2433. #else
  2434. #if defined(SVR4) || defined(SYSV)
  2435.     return kill (-pid, sig);
  2436. #else
  2437.     return killpg (pid, sig);
  2438. #endif
  2439. #endif
  2440. }
  2441.  
  2442. /* ARGSUSED */
  2443. static void
  2444. DeleteWindow(w, event, params, num_params)
  2445.     Widget w;
  2446.     XEvent *event;
  2447.     String *params;
  2448.     Cardinal *num_params;
  2449. {
  2450.   if (w == toplevel)
  2451.     if (term->screen.Tshow)
  2452.       hide_vt_window();
  2453.     else
  2454.       do_hangup(w);
  2455.   else
  2456.     if (term->screen.Vshow)
  2457.       hide_tek_window();
  2458.     else
  2459.       do_hangup(w);
  2460. }
  2461.  
  2462. /* ARGSUSED */
  2463. static void
  2464. KeyboardMapping(w, event, params, num_params)
  2465.     Widget w;
  2466.     XEvent *event;
  2467.     String *params;
  2468.     Cardinal *num_params;
  2469. {
  2470.     switch (event->type) {
  2471.        case MappingNotify:
  2472.     XRefreshKeyboardMapping(&event->xmapping);
  2473.     break;
  2474.     }
  2475. }
  2476.