"Fossies" - the Fresh Open Source Software Archive

Member "xterm-368/main.c" (3 Jun 2021, 157424 Bytes) of package /linux/misc/xterm-368.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 367_vs_368.

    1 /* $XTermId: main.c,v 1.881 2021/06/03 21:23:20 tom Exp $ */
    2 
    3 /*
    4  * Copyright 2002-2020,2021 by Thomas E. Dickey
    5  *
    6  *                         All Rights Reserved
    7  *
    8  * Permission is hereby granted, free of charge, to any person obtaining a
    9  * copy of this software and associated documentation files (the
   10  * "Software"), to deal in the Software without restriction, including
   11  * without limitation the rights to use, copy, modify, merge, publish,
   12  * distribute, sublicense, and/or sell copies of the Software, and to
   13  * permit persons to whom the Software is furnished to do so, subject to
   14  * the following conditions:
   15  *
   16  * The above copyright notice and this permission notice shall be included
   17  * in all copies or substantial portions of the Software.
   18  *
   19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   22  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
   23  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
   24  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
   25  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   26  *
   27  * Except as contained in this notice, the name(s) of the above copyright
   28  * holders shall not be used in advertising or otherwise to promote the
   29  * sale, use or other dealings in this Software without prior written
   30  * authorization.
   31  *
   32  * Copyright 1987, 1988  X Consortium
   33  *
   34  * Permission to use, copy, modify, distribute, and sell this software and its
   35  * documentation for any purpose is hereby granted without fee, provided that
   36  * the above copyright notice appear in all copies and that both that
   37  * copyright notice and this permission notice appear in supporting
   38  * documentation.
   39  *
   40  * The above copyright notice and this permission notice shall be included in
   41  * all copies or substantial portions of the Software.
   42  *
   43  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   44  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   45  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
   46  * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
   47  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
   48  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   49  *
   50  * Except as contained in this notice, the name of the X Consortium shall not be
   51  * used in advertising or otherwise to promote the sale, use or other dealings
   52  * in this Software without prior written authorization from the X Consortium.
   53  *
   54  * Copyright 1987, 1988 by Digital Equipment Corporation, Maynard.
   55  *
   56  *                         All Rights Reserved
   57  *
   58  * Permission to use, copy, modify, and distribute this software and its
   59  * documentation for any purpose and without fee is hereby granted,
   60  * provided that the above copyright notice appear in all copies and that
   61  * both that copyright notice and this permission notice appear in
   62  * supporting documentation, and that the name of Digital not be used in
   63  * advertising or publicity pertaining to distribution of the software
   64  * without specific, written prior permission.
   65  *
   66  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
   67  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
   68  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
   69  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
   70  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
   71  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
   72  * SOFTWARE.
   73  */
   74 
   75 /*
   76  *               W A R N I N G
   77  *
   78  * If you think you know what all of this code is doing, you are
   79  * probably very mistaken.  There be serious and nasty dragons here.
   80  *
   81  * This client is *not* to be taken as an example of how to write X
   82  * Toolkit applications.  It is in need of a substantial rewrite,
   83  * ideally to create a generic tty widget with several different parsing
   84  * widgets so that you can plug 'em together any way you want.  Don't
   85  * hold your breath, though....
   86  */
   87 
   88 /* main.c */
   89 
   90 #define RES_OFFSET(field)   XtOffsetOf(XTERM_RESOURCE, field)
   91 
   92 #include <xterm.h>
   93 #include <version.h>
   94 #include <graphics.h>
   95 
   96 #if OPT_TOOLBAR
   97 
   98 #if defined(HAVE_LIB_XAW)
   99 #include <X11/Xaw/Form.h>
  100 #elif defined(HAVE_LIB_XAW3D)
  101 #include <X11/Xaw3d/Form.h>
  102 #elif defined(HAVE_LIB_XAW3DXFT)
  103 #include <X11/Xaw3dxft/Form.h>
  104 #include <X11/Xaw3dxft/Xaw3dXft.h>
  105 #elif defined(HAVE_LIB_NEXTAW)
  106 #include <X11/neXtaw/Form.h>
  107 #elif defined(HAVE_LIB_XAWPLUS)
  108 #include <X11/XawPlus/Form.h>
  109 #endif
  110 
  111 #else
  112 
  113 #if defined(HAVE_LIB_XAW3DXFT)
  114 #include <X11/Xaw3dxft/Xaw3dXft.h>
  115 #endif
  116 
  117 #endif /* OPT_TOOLBAR */
  118 
  119 #include <pwd.h>
  120 #include <ctype.h>
  121 
  122 #include <data.h>
  123 #include <error.h>
  124 #include <menu.h>
  125 #include <main.h>
  126 #include <xstrings.h>
  127 #include <xtermcap.h>
  128 #include <xterm_io.h>
  129 
  130 #if OPT_WIDE_CHARS
  131 #include <charclass.h>
  132 #endif
  133 
  134 #ifdef __osf__
  135 #define USE_SYSV_SIGNALS
  136 #define WTMP
  137 #include <pty.h>        /* openpty() */
  138 #endif
  139 
  140 #ifdef __sgi
  141 #include <grp.h>        /* initgroups() */
  142 #endif
  143 
  144 static GCC_NORETURN void hungtty(int);
  145 static GCC_NORETURN void Syntax(char *);
  146 static GCC_NORETURN void HsSysError(int);
  147 
  148 #if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE) || ( defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 1) )
  149 #define USE_POSIX_SIGNALS
  150 #endif
  151 
  152 #if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
  153 /* older SYSV systems cannot ignore SIGHUP.
  154    Shell hangs, or you get extra shells, or something like that */
  155 #define USE_SYSV_SIGHUP
  156 #endif
  157 
  158 #if defined(sony) && defined(bsd43) && !defined(KANJI)
  159 #define KANJI
  160 #endif
  161 
  162 #ifdef linux
  163 #define USE_SYSV_PGRP
  164 #define USE_SYSV_SIGNALS
  165 #define WTMP
  166 #ifdef __GLIBC__
  167 #if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
  168 #include <pty.h>
  169 #endif
  170 #endif
  171 #endif
  172 
  173 #ifdef __MVS__
  174 #define USE_SYSV_PGRP
  175 #define USE_SYSV_SIGNALS
  176 #endif
  177 
  178 #ifdef __CYGWIN__
  179 #define WTMP
  180 #endif
  181 
  182 #ifdef __SCO__
  183 #ifndef _SVID3
  184 #define _SVID3
  185 #endif
  186 #endif
  187 
  188 #if defined(__GLIBC__) && !defined(linux)
  189 #define USE_SYSV_PGRP
  190 #define WTMP
  191 #endif
  192 
  193 #if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID) || defined(HAVE_INITGROUPS)
  194 #include <grp.h>
  195 #endif
  196 
  197 #ifndef TTY_GROUP_NAME
  198 #define TTY_GROUP_NAME "tty"
  199 #endif
  200 
  201 #include <sys/stat.h>
  202 
  203 #ifdef Lynx
  204 #ifndef BSDLY
  205 #define BSDLY   0
  206 #endif
  207 #ifndef VTDLY
  208 #define VTDLY   0
  209 #endif
  210 #ifndef FFDLY
  211 #define FFDLY   0
  212 #endif
  213 #endif
  214 
  215 #ifdef SYSV         /* { */
  216 
  217 #ifdef USE_USG_PTYS     /* AT&T SYSV has no ptyio.h */
  218 #include <sys/stropts.h>    /* for I_PUSH */
  219 #include <poll.h>       /* for POLLIN */
  220 #endif /* USE_USG_PTYS */
  221 
  222 #define USE_SYSV_SIGNALS
  223 #define USE_SYSV_PGRP
  224 
  225 #if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
  226 #define USE_SYSV_ENVVARS    /* COLUMNS/LINES vs. TERMCAP */
  227 #endif
  228 
  229 /*
  230  * now get system-specific includes
  231  */
  232 #ifdef macII
  233 #include <sys/ttychars.h>
  234 #undef USE_SYSV_ENVVARS
  235 #undef FIOCLEX
  236 #undef FIONCLEX
  237 #define setpgrp2 setpgrp
  238 #include <sgtty.h>
  239 #include <sys/resource.h>
  240 #endif
  241 
  242 #ifdef __hpux
  243 #include <sys/ptyio.h>
  244 #endif /* __hpux */
  245 
  246 #ifdef __osf__
  247 #undef  USE_SYSV_PGRP
  248 #define setpgrp setpgid
  249 #endif
  250 
  251 #ifdef __sgi
  252 #include <sys/sysmacros.h>
  253 #endif /* __sgi */
  254 
  255 #ifdef sun
  256 #include <sys/strredir.h>
  257 #endif
  258 
  259 #else /* } !SYSV { */ /* BSD systems */
  260 
  261 #ifdef __QNX__
  262 
  263 #ifndef __QNXNTO__
  264 #define ttyslot() 1
  265 #else
  266 #define USE_SYSV_PGRP
  267 extern __inline__
  268 int
  269 ttyslot(void)
  270 {
  271     return 1;           /* yuk */
  272 }
  273 #endif
  274 
  275 #else
  276 
  277 #if defined(__INTERIX) || defined(__APPLE__)
  278 #define setpgrp setpgid
  279 #endif
  280 
  281 #ifndef linux
  282 #ifndef VMS
  283 #ifndef USE_POSIX_TERMIOS
  284 #ifndef USE_ANY_SYSV_TERMIO
  285 #include <sgtty.h>
  286 #endif
  287 #endif /* USE_POSIX_TERMIOS */
  288 #ifdef Lynx
  289 #include <resource.h>
  290 #else
  291 #include <sys/resource.h>
  292 #endif
  293 #endif /* !VMS */
  294 #endif /* !linux */
  295 
  296 #endif /* __QNX__ */
  297 
  298 #endif /* } !SYSV */
  299 
  300 /* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
  301 #if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
  302 #ifndef NOFILE
  303 #define NOFILE OPEN_MAX
  304 #endif
  305 #elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
  306 #include <sys/param.h>      /* for NOFILE */
  307 #endif
  308 
  309 #if defined(BSD) && (BSD >= 199103)
  310 #define WTMP
  311 #endif
  312 
  313 #include <stdio.h>
  314 
  315 #ifdef __hpux
  316 #include <sys/utsname.h>
  317 #endif /* __hpux */
  318 
  319 #if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
  320 #define ttyslot() 1
  321 #endif /* apollo */
  322 
  323 #if defined(UTMPX_FOR_UTMP)
  324 #define UTMP_STR utmpx
  325 #else
  326 #define UTMP_STR utmp
  327 #endif
  328 
  329 #if defined(USE_UTEMPTER)
  330 #include <utempter.h>
  331 #if 1
  332 #define UTEMPTER_ADD(pty,hostname,master_fd) utempter_add_record(master_fd, hostname)
  333 #define UTEMPTER_DEL()                       utempter_remove_added_record ()
  334 #else
  335 #define UTEMPTER_ADD(pty,hostname,master_fd) addToUtmp(pty, hostname, master_fd)
  336 #define UTEMPTER_DEL()                       removeFromUtmp()
  337 #endif
  338 #endif
  339 
  340 #if defined(I_FIND) && defined(I_PUSH)
  341 #define PUSH_FAILS(fd,name) ioctl(fd, I_FIND, name) == 0 \
  342              && ioctl(fd, I_PUSH, name) < 0
  343 #else
  344 #define PUSH_FAILS(fd,name) ioctl(fd, I_PUSH, name) < 0
  345 #endif
  346 
  347 #if defined(UTMPX_FOR_UTMP)
  348 
  349 #include <utmpx.h>
  350 
  351 #define call_endutent  endutxent
  352 #define call_getutid   getutxid
  353 #define call_pututline pututxline
  354 #define call_setutent  setutxent
  355 #define call_updwtmp   updwtmpx
  356 
  357 #elif defined(HAVE_UTMP)
  358 
  359 #include <utmp.h>
  360 
  361 #if defined(_CRAY) && (OSMAJORVERSION < 8)
  362 extern struct utmp *getutid __((struct utmp * _Id));
  363 #endif
  364 
  365 #define call_endutent  endutent
  366 #define call_getutid   getutid
  367 #define call_pututline pututline
  368 #define call_setutent  setutent
  369 #define call_updwtmp   updwtmp
  370 
  371 #endif
  372 
  373 #if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
  374 #include <lastlog.h>        /* caution: glibc includes utmp.h here */
  375 #endif
  376 
  377 #ifndef USE_LASTLOGX
  378 #if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
  379 #define USE_LASTLOGX 1
  380 #endif
  381 #endif
  382 
  383 #ifdef  PUCC_PTYD
  384 #include <local/openpty.h>
  385 #endif /* PUCC_PTYD */
  386 
  387 #if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
  388 #include <util.h>       /* openpty() */
  389 #endif
  390 
  391 #if defined(__FreeBSD__) || defined(__DragonFly__)
  392 #include <libutil.h>        /* openpty() */
  393 #endif
  394 
  395 #if !defined(UTMP_FILENAME)
  396 #if defined(UTMP_FILE)
  397 #define UTMP_FILENAME UTMP_FILE
  398 #elif defined(_PATH_UTMP)
  399 #define UTMP_FILENAME _PATH_UTMP
  400 #else
  401 #define UTMP_FILENAME "/etc/utmp"
  402 #endif
  403 #endif
  404 
  405 #ifndef LASTLOG_FILENAME
  406 #ifdef _PATH_LASTLOG
  407 #define LASTLOG_FILENAME _PATH_LASTLOG
  408 #else
  409 #define LASTLOG_FILENAME "/usr/adm/lastlog" /* only on BSD systems */
  410 #endif
  411 #endif
  412 
  413 #if !defined(WTMP_FILENAME)
  414 #if defined(WTMP_FILE)
  415 #define WTMP_FILENAME WTMP_FILE
  416 #elif defined(_PATH_WTMP)
  417 #define WTMP_FILENAME _PATH_WTMP
  418 #elif defined(SYSV)
  419 #define WTMP_FILENAME "/etc/wtmp"
  420 #else
  421 #define WTMP_FILENAME "/usr/adm/wtmp"
  422 #endif
  423 #endif
  424 
  425 #include <signal.h>
  426 
  427 #if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
  428 #undef SIGTSTP          /* defined, but not the BSD way */
  429 #endif
  430 
  431 #ifdef SIGTSTP
  432 #include <sys/wait.h>
  433 #endif
  434 
  435 #if defined(__SCO__) || defined(__UNIXWARE__)
  436 #undef ECHOKE
  437 #undef ECHOCTL
  438 #endif
  439 
  440 #if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
  441 #include <sys/ttydefaults.h>
  442 #endif
  443 
  444 #ifdef X_NOT_POSIX
  445 extern long lseek();
  446 #if defined(USG) || defined(SVR4)
  447 extern unsigned sleep();
  448 #else
  449 extern void sleep();
  450 #endif
  451 extern char *ttyname();
  452 #endif
  453 
  454 #if defined(SYSV) && defined(DECL_PTSNAME)
  455 extern char *ptsname(int);
  456 #endif
  457 
  458 #ifndef VMS
  459 static void reapchild(int /* n */ );
  460 static int spawnXTerm(XtermWidget   /* xw */
  461               ,unsigned /* line_speed */ );
  462 static void remove_termcap_entry(char *, const char *);
  463 #ifdef USE_PTY_SEARCH
  464 static int pty_search(int * /* pty */ );
  465 #endif
  466 #endif /* ! VMS */
  467 
  468 static int get_pty(int *pty, char *from);
  469 static void resize_termcap(XtermWidget xw);
  470 static void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
  471 
  472 static Bool added_utmp_entry = False;
  473 
  474 #ifdef HAVE_POSIX_SAVED_IDS
  475 static uid_t save_euid;
  476 static gid_t save_egid;
  477 #endif
  478 
  479 static uid_t save_ruid;
  480 static gid_t save_rgid;
  481 
  482 #if defined(USE_UTMP_SETGID)
  483 static int really_get_pty(int *pty, char *from);
  484 #endif
  485 
  486 #if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
  487 static Bool xterm_exiting = False;
  488 #endif
  489 
  490 static char *explicit_shname = NULL;
  491 
  492 /*
  493 ** Ordinarily it should be okay to omit the assignment in the following
  494 ** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
  495 ** it? Without the assignment though the compiler will init command_to_exec
  496 ** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
  497 ** SEGV.
  498 */
  499 static char **command_to_exec = NULL;
  500 
  501 #if OPT_LUIT_PROG
  502 static char **command_to_exec_with_luit = NULL;
  503 static unsigned command_length_with_luit = 0;
  504 #endif
  505 
  506 #define TERMCAP_ERASE "kb"
  507 #define VAL_INITIAL_ERASE A2E(8)
  508 
  509 /* choose a nice default value for speed - if we make it too low, users who
  510  * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
  511  * higher value is not useful since legacy applications (termcap) that care
  512  * about padding generally store the code in a short, which does not have
  513  * enough bits for the extended values.
  514  */
  515 #ifdef B38400           /* everyone should define this */
  516 #define VAL_LINE_SPEED B38400
  517 #else /* ...but xterm's used this for a long time */
  518 #define VAL_LINE_SPEED B9600
  519 #endif
  520 
  521 /*
  522  * Allow use of system default characters if defined and reasonable.
  523  * These are based on the BSD ttydefaults.h
  524  */
  525 #ifndef CBRK
  526 #define CBRK     0xff       /* was 0 */
  527 #endif
  528 #ifndef CDISCARD
  529 #define CDISCARD CONTROL('O')
  530 #endif
  531 #ifndef CDSUSP
  532 #define CDSUSP   CONTROL('Y')
  533 #endif
  534 #ifndef CEOF
  535 #define CEOF     CONTROL('D')
  536 #endif
  537 #ifndef CEOL
  538 #define CEOL     0xff       /* was 0 */
  539 #endif
  540 #ifndef CERASE
  541 #define CERASE   0177
  542 #endif
  543 #ifndef CERASE2
  544 #define CERASE2  CONTROL('H')
  545 #endif
  546 #ifndef CFLUSH
  547 #define CFLUSH   CONTROL('O')
  548 #endif
  549 #ifndef CINTR
  550 #define CINTR    CONTROL('C')
  551 #endif
  552 #ifndef CKILL
  553 #define CKILL    CONTROL('U')   /* was '@' */
  554 #endif
  555 #ifndef CLNEXT
  556 #define CLNEXT   CONTROL('V')
  557 #endif
  558 #ifndef CNUL
  559 #define CNUL     0
  560 #endif
  561 #ifndef CQUIT
  562 #define CQUIT    CONTROL('\\')
  563 #endif
  564 #ifndef CRPRNT
  565 #define CRPRNT   CONTROL('R')
  566 #endif
  567 #ifndef CREPRINT
  568 #define CREPRINT CRPRNT
  569 #endif
  570 #ifndef CSTART
  571 #define CSTART   CONTROL('Q')
  572 #endif
  573 #ifndef CSTATUS
  574 #define CSTATUS  CONTROL('T')
  575 #endif
  576 #ifndef CSTOP
  577 #define CSTOP    CONTROL('S')
  578 #endif
  579 #ifndef CSUSP
  580 #define CSUSP    CONTROL('Z')
  581 #endif
  582 #ifndef CSWTCH
  583 #define CSWTCH   0
  584 #endif
  585 #ifndef CWERASE
  586 #define CWERASE  CONTROL('W')
  587 #endif
  588 
  589 #ifdef USE_ANY_SYSV_TERMIO
  590 #define TERMIO_STRUCT struct termio
  591 #define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
  592 #define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
  593 #define ttyFlush(fd)          ioctl(fd, TCFLSH, 1)
  594 #elif defined(USE_POSIX_TERMIOS)
  595 #define TERMIO_STRUCT struct termios
  596 #define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
  597 #define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
  598 #define ttyFlush(fd)          tcflush(fd, TCOFLUSH)
  599 #endif /* USE_ANY_SYSV_TERMIO */
  600 
  601 #ifndef VMS
  602 #ifdef TERMIO_STRUCT
  603 /* The following structures are initialized in main() in order
  604 ** to eliminate any assumptions about the internal order of their
  605 ** contents.
  606 */
  607 static TERMIO_STRUCT d_tio;
  608 
  609 #ifndef ONLCR
  610 #define ONLCR 0
  611 #endif
  612 
  613 #ifndef OPOST
  614 #define OPOST 0
  615 #endif
  616 
  617 #define D_TIO_FLAGS (OPOST | ONLCR)
  618 
  619 #ifdef HAS_LTCHARS
  620 static struct ltchars d_ltc;
  621 #endif /* HAS_LTCHARS */
  622 
  623 #ifdef TIOCLSET
  624 static unsigned int d_lmode;
  625 #endif /* TIOCLSET */
  626 
  627 #else /* !TERMIO_STRUCT */
  628 
  629 #define D_SG_FLAGS (EVENP | ODDP | ECHO | CRMOD)
  630 
  631 static struct sgttyb d_sg =
  632 {
  633     0, 0, 0177, CKILL, (D_SG_FLAGS | XTABS)
  634 };
  635 static struct tchars d_tc =
  636 {
  637     CINTR, CQUIT, CSTART,
  638     CSTOP, CEOF, CBRK
  639 };
  640 static struct ltchars d_ltc =
  641 {
  642     CSUSP, CDSUSP, CRPRNT,
  643     CFLUSH, CWERASE, CLNEXT
  644 };
  645 static int d_disipline = NTTYDISC;
  646 static long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
  647 #ifdef sony
  648 static long int d_jmode = KM_SYSSJIS | KM_ASCII;
  649 static struct jtchars d_jtc =
  650 {
  651     'J', 'B'
  652 };
  653 #endif /* sony */
  654 #endif /* TERMIO_STRUCT */
  655 #endif /* ! VMS */
  656 
  657 /*
  658  * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
  659  * SVR4 has only termio.c_cc, but it includes everything from ltchars.
  660  * POSIX termios has termios.c_cc, which is similar to SVR4.
  661  */
  662 #define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
  663 static Boolean override_tty_modes = False;
  664 /* *INDENT-OFF* */
  665 static struct {
  666     const char *name;
  667     size_t len;
  668     int set;
  669     int value;
  670 } ttyModes[] = {
  671     TTYMODE("intr"),        /* tchars.t_intrc ; VINTR */
  672 #define XTTYMODE_intr   0
  673     TTYMODE("quit"),        /* tchars.t_quitc ; VQUIT */
  674 #define XTTYMODE_quit   1
  675     TTYMODE("erase"),       /* sgttyb.sg_erase ; VERASE */
  676 #define XTTYMODE_erase  2
  677     TTYMODE("kill"),        /* sgttyb.sg_kill ; VKILL */
  678 #define XTTYMODE_kill   3
  679     TTYMODE("eof"),     /* tchars.t_eofc ; VEOF */
  680 #define XTTYMODE_eof    4
  681     TTYMODE("eol"),     /* VEOL */
  682 #define XTTYMODE_eol    5
  683     TTYMODE("swtch"),       /* VSWTCH */
  684 #define XTTYMODE_swtch  6
  685     TTYMODE("start"),       /* tchars.t_startc ; VSTART */
  686 #define XTTYMODE_start  7
  687     TTYMODE("stop"),        /* tchars.t_stopc ; VSTOP */
  688 #define XTTYMODE_stop   8
  689     TTYMODE("brk"),     /* tchars.t_brkc */
  690 #define XTTYMODE_brk    9
  691     TTYMODE("susp"),        /* ltchars.t_suspc ; VSUSP */
  692 #define XTTYMODE_susp   10
  693     TTYMODE("dsusp"),       /* ltchars.t_dsuspc ; VDSUSP */
  694 #define XTTYMODE_dsusp  11
  695     TTYMODE("rprnt"),       /* ltchars.t_rprntc ; VREPRINT */
  696 #define XTTYMODE_rprnt  12
  697     TTYMODE("flush"),       /* ltchars.t_flushc ; VDISCARD */
  698 #define XTTYMODE_flush  13
  699     TTYMODE("weras"),       /* ltchars.t_werasc ; VWERASE */
  700 #define XTTYMODE_weras  14
  701     TTYMODE("lnext"),       /* ltchars.t_lnextc ; VLNEXT */
  702 #define XTTYMODE_lnext  15
  703     TTYMODE("status"),      /* VSTATUS */
  704 #define XTTYMODE_status 16
  705     TTYMODE("erase2"),      /* VERASE2 */
  706 #define XTTYMODE_erase2 17
  707     TTYMODE("eol2"),        /* VEOL2 */
  708 #define XTTYMODE_eol2   18
  709     TTYMODE("tabs"),        /* TAB0 */
  710 #define XTTYMODE_tabs   19
  711     TTYMODE("-tabs"),       /* TAB3 */
  712 #define XTTYMODE__tabs  20
  713 };
  714 
  715 #ifndef TAB0
  716 #define TAB0 0
  717 #endif
  718 
  719 #ifndef TAB3
  720 #if defined(OXTABS)
  721 #define TAB3 OXTABS
  722 #elif defined(XTABS)
  723 #define TAB3 XTABS
  724 #endif
  725 #endif
  726 
  727 #ifndef TABDLY
  728 #define TABDLY (TAB0|TAB3)
  729 #endif
  730 
  731 #define isTtyMode(p,q) (ttyChars[p].myMode == q && ttyModes[q].set)
  732 
  733 #define isTabMode(n) \
  734     (isTtyMode(n, XTTYMODE_tabs) || \
  735      isTtyMode(n, XTTYMODE__tabs))
  736 
  737 #define TMODE(ind,var) \
  738     if (ttyModes[ind].set) \
  739         var = (cc_t) ttyModes[ind].value
  740 
  741 #define validTtyChar(data, n) \
  742         (ttyChars[n].sysMode >= 0 && \
  743          ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
  744 
  745 static const struct {
  746     int sysMode;
  747     int myMode;
  748     int myDefault;
  749 } ttyChars[] = {
  750 #ifdef VINTR
  751     { VINTR,    XTTYMODE_intr,   CINTR },
  752 #endif
  753 #ifdef VQUIT
  754     { VQUIT,    XTTYMODE_quit,   CQUIT },
  755 #endif
  756 #ifdef VERASE
  757     { VERASE,   XTTYMODE_erase,  CERASE },
  758 #endif
  759 #ifdef VKILL
  760     { VKILL,    XTTYMODE_kill,   CKILL },
  761 #endif
  762 #ifdef VEOF
  763     { VEOF,     XTTYMODE_eof,    CEOF },
  764 #endif
  765 #ifdef VEOL
  766     { VEOL,     XTTYMODE_eol,    CEOL },
  767 #endif
  768 #ifdef VSWTCH
  769     { VSWTCH,   XTTYMODE_swtch,  CNUL },
  770 #endif
  771 #ifdef VSTART
  772     { VSTART,   XTTYMODE_start,  CSTART },
  773 #endif
  774 #ifdef VSTOP
  775     { VSTOP,    XTTYMODE_stop,   CSTOP },
  776 #endif
  777 #ifdef VSUSP
  778     { VSUSP,    XTTYMODE_susp,   CSUSP },
  779 #endif
  780 #ifdef VDSUSP
  781     { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
  782 #endif
  783 #ifdef VREPRINT
  784     { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
  785 #endif
  786 #ifdef VDISCARD
  787     { VDISCARD, XTTYMODE_flush,  CDISCARD },
  788 #endif
  789 #ifdef VWERASE
  790     { VWERASE,  XTTYMODE_weras,  CWERASE },
  791 #endif
  792 #ifdef VLNEXT
  793     { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
  794 #endif
  795 #ifdef VSTATUS
  796     { VSTATUS,  XTTYMODE_status, CSTATUS },
  797 #endif
  798 #ifdef VERASE2
  799     { VERASE2,  XTTYMODE_erase2, CERASE2 },
  800 #endif
  801 #ifdef VEOL2
  802     { VEOL2,    XTTYMODE_eol2,   CNUL },
  803 #endif
  804     { -1,       XTTYMODE_tabs,   TAB0 },
  805     { -1,       XTTYMODE__tabs,  TAB3 },
  806 };
  807 /* *INDENT-ON* */
  808 
  809 static int parse_tty_modes(char *s);
  810 
  811 #ifndef USE_UTEMPTER
  812 #ifdef USE_SYSV_UTMP
  813 #if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
  814 extern struct utmp *getutid();
  815 #endif /* AIXV3 */
  816 
  817 #else /* not USE_SYSV_UTMP */
  818 static char etc_utmp[] = UTMP_FILENAME;
  819 #endif /* USE_SYSV_UTMP */
  820 
  821 #if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
  822 static char etc_lastlog[] = LASTLOG_FILENAME;
  823 #else
  824 #undef USE_LASTLOG
  825 #endif
  826 
  827 #ifdef WTMP
  828 static char etc_wtmp[] = WTMP_FILENAME;
  829 #endif
  830 #endif /* !USE_UTEMPTER */
  831 
  832 /*
  833  * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
  834  * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
  835  * WTMP and USE_LASTLOG.
  836  */
  837 #ifdef USE_LOGIN_DASH_P
  838 #ifndef LOGIN_FILENAME
  839 #define LOGIN_FILENAME "/bin/login"
  840 #endif
  841 static char bin_login[] = LOGIN_FILENAME;
  842 #endif
  843 
  844 static char noPassedPty[2];
  845 static char *passedPty = noPassedPty;   /* name if pty if slave */
  846 
  847 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
  848 static int Console;
  849 #include <X11/Xmu/SysUtil.h>    /* XmuGetHostname */
  850 #define MIT_CONSOLE_LEN 12
  851 #define MIT_CONSOLE "MIT_CONSOLE_"
  852 static char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
  853 static Atom mit_console;
  854 #endif /* TIOCCONS */
  855 
  856 #ifndef USE_SYSV_UTMP
  857 static int tslot;
  858 #endif /* USE_SYSV_UTMP */
  859 static sigjmp_buf env;
  860 
  861 #define SetUtmpHost(dst, screen) \
  862     { \
  863         char host[sizeof(dst) + 1]; \
  864         strncpy(host, DisplayString(screen->display), sizeof(host) - 1); \
  865         host[sizeof(dst)] = '\0'; \
  866         TRACE(("DisplayString(%s)\n", host)); \
  867         if (!resource.utmpDisplayId) { \
  868         char *endptr = strrchr(host, ':'); \
  869         if (endptr) { \
  870             TRACE(("trimming display-id '%s'\n", host)); \
  871             *endptr = '\0'; \
  872         } \
  873         } \
  874         copy_filled(dst, host, sizeof(dst)); \
  875     }
  876 
  877 #ifdef HAVE_UTMP_UT_SYSLEN
  878 #  define SetUtmpSysLen(utmp)              \
  879     { \
  880         utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
  881         utmp.ut_syslen = (short) ((int) strlen(utmp.ut_host) + 1); \
  882     }
  883 #endif
  884 
  885 /* used by VT (charproc.c) */
  886 
  887 static XtResource application_resources[] =
  888 {
  889     Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
  890     Sres(XtNtitle, XtCTitle, title, NULL),
  891     Sres(XtNiconHint, XtCIconHint, icon_hint, NULL),
  892     Sres(XtNiconName, XtCIconName, icon_name, NULL),
  893     Sres("termName", "TermName", term_name, NULL),
  894     Sres("ttyModes", "TtyModes", tty_modes, NULL),
  895     Sres("validShells", "ValidShells", valid_shells, NULL),
  896     Bres("hold", "Hold", hold_screen, False),
  897     Bres("utmpInhibit", "UtmpInhibit", utmpInhibit, False),
  898     Bres("utmpDisplayId", "UtmpDisplayId", utmpDisplayId, True),
  899     Bres("messages", "Messages", messages, True),
  900     Ires("minBufSize", "MinBufSize", minBufSize, 4096),
  901     Ires("maxBufSize", "MaxBufSize", maxBufSize, 32768),
  902     Sres("menuLocale", "MenuLocale", menuLocale, DEF_MENU_LOCALE),
  903     Sres("omitTranslation", "OmitTranslation", omitTranslation, NULL),
  904     Sres("keyboardType", "KeyboardType", keyboardType, "unknown"),
  905 #ifdef HAVE_LIB_XCURSOR
  906     Sres("cursorTheme", "CursorTheme", cursorTheme, "none"),
  907 #endif
  908 #if OPT_PRINT_ON_EXIT
  909     Ires("printModeImmediate", "PrintModeImmediate", printModeNow, 0),
  910     Ires("printOptsImmediate", "PrintOptsImmediate", printOptsNow, 9),
  911     Sres("printFileImmediate", "PrintFileImmediate", printFileNow, NULL),
  912     Ires("printModeOnXError", "PrintModeOnXError", printModeOnXError, 0),
  913     Ires("printOptsOnXError", "PrintOptsOnXError", printOptsOnXError, 9),
  914     Sres("printFileOnXError", "PrintFileOnXError", printFileOnXError, NULL),
  915 #endif
  916 #if OPT_SUNPC_KBD
  917     Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
  918 #endif
  919 #if OPT_HP_FUNC_KEYS
  920     Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
  921 #endif
  922 #if OPT_SCO_FUNC_KEYS
  923     Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
  924 #endif
  925 #if OPT_SUN_FUNC_KEYS
  926     Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
  927 #endif
  928 #if OPT_TCAP_FKEYS
  929     Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
  930 #endif
  931 #if OPT_INITIAL_ERASE
  932     Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
  933     Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
  934 #endif
  935     Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
  936 #if OPT_ZICONBEEP
  937     Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
  938     Sres("zIconTitleFormat", "ZIconTitleFormat", zIconFormat, "*** %s"),
  939 #endif
  940 #if OPT_PTY_HANDSHAKE
  941     Bres("waitForMap", "WaitForMap", wait_for_map, False),
  942     Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
  943     Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
  944 #endif
  945 #if OPT_REPORT_CCLASS
  946     Bres("reportCClass", "ReportCClass", reportCClass, False),
  947 #endif
  948 #if OPT_REPORT_COLORS
  949     Bres("reportColors", "ReportColors", reportColors, False),
  950 #endif
  951 #if OPT_REPORT_FONTS
  952     Bres("reportFonts", "ReportFonts", reportFonts, False),
  953 #endif
  954 #if OPT_REPORT_ICONS
  955     Bres("reportIcons", "ReportIcons", reportIcons, False),
  956 #endif
  957 #if OPT_XRES_QUERY
  958     Bres("reportXRes", "ReportXRes", reportXRes, False),
  959 #endif
  960 #if OPT_SAME_NAME
  961     Bres("sameName", "SameName", sameName, True),
  962 #endif
  963 #if OPT_SESSION_MGT
  964     Bres("sessionMgt", "SessionMgt", sessionMgt, True),
  965 #endif
  966 #if OPT_TOOLBAR
  967     Bres(XtNtoolBar, XtCToolBar, toolBar, True),
  968 #endif
  969 #if OPT_MAXIMIZE
  970     Bres(XtNmaximized, XtCMaximized, maximized, False),
  971     Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
  972 #endif
  973 #if USE_DOUBLE_BUFFER
  974     Bres(XtNbuffered, XtCBuffered, buffered, DEF_DOUBLE_BUFFER),
  975     Ires(XtNbufferedFPS, XtCBufferedFPS, buffered_fps, 40),
  976 #endif
  977 };
  978 
  979 static String fallback_resources[] =
  980 {
  981 #if OPT_TOOLBAR
  982     "*toolBar: false",
  983 #endif
  984     "*SimpleMenu*menuLabel.vertSpace: 100",
  985     "*SimpleMenu*HorizontalMargins: 16",
  986     "*SimpleMenu*Sme.height: 16",
  987     "*SimpleMenu*Cursor: left_ptr",
  988     "*mainMenu.Label:  Main Options (no app-defaults)",
  989     "*vtMenu.Label:  VT Options (no app-defaults)",
  990     "*fontMenu.Label:  VT Fonts (no app-defaults)",
  991 #if OPT_TEK4014
  992     "*tekMenu.Label:  Tek Options (no app-defaults)",
  993 #endif
  994     NULL
  995 };
  996 
  997 /* Command line options table.  Only resources are entered here...there is a
  998    pass over the remaining options after XrmParseCommand is let loose. */
  999 /* *INDENT-OFF* */
 1000 #define DATA(option,pattern,type,value) { (char *) option, (char *) pattern, type, (XPointer) value }
 1001 static XrmOptionDescRec optionDescList[] = {
 1002 DATA("-geometry",   "*vt100.geometry",XrmoptionSepArg,  NULL),
 1003 DATA("-132",        "*c132",    XrmoptionNoArg,     "on"),
 1004 DATA("+132",        "*c132",    XrmoptionNoArg,     "off"),
 1005 DATA("-ah",     "*alwaysHighlight", XrmoptionNoArg, "on"),
 1006 DATA("+ah",     "*alwaysHighlight", XrmoptionNoArg, "off"),
 1007 DATA("-aw",     "*autoWrap",    XrmoptionNoArg,     "on"),
 1008 DATA("+aw",     "*autoWrap",    XrmoptionNoArg,     "off"),
 1009 #ifndef NO_ACTIVE_ICON
 1010 DATA("-ai",     "*activeIcon",  XrmoptionNoArg,     "off"),
 1011 DATA("+ai",     "*activeIcon",  XrmoptionNoArg,     "on"),
 1012 #endif /* NO_ACTIVE_ICON */
 1013 DATA("-b",      "*internalBorder",XrmoptionSepArg,  NULL),
 1014 DATA("-bc",     "*cursorBlink", XrmoptionNoArg,     "on"),
 1015 DATA("+bc",     "*cursorBlink", XrmoptionNoArg,     "off"),
 1016 DATA("-bcf",        "*cursorOffTime",XrmoptionSepArg,   NULL),
 1017 DATA("-bcn",        "*cursorOnTime",XrmoptionSepArg,    NULL),
 1018 DATA("-bdc",        "*colorBDMode", XrmoptionNoArg,     "off"),
 1019 DATA("+bdc",        "*colorBDMode", XrmoptionNoArg,     "on"),
 1020 DATA("-cb",     "*cutToBeginningOfLine", XrmoptionNoArg, "off"),
 1021 DATA("+cb",     "*cutToBeginningOfLine", XrmoptionNoArg, "on"),
 1022 DATA("-cc",     "*charClass",   XrmoptionSepArg,    NULL),
 1023 DATA("-cm",     "*colorMode",   XrmoptionNoArg,     "off"),
 1024 DATA("+cm",     "*colorMode",   XrmoptionNoArg,     "on"),
 1025 DATA("-cn",     "*cutNewline",  XrmoptionNoArg,     "off"),
 1026 DATA("+cn",     "*cutNewline",  XrmoptionNoArg,     "on"),
 1027 DATA("-cr",     "*cursorColor", XrmoptionSepArg,    NULL),
 1028 DATA("-cu",     "*curses",  XrmoptionNoArg,     "on"),
 1029 DATA("+cu",     "*curses",  XrmoptionNoArg,     "off"),
 1030 DATA("-dc",     "*dynamicColors",XrmoptionNoArg,    "off"),
 1031 DATA("+dc",     "*dynamicColors",XrmoptionNoArg,    "on"),
 1032 DATA("-fb",     "*boldFont",    XrmoptionSepArg,    NULL),
 1033 DATA("-fbb",        "*freeBoldBox", XrmoptionNoArg,     "off"),
 1034 DATA("+fbb",        "*freeBoldBox", XrmoptionNoArg,     "on"),
 1035 DATA("-fbx",        "*forceBoxChars", XrmoptionNoArg,   "off"),
 1036 DATA("+fbx",        "*forceBoxChars", XrmoptionNoArg,   "on"),
 1037 DATA("-fc",     "*initialFont", XrmoptionSepArg,    NULL),
 1038 #ifndef NO_ACTIVE_ICON
 1039 DATA("-fi",     "*iconFont",    XrmoptionSepArg,    NULL),
 1040 #endif /* NO_ACTIVE_ICON */
 1041 #if OPT_RENDERFONT
 1042 DATA("-fa",     "*faceName",    XrmoptionSepArg,    NULL),
 1043 DATA("-fd",     "*faceNameDoublesize", XrmoptionSepArg, NULL),
 1044 DATA("-fs",     "*faceSize",    XrmoptionSepArg,    NULL),
 1045 #endif
 1046 #if OPT_WIDE_ATTRS && OPT_ISO_COLORS
 1047 DATA("-itc",        "*colorITMode", XrmoptionNoArg,     "off"),
 1048 DATA("+itc",        "*colorITMode", XrmoptionNoArg,     "on"),
 1049 #endif
 1050 #if OPT_WIDE_CHARS
 1051 DATA("-fw",     "*wideFont",    XrmoptionSepArg,    NULL),
 1052 DATA("-fwb",        "*wideBoldFont", XrmoptionSepArg,   NULL),
 1053 #endif
 1054 #if OPT_INPUT_METHOD
 1055 DATA("-fx",     "*ximFont", XrmoptionSepArg,    NULL),
 1056 #endif
 1057 #if OPT_HIGHLIGHT_COLOR
 1058 DATA("-hc",     "*highlightColor", XrmoptionSepArg, NULL),
 1059 DATA("-hm",     "*highlightColorMode", XrmoptionNoArg,  "on"),
 1060 DATA("+hm",     "*highlightColorMode", XrmoptionNoArg,  "off"),
 1061 DATA("-selfg",      "*highlightTextColor", XrmoptionSepArg, NULL),
 1062 DATA("-selbg",      "*highlightColor", XrmoptionSepArg, NULL),
 1063 #endif
 1064 #if OPT_HP_FUNC_KEYS
 1065 DATA("-hf",     "*hpFunctionKeys",XrmoptionNoArg,   "on"),
 1066 DATA("+hf",     "*hpFunctionKeys",XrmoptionNoArg,   "off"),
 1067 #endif
 1068 DATA("-hold",       "*hold",    XrmoptionNoArg,     "on"),
 1069 DATA("+hold",       "*hold",    XrmoptionNoArg,     "off"),
 1070 #if OPT_INITIAL_ERASE
 1071 DATA("-ie",     "*ptyInitialErase", XrmoptionNoArg, "on"),
 1072 DATA("+ie",     "*ptyInitialErase", XrmoptionNoArg, "off"),
 1073 #endif
 1074 DATA("-j",      "*jumpScroll",  XrmoptionNoArg,     "on"),
 1075 DATA("+j",      "*jumpScroll",  XrmoptionNoArg,     "off"),
 1076 #if OPT_C1_PRINT
 1077 DATA("-k8",     "*allowC1Printable", XrmoptionNoArg,    "on"),
 1078 DATA("+k8",     "*allowC1Printable", XrmoptionNoArg,    "off"),
 1079 #endif
 1080 DATA("-kt",     "*keyboardType", XrmoptionSepArg,   NULL),
 1081 /* parse logging options anyway for compatibility */
 1082 DATA("-l",      "*logging", XrmoptionNoArg,     "on"),
 1083 DATA("+l",      "*logging", XrmoptionNoArg,     "off"),
 1084 DATA("-lf",     "*logFile", XrmoptionSepArg,    NULL),
 1085 DATA("-ls",     "*loginShell",  XrmoptionNoArg,     "on"),
 1086 DATA("+ls",     "*loginShell",  XrmoptionNoArg,     "off"),
 1087 DATA("-mb",     "*marginBell",  XrmoptionNoArg,     "on"),
 1088 DATA("+mb",     "*marginBell",  XrmoptionNoArg,     "off"),
 1089 DATA("-mc",     "*multiClickTime", XrmoptionSepArg, NULL),
 1090 DATA("-mesg",       "*messages",    XrmoptionNoArg,     "off"),
 1091 DATA("+mesg",       "*messages",    XrmoptionNoArg,     "on"),
 1092 DATA("-ms",     "*pointerColor",XrmoptionSepArg,    NULL),
 1093 DATA("-nb",     "*nMarginBell", XrmoptionSepArg,    NULL),
 1094 DATA("-nul",        "*underLine",   XrmoptionNoArg,     "off"),
 1095 DATA("+nul",        "*underLine",   XrmoptionNoArg,     "on"),
 1096 DATA("-pc",     "*boldColors",  XrmoptionNoArg,     "on"),
 1097 DATA("+pc",     "*boldColors",  XrmoptionNoArg,     "off"),
 1098 DATA("-pf",     "*pointerFont", XrmoptionSepArg,    NULL),
 1099 DATA("-rw",     "*reverseWrap", XrmoptionNoArg,     "on"),
 1100 DATA("+rw",     "*reverseWrap", XrmoptionNoArg,     "off"),
 1101 DATA("-s",      "*multiScroll", XrmoptionNoArg,     "on"),
 1102 DATA("+s",      "*multiScroll", XrmoptionNoArg,     "off"),
 1103 DATA("-sb",     "*scrollBar",   XrmoptionNoArg,     "on"),
 1104 DATA("+sb",     "*scrollBar",   XrmoptionNoArg,     "off"),
 1105 #if OPT_REPORT_CCLASS
 1106 DATA("-report-charclass","*reportCClass", XrmoptionNoArg,   "on"),
 1107 #endif
 1108 #if OPT_REPORT_COLORS
 1109 DATA("-report-colors",  "*reportColors", XrmoptionNoArg,    "on"),
 1110 #endif
 1111 #if OPT_REPORT_ICONS
 1112 DATA("-report-icons",   "*reportIcons", XrmoptionNoArg,     "on"),
 1113 #endif
 1114 #if OPT_REPORT_FONTS
 1115 DATA("-report-fonts",   "*reportFonts", XrmoptionNoArg,     "on"),
 1116 #endif
 1117 #if OPT_XRES_QUERY
 1118 DATA("-report-xres",    "*reportXRes",  XrmoptionNoArg,     "on"),
 1119 #endif
 1120 #ifdef SCROLLBAR_RIGHT
 1121 DATA("-leftbar",    "*rightScrollBar", XrmoptionNoArg,  "off"),
 1122 DATA("-rightbar",   "*rightScrollBar", XrmoptionNoArg,  "on"),
 1123 #endif
 1124 DATA("-rvc",        "*colorRVMode", XrmoptionNoArg,     "off"),
 1125 DATA("+rvc",        "*colorRVMode", XrmoptionNoArg,     "on"),
 1126 DATA("-sf",     "*sunFunctionKeys", XrmoptionNoArg, "on"),
 1127 DATA("+sf",     "*sunFunctionKeys", XrmoptionNoArg, "off"),
 1128 DATA("-sh",     "*scaleHeight", XrmoptionSepArg,    NULL),
 1129 DATA("-si",     "*scrollTtyOutput", XrmoptionNoArg, "off"),
 1130 DATA("+si",     "*scrollTtyOutput", XrmoptionNoArg, "on"),
 1131 DATA("-sk",     "*scrollKey",   XrmoptionNoArg,     "on"),
 1132 DATA("+sk",     "*scrollKey",   XrmoptionNoArg,     "off"),
 1133 DATA("-sl",     "*saveLines",   XrmoptionSepArg,    NULL),
 1134 #if OPT_SUNPC_KBD
 1135 DATA("-sp",     "*sunKeyboard", XrmoptionNoArg,     "on"),
 1136 DATA("+sp",     "*sunKeyboard", XrmoptionNoArg,     "off"),
 1137 #endif
 1138 #if OPT_TEK4014
 1139 DATA("-t",      "*tekStartup",  XrmoptionNoArg,     "on"),
 1140 DATA("+t",      "*tekStartup",  XrmoptionNoArg,     "off"),
 1141 #endif
 1142 DATA("-ti",     "*decTerminalID",XrmoptionSepArg,   NULL),
 1143 DATA("-tm",     "*ttyModes",    XrmoptionSepArg,    NULL),
 1144 DATA("-tn",     "*termName",    XrmoptionSepArg,    NULL),
 1145 #if OPT_WIDE_CHARS
 1146 DATA("-u8",     "*utf8",    XrmoptionNoArg,     "2"),
 1147 DATA("+u8",     "*utf8",    XrmoptionNoArg,     "0"),
 1148 #endif
 1149 #if OPT_LUIT_PROG
 1150 DATA("-lc",     "*locale",  XrmoptionNoArg,     "on"),
 1151 DATA("+lc",     "*locale",  XrmoptionNoArg,     "off"),
 1152 DATA("-lcc",        "*localeFilter",XrmoptionSepArg,    NULL),
 1153 DATA("-en",     "*locale",  XrmoptionSepArg,    NULL),
 1154 #endif
 1155 DATA("-uc",     "*cursorUnderLine", XrmoptionNoArg, "on"),
 1156 DATA("+uc",     "*cursorUnderLine", XrmoptionNoArg, "off"),
 1157 DATA("-ulc",        "*colorULMode", XrmoptionNoArg,     "off"),
 1158 DATA("+ulc",        "*colorULMode", XrmoptionNoArg,     "on"),
 1159 DATA("-ulit",           "*italicULMode", XrmoptionNoArg,        "off"),
 1160 DATA("+ulit",           "*italicULMode", XrmoptionNoArg,        "on"),
 1161 DATA("-ut",     "*utmpInhibit", XrmoptionNoArg,     "on"),
 1162 DATA("+ut",     "*utmpInhibit", XrmoptionNoArg,     "off"),
 1163 DATA("-im",     "*useInsertMode", XrmoptionNoArg,   "on"),
 1164 DATA("+im",     "*useInsertMode", XrmoptionNoArg,   "off"),
 1165 DATA("-vb",     "*visualBell",  XrmoptionNoArg,     "on"),
 1166 DATA("+vb",     "*visualBell",  XrmoptionNoArg,     "off"),
 1167 DATA("-pob",        "*popOnBell",   XrmoptionNoArg,     "on"),
 1168 DATA("+pob",        "*popOnBell",   XrmoptionNoArg,     "off"),
 1169 #if OPT_WIDE_CHARS
 1170 DATA("-wc",     "*wideChars",   XrmoptionNoArg,     "on"),
 1171 DATA("+wc",     "*wideChars",   XrmoptionNoArg,     "off"),
 1172 DATA("-mk_width",   "*mkWidth", XrmoptionNoArg,     "on"),
 1173 DATA("+mk_width",   "*mkWidth", XrmoptionNoArg,     "off"),
 1174 DATA("-cjk_width",  "*cjkWidth",    XrmoptionNoArg,     "on"),
 1175 DATA("+cjk_width",  "*cjkWidth",    XrmoptionNoArg,     "off"),
 1176 #endif
 1177 DATA("-wf",     "*waitForMap",  XrmoptionNoArg,     "on"),
 1178 DATA("+wf",     "*waitForMap",  XrmoptionNoArg,     "off"),
 1179 #if OPT_ZICONBEEP
 1180 DATA("-ziconbeep",  "*zIconBeep",   XrmoptionSepArg,    NULL),
 1181 #endif
 1182 #if OPT_SAME_NAME
 1183 DATA("-samename",   "*sameName",    XrmoptionNoArg,     "on"),
 1184 DATA("+samename",   "*sameName",    XrmoptionNoArg,     "off"),
 1185 #endif
 1186 #if OPT_SESSION_MGT
 1187 DATA("-sm",     "*sessionMgt",  XrmoptionNoArg,     "on"),
 1188 DATA("+sm",     "*sessionMgt",  XrmoptionNoArg,     "off"),
 1189 #endif
 1190 #if OPT_TOOLBAR
 1191 DATA("-tb",     "*"XtNtoolBar,  XrmoptionNoArg,     "on"),
 1192 DATA("+tb",     "*"XtNtoolBar,  XrmoptionNoArg,     "off"),
 1193 #endif
 1194 #if OPT_MAXIMIZE
 1195 DATA("-maximized",  "*maximized",   XrmoptionNoArg,     "on"),
 1196 DATA("+maximized",  "*maximized",   XrmoptionNoArg,     "off"),
 1197 DATA("-fullscreen", "*fullscreen",  XrmoptionNoArg,     "on"),
 1198 DATA("+fullscreen", "*fullscreen",  XrmoptionNoArg,     "off"),
 1199 #endif
 1200 /* options that we process ourselves */
 1201 DATA("-help",       NULL,       XrmoptionSkipNArgs, NULL),
 1202 DATA("-version",    NULL,       XrmoptionSkipNArgs, NULL),
 1203 DATA("-baudrate",   NULL,       XrmoptionSkipArg,   NULL),
 1204 DATA("-class",      NULL,       XrmoptionSkipArg,   NULL),
 1205 DATA("-e",      NULL,       XrmoptionSkipLine,  NULL),
 1206 DATA("-into",       NULL,       XrmoptionSkipArg,   NULL),
 1207 /* bogus old compatibility stuff for which there are
 1208    standard XtOpenApplication options now */
 1209 DATA("%",       "*tekGeometry", XrmoptionStickyArg, NULL),
 1210 DATA("#",       ".iconGeometry",XrmoptionStickyArg, NULL),
 1211 DATA("-T",      ".title",   XrmoptionSepArg,    NULL),
 1212 DATA("-n",      "*iconName",    XrmoptionSepArg,    NULL),
 1213 DATA("-r",      "*reverseVideo",XrmoptionNoArg,     "on"),
 1214 DATA("+r",      "*reverseVideo",XrmoptionNoArg,     "off"),
 1215 DATA("-rv",     "*reverseVideo",XrmoptionNoArg,     "on"),
 1216 DATA("+rv",     "*reverseVideo",XrmoptionNoArg,     "off"),
 1217 DATA("-w",      ".borderWidth", XrmoptionSepArg,    NULL),
 1218 #undef DATA
 1219 };
 1220 
 1221 static OptionHelp xtermOptions[] = {
 1222 { "-version",              "print the version number" },
 1223 { "-help",                 "print out this message" },
 1224 { "-display displayname",  "X server to contact" },
 1225 { "-geometry geom",        "size (in characters) and position" },
 1226 { "-/+rv",                 "turn on/off reverse video" },
 1227 { "-bg color",             "background color" },
 1228 { "-fg color",             "foreground color" },
 1229 { "-bd color",             "border color" },
 1230 { "-bw number",            "border width in pixels" },
 1231 { "-fn fontname",          "normal text font" },
 1232 { "-fb fontname",          "bold text font" },
 1233 { "-fc fontmenu",          "start with named fontmenu choice" },
 1234 { "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
 1235 { "-/+fbx",                "turn off/on linedrawing characters"},
 1236 #if OPT_RENDERFONT
 1237 { "-fa pattern",           "FreeType font-selection pattern" },
 1238 { "-fd pattern",           "FreeType Doublesize font-selection pattern" },
 1239 { "-fs size",              "FreeType font-size" },
 1240 #endif
 1241 #if OPT_WIDE_CHARS
 1242 { "-fw fontname",          "doublewidth text font" },
 1243 { "-fwb fontname",         "doublewidth bold text font" },
 1244 #endif
 1245 #if OPT_INPUT_METHOD
 1246 { "-fx fontname",          "XIM fontset" },
 1247 #endif
 1248 { "-iconic",               "start iconic" },
 1249 { "-name string",          "client instance, icon, and title strings" },
 1250 { "-baudrate rate",        "set line-speed (default 38400)" },
 1251 { "-class string",         "class string (XTerm)" },
 1252 { "-title string",         "title string" },
 1253 { "-xrm resourcestring",   "additional resource specifications" },
 1254 { "-/+132",                "turn on/off 80/132 column switching" },
 1255 { "-/+ah",                 "turn on/off always highlight" },
 1256 #ifndef NO_ACTIVE_ICON
 1257 { "-/+ai",                 "turn off/on active icon" },
 1258 { "-fi fontname",          "icon font for active icon" },
 1259 #endif /* NO_ACTIVE_ICON */
 1260 { "-b number",             "internal border in pixels" },
 1261 { "-/+bc",                 "turn on/off text cursor blinking" },
 1262 { "-bcf milliseconds",     "time text cursor is off when blinking"},
 1263 { "-bcn milliseconds",     "time text cursor is on when blinking"},
 1264 { "-/+bdc",                "turn off/on display of bold as color"},
 1265 { "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
 1266 { "-cc classrange",        "specify additional character classes" },
 1267 { "-/+cm",                 "turn off/on ANSI color mode" },
 1268 { "-/+cn",                 "turn on/off cut newline inhibit" },
 1269 { "-pf fontname",          "cursor font for text area pointer" },
 1270 { "-cr color",             "text cursor color" },
 1271 { "-/+cu",                 "turn on/off curses emulation" },
 1272 { "-/+dc",                 "turn off/on dynamic color selection" },
 1273 #if OPT_HIGHLIGHT_COLOR
 1274 { "-/+hm",                 "turn on/off selection-color override" },
 1275 { "-selbg color",          "selection background color" },
 1276 { "-selfg color",          "selection foreground color" },
 1277 /* -hc is deprecated, not shown in help message */
 1278 #endif
 1279 #if OPT_HP_FUNC_KEYS
 1280 { "-/+hf",                 "turn on/off HP Function Key escape codes" },
 1281 #endif
 1282 { "-/+hold",               "turn on/off logic that retains window after exit" },
 1283 #if OPT_INITIAL_ERASE
 1284 { "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
 1285 #endif
 1286 { "-/+im",                 "use insert mode for TERMCAP" },
 1287 { "-/+j",                  "turn on/off jump scroll" },
 1288 #if OPT_C1_PRINT
 1289 { "-/+k8",                 "turn on/off C1-printable classification"},
 1290 #endif
 1291 { "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
 1292 #ifdef ALLOWLOGGING
 1293 { "-/+l",                  "turn on/off logging" },
 1294 { "-lf filename",          "logging filename (use '-' for standard out)" },
 1295 #else
 1296 { "-/+l",                  "turn on/off logging (not supported)" },
 1297 { "-lf filename",          "logging filename (not supported)" },
 1298 #endif
 1299 { "-/+ls",                 "turn on/off login shell" },
 1300 { "-/+mb",                 "turn on/off margin bell" },
 1301 { "-mc milliseconds",      "multiclick time in milliseconds" },
 1302 { "-/+mesg",               "forbid/allow messages" },
 1303 { "-ms color",             "pointer color" },
 1304 { "-nb number",            "margin bell in characters from right end" },
 1305 { "-/+nul",                "turn off/on display of underlining" },
 1306 { "-/+aw",                 "turn on/off auto wraparound" },
 1307 { "-/+pc",                 "turn on/off PC-style bold colors" },
 1308 { "-/+rw",                 "turn on/off reverse wraparound" },
 1309 { "-/+s",                  "turn on/off multiscroll" },
 1310 { "-/+sb",                 "turn on/off scrollbar" },
 1311 #if OPT_REPORT_CCLASS
 1312 {"-report-charclass",      "report \"charClass\" after initialization"},
 1313 #endif
 1314 #if OPT_REPORT_COLORS
 1315 { "-report-colors",        "report colors as they are allocated" },
 1316 #endif
 1317 #if OPT_REPORT_FONTS
 1318 { "-report-fonts",         "report fonts as loaded to stdout" },
 1319 #endif
 1320 #if OPT_REPORT_ICONS
 1321 { "-report-icons",     "report title/icon updates" },
 1322 #endif
 1323 #if OPT_XRES_QUERY
 1324 { "-report-xres",          "report X resources for VT100 widget" },
 1325 #endif
 1326 #ifdef SCROLLBAR_RIGHT
 1327 { "-rightbar",             "force scrollbar right (default left)" },
 1328 { "-leftbar",              "force scrollbar left" },
 1329 #endif
 1330 { "-/+rvc",                "turn off/on display of reverse as color" },
 1331 { "-/+sf",                 "turn on/off Sun Function Key escape codes" },
 1332 { "-sh number",            "scale line-height values by the given number" },
 1333 { "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
 1334 { "-/+sk",                 "turn on/off scroll-on-keypress" },
 1335 { "-sl number",            "number of scrolled lines to save" },
 1336 #if OPT_SUNPC_KBD
 1337 { "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
 1338 #endif
 1339 #if OPT_TEK4014
 1340 { "-/+t",                  "turn on/off Tek emulation window" },
 1341 #endif
 1342 #if OPT_TOOLBAR
 1343 { "-/+tb",                 "turn on/off toolbar" },
 1344 #endif
 1345 { "-ti termid",            "terminal identifier" },
 1346 { "-tm string",            "terminal mode keywords and characters" },
 1347 { "-tn name",              "TERM environment variable name" },
 1348 #if OPT_WIDE_CHARS
 1349 { "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
 1350 #endif
 1351 #if OPT_LUIT_PROG
 1352 { "-/+lc",                 "turn on/off locale mode using luit" },
 1353 { "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
 1354 /* -en is deprecated, not shown in help message */
 1355 #endif
 1356 { "-/+uc",                 "turn on/off underline cursor" },
 1357 { "-/+ulc",                "turn off/on display of underline as color" },
 1358 { "-/+ulit",               "turn off/on display of underline as italics" },
 1359 #ifdef HAVE_UTMP
 1360 { "-/+ut",                 "turn on/off utmp support" },
 1361 #else
 1362 { "-/+ut",                 "turn on/off utmp support (not available)" },
 1363 #endif
 1364 { "-/+vb",                 "turn on/off visual bell" },
 1365 { "-/+pob",                "turn on/off pop on bell" },
 1366 #if OPT_WIDE_ATTRS && OPT_ISO_COLORS
 1367 { "-/+itc",                "turn off/on display of italic as color"},
 1368 #endif
 1369 #if OPT_WIDE_CHARS
 1370 { "-/+wc",                 "turn on/off wide-character mode" },
 1371 { "-/+mk_width",           "turn on/off simple width convention" },
 1372 { "-/+cjk_width",          "turn on/off legacy CJK width convention" },
 1373 #endif
 1374 { "-/+wf",                 "turn on/off wait for map before command exec" },
 1375 { "-e command args ...",   "command to execute" },
 1376 #if OPT_TEK4014
 1377 { "%geom",                 "Tek window geometry" },
 1378 #endif
 1379 { "#geom",                 "icon window geometry" },
 1380 { "-T string",             "title name for window" },
 1381 { "-n string",             "icon name for window" },
 1382 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
 1383 { "-C",                    "intercept console messages" },
 1384 #else
 1385 { "-C",                    "intercept console messages (not supported)" },
 1386 #endif
 1387 { "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
 1388 { "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
 1389 #if OPT_ZICONBEEP
 1390 { "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
 1391 #endif
 1392 #if OPT_SAME_NAME
 1393 { "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
 1394 #endif
 1395 #if OPT_SESSION_MGT
 1396 { "-/+sm",                 "turn on/off the session-management support" },
 1397 #endif
 1398 #if OPT_MAXIMIZE
 1399 {"-/+maximized",           "turn on/off maximize on startup" },
 1400 {"-/+fullscreen",          "turn on/off fullscreen on startup" },
 1401 #endif
 1402 { NULL, NULL }};
 1403 /* *INDENT-ON* */
 1404 
 1405 static const char *const message[] =
 1406 {
 1407     "Fonts should be fixed width and, if both normal and bold are specified, should",
 1408     "have the same size.  If only a normal font is specified, it will be used for",
 1409     "both normal and bold text (by doing overstriking).  The -e option, if given,",
 1410     "must appear at the end of the command line, otherwise the user's default shell",
 1411     "will be started.  Options that start with a plus sign (+) restore the default.",
 1412     NULL};
 1413 
 1414 /*
 1415  * Decode a key-definition.  This combines the termcap and ttyModes, for
 1416  * comparison.  Note that octal escapes in ttyModes are done by the normal
 1417  * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
 1418  */
 1419 static int
 1420 decode_keyvalue(char **ptr, int termcap)
 1421 {
 1422     char *string = *ptr;
 1423     int value = -1;
 1424 
 1425     TRACE(("decode_keyvalue '%s'\n", string));
 1426     if (*string == '^') {
 1427     switch (*++string) {
 1428     case '?':
 1429         value = A2E(ANSI_DEL);
 1430         break;
 1431     case '-':
 1432         if (!termcap) {
 1433         errno = 0;
 1434 #if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
 1435         value = _POSIX_VDISABLE;
 1436 #endif
 1437 #if defined(_PC_VDISABLE)
 1438         if (value == -1) {
 1439             value = (int) fpathconf(0, _PC_VDISABLE);
 1440             if (value == -1) {
 1441             if (errno != 0)
 1442                 break;  /* skip this (error) */
 1443             value = 0377;
 1444             }
 1445         }
 1446 #elif defined(VDISABLE)
 1447         if (value == -1)
 1448             value = VDISABLE;
 1449 #endif
 1450         break;
 1451         }
 1452         /* FALLTHRU */
 1453     default:
 1454         value = CONTROL(*string);
 1455         break;
 1456     }
 1457     ++string;
 1458     } else if (termcap && (*string == '\\')) {
 1459     char *s = (string + 1);
 1460     char *d;
 1461     int temp = (int) strtol(s, &d, 8);
 1462     if (PartS2L(s, d) && temp > 0) {
 1463         value = temp;
 1464         string = d;
 1465     }
 1466     } else {
 1467     value = CharOf(*string);
 1468     ++string;
 1469     }
 1470     *ptr = string;
 1471     TRACE(("...decode_keyvalue %#x\n", value));
 1472     return value;
 1473 }
 1474 
 1475 static int
 1476 matchArg(XrmOptionDescRec * table, const char *param)
 1477 {
 1478     int result = -1;
 1479     int n;
 1480     int ch;
 1481 
 1482     for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
 1483     if (param[n] == ch) {
 1484         result = n;
 1485     } else {
 1486         if (param[n] != '\0')
 1487         result = -1;
 1488         break;
 1489     }
 1490     }
 1491 
 1492     return result;
 1493 }
 1494 
 1495 /* return the number of argv[] entries which constitute arguments of option */
 1496 static int
 1497 countArg(XrmOptionDescRec * item)
 1498 {
 1499     int result = 0;
 1500 
 1501     switch (item->argKind) {
 1502     case XrmoptionNoArg:
 1503     /* FALLTHRU */
 1504     case XrmoptionIsArg:
 1505     /* FALLTHRU */
 1506     case XrmoptionStickyArg:
 1507     break;
 1508     case XrmoptionSepArg:
 1509     /* FALLTHRU */
 1510     case XrmoptionResArg:
 1511     /* FALLTHRU */
 1512     case XrmoptionSkipArg:
 1513     result = 1;
 1514     break;
 1515     case XrmoptionSkipLine:
 1516     break;
 1517     case XrmoptionSkipNArgs:
 1518     result = (int) (long) (item->value);
 1519     break;
 1520     }
 1521     return result;
 1522 }
 1523 
 1524 #define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
 1525 
 1526 /*
 1527  * Parse the argument list, more/less as XtInitialize, etc., would do, so we
 1528  * can find our own "-help" and "-version" options reliably.  Improve on just
 1529  * doing that, by detecting ambiguous options (things that happen to match the
 1530  * abbreviated option we are examining), and making it smart enough to handle
 1531  * "-d" as an abbreviation for "-display".  Doing this requires checking the
 1532  * standard table (something that the X libraries should do).
 1533  */
 1534 static XrmOptionDescRec *
 1535 parseArg(int *num, char **argv, char **valuep)
 1536 {
 1537     /* table adapted from XtInitialize, used here to improve abbreviations */
 1538     /* *INDENT-OFF* */
 1539 #define DATA(option,kind) { (char *) option, NULL, kind, (XtPointer) NULL }
 1540     static XrmOptionDescRec opTable[] = {
 1541     DATA("+synchronous",       XrmoptionNoArg),
 1542     DATA("-background",    XrmoptionSepArg),
 1543     DATA("-bd",        XrmoptionSepArg),
 1544     DATA("-bg",        XrmoptionSepArg),
 1545     DATA("-bordercolor",       XrmoptionSepArg),
 1546     DATA("-borderwidth",       XrmoptionSepArg),
 1547     DATA("-bw",        XrmoptionSepArg),
 1548     DATA("-display",       XrmoptionSepArg),
 1549     DATA("-fg",        XrmoptionSepArg),
 1550     DATA("-fn",        XrmoptionSepArg),
 1551     DATA("-font",          XrmoptionSepArg),
 1552     DATA("-foreground",    XrmoptionSepArg),
 1553     DATA("-iconic",        XrmoptionNoArg),
 1554     DATA("-name",          XrmoptionSepArg),
 1555     DATA("-reverse",       XrmoptionNoArg),
 1556     DATA("-selectionTimeout",  XrmoptionSepArg),
 1557     DATA("-synchronous",       XrmoptionNoArg),
 1558     DATA("-title",         XrmoptionSepArg),
 1559     DATA("-xnllanguage",       XrmoptionSepArg),
 1560     DATA("-xrm",           XrmoptionResArg),
 1561     DATA("-xtsessionID",       XrmoptionSepArg),
 1562     /* These xterm options are processed after XtOpenApplication */
 1563 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
 1564     DATA("-C",         XrmoptionNoArg),
 1565 #endif /* TIOCCONS */
 1566     DATA("-S",         XrmoptionStickyArg),
 1567     DATA("-D",         XrmoptionNoArg),
 1568     };
 1569 #undef DATA
 1570     /* *INDENT-ON* */
 1571     XrmOptionDescRec *result = 0;
 1572     Cardinal inlist;
 1573     Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
 1574     int atbest = -1;
 1575     int best = -1;
 1576     int test;
 1577     Boolean exact = False;
 1578     int ambiguous1 = -1;
 1579     int ambiguous2 = -1;
 1580     char *option;
 1581     char *value;
 1582 
 1583 #define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
 1584          ? &optionDescList[n] \
 1585          : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
 1586 
 1587     if ((option = argv[*num]) != 0) {
 1588     Boolean need_value;
 1589     Boolean have_value = False;
 1590 
 1591     TRACE(("parseArg %s\n", option));
 1592     if ((value = argv[(*num) + 1]) != 0) {
 1593         have_value = (Boolean) !isOption(value);
 1594     }
 1595     for (inlist = 0; inlist < limit; ++inlist) {
 1596         XrmOptionDescRec *check = ITEM(inlist);
 1597 
 1598         test = matchArg(check, option);
 1599         if (test < 0)
 1600         continue;
 1601 
 1602         /* check for exact match */
 1603         if ((test + 1) == (int) strlen(check->option)) {
 1604         if (check->argKind == XrmoptionStickyArg) {
 1605             if (strlen(option) > strlen(check->option)) {
 1606             exact = True;
 1607             atbest = (int) inlist;
 1608             break;
 1609             }
 1610         } else if ((test + 1) == (int) strlen(option)) {
 1611             exact = True;
 1612             atbest = (int) inlist;
 1613             break;
 1614         }
 1615         }
 1616 
 1617         need_value = (Boolean) (test > 0 && countArg(check) > 0);
 1618 
 1619         if (need_value && value != 0) {
 1620         ;
 1621         } else if (need_value ^ have_value) {
 1622         TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
 1623         continue;
 1624         }
 1625 
 1626         /* special-case for our own options - always allow abbreviation */
 1627         if (test > 0
 1628         && ITEM(inlist)->argKind >= XrmoptionSkipArg) {
 1629         atbest = (int) inlist;
 1630         if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
 1631             /* in particular, silence a warning about ambiguity */
 1632             exact = 1;
 1633         }
 1634         break;
 1635         }
 1636         if (test > best) {
 1637         best = test;
 1638         atbest = (int) inlist;
 1639         } else if (test == best) {
 1640         if (atbest >= 0) {
 1641             if (atbest > 0) {
 1642             ambiguous1 = (int) inlist;
 1643             ambiguous2 = (int) atbest;
 1644             }
 1645             atbest = -1;
 1646         }
 1647         }
 1648     }
 1649     }
 1650 
 1651     *valuep = 0;
 1652     if (atbest >= 0) {
 1653     result = ITEM(atbest);
 1654     if (!exact) {
 1655         if (ambiguous1 >= 0 && ambiguous2 >= 0) {
 1656         xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
 1657                  ITEM(ambiguous1)->option,
 1658                  ITEM(ambiguous2)->option);
 1659         } else if (strlen(option) > strlen(result->option)) {
 1660         result = 0;
 1661         }
 1662     }
 1663     if (result != 0) {
 1664         TRACE(("...result %s\n", result->option));
 1665         /* expand abbreviations */
 1666         if (result->argKind != XrmoptionStickyArg) {
 1667         if (strcmp(argv[*num], result->option)) {
 1668             argv[*num] = x_strdup(result->option);
 1669         }
 1670         }
 1671 
 1672         /* adjust (*num) to skip option value */
 1673         (*num) += countArg(result);
 1674         TRACE(("...next %s\n", NonNull(argv[*num])));
 1675         if (result->argKind == XrmoptionSkipArg) {
 1676         *valuep = argv[*num];
 1677         TRACE(("...parameter %s\n", NonNull(*valuep)));
 1678         }
 1679     }
 1680     }
 1681 #undef ITEM
 1682     return result;
 1683 }
 1684 
 1685 static void
 1686 Syntax(char *badOption)
 1687 {
 1688     OptionHelp *opt;
 1689     OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
 1690     int col;
 1691 
 1692     TRACE(("Syntax error at %s\n", badOption));
 1693     xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
 1694 
 1695     fprintf(stderr, "usage:  %s", ProgramName);
 1696     col = 8 + (int) strlen(ProgramName);
 1697     for (opt = list; opt->opt; opt++) {
 1698     int len = 3 + (int) strlen(opt->opt);   /* space [ string ] */
 1699     if (col + len > 79) {
 1700         fprintf(stderr, "\r\n   ");     /* 3 spaces */
 1701         col = 3;
 1702     }
 1703     fprintf(stderr, " [%s]", opt->opt);
 1704     col += len;
 1705     }
 1706 
 1707     fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
 1708         ProgramName);
 1709     exit(1);
 1710 }
 1711 
 1712 static void
 1713 Version(void)
 1714 {
 1715     printf("%s\n", xtermVersion());
 1716     fflush(stdout);
 1717 }
 1718 
 1719 static void
 1720 Help(void)
 1721 {
 1722     OptionHelp *opt;
 1723     OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
 1724     const char *const *cpp;
 1725 
 1726     printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
 1727        xtermVersion(), ProgramName);
 1728     printf("where options include:\n");
 1729     for (opt = list; opt->opt; opt++) {
 1730     printf("    %-28s %s\n", opt->opt, opt->desc);
 1731     }
 1732 
 1733     putchar('\n');
 1734     for (cpp = message; *cpp; cpp++)
 1735     puts(*cpp);
 1736     putchar('\n');
 1737     fflush(stdout);
 1738 }
 1739 
 1740 static void
 1741 NeedParam(XrmOptionDescRec * option_ptr, const char *option_val)
 1742 {
 1743     if (IsEmpty(option_val)) {
 1744     xtermWarning("option %s requires a value\n", option_ptr->option);
 1745     exit(1);
 1746     }
 1747 }
 1748 
 1749 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
 1750 /* ARGSUSED */
 1751 static Boolean
 1752 ConvertConsoleSelection(Widget w GCC_UNUSED,
 1753             Atom *selection GCC_UNUSED,
 1754             Atom *target GCC_UNUSED,
 1755             Atom *type GCC_UNUSED,
 1756             XtPointer *value GCC_UNUSED,
 1757             unsigned long *length GCC_UNUSED,
 1758             int *format GCC_UNUSED)
 1759 {
 1760     /* we don't save console output, so can't offer it */
 1761     return False;
 1762 }
 1763 #endif /* TIOCCONS */
 1764 
 1765 /*
 1766  * DeleteWindow(): Action proc to implement ICCCM delete_window.
 1767  */
 1768 /* ARGSUSED */
 1769 static void
 1770 DeleteWindow(Widget w,
 1771          XEvent *event GCC_UNUSED,
 1772          String *params GCC_UNUSED,
 1773          Cardinal *num_params GCC_UNUSED)
 1774 {
 1775 #if OPT_TEK4014
 1776     if (w == toplevel) {
 1777     if (TEK4014_SHOWN(term))
 1778         hide_vt_window();
 1779     else
 1780         do_hangup(w, (XtPointer) 0, (XtPointer) 0);
 1781     } else if (TScreenOf(term)->Vshow)
 1782     hide_tek_window();
 1783     else
 1784 #endif
 1785     do_hangup(w, (XtPointer) 0, (XtPointer) 0);
 1786 }
 1787 
 1788 /* ARGSUSED */
 1789 static void
 1790 KeyboardMapping(Widget w GCC_UNUSED,
 1791         XEvent *event,
 1792         String *params GCC_UNUSED,
 1793         Cardinal *num_params GCC_UNUSED)
 1794 {
 1795     switch (event->type) {
 1796     case MappingNotify:
 1797     XRefreshKeyboardMapping(&event->xmapping);
 1798     break;
 1799     }
 1800 }
 1801 
 1802 static XtActionsRec actionProcs[] =
 1803 {
 1804     {"DeleteWindow", DeleteWindow},
 1805     {"KeyboardMapping", KeyboardMapping},
 1806 };
 1807 
 1808 /*
 1809  * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
 1810  * the "tty01" or "pts/1" portion, and return that for use as an identifier for
 1811  * utmp.
 1812  */
 1813 static char *
 1814 my_pty_name(char *device)
 1815 {
 1816     size_t len = strlen(device);
 1817     Bool name = False;
 1818 
 1819     while (len != 0) {
 1820     int ch = device[len - 1];
 1821     if (isdigit(ch)) {
 1822         len--;
 1823     } else if (ch == '/') {
 1824         if (name)
 1825         break;
 1826         len--;
 1827     } else if (isalpha(ch)) {
 1828         name = True;
 1829         len--;
 1830     } else {
 1831         break;
 1832     }
 1833     }
 1834     TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
 1835     return device + len;
 1836 }
 1837 
 1838 /*
 1839  * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
 1840  * last few characters for a utmp identifier.
 1841  */
 1842 static char *
 1843 my_pty_id(char *device)
 1844 {
 1845     char *name = my_pty_name(device);
 1846     char *leaf = x_basename(name);
 1847 
 1848     if (name == leaf) {     /* no '/' in the name */
 1849     int len = (int) strlen(leaf);
 1850     if (PTYCHARLEN < len)
 1851         leaf = leaf + (len - PTYCHARLEN);
 1852     }
 1853     TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
 1854     return leaf;
 1855 }
 1856 
 1857 /*
 1858  * Set the tty/pty identifier
 1859  */
 1860 static void
 1861 set_pty_id(char *device, char *id)
 1862 {
 1863     char *name = my_pty_name(device);
 1864     char *leaf = x_basename(name);
 1865 
 1866     if (name == leaf) {
 1867     strcpy(my_pty_id(device), id);
 1868     } else {
 1869     strcpy(leaf, id);
 1870     }
 1871     TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
 1872 }
 1873 
 1874 /*
 1875  * The original -S option accepts two characters to identify the pty, and a
 1876  * file-descriptor (assumed to be nonzero).  That is not general enough, so we
 1877  * check first if the option contains a '/' to delimit the two fields, and if
 1878  * not, fall-thru to the original logic.
 1879  */
 1880 static Bool
 1881 ParseSccn(char *option)
 1882 {
 1883     char *leaf = x_basename(option);
 1884     Bool code = False;
 1885 
 1886     passedPty = x_strdup(option);
 1887     if (leaf != option) {
 1888     if (leaf - option > 0
 1889         && isdigit(CharOf(*leaf))
 1890         && sscanf(leaf, "%d", &am_slave) == 1) {
 1891         size_t len = (size_t) (leaf - option - 1);
 1892         /*
 1893          * If we have a slash, we only care about the part after the slash,
 1894          * which is a file-descriptor.  The part before the slash can be
 1895          * the /dev/pts/XXX value, but since we do not need to reopen it,
 1896          * it is useful mainly for display in a "ps -ef".
 1897          */
 1898         passedPty[len] = 0;
 1899         code = True;
 1900     }
 1901     } else {
 1902     code = (sscanf(option, "%c%c%d",
 1903                passedPty, passedPty + 1, &am_slave) == 3);
 1904     passedPty[2] = '\0';
 1905     }
 1906     TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
 1907        passedPty, am_slave, code ? "OK" : "ERR"));
 1908     return code;
 1909 }
 1910 
 1911 #if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
 1912 /*
 1913  * From "man utmp":
 1914  * xterm and other terminal emulators directly create a USER_PROCESS record
 1915  * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
 1916  * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
 1917  * recycle it, otherwise they create a new entry.  If they can, they will mark
 1918  * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
 1919  * ut_time, ut_user and ut_host as well.
 1920  *
 1921  * Generally ut_id allows no more than 3 characters (plus null), even if the
 1922  * pty implementation allows more than 3 digits.
 1923  */
 1924 static char *
 1925 my_utmp_id(char *device)
 1926 {
 1927     typedef struct UTMP_STR UTMP_STRUCT;
 1928 #define UTIDSIZE    (sizeof(((UTMP_STRUCT *)NULL)->ut_id))
 1929     static char result[UTIDSIZE + 1];
 1930 
 1931 #if defined(__SCO__) || defined(__UNIXWARE__)
 1932     /*
 1933      * Legend does not support old-style pty's, has no related compatibility
 1934      * issues, and can use the available space in ut_id differently from the
 1935      * default convention.
 1936      *
 1937      * This scheme is intended to avoid conflicts both with other users of
 1938      * utmpx as well as between multiple xterms.  First, Legend uses all of the
 1939      * characters of ut_id, and adds no terminating NUL is required (the
 1940      * default scheme may add a trailing NUL).  Second, all xterm entries will
 1941      * start with the letter 'x' followed by three digits, which will be the
 1942      * last three digits of the device name, regardless of the format of the
 1943      * device name, with leading 0's added where necessary.  For instance, an
 1944      * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
 1945      * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
 1946      * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
 1947      */
 1948     int len, n;
 1949 
 1950     len = strlen(device);
 1951     n = UTIDSIZE;
 1952     result[n] = '\0';
 1953     while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
 1954     result[--n] = device[--len];
 1955     while (n > 0)
 1956     result[--n] = '0';
 1957     result[0] = 'x';
 1958 #else
 1959     char *name = my_pty_name(device);
 1960     char *leaf = x_basename(name);
 1961     size_t len = strlen(leaf);
 1962 
 1963     if ((UTIDSIZE - 1) < len)
 1964     leaf = leaf + (len - (UTIDSIZE - 1));
 1965     sprintf(result, "p%s", leaf);
 1966 #endif
 1967 
 1968     TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
 1969     return result;
 1970 }
 1971 #endif /* USE_SYSV_UTMP */
 1972 
 1973 #ifdef USE_POSIX_SIGNALS
 1974 
 1975 typedef void (*sigfunc) (int);
 1976 
 1977 /* make sure we sure we ignore SIGCHLD for the cases parent
 1978    has just been stopped and not actually killed */
 1979 
 1980 static sigfunc
 1981 posix_signal(int signo, sigfunc func)
 1982 {
 1983     struct sigaction act, oact;
 1984 
 1985     act.sa_handler = func;
 1986     sigemptyset(&act.sa_mask);
 1987 #ifdef SA_RESTART
 1988     act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
 1989 #else
 1990     act.sa_flags = SA_NOCLDSTOP;
 1991 #endif
 1992     if (sigaction(signo, &act, &oact) < 0)
 1993     return (SIG_ERR);
 1994     return (oact.sa_handler);
 1995 }
 1996 
 1997 #endif /* USE_POSIX_SIGNALS */
 1998 
 1999 #if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
 2000 static void
 2001 disableSetUid(void)
 2002 {
 2003     TRACE(("process %d disableSetUid\n", (int) getpid()));
 2004     if (setuid(save_ruid) == -1) {
 2005     xtermWarning("unable to reset uid\n");
 2006     exit(1);
 2007     }
 2008     TRACE_IDS;
 2009 }
 2010 #else
 2011 #define disableSetUid()     /* nothing */
 2012 #endif /* DISABLE_SETUID */
 2013 
 2014 #if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
 2015 static void
 2016 disableSetGid(void)
 2017 {
 2018     TRACE(("process %d disableSetGid\n", (int) getpid()));
 2019     if (setegid(save_rgid) == -1) {
 2020     xtermWarning("unable to reset effective gid\n");
 2021     exit(1);
 2022     }
 2023     TRACE_IDS;
 2024 }
 2025 #else
 2026 #define disableSetGid()     /* nothing */
 2027 #endif /* DISABLE_SETGID */
 2028 
 2029 #if defined(HAVE_POSIX_SAVED_IDS)
 2030 #if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
 2031 static void
 2032 setEffectiveGroup(gid_t group)
 2033 {
 2034     TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
 2035     if (setegid(group) == -1) {
 2036 #ifdef __MVS__
 2037     if (!(errno == EMVSERR))    /* could happen if _BPX_SHAREAS=REUSE */
 2038 #endif
 2039     {
 2040         xtermPerror("setegid(%d)", (int) group);
 2041     }
 2042     }
 2043     TRACE_IDS;
 2044 }
 2045 #endif
 2046 
 2047 #if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
 2048 static void
 2049 setEffectiveUser(uid_t user)
 2050 {
 2051     TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
 2052     if (seteuid(user) == -1) {
 2053 #ifdef __MVS__
 2054     if (!(errno == EMVSERR))
 2055 #endif
 2056     {
 2057         xtermPerror("seteuid(%d)", (int) user);
 2058     }
 2059     }
 2060     TRACE_IDS;
 2061 }
 2062 #endif
 2063 #endif /* HAVE_POSIX_SAVED_IDS */
 2064 
 2065 #if OPT_LUIT_PROG
 2066 static Boolean
 2067 complex_command(char **args)
 2068 {
 2069     Boolean result = False;
 2070     if (x_countargv(args) == 1) {
 2071     char *check = xtermFindShell(args[0], False);
 2072     if (check == 0) {
 2073         result = True;
 2074     } else {
 2075         free(check);
 2076     }
 2077     }
 2078     return result;
 2079 }
 2080 #endif
 2081 
 2082 static unsigned
 2083 lookup_baudrate(const char *value)
 2084 {
 2085     struct speed {
 2086     unsigned given_speed;   /* values for 'ospeed' */
 2087     unsigned actual_speed;  /* the actual speed */
 2088     };
 2089 
 2090 #define DATA(number) { B##number, number }
 2091 
 2092     static struct speed const speeds[] =
 2093     {
 2094     DATA(0),
 2095     DATA(50),
 2096     DATA(75),
 2097     DATA(110),
 2098     DATA(134),
 2099     DATA(150),
 2100     DATA(200),
 2101     DATA(300),
 2102     DATA(600),
 2103     DATA(1200),
 2104     DATA(1800),
 2105     DATA(2400),
 2106     DATA(4800),
 2107     DATA(9600),
 2108 #ifdef B19200
 2109     DATA(19200),
 2110 #elif defined(EXTA)
 2111     {EXTA, 19200},
 2112 #endif
 2113 #ifdef B28800
 2114     DATA(28800),
 2115 #endif
 2116 #ifdef B38400
 2117     DATA(38400),
 2118 #elif defined(EXTB)
 2119     {EXTB, 38400},
 2120 #endif
 2121 #ifdef B57600
 2122     DATA(57600),
 2123 #endif
 2124 #ifdef B76800
 2125     DATA(76800),
 2126 #endif
 2127 #ifdef B115200
 2128     DATA(115200),
 2129 #endif
 2130 #ifdef B153600
 2131     DATA(153600),
 2132 #endif
 2133 #ifdef B230400
 2134     DATA(230400),
 2135 #endif
 2136 #ifdef B307200
 2137     DATA(307200),
 2138 #endif
 2139 #ifdef B460800
 2140     DATA(460800),
 2141 #endif
 2142 #ifdef B500000
 2143     DATA(500000),
 2144 #endif
 2145 #ifdef B576000
 2146     DATA(576000),
 2147 #endif
 2148 #ifdef B921600
 2149     DATA(921600),
 2150 #endif
 2151 #ifdef B1000000
 2152     DATA(1000000),
 2153 #endif
 2154 #ifdef B1152000
 2155     DATA(1152000),
 2156 #endif
 2157 #ifdef B1500000
 2158     DATA(1500000),
 2159 #endif
 2160 #ifdef B2000000
 2161     DATA(2000000),
 2162 #endif
 2163 #ifdef B2500000
 2164     DATA(2500000),
 2165 #endif
 2166 #ifdef B3000000
 2167     DATA(3000000),
 2168 #endif
 2169 #ifdef B3500000
 2170     DATA(3500000),
 2171 #endif
 2172 #ifdef B4000000
 2173     DATA(4000000),
 2174 #endif
 2175     };
 2176 #undef DATA
 2177     unsigned result = 0;
 2178     long check;
 2179     char *next;
 2180     if (x_toupper(*value) == 'B')
 2181     value++;
 2182     if (isdigit(CharOf(*value))) {
 2183     check = strtol(value, &next, 10);
 2184     if (FullS2L(value, next) && (check > 0)) {
 2185         Cardinal n;
 2186         for (n = 0; n < XtNumber(speeds); ++n) {
 2187         if (speeds[n].actual_speed == (unsigned) check) {
 2188             result = speeds[n].given_speed;
 2189             break;
 2190         }
 2191         }
 2192     }
 2193     }
 2194     if (result == 0) {
 2195     fprintf(stderr, "unsupported value for baudrate: %s\n", value);
 2196     }
 2197     return result;
 2198 }
 2199 
 2200 int
 2201 main(int argc, char *argv[]ENVP_ARG)
 2202 {
 2203 #if OPT_MAXIMIZE
 2204 #define DATA(name) { #name, es##name }
 2205     static const FlagList tblFullscreen[] =
 2206     {
 2207     DATA(Always),
 2208     DATA(Never)
 2209     };
 2210 #undef DATA
 2211 #endif
 2212 
 2213     Widget form_top, menu_top;
 2214     Dimension menu_high;
 2215     TScreen *screen;
 2216     int mode;
 2217     char *my_class = x_strdup(DEFCLASS);
 2218     unsigned line_speed = VAL_LINE_SPEED;
 2219     Window winToEmbedInto = None;
 2220 #if defined(HAVE_LIB_XAW3DXFT)
 2221     Xaw3dXftData *xaw3dxft_data;
 2222 #endif
 2223 
 2224     ProgramName = x_strdup(x_basename(argv[0]));
 2225     ProgramPath = xtermFindShell(argv[0], True);
 2226     if (ProgramPath != NULL)
 2227     argv[0] = ProgramPath;
 2228 
 2229 #ifdef HAVE_POSIX_SAVED_IDS
 2230     save_euid = geteuid();
 2231     save_egid = getegid();
 2232 #endif
 2233 
 2234     save_ruid = getuid();
 2235     save_rgid = getgid();
 2236 
 2237 #if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
 2238 #if defined(DISABLE_SETUID)
 2239     disableSetUid();
 2240 #endif
 2241 #if defined(DISABLE_SETGID)
 2242     disableSetGid();
 2243 #endif
 2244     TRACE_IDS;
 2245 #endif
 2246 
 2247     /* extra length in case longer tty name like /dev/ttyq255 */
 2248     ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
 2249 #ifdef USE_PTY_DEVICE
 2250     ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
 2251     if (!ttydev || !ptydev)
 2252 #else
 2253     if (!ttydev)
 2254 #endif
 2255     {
 2256     xtermWarning("unable to allocate memory for ttydev or ptydev\n");
 2257     exit(1);
 2258     }
 2259     strcpy(ttydev, TTYDEV);
 2260 #ifdef USE_PTY_DEVICE
 2261     strcpy(ptydev, PTYDEV);
 2262 #endif
 2263 
 2264 #if defined(USE_UTMP_SETGID)
 2265     get_pty(NULL, NULL);
 2266     disableSetUid();
 2267     disableSetGid();
 2268     TRACE_IDS;
 2269 #define get_pty(pty, from) really_get_pty(pty, from)
 2270 #endif
 2271 
 2272     /* Do these first, since we may not be able to open the display */
 2273     TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
 2274     TRACE_ARGV("Before XtOpenApplication", argv);
 2275     restart_params = 0;
 2276     if (argc > 1) {
 2277     XrmOptionDescRec *option_ptr;
 2278     char *option_value;
 2279     int n;
 2280     Bool quit = False;
 2281 
 2282     for (n = 1; n < argc; n++) {
 2283         if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
 2284         if (argv[n] == 0) {
 2285             break;
 2286         } else if (isOption(argv[n])) {
 2287             Syntax(argv[n]);
 2288         } else if (explicit_shname != 0) {
 2289             xtermWarning("Explicit shell already was %s\n", explicit_shname);
 2290             Syntax(argv[n]);
 2291         }
 2292         explicit_shname = xtermFindShell(argv[n], True);
 2293         if (explicit_shname == 0)
 2294             exit(0);
 2295         TRACE(("...explicit shell %s\n", explicit_shname));
 2296         restart_params = (argc - n);
 2297         } else if (!strcmp(option_ptr->option, "-e")) {
 2298         command_to_exec = (argv + n + 1);
 2299         if (!command_to_exec[0])
 2300             Syntax(argv[n]);
 2301         restart_params = (argc - n);
 2302         break;
 2303         } else if (!strcmp(option_ptr->option, "-version")) {
 2304         Version();
 2305         quit = True;
 2306         } else if (!strcmp(option_ptr->option, "-help")) {
 2307         Help();
 2308         quit = True;
 2309         } else if (!strcmp(option_ptr->option, "-baudrate")) {
 2310         NeedParam(option_ptr, option_value);
 2311         if ((line_speed = lookup_baudrate(option_value)) == 0) {
 2312             Help();
 2313             quit = True;
 2314         }
 2315         } else if (!strcmp(option_ptr->option, "-class")) {
 2316         NeedParam(option_ptr, option_value);
 2317         free(my_class);
 2318         if ((my_class = x_strdup(option_value)) == 0) {
 2319             Help();
 2320             quit = True;
 2321         }
 2322         } else if (!strcmp(option_ptr->option, "-into")) {
 2323         char *endPtr;
 2324         NeedParam(option_ptr, option_value);
 2325         winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
 2326         if (!FullS2L(option_value, endPtr)) {
 2327             Help();
 2328             quit = True;
 2329         }
 2330         }
 2331     }
 2332     if (quit)
 2333         exit(0);
 2334     /*
 2335      * If there is anything left unparsed, and we're not using "-e",
 2336      * then give up.
 2337      */
 2338     if (n < argc && !command_to_exec) {
 2339         Syntax(argv[n]);
 2340     }
 2341     }
 2342 
 2343     /* This dumped core on HP-UX 9.05 with X11R5 */
 2344 #if OPT_I18N_SUPPORT
 2345     XtSetLanguageProc(NULL, NULL, NULL);
 2346 #endif
 2347 
 2348     /* enable Xft support in Xaw3DXft */
 2349 #if defined(HAVE_LIB_XAW3DXFT)
 2350     GET_XAW3DXFT_DATA(xaw3dxft_data);
 2351     xaw3dxft_data->encoding = -1;
 2352 #endif
 2353 
 2354 #ifdef TERMIO_STRUCT        /* { */
 2355     /* Initialization is done here rather than above in order
 2356      * to prevent any assumptions about the order of the contents
 2357      * of the various terminal structures (which may change from
 2358      * implementation to implementation).
 2359      */
 2360     memset(&d_tio, 0, sizeof(d_tio));
 2361     d_tio.c_iflag = ICRNL | IXON;
 2362     d_tio.c_oflag = TAB3 | D_TIO_FLAGS;
 2363     {
 2364     Cardinal nn;
 2365 
 2366     /* fill in default-values */
 2367     for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
 2368         if (validTtyChar(d_tio, nn)) {
 2369         d_tio.c_cc[ttyChars[nn].sysMode] =
 2370             (cc_t) ttyChars[nn].myDefault;
 2371         }
 2372     }
 2373     }
 2374 #if defined(macII) || defined(ATT) || defined(CRAY) /* { */
 2375     d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
 2376     d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
 2377 #ifdef ECHOKE
 2378     d_tio.c_lflag |= ECHOKE | IEXTEN;
 2379 #endif
 2380 #ifdef ECHOCTL
 2381     d_tio.c_lflag |= ECHOCTL | IEXTEN;
 2382 #endif
 2383 #ifndef USE_TERMIOS     /* { */
 2384     d_tio.c_line = 0;
 2385 #endif /* } */
 2386 #ifdef HAS_LTCHARS      /* { */
 2387     d_ltc.t_suspc = CSUSP;  /* t_suspc */
 2388     d_ltc.t_dsuspc = CDSUSP;    /* t_dsuspc */
 2389     d_ltc.t_rprntc = CRPRNT;
 2390     d_ltc.t_flushc = CFLUSH;
 2391     d_ltc.t_werasc = CWERASE;
 2392     d_ltc.t_lnextc = CLNEXT;
 2393 #endif /* } HAS_LTCHARS */
 2394 #ifdef TIOCLSET         /* { */
 2395     d_lmode = 0;
 2396 #endif /* } TIOCLSET */
 2397 #else /* }{ else !macII, ATT, CRAY */
 2398 #ifndef USE_POSIX_TERMIOS
 2399 #ifdef BAUD_0           /* { */
 2400     d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
 2401 #else /* }{ !BAUD_0 */
 2402     d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
 2403 #endif /* } !BAUD_0 */
 2404 #else /* USE_POSIX_TERMIOS */
 2405     d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
 2406     cfsetispeed(&d_tio, line_speed);
 2407     cfsetospeed(&d_tio, line_speed);
 2408 #endif
 2409     d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
 2410 #ifdef ECHOKE
 2411     d_tio.c_lflag |= ECHOKE | IEXTEN;
 2412 #endif
 2413 #ifdef ECHOCTL
 2414     d_tio.c_lflag |= ECHOCTL | IEXTEN;
 2415 #endif
 2416 #ifndef USE_POSIX_TERMIOS
 2417 #ifdef NTTYDISC
 2418     d_tio.c_line = NTTYDISC;
 2419 #else
 2420     d_tio.c_line = 0;
 2421 #endif
 2422 #endif /* USE_POSIX_TERMIOS */
 2423 #ifdef __sgi
 2424     d_tio.c_cflag &= ~(HUPCL | PARENB);
 2425     d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
 2426 #endif
 2427 #ifdef __MVS__
 2428     d_tio.c_cflag &= ~(HUPCL | PARENB);
 2429 #endif
 2430     {
 2431     Cardinal nn;
 2432     int i;
 2433 
 2434     /* try to inherit tty settings */
 2435     for (i = 0; i <= 2; i++) {
 2436         TERMIO_STRUCT deftio;
 2437         if (ttyGetAttr(i, &deftio) == 0) {
 2438         for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
 2439             if (validTtyChar(d_tio, nn)) {
 2440             d_tio.c_cc[ttyChars[nn].sysMode] =
 2441                 deftio.c_cc[ttyChars[nn].sysMode];
 2442             }
 2443         }
 2444         break;
 2445         }
 2446     }
 2447     }
 2448 #if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)  /* { */
 2449     d_tio.c_cc[VMIN] = 1;
 2450     d_tio.c_cc[VTIME] = 0;
 2451 #endif /* } */
 2452 #ifdef HAS_LTCHARS      /* { */
 2453     d_ltc.t_suspc = CharOf('\000'); /* t_suspc */
 2454     d_ltc.t_dsuspc = CharOf('\000');    /* t_dsuspc */
 2455     d_ltc.t_rprntc = CharOf('\377');    /* reserved... */
 2456     d_ltc.t_flushc = CharOf('\377');
 2457     d_ltc.t_werasc = CharOf('\377');
 2458     d_ltc.t_lnextc = CharOf('\377');
 2459 #endif /* } HAS_LTCHARS */
 2460 
 2461 #ifdef TIOCLSET         /* { */
 2462     d_lmode = 0;
 2463 #endif /* } TIOCLSET */
 2464 #endif /* } macII, ATT, CRAY */
 2465 #endif /* } TERMIO_STRUCT */
 2466 
 2467     /* Init the Toolkit. */
 2468     {
 2469 #if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
 2470     setEffectiveGroup(save_rgid);
 2471     setEffectiveUser(save_ruid);
 2472     TRACE_IDS;
 2473 #endif
 2474     toplevel = xtermOpenApplication(&app_con,
 2475                     my_class,
 2476                     optionDescList,
 2477                     XtNumber(optionDescList),
 2478                     &argc, argv,
 2479                     fallback_resources,
 2480                     sessionShellWidgetClass,
 2481                     NULL, 0);
 2482     TRACE(("created toplevel widget %p, window %#lx\n",
 2483            (void *) toplevel, XtWindow(toplevel)));
 2484 
 2485     XtGetApplicationResources(toplevel, (XtPointer) &resource,
 2486                   application_resources,
 2487                   XtNumber(application_resources), NULL, 0);
 2488     TRACE_XRES();
 2489 #ifdef HAVE_LIB_XCURSOR
 2490     if (!strcmp(resource.cursorTheme, "none")) {
 2491         TRACE(("startup with no cursorTheme\n"));
 2492         init_colored_cursor(XtDisplay(toplevel));
 2493     } else {
 2494         const char *theme = resource.cursorTheme;
 2495         if (IsEmpty(theme))
 2496         theme = "default";
 2497         TRACE(("startup with \"%s\" cursorTheme\n", theme));
 2498         xtermSetenv("XCURSOR_THEME", theme);
 2499     }
 2500 #endif
 2501 #if USE_DOUBLE_BUFFER
 2502     if (resource.buffered_fps <= 0)
 2503         resource.buffered_fps = DEF_BUFFER_RATE;
 2504     if (resource.buffered_fps > 100)
 2505         resource.buffered_fps = 100;
 2506 #endif
 2507 #if OPT_MAXIMIZE
 2508     resource.fullscreen = extendedBoolean(resource.fullscreen_s,
 2509                           tblFullscreen,
 2510                           esLAST);
 2511 #endif
 2512     VTInitTranslations();
 2513 #if OPT_PTY_HANDSHAKE
 2514     resource.wait_for_map0 = resource.wait_for_map;
 2515 #endif
 2516 
 2517 #if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
 2518 #if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
 2519 #if !defined(DISABLE_SETUID)
 2520     setEffectiveUser(save_euid);
 2521 #endif
 2522 #if !defined(DISABLE_SETGID)
 2523     setEffectiveGroup(save_egid);
 2524 #endif
 2525     TRACE_IDS;
 2526 #endif
 2527 #endif
 2528     }
 2529 
 2530     /*
 2531      * ICCCM delete_window.
 2532      */
 2533     XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
 2534 
 2535     /*
 2536      * fill in terminal modes
 2537      */
 2538     if (resource.tty_modes) {
 2539     int n = parse_tty_modes(resource.tty_modes);
 2540     if (n < 0) {
 2541         xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
 2542     } else if (n > 0) {
 2543         override_tty_modes = True;
 2544     }
 2545     }
 2546     initZIconBeep();
 2547     hold_screen = resource.hold_screen ? 1 : 0;
 2548     if (resource.icon_geometry != NULL) {
 2549     int scr, junk;
 2550     int ix, iy;
 2551     Arg args[2];
 2552 
 2553     for (scr = 0;       /* yyuucchh */
 2554          XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
 2555          scr++) ;
 2556 
 2557     args[0].name = XtNiconX;
 2558     args[1].name = XtNiconY;
 2559     XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
 2560           0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
 2561     args[0].value = (XtArgVal) ix;
 2562     args[1].value = (XtArgVal) iy;
 2563     XtSetValues(toplevel, args, 2);
 2564     }
 2565 
 2566     XtSetValues(toplevel, ourTopLevelShellArgs,
 2567         number_ourTopLevelShellArgs);
 2568 
 2569 #if OPT_WIDE_CHARS
 2570     /* seems as good a place as any */
 2571     init_classtab();
 2572 #endif
 2573 
 2574     /* Parse the rest of the command line */
 2575     TRACE_ARGV("After XtOpenApplication", argv);
 2576     for (argc--, argv++; argc > 0; argc--, argv++) {
 2577     if (!isOption(*argv)) {
 2578 #ifdef VMS
 2579         Syntax(*argv);
 2580 #else
 2581         if (argc > 1)
 2582         Syntax(*argv);
 2583         continue;
 2584 #endif
 2585     }
 2586 
 2587     TRACE(("parsing %s\n", argv[0]));
 2588     switch (argv[0][1]) {
 2589     case 'C':
 2590 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
 2591 #ifndef __sgi
 2592         {
 2593         struct stat sbuf;
 2594 
 2595         /* Must be owner and have read/write permission.
 2596            xdm cooperates to give the console the right user. */
 2597         if (!stat("/dev/console", &sbuf) &&
 2598             (sbuf.st_uid == save_ruid) &&
 2599             !access("/dev/console", R_OK | W_OK)) {
 2600             Console = True;
 2601         } else
 2602             Console = False;
 2603         }
 2604 #else /* __sgi */
 2605         Console = True;
 2606 #endif /* __sgi */
 2607 #endif /* TIOCCONS */
 2608         continue;
 2609     case 'S':
 2610         if (!ParseSccn(*argv + 2))
 2611         Syntax(*argv);
 2612         continue;
 2613 #ifdef DEBUG
 2614     case 'D':
 2615         debug = True;
 2616         continue;
 2617 #endif /* DEBUG */
 2618     case 'b':
 2619         if (strcmp(argv[0], "-baudrate"))
 2620         Syntax(*argv);
 2621         argc--;
 2622         argv++;
 2623         continue;
 2624     case 'c':
 2625         if (strcmp(argv[0], "-class"))
 2626         Syntax(*argv);
 2627         argc--;
 2628         argv++;
 2629         continue;
 2630     case 'e':
 2631         if (strcmp(argv[0], "-e"))
 2632         Syntax(*argv);
 2633         command_to_exec = (argv + 1);
 2634         break;
 2635     case 'i':
 2636         if (strcmp(argv[0], "-into"))
 2637         Syntax(*argv);
 2638         argc--;
 2639         argv++;
 2640         continue;
 2641 
 2642     default:
 2643         Syntax(*argv);
 2644     }
 2645     break;
 2646     }
 2647 
 2648     SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
 2649 
 2650     term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
 2651                          form_top,
 2652 #if OPT_TOOLBAR
 2653                          XtNmenuBar, menu_top,
 2654                          XtNresizable, True,
 2655                          XtNfromVert, menu_top,
 2656                          XtNleft, XawChainLeft,
 2657                          XtNright, XawChainRight,
 2658                          XtNtop, XawChainTop,
 2659                          XtNbottom, XawChainBottom,
 2660                          XtNmenuHeight, menu_high,
 2661 #endif
 2662                          (XtPointer) 0);
 2663     TRACE(("created vt100 widget %p, window %#lx\n",
 2664        (void *) term, XtWindow(term)));
 2665     decode_keyboard_type(term, &resource);
 2666 
 2667     screen = TScreenOf(term);
 2668     screen->inhibit = 0;
 2669 
 2670 #ifdef ALLOWLOGGING
 2671     if (term->misc.logInhibit)
 2672     screen->inhibit |= I_LOG;
 2673 #endif
 2674     if (term->misc.signalInhibit)
 2675     screen->inhibit |= I_SIGNAL;
 2676 #if OPT_TEK4014
 2677     if (term->misc.tekInhibit)
 2678     screen->inhibit |= I_TEK;
 2679 #endif
 2680 
 2681     /*
 2682      * We might start by showing the tek4014 window.
 2683      */
 2684 #if OPT_TEK4014
 2685     if (screen->inhibit & I_TEK)
 2686     TEK4014_ACTIVE(term) = False;
 2687 
 2688     if (TEK4014_ACTIVE(term) && !TekInit())
 2689     SysError(ERROR_INIT);
 2690 #endif
 2691 
 2692     /*
 2693      * Start the toolbar at this point, after the first window has been setup.
 2694      */
 2695 #if OPT_TOOLBAR
 2696     ShowToolbar(resource.toolBar);
 2697 #endif
 2698 
 2699     xtermOpenSession();
 2700 
 2701     /*
 2702      * Set title and icon name if not specified
 2703      */
 2704     if (command_to_exec) {
 2705     Arg args[2];
 2706 
 2707     if (!resource.title) {
 2708         if (command_to_exec) {
 2709         resource.title = x_basename(command_to_exec[0]);
 2710         }           /* else not reached */
 2711     }
 2712 
 2713     if (!resource.icon_name)
 2714         resource.icon_name = resource.title;
 2715     XtSetArg(args[0], XtNtitle, resource.title);
 2716     XtSetArg(args[1], XtNiconName, resource.icon_name);
 2717 
 2718     TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
 2719            resource.title,
 2720            resource.icon_name,
 2721            NonNull(resource.icon_hint),
 2722            *command_to_exec));
 2723 
 2724     XtSetValues(toplevel, args, 2);
 2725     }
 2726 #if OPT_LUIT_PROG
 2727     if (term->misc.callfilter) {
 2728     char **split_filter = x_splitargs(term->misc.localefilter);
 2729     unsigned count_split = x_countargv(split_filter);
 2730     unsigned count_exec = x_countargv(command_to_exec);
 2731     unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
 2732 
 2733     command_to_exec_with_luit = TypeCallocN(char *,
 2734                           (count_split
 2735                            + count_exec
 2736                            + count_using
 2737                            + 8));
 2738     if (command_to_exec_with_luit == NULL)
 2739         SysError(ERROR_LUMALLOC);
 2740 
 2741     x_appendargv(command_to_exec_with_luit, split_filter);
 2742     if (count_using) {
 2743         char *encoding_opt[4];
 2744         encoding_opt[0] = x_strdup("-encoding");
 2745         encoding_opt[1] = term->misc.locale_str;
 2746         encoding_opt[2] = 0;
 2747         x_appendargv(command_to_exec_with_luit, encoding_opt);
 2748     }
 2749     command_length_with_luit = x_countargv(command_to_exec_with_luit);
 2750     if (count_exec) {
 2751         static char *fixup_shell[] =
 2752         {(char *) "sh", (char *) "-c", 0};
 2753         char *delimiter[2];
 2754         delimiter[0] = x_strdup("--");
 2755         delimiter[1] = 0;
 2756         x_appendargv(command_to_exec_with_luit, delimiter);
 2757         if (complex_command(command_to_exec)) {
 2758         x_appendargv(command_to_exec_with_luit, fixup_shell);
 2759         }
 2760         x_appendargv(command_to_exec_with_luit, command_to_exec);
 2761     }
 2762     TRACE_ARGV("luit command", command_to_exec_with_luit);
 2763     xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
 2764     }
 2765 #endif
 2766 
 2767     if_DEBUG({
 2768     /* Set up stderr properly.  Opening this log file cannot be
 2769        done securely by a privileged xterm process (although we try),
 2770        so the debug feature is disabled by default. */
 2771     char dbglogfile[TIMESTAMP_LEN + 20];
 2772     int i = -1;
 2773     timestamp_filename(dbglogfile, "xterm.debug.log.");
 2774     if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
 2775         i = open(dbglogfile, O_WRONLY | O_TRUNC);
 2776     }
 2777     if (i >= 0) {
 2778         dup2(i, 2);
 2779 
 2780         /* mark this file as close on exec */
 2781         (void) fcntl(i, F_SETFD, 1);
 2782     }
 2783     });
 2784 
 2785     spawnXTerm(term, line_speed);
 2786 
 2787 #ifndef VMS
 2788     /* Child process is out there, let's catch its termination */
 2789 
 2790 #ifdef USE_POSIX_SIGNALS
 2791     (void) posix_signal(SIGCHLD, reapchild);
 2792 #else
 2793     (void) signal(SIGCHLD, reapchild);
 2794 #endif
 2795     /* Realize procs have now been executed */
 2796 
 2797     if (am_slave >= 0) {    /* Write window id so master end can read and use */
 2798     char buf[80];
 2799 
 2800     buf[0] = '\0';
 2801     sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
 2802     IGNORE_RC(write(screen->respond, buf, strlen(buf)));
 2803     }
 2804 #ifdef AIXV3
 2805 #if (OSMAJORVERSION < 4)
 2806     /* In AIXV3, xterms started from /dev/console have CLOCAL set.
 2807      * This means we need to clear CLOCAL so that SIGHUP gets sent
 2808      * to the slave-pty process when xterm exits.
 2809      */
 2810 
 2811     {
 2812     TERMIO_STRUCT tio;
 2813 
 2814     if (ttyGetAttr(screen->respond, &tio) == -1)
 2815         SysError(ERROR_TIOCGETP);
 2816 
 2817     tio.c_cflag &= ~(CLOCAL);
 2818 
 2819     if (ttySetAttr(screen->respond, &tio) == -1)
 2820         SysError(ERROR_TIOCSETP);
 2821     }
 2822 #endif
 2823 #endif
 2824 #if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__) || defined(__minix)
 2825     if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
 2826     SysError(ERROR_F_GETFL);
 2827 #ifdef O_NDELAY
 2828     mode |= O_NDELAY;
 2829 #else
 2830     mode |= O_NONBLOCK;
 2831 #endif /* O_NDELAY */
 2832     if (fcntl(screen->respond, F_SETFL, mode))
 2833     SysError(ERROR_F_SETFL);
 2834 #else /* !USE_ANY_SYSV_TERMIO */
 2835     mode = 1;
 2836     if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
 2837     SysError(ERROR_FIONBIO);
 2838 #endif /* USE_ANY_SYSV_TERMIO, etc */
 2839 
 2840     /* The erase character is used to delete the current completion */
 2841 #if OPT_DABBREV
 2842 #ifdef TERMIO_STRUCT
 2843     screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
 2844 #else
 2845     screen->dabbrev_erase_char = d_sg.sg_erase;
 2846 #endif
 2847     TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
 2848 #endif
 2849 
 2850     FD_ZERO(&pty_mask);
 2851     FD_ZERO(&X_mask);
 2852     FD_ZERO(&Select_mask);
 2853     FD_SET(screen->respond, &pty_mask);
 2854     FD_SET(ConnectionNumber(screen->display), &X_mask);
 2855     FD_SET(screen->respond, &Select_mask);
 2856     FD_SET(ConnectionNumber(screen->display), &Select_mask);
 2857     max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
 2858          ? (1 + ConnectionNumber(screen->display))
 2859          : (1 + screen->respond));
 2860 
 2861 #endif /* !VMS */
 2862     if_DEBUG({
 2863     TRACE(("debugging on pid %d\n", (int) getpid()));
 2864     });
 2865     XSetErrorHandler(xerror);
 2866     XSetIOErrorHandler(xioerror);
 2867 #if OPT_SESSION_MGT
 2868     IceSetIOErrorHandler(ice_error);
 2869 #endif
 2870 
 2871     initPtyData(&VTbuffer);
 2872 #ifdef ALLOWLOGGING
 2873     if (term->misc.log_on) {
 2874     StartLog(term);
 2875     }
 2876 #endif
 2877 
 2878     xtermEmbedWindow(winToEmbedInto);
 2879 #if OPT_COLOR_RES
 2880     TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
 2881        term->misc.re_verse0 ? "reverse" : "normal",
 2882        NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
 2883        NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
 2884 
 2885     if (term->misc.re_verse0) {
 2886     if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
 2887         && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
 2888         TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
 2889         TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
 2890     } else {
 2891         ReverseVideo(term);
 2892     }
 2893     term->misc.re_verse = True;
 2894     update_reversevideo();
 2895     TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
 2896            term->misc.re_verse ? "reverse" : "normal",
 2897            NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
 2898            NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
 2899     }
 2900 #endif /* OPT_COLOR_RES */
 2901 
 2902 #if OPT_MAXIMIZE
 2903     if (resource.maximized)
 2904     RequestMaximize(term, True);
 2905 #endif
 2906     for (;;) {
 2907 #if OPT_TEK4014
 2908     if (TEK4014_ACTIVE(term))
 2909         TekRun();
 2910     else
 2911 #endif
 2912         VTRun(term);
 2913     }
 2914 }
 2915 
 2916 #if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
 2917 #define USE_OPENPTY 1
 2918 static int opened_tty = -1;
 2919 #endif
 2920 
 2921 /*
 2922  * This function opens up a pty master and stuffs its value into pty.
 2923  *
 2924  * If it finds one, it returns a value of 0.  If it does not find one,
 2925  * it returns a value of !0.  This routine is designed to be re-entrant,
 2926  * so that if a pty master is found and later, we find that the slave
 2927  * has problems, we can re-enter this function and get another one.
 2928  */
 2929 static int
 2930 get_pty(int *pty, char *from GCC_UNUSED)
 2931 {
 2932     int result = 1;
 2933 
 2934 #if defined(USE_OPENPTY)
 2935     result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
 2936     if (opened_tty >= 0) {
 2937     close(opened_tty);
 2938     opened_tty = -1;
 2939     }
 2940 #elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
 2941     if ((*pty = posix_openpt(O_RDWR)) >= 0) {
 2942     char *name = ptsname(*pty);
 2943     if (name != 0) {
 2944         strcpy(ttydev, name);
 2945         result = 0;
 2946     }
 2947     }
 2948 #ifdef USE_PTY_SEARCH
 2949     if (result) {
 2950     result = pty_search(pty);
 2951     }
 2952 #endif
 2953 #elif defined(PUCC_PTYD)
 2954     result = ((*pty = openrpty(ttydev, ptydev,
 2955                    (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
 2956                    save_ruid, from)) < 0);
 2957 #elif defined(__QNXNTO__)
 2958     result = pty_search(pty);
 2959 #else
 2960 #if defined(USE_USG_PTYS) || defined(__CYGWIN__)
 2961 #if defined(__MVS__)
 2962     result = pty_search(pty);
 2963 #else
 2964     result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
 2965 #endif
 2966 #if defined(SVR4) || defined(__SCO__)
 2967     if (!result)
 2968     strcpy(ttydev, ptsname(*pty));
 2969 #endif
 2970 
 2971 #elif defined(AIXV3)
 2972 
 2973     if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
 2974     strcpy(ttydev, ttyname(*pty));
 2975     result = 0;
 2976     }
 2977 #elif defined(__convex__)
 2978 
 2979     char *pty_name;
 2980     extern char *getpty(void);
 2981 
 2982     while ((pty_name = getpty()) != NULL) {
 2983     if ((*pty = open(pty_name, O_RDWR)) >= 0) {
 2984         strcpy(ptydev, pty_name);
 2985         strcpy(ttydev, pty_name);
 2986         *x_basename(ttydev) = 't';
 2987         result = 0;
 2988         break;
 2989     }
 2990     }
 2991 
 2992 #elif defined(sequent)
 2993 
 2994     result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
 2995 
 2996 #elif defined(__sgi) && (OSMAJORVERSION >= 4)
 2997 
 2998     char *tty_name;
 2999 
 3000     tty_name = _getpty(pty, O_RDWR, 0622, 0);
 3001     if (tty_name != 0) {
 3002     strcpy(ttydev, tty_name);
 3003     result = 0;
 3004     }
 3005 #elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
 3006 
 3007     struct stat fstat_buf;
 3008 
 3009     *pty = open("/dev/ptc", O_RDWR);
 3010     if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
 3011     result = 0;
 3012     sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
 3013     }
 3014 #elif defined(__hpux)
 3015 
 3016     /*
 3017      * Use the clone device if it works, otherwise use pty_search logic.
 3018      */
 3019     if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
 3020     char *name = ptsname(*pty);
 3021     if (name != 0) {
 3022         strcpy(ttydev, name);
 3023         result = 0;
 3024     } else {        /* permissions, or other unexpected problem */
 3025         close(*pty);
 3026         *pty = -1;
 3027         result = pty_search(pty);
 3028     }
 3029     } else {
 3030     result = pty_search(pty);
 3031     }
 3032 
 3033 #else
 3034 
 3035     result = pty_search(pty);
 3036 
 3037 #endif
 3038 #endif
 3039 
 3040     TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
 3041        ttydev != 0 ? ttydev : "?",
 3042        ptydev != 0 ? ptydev : "?",
 3043        result ? "FAIL" : "OK",
 3044        pty != 0 ? *pty : -1));
 3045     return result;
 3046 }
 3047 
 3048 static void
 3049 set_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
 3050 {
 3051 #ifdef USE_TTY_GROUP
 3052     struct group *ttygrp;
 3053 
 3054     if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
 3055     gid = (unsigned) ttygrp->gr_gid;
 3056     mode &= 0660U;
 3057     }
 3058     endgrent();
 3059 #endif /* USE_TTY_GROUP */
 3060 
 3061     TRACE_IDS;
 3062     set_owner(ttydev, (unsigned) uid, gid, mode);
 3063 }
 3064 
 3065 #ifdef get_pty          /* USE_UTMP_SETGID */
 3066 #undef get_pty
 3067 /*
 3068  * Call the real get_pty() before relinquishing root-setuid, caching the
 3069  * result.
 3070  */
 3071 static int
 3072 get_pty(int *pty, char *from)
 3073 {
 3074     static int m_pty = -1;
 3075     int result = -1;
 3076 
 3077     if (pty == NULL) {
 3078     result = really_get_pty(&m_pty, from);
 3079 
 3080     seteuid(0);
 3081     set_pty_permissions(save_ruid, save_rgid, 0600U);
 3082     seteuid(save_ruid);
 3083     TRACE_IDS;
 3084 
 3085     } else if (m_pty != -1) {
 3086     *pty = m_pty;
 3087     result = 0;
 3088     } else {
 3089     result = -1;
 3090     }
 3091     TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
 3092        ttydev != 0 ? ttydev : "?",
 3093        ptydev != 0 ? ptydev : "?",
 3094        result ? "FAIL" : "OK",
 3095        pty != 0 ? *pty : -1));
 3096 #ifdef USE_OPENPTY
 3097     if (opened_tty >= 0) {
 3098     close(opened_tty);
 3099     opened_tty = -1;
 3100     }
 3101 #endif
 3102     return result;
 3103 }
 3104 #endif
 3105 
 3106 /*
 3107  * Called from get_pty to iterate over likely pseudo terminals
 3108  * we might allocate.  Used on those systems that do not have
 3109  * a functional interface for allocating a pty.
 3110  * Returns 0 if found a pty, 1 if fails.
 3111  */
 3112 #ifdef USE_PTY_SEARCH
 3113 static int
 3114 pty_search(int *pty)
 3115 {
 3116     static int devindex = 0, letter = 0;
 3117 
 3118 #if defined(CRAY) || defined(__MVS__)
 3119     while (devindex < MAXPTTYS) {
 3120     sprintf(ttydev, TTYFORMAT, devindex);
 3121     sprintf(ptydev, PTYFORMAT, devindex);
 3122     devindex++;
 3123 
 3124     TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
 3125     if ((*pty = open(ptydev, O_RDWR)) >= 0) {
 3126         return 0;
 3127     }
 3128     }
 3129 #else /* CRAY || __MVS__ */
 3130     while (PTYCHAR1[letter]) {
 3131     ttydev[strlen(ttydev) - 2] =
 3132         ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
 3133 
 3134     while (PTYCHAR2[devindex]) {
 3135         ttydev[strlen(ttydev) - 1] =
 3136         ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
 3137         devindex++;
 3138 
 3139         TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
 3140         if ((*pty = open(ptydev, O_RDWR)) >= 0) {
 3141 #ifdef sun
 3142         /* Need to check the process group of the pty.
 3143          * If it exists, then the slave pty is in use,
 3144          * and we need to get another one.
 3145          */
 3146         int pgrp_rtn;
 3147         if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
 3148             close(*pty);
 3149             continue;
 3150         }
 3151 #endif /* sun */
 3152         return 0;
 3153         }
 3154     }
 3155     devindex = 0;
 3156     letter++;
 3157     }
 3158 #endif /* CRAY else */
 3159     /*
 3160      * We were unable to allocate a pty master!  Return an error
 3161      * condition and let our caller terminate cleanly.
 3162      */
 3163     return 1;
 3164 }
 3165 #endif /* USE_PTY_SEARCH */
 3166 
 3167 /*
 3168  * The only difference in /etc/termcap between 4014 and 4015 is that
 3169  * the latter has support for switching character sets.  We support the
 3170  * 4015 protocol, but ignore the character switches.  Therefore, we
 3171  * choose 4014 over 4015.
 3172  *
 3173  * Features of the 4014 over the 4012: larger (19") screen, 12-bit
 3174  * graphics addressing (compatible with 4012 10-bit addressing),
 3175  * special point plot mode, incremental plot mode (not implemented in
 3176  * later Tektronix terminals), and 4 character sizes.
 3177  * All of these are supported by xterm.
 3178  */
 3179 
 3180 #if OPT_TEK4014
 3181 static const char *const tekterm[] =
 3182 {
 3183     "tek4014",
 3184     "tek4015",          /* 4014 with APL character set support */
 3185     "tek4012",          /* 4010 with lower case */
 3186     "tek4013",          /* 4012 with APL character set support */
 3187     "tek4010",          /* small screen, upper-case only */
 3188     "dumb",
 3189     0
 3190 };
 3191 #endif
 3192 
 3193 /* The VT102 is a VT100 with the Advanced Video Option included standard.
 3194  * It also adds Escape sequences for insert/delete character/line.
 3195  * The VT220 adds 8-bit character sets, selective erase.
 3196  * The VT320 adds a 25th status line, terminal state interrogation.
 3197  * The VT420 has up to 48 lines on the screen.
 3198  */
 3199 
 3200 static const char *const vtterm[] =
 3201 {
 3202 #ifdef USE_X11TERM
 3203     "x11term",          /* for people who want special term name */
 3204 #endif
 3205     DFT_TERMTYPE,       /* for people who want special term name */
 3206     "xterm",            /* the preferred name, should be fastest */
 3207     "vt102",
 3208     "vt100",
 3209     "ansi",
 3210     "dumb",
 3211     0
 3212 };
 3213 
 3214 /* ARGSUSED */
 3215 static void
 3216 hungtty(int i GCC_UNUSED)
 3217 {
 3218     DEBUG_MSG("handle:hungtty\n");
 3219     siglongjmp(env, 1);
 3220 }
 3221 
 3222 #if OPT_PTY_HANDSHAKE
 3223 #define NO_FDS {-1, -1}
 3224 
 3225 static int cp_pipe[2] = NO_FDS; /* this pipe is used for child to parent transfer */
 3226 static int pc_pipe[2] = NO_FDS; /* this pipe is used for parent to child transfer */
 3227 
 3228 typedef enum {          /* c == child, p == parent                        */
 3229     PTY_BAD,            /* c->p: can't open pty slave for some reason     */
 3230     PTY_FATALERROR,     /* c->p: we had a fatal error with the pty        */
 3231     PTY_GOOD,           /* c->p: we have a good pty, let's go on          */
 3232     PTY_NEW,            /* p->c: here is a new pty slave, try this        */
 3233     PTY_NOMORE,         /* p->c; no more pty's, terminate                 */
 3234     UTMP_ADDED,         /* c->p: utmp entry has been added                */
 3235     UTMP_TTYSLOT,       /* c->p: here is my ttyslot                       */
 3236     PTY_EXEC            /* p->c: window has been mapped the first time    */
 3237 } status_t;
 3238 
 3239 #define HANDSHAKE_LEN   1024
 3240 
 3241 typedef struct {
 3242     status_t status;
 3243     int error;
 3244     int fatal_error;
 3245     int tty_slot;
 3246     int rows;
 3247     int cols;
 3248     char buffer[HANDSHAKE_LEN];
 3249 } handshake_t;
 3250 
 3251 /* the buffer is large enough that we can always have a trailing null */
 3252 #define copy_handshake(dst, src) \
 3253     strncpy(dst.buffer, src, (size_t)HANDSHAKE_LEN - 1)[HANDSHAKE_LEN - 1] = '\0'
 3254 
 3255 #if OPT_TRACE
 3256 static void
 3257 trace_handshake(const char *tag, handshake_t * data)
 3258 {
 3259     const char *status = "?";
 3260     switch (data->status) {
 3261     case PTY_BAD:
 3262     status = "PTY_BAD";
 3263     break;
 3264     case PTY_FATALERROR:
 3265     status = "PTY_FATALERROR";
 3266     break;
 3267     case PTY_GOOD:
 3268     status = "PTY_GOOD";
 3269     break;
 3270     case PTY_NEW:
 3271     status = "PTY_NEW";
 3272     break;
 3273     case PTY_NOMORE:
 3274     status = "PTY_NOMORE";
 3275     break;
 3276     case UTMP_ADDED:
 3277     status = "UTMP_ADDED";
 3278     break;
 3279     case UTMP_TTYSLOT:
 3280     status = "UTMP_TTYSLOT";
 3281     break;
 3282     case PTY_EXEC:
 3283     status = "PTY_EXEC";
 3284     break;
 3285     }
 3286     TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
 3287        tag,
 3288        status,
 3289        data->error,
 3290        data->fatal_error,
 3291        data->buffer));
 3292 }
 3293 #define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
 3294 #else
 3295 #define TRACE_HANDSHAKE(tag, data)  /* nothing */
 3296 #endif
 3297 
 3298 /* HsSysError()
 3299  *
 3300  * This routine does the equivalent of a SysError but it handshakes
 3301  * over the errno and error exit to the master process so that it can
 3302  * display our error message and exit with our exit code so that the
 3303  * user can see it.
 3304  */
 3305 
 3306 static void
 3307 HsSysError(int error)
 3308 {
 3309     handshake_t handshake;
 3310 
 3311     memset(&handshake, 0, sizeof(handshake));
 3312     handshake.status = PTY_FATALERROR;
 3313     handshake.error = errno;
 3314     handshake.fatal_error = error;
 3315     copy_handshake(handshake, ttydev);
 3316 
 3317     if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
 3318     TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
 3319            handshake.error,
 3320            handshake.fatal_error,
 3321            handshake.buffer));
 3322     TRACE_HANDSHAKE("writing", &handshake);
 3323     IGNORE_RC(write(cp_pipe[1],
 3324             (const char *) &handshake,
 3325             sizeof(handshake)));
 3326     } else {
 3327     xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
 3328              handshake.error,
 3329              handshake.fatal_error,
 3330              handshake.buffer);
 3331     fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
 3332     fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
 3333     }
 3334     exit(error);
 3335 }
 3336 
 3337 void
 3338 first_map_occurred(void)
 3339 {
 3340     if (resource.wait_for_map) {
 3341     if (pc_pipe[1] >= 0) {
 3342         handshake_t handshake;
 3343         TScreen *screen = TScreenOf(term);
 3344 
 3345         memset(&handshake, 0, sizeof(handshake));
 3346         handshake.status = PTY_EXEC;
 3347         handshake.rows = screen->max_row;
 3348         handshake.cols = screen->max_col;
 3349 
 3350         TRACE(("first_map_occurred: %dx%d\n", MaxRows(screen), MaxCols(screen)));
 3351         TRACE_HANDSHAKE("writing", &handshake);
 3352         IGNORE_RC(write(pc_pipe[1],
 3353                 (const char *) &handshake,
 3354                 sizeof(handshake)));
 3355         close(cp_pipe[0]);
 3356         close(pc_pipe[1]);
 3357     }
 3358     resource.wait_for_map = False;
 3359     }
 3360 }
 3361 #else
 3362 /*
 3363  * temporary hack to get xterm working on att ptys
 3364  */
 3365 static void
 3366 HsSysError(int error)
 3367 {
 3368     xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
 3369          error, errno, ttydev);
 3370     exit(error);
 3371 }
 3372 #endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
 3373 
 3374 #ifndef VMS
 3375 static void
 3376 set_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
 3377 {
 3378     int why;
 3379 
 3380     TRACE_IDS;
 3381     TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
 3382        device, (int) uid, (int) gid, (unsigned) mode));
 3383 
 3384     if (chown(device, (uid_t) uid, (gid_t) gid) < 0) {
 3385     why = errno;
 3386     if (why != ENOENT
 3387         && save_ruid == 0) {
 3388         xtermPerror("Cannot chown %s to %ld,%ld",
 3389             device, (long) uid, (long) gid);
 3390     }
 3391     TRACE(("...chown failed: %s\n", strerror(why)));
 3392     } else if (chmod(device, (mode_t) mode) < 0) {
 3393     why = errno;
 3394     if (why != ENOENT) {
 3395         struct stat sb;
 3396         if (stat(device, &sb) < 0) {
 3397         xtermPerror("Cannot chmod %s to %03o",
 3398                 device, (unsigned) mode);
 3399         } else if (mode != (sb.st_mode & 0777U)) {
 3400         xtermPerror("Cannot chmod %s to %03lo currently %03lo",
 3401                 device,
 3402                 (unsigned long) mode,
 3403                 (unsigned long) (sb.st_mode & 0777U));
 3404         TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
 3405                (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
 3406         }
 3407     }
 3408     TRACE(("...chmod failed: %s\n", strerror(why)));
 3409     }
 3410 }
 3411 
 3412 /*
 3413  * utmp data may not be null-terminated; even if it is, there may be garbage
 3414  * after the null.  This fills the unused part of the result with nulls.
 3415  */
 3416 static void
 3417 copy_filled(char *target, const char *source, size_t len)
 3418 {
 3419     size_t used = 0;
 3420     while (used < len) {
 3421     if ((target[used] = source[used]) == 0)
 3422         break;
 3423     ++used;
 3424     }
 3425     while (used < len) {
 3426     target[used++] = '\0';
 3427     }
 3428 }
 3429 
 3430 #if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
 3431 /*
 3432  * getutid() only looks at ut_type and ut_id.
 3433  * But we'll also check ut_line in find_utmp().
 3434  */
 3435 static void
 3436 init_utmp(int type, struct UTMP_STR *tofind)
 3437 {
 3438     memset(tofind, 0, sizeof(*tofind));
 3439     tofind->ut_type = (short) type;
 3440     copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
 3441     copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
 3442 }
 3443 
 3444 /*
 3445  * We could use getutline() if we didn't support old systems.
 3446  */
 3447 static struct UTMP_STR *
 3448 find_utmp(struct UTMP_STR *tofind)
 3449 {
 3450     struct UTMP_STR *result;
 3451     struct UTMP_STR limited;
 3452     struct UTMP_STR working;
 3453 
 3454     for (;;) {
 3455     memset(&working, 0, sizeof(working));
 3456     working.ut_type = tofind->ut_type;
 3457     copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
 3458 #if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
 3459     working.ut_type = 0;
 3460 #endif
 3461     if ((result = call_getutid(&working)) == 0)
 3462         break;
 3463     copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line));
 3464     if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
 3465         break;
 3466     /*
 3467      * Solaris, IRIX64 and HPUX manpages say to fill the static area
 3468      * pointed to by the return-value to zeros if searching for multiple
 3469      * occurrences.  Otherwise it will continue to return the same value.
 3470      */
 3471     memset(result, 0, sizeof(*result));
 3472     }
 3473     return result;
 3474 }
 3475 #endif /* HAVE_UTMP... */
 3476 
 3477 #define close_fd(fd) close(fd), fd = -1
 3478 
 3479 #if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
 3480 #define USE_NO_DEV_TTY 1
 3481 #else
 3482 #define USE_NO_DEV_TTY 0
 3483 #endif
 3484 
 3485 static int
 3486 same_leaf(char *a, char *b)
 3487 {
 3488     char *p = x_basename(a);
 3489     char *q = x_basename(b);
 3490     return !strcmp(p, q);
 3491 }
 3492 
 3493 /*
 3494  * "good enough" (inode wouldn't port to Cygwin)
 3495  */
 3496 static int
 3497 same_file(const char *a, const char *b)
 3498 {
 3499     struct stat asb;
 3500     struct stat bsb;
 3501     int result = 0;
 3502 
 3503     if ((stat(a, &asb) == 0)
 3504     && (stat(b, &bsb) == 0)
 3505     && ((asb.st_mode & S_IFMT) == S_IFREG)
 3506     && ((bsb.st_mode & S_IFMT) == S_IFREG)
 3507     && (asb.st_mtime == bsb.st_mtime)
 3508     && (asb.st_size == bsb.st_size)) {
 3509     result = 1;
 3510     }
 3511     return result;
 3512 }
 3513 
 3514 static int
 3515 findValidShell(const char *haystack, const char *needle)
 3516 {
 3517     int result = -1;
 3518     int count = -1;
 3519     const char *s, *t;
 3520     size_t have;
 3521     size_t want = strlen(needle);
 3522 
 3523     TRACE(("findValidShell:\n%s\n", NonNull(haystack)));
 3524 
 3525     for (s = haystack; (s != 0) && (*s != '\0'); s = t) {
 3526     ++count;
 3527     if ((t = strchr(s, '\n')) == 0) {
 3528         t = s + strlen(s);
 3529     }
 3530     have = (size_t) (t - s);
 3531 
 3532     if ((have >= want) && (*s != '#')) {
 3533         char *p = malloc(have + 1);
 3534 
 3535         if (p != 0) {
 3536         char *q;
 3537 
 3538         memcpy(p, s, have);
 3539         p[have] = '\0';
 3540         if ((q = x_strtrim(p)) != 0) {
 3541             TRACE(("...test %s\n", q));
 3542             if (!strcmp(q, needle)) {
 3543             result = count;
 3544             } else if (same_leaf(q, (char *) needle) &&
 3545                    same_file(q, needle)) {
 3546             result = count;
 3547             }
 3548             free(q);
 3549         }
 3550         free(p);
 3551         }
 3552         if (result >= 0)
 3553         break;
 3554     }
 3555     while (*t == '\n') {
 3556         ++t;
 3557     }
 3558     }
 3559     return result;
 3560 }
 3561 
 3562 static int
 3563 ourValidShell(const char *pathname)
 3564 {
 3565     return findValidShell(x_strtrim(resource.valid_shells), pathname);
 3566 }
 3567 
 3568 #if defined(HAVE_GETUSERSHELL) && defined(HAVE_ENDUSERSHELL)
 3569 static Boolean
 3570 validShell(const char *pathname)
 3571 {
 3572     int result = -1;
 3573 
 3574     if (validProgram(pathname)) {
 3575     char *q;
 3576     int count = -1;
 3577 
 3578     TRACE(("validShell:getusershell\n"));
 3579     while ((q = getusershell()) != 0) {
 3580         ++count;
 3581         TRACE(("...test \"%s\"\n", q));
 3582         if (!strcmp(q, pathname)) {
 3583         result = count;
 3584         break;
 3585         }
 3586     }
 3587     endusershell();
 3588 
 3589     if (result < 0)
 3590         result = ourValidShell(pathname);
 3591     }
 3592 
 3593     TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
 3594     return (result >= 0);
 3595 }
 3596 #else
 3597 /*
 3598  * Only set $SHELL for paths found in the standard location.
 3599  */
 3600 static Boolean
 3601 validShell(const char *pathname)
 3602 {
 3603     int result = -1;
 3604     const char *ok_shells = "/etc/shells";
 3605     char *blob;
 3606     struct stat sb;
 3607     size_t rc;
 3608     FILE *fp;
 3609 
 3610     if (validProgram(pathname)) {
 3611 
 3612     TRACE(("validShell:%s\n", ok_shells));
 3613 
 3614     if (stat(ok_shells, &sb) == 0
 3615         && (sb.st_mode & S_IFMT) == S_IFREG
 3616         && ((size_t) sb.st_size > 0)
 3617         && ((size_t) sb.st_size < (((size_t) ~0) - 2))
 3618         && (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
 3619 
 3620         if ((fp = fopen(ok_shells, "r")) != 0) {
 3621         rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
 3622         fclose(fp);
 3623 
 3624         if (rc == (size_t) sb.st_size) {
 3625             blob[rc] = '\0';
 3626             result = findValidShell(blob, pathname);
 3627         }
 3628         }
 3629         free(blob);
 3630     }
 3631     if (result < 0)
 3632         result = ourValidShell(pathname);
 3633     }
 3634     TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
 3635     return (result > 0);
 3636 }
 3637 #endif
 3638 
 3639 static char *
 3640 resetShell(char *oldPath)
 3641 {
 3642     char *newPath = x_strdup("/bin/sh");
 3643     char *envPath = getenv("SHELL");
 3644     free(oldPath);
 3645     if (!IsEmpty(envPath))
 3646     xtermSetenv("SHELL", newPath);
 3647     return newPath;
 3648 }
 3649 
 3650 /*
 3651  *  Inits pty and tty and forks a login process.
 3652  *  Does not close fd Xsocket.
 3653  *  If slave, the pty named in passedPty is already open for use
 3654  */
 3655 static int
 3656 spawnXTerm(XtermWidget xw, unsigned line_speed)
 3657 {
 3658     TScreen *screen = TScreenOf(xw);
 3659     Cardinal nn;
 3660 #if OPT_PTY_HANDSHAKE
 3661     Bool got_handshake_size = False;
 3662     handshake_t handshake;
 3663     int done;
 3664 #endif
 3665 #if OPT_INITIAL_ERASE
 3666     int initial_erase = VAL_INITIAL_ERASE;
 3667     Bool setInitialErase;
 3668 #endif
 3669     int rc = 0;
 3670     int ttyfd = -1;
 3671     Bool ok_termcap;
 3672     char *newtc;
 3673 
 3674 #ifdef TERMIO_STRUCT
 3675     TERMIO_STRUCT tio;
 3676 #ifdef __MVS__
 3677     TERMIO_STRUCT gio;
 3678 #endif /* __MVS__ */
 3679 #ifdef TIOCLSET
 3680     unsigned lmode;
 3681 #endif /* TIOCLSET */
 3682 #ifdef HAS_LTCHARS
 3683     struct ltchars ltc;
 3684 #endif /* HAS_LTCHARS */
 3685 #else /* !TERMIO_STRUCT */
 3686     int ldisc = 0;
 3687     int discipline;
 3688     unsigned lmode;
 3689     struct tchars tc;
 3690     struct ltchars ltc;
 3691     struct sgttyb sg;
 3692 #ifdef sony
 3693     int jmode;
 3694     struct jtchars jtc;
 3695 #endif /* sony */
 3696 #endif /* TERMIO_STRUCT */
 3697 
 3698     char *shell_path = 0;
 3699     char *shname, *shname_minus;
 3700     int i;
 3701 #if USE_NO_DEV_TTY
 3702     int no_dev_tty = False;
 3703 #endif
 3704     const char *const *envnew;  /* new environment */
 3705     char buf[64];
 3706     char *TermName = NULL;
 3707 #ifdef TTYSIZE_STRUCT
 3708     TTYSIZE_STRUCT ts;
 3709 #endif
 3710     struct passwd pw;
 3711     char *login_name = NULL;
 3712 #ifndef USE_UTEMPTER
 3713 #ifdef HAVE_UTMP
 3714     struct UTMP_STR utmp;
 3715 #ifdef USE_SYSV_UTMP
 3716     struct UTMP_STR *utret = NULL;
 3717 #endif
 3718 #ifdef USE_LASTLOG
 3719     struct lastlog lastlog;
 3720 #endif
 3721 #ifdef USE_LASTLOGX
 3722     struct lastlogx lastlogx;
 3723 #endif /* USE_LASTLOG */
 3724 #endif /* HAVE_UTMP */
 3725 #endif /* !USE_UTEMPTER */
 3726 
 3727 #if OPT_TRACE
 3728     unsigned long xterm_parent = (unsigned long) getpid();
 3729 #endif
 3730 
 3731     /* Noisy compilers (suppress some unused-variable warnings) */
 3732     (void) rc;
 3733 #if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
 3734     (void) utret;
 3735 #endif
 3736 
 3737     screen->uid = save_ruid;
 3738     screen->gid = save_rgid;
 3739 
 3740 #ifdef SIGTTOU
 3741     /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
 3742     signal(SIGTTOU, SIG_IGN);
 3743 #endif
 3744 
 3745 #if OPT_PTY_HANDSHAKE
 3746     memset(&handshake, 0, sizeof(handshake));
 3747 #endif
 3748 
 3749     if (am_slave >= 0) {
 3750     screen->respond = am_slave;
 3751     set_pty_id(ttydev, passedPty);
 3752 #ifdef USE_PTY_DEVICE
 3753     set_pty_id(ptydev, passedPty);
 3754 #endif
 3755     if (xtermResetIds(screen) < 0)
 3756         exit(1);
 3757     } else {
 3758     Bool tty_got_hung;
 3759 
 3760     /*
 3761      * Sometimes /dev/tty hangs on open (as in the case of a pty
 3762      * that has gone away).  Simply make up some reasonable
 3763      * defaults.
 3764      */
 3765 
 3766     if (!sigsetjmp(env, 1)) {
 3767         signal(SIGALRM, hungtty);
 3768         alarm(2);       /* alarm(1) might return too soon */
 3769         ttyfd = open("/dev/tty", O_RDWR);
 3770         alarm(0);
 3771         tty_got_hung = False;
 3772     } else {
 3773         tty_got_hung = True;
 3774         ttyfd = -1;
 3775         errno = ENXIO;
 3776     }
 3777     shell_path = 0;
 3778     memset(&pw, 0, sizeof(pw));
 3779 #if OPT_PTY_HANDSHAKE
 3780     got_handshake_size = False;
 3781 #endif /* OPT_PTY_HANDSHAKE */
 3782 #if OPT_INITIAL_ERASE
 3783     initial_erase = VAL_INITIAL_ERASE;
 3784 #endif
 3785     signal(SIGALRM, SIG_DFL);
 3786 
 3787     /*
 3788      * Check results and ignore current control terminal if
 3789      * necessary.  ENXIO is what is normally returned if there is
 3790      * no controlling terminal, but some systems (e.g. SunOS 4.0)
 3791      * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
 3792      * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
 3793      * if xterm is run within a jail.
 3794      */
 3795 #if USE_NO_DEV_TTY
 3796     no_dev_tty = False;
 3797 #endif
 3798     if (ttyfd < 0) {
 3799         if (tty_got_hung || errno == ENXIO || errno == EIO ||
 3800         errno == ENOENT ||
 3801 #ifdef ENODEV
 3802         errno == ENODEV ||
 3803 #endif
 3804         errno == EINVAL || errno == ENOTTY || errno == EACCES) {
 3805 #if USE_NO_DEV_TTY
 3806         no_dev_tty = True;
 3807 #endif
 3808 #ifdef HAS_LTCHARS
 3809         ltc = d_ltc;
 3810 #endif /* HAS_LTCHARS */
 3811 #ifdef TIOCLSET
 3812         lmode = d_lmode;
 3813 #endif /* TIOCLSET */
 3814 #ifdef TERMIO_STRUCT
 3815         tio = d_tio;
 3816 #else /* !TERMIO_STRUCT */
 3817         sg = d_sg;
 3818         tc = d_tc;
 3819         discipline = d_disipline;
 3820 #ifdef sony
 3821         jmode = d_jmode;
 3822         jtc = d_jtc;
 3823 #endif /* sony */
 3824 #endif /* TERMIO_STRUCT */
 3825         } else {
 3826         SysError(ERROR_OPDEVTTY);
 3827         }
 3828     } else {
 3829 
 3830         /* Get a copy of the current terminal's state,
 3831          * if we can.  Some systems (e.g., SVR4 and MacII)
 3832          * may not have a controlling terminal at this point
 3833          * if started directly from xdm or xinit,
 3834          * in which case we just use the defaults as above.
 3835          */
 3836 #ifdef HAS_LTCHARS
 3837         if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
 3838         ltc = d_ltc;
 3839 #endif /* HAS_LTCHARS */
 3840 #ifdef TIOCLSET
 3841         if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
 3842         lmode = d_lmode;
 3843 #endif /* TIOCLSET */
 3844 #ifdef TERMIO_STRUCT
 3845         rc = ttyGetAttr(ttyfd, &tio);
 3846         if (rc == -1)
 3847         tio = d_tio;
 3848 #else /* !TERMIO_STRUCT */
 3849         rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
 3850         if (rc == -1)
 3851         sg = d_sg;
 3852         if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
 3853         tc = d_tc;
 3854         if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
 3855         discipline = d_disipline;
 3856 #ifdef sony
 3857         if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
 3858         jmode = d_jmode;
 3859         if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
 3860         jtc = d_jtc;
 3861 #endif /* sony */
 3862 #endif /* TERMIO_STRUCT */
 3863 
 3864         /*
 3865          * If ptyInitialErase is set, we want to get the pty's
 3866          * erase value.  Just in case that will fail, first get
 3867          * the value from /dev/tty, so we will have something
 3868          * at least.
 3869          */
 3870 #if OPT_INITIAL_ERASE
 3871         if (resource.ptyInitialErase) {
 3872 #ifdef TERMIO_STRUCT
 3873         initial_erase = tio.c_cc[VERASE];
 3874 #else /* !TERMIO_STRUCT */
 3875         initial_erase = sg.sg_erase;
 3876 #endif /* TERMIO_STRUCT */
 3877         TRACE(("%s initial_erase:%d (from /dev/tty)\n",
 3878                rc == 0 ? "OK" : "FAIL",
 3879                initial_erase));
 3880         }
 3881 #endif
 3882 #ifdef __MVS__
 3883         if (ttyGetAttr(ttyfd, &gio) == 0) {
 3884         gio.c_cflag &= ~(HUPCL | PARENB);
 3885         ttySetAttr(ttyfd, &gio);
 3886         }
 3887 #endif /* __MVS__ */
 3888 
 3889         close_fd(ttyfd);
 3890     }
 3891 
 3892     if (get_pty(&screen->respond, XDisplayString(screen->display))) {
 3893         SysError(ERROR_PTYS);
 3894     }
 3895     TRACE_GET_TTYSIZE(screen->respond, "after get_pty");
 3896 #if OPT_INITIAL_ERASE
 3897     if (resource.ptyInitialErase) {
 3898 #ifdef TERMIO_STRUCT
 3899         TERMIO_STRUCT my_tio;
 3900         rc = ttyGetAttr(screen->respond, &my_tio);
 3901         if (rc == 0)
 3902         initial_erase = my_tio.c_cc[VERASE];
 3903 #else /* !TERMIO_STRUCT */
 3904         struct sgttyb my_sg;
 3905         rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg);
 3906         if (rc == 0)
 3907         initial_erase = my_sg.sg_erase;
 3908 #endif /* TERMIO_STRUCT */
 3909         TRACE(("%s initial_erase:%d (from pty)\n",
 3910            (rc == 0) ? "OK" : "FAIL",
 3911            initial_erase));
 3912     }
 3913 #endif /* OPT_INITIAL_ERASE */
 3914     }
 3915 
 3916     /* avoid double MapWindow requests */
 3917     XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
 3918 
 3919     wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
 3920                    False);
 3921 
 3922     if (!TEK4014_ACTIVE(xw))
 3923     VTInit(xw);     /* realize now so know window size for tty driver */
 3924 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
 3925     if (Console) {
 3926     /*
 3927      * Inform any running xconsole program
 3928      * that we are going to steal the console.
 3929      */
 3930     XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
 3931     mit_console = XInternAtom(screen->display, mit_console_name, False);
 3932     /* the user told us to be the console, so we can use CurrentTime */
 3933     XtOwnSelection(SHELL_OF(CURRENT_EMU()),
 3934                mit_console, CurrentTime,
 3935                ConvertConsoleSelection, NULL, NULL);
 3936     }
 3937 #endif
 3938 #if OPT_TEK4014
 3939     if (TEK4014_ACTIVE(xw)) {
 3940     envnew = tekterm;
 3941     } else
 3942 #endif
 3943     {
 3944     envnew = vtterm;
 3945     }
 3946 
 3947     /*
 3948      * This used to exit if no termcap entry was found for the specified
 3949      * terminal name.  That's a little unfriendly, so instead we'll allow
 3950      * the program to proceed (but not to set $TERMCAP) if the termcap
 3951      * entry is not found.
 3952      */
 3953     ok_termcap = True;
 3954     if (!get_termcap(xw, TermName = resource.term_name)) {
 3955     const char *last = NULL;
 3956     char *next;
 3957 
 3958     TermName = x_strdup(*envnew);
 3959     ok_termcap = False;
 3960     while (*envnew != NULL) {
 3961         if (last == NULL || strcmp(last, *envnew)) {
 3962         next = x_strdup(*envnew);
 3963         if (get_termcap(xw, next)) {
 3964             free(TermName);
 3965             TermName = next;
 3966             ok_termcap = True + 1;
 3967             break;
 3968         } else {
 3969             free(next);
 3970         }
 3971         }
 3972         last = *envnew;
 3973         envnew++;
 3974     }
 3975     }
 3976     if (ok_termcap) {
 3977     resource.term_name = x_strdup(TermName);
 3978     resize_termcap(xw);
 3979     }
 3980 
 3981     /*
 3982      * Check if ptyInitialErase is not set.  If so, we rely on the termcap
 3983      * (or terminfo) to tell us what the erase mode should be set to.
 3984      */
 3985 #if OPT_INITIAL_ERASE
 3986     TRACE(("resource ptyInitialErase is %sset\n",
 3987        resource.ptyInitialErase ? "" : "not "));
 3988     setInitialErase = False;
 3989     if (override_tty_modes && ttyModes[XTTYMODE_erase].set) {
 3990     initial_erase = ttyModes[XTTYMODE_erase].value;
 3991     setInitialErase = True;
 3992     } else if (resource.ptyInitialErase) {
 3993     /* EMPTY */ ;
 3994     } else if (ok_termcap) {
 3995     char *s = get_tcap_erase(xw);
 3996     TRACE(("...extracting initial_erase value from termcap\n"));
 3997     if (s != 0) {
 3998         char *save = s;
 3999         initial_erase = decode_keyvalue(&s, True);
 4000         setInitialErase = True;
 4001         free(save);
 4002     }
 4003     }
 4004     TRACE(("...initial_erase:%d\n", initial_erase));
 4005 
 4006     TRACE(("resource backarrowKeyIsErase is %sset\n",
 4007        resource.backarrow_is_erase ? "" : "not "));
 4008     if (resource.backarrow_is_erase) {  /* see input.c */
 4009     if (initial_erase == ANSI_DEL) {
 4010         UIntClr(xw->keyboard.flags, MODE_DECBKM);
 4011     } else {
 4012         xw->keyboard.flags |= MODE_DECBKM;
 4013         xw->keyboard.reset_DECBKM = 1;
 4014     }
 4015     TRACE(("...sets DECBKM %s\n",
 4016            (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
 4017     } else {
 4018     xw->keyboard.reset_DECBKM = 2;
 4019     }
 4020 #endif /* OPT_INITIAL_ERASE */
 4021 
 4022 #ifdef TTYSIZE_STRUCT
 4023     /* tell tty how big window is */
 4024 #if OPT_TEK4014
 4025     if (TEK4014_ACTIVE(xw)) {
 4026     setup_winsize(ts, TDefaultRows, TDefaultCols,
 4027               TFullHeight(TekScreenOf(tekWidget)),
 4028               TFullWidth(TekScreenOf(tekWidget)));
 4029     } else
 4030 #endif
 4031     {
 4032     setup_winsize(ts, MaxRows(screen), MaxCols(screen),
 4033               FullHeight(screen), FullWidth(screen));
 4034     }
 4035     TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
 4036     TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
 4037        TTYSIZE_ROWS(ts),
 4038        TTYSIZE_COLS(ts), i));
 4039 #endif /* TTYSIZE_STRUCT */
 4040 
 4041 #if !defined(USE_OPENPTY)
 4042 #if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
 4043     /*
 4044      * utempter checks the ownership of the device; some implementations
 4045      * set ownership in grantpt - do this first.
 4046      */
 4047     grantpt(screen->respond);
 4048 #endif
 4049 #if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
 4050     unlockpt(screen->respond);
 4051     TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
 4052 #endif
 4053 #endif /* !USE_OPENPTY */
 4054 
 4055     added_utmp_entry = False;
 4056 #if defined(USE_UTEMPTER)
 4057 #undef UTMP
 4058     if ((xw->misc.login_shell || !command_to_exec) && !resource.utmpInhibit) {
 4059     struct UTMP_STR dummy;
 4060 
 4061     /* Note: utempter may trim it anyway */
 4062     SetUtmpHost(dummy.ut_host, screen);
 4063     TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
 4064            ttydev, dummy.ut_host, screen->respond));
 4065     UTEMPTER_ADD(ttydev, dummy.ut_host, screen->respond);
 4066     added_utmp_entry = True;
 4067     }
 4068 #endif
 4069 
 4070     if (am_slave < 0) {
 4071 #if OPT_PTY_HANDSHAKE
 4072     if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
 4073         SysError(ERROR_FORK);
 4074 #endif
 4075     TRACE(("Forking...\n"));
 4076     if ((screen->pid = fork()) == -1)
 4077         SysError(ERROR_FORK);
 4078 
 4079     if (screen->pid == 0) {
 4080 #ifdef USE_USG_PTYS
 4081         int ptyfd = -1;
 4082         char *pty_name;
 4083 #endif
 4084         /*
 4085          * now in child process
 4086          */
 4087 #if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
 4088         int pgrp = setsid();    /* variable may not be used... */
 4089 #else
 4090         int pgrp = getpid();
 4091 #endif
 4092         TRACE_CHILD
 4093 
 4094 #ifdef USE_USG_PTYS
 4095 #ifdef HAVE_SETPGID
 4096         setpgid(0, 0);
 4097 #else
 4098         setpgrp();
 4099 #endif
 4100         unlockpt(screen->respond);
 4101         TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
 4102         if ((pty_name = ptsname(screen->respond)) == 0) {
 4103         SysError(ERROR_PTSNAME);
 4104         } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
 4105         SysError(ERROR_OPPTSNAME);
 4106         }
 4107 #ifdef I_PUSH
 4108         else if (PUSH_FAILS(ptyfd, "ptem")) {
 4109         SysError(ERROR_PTEM);
 4110         }
 4111 #if !defined(SVR4) && !(defined(SYSV) && defined(i386))
 4112         else if (!x_getenv("CONSEM")
 4113              && PUSH_FAILS(ptyfd, "consem")) {
 4114         SysError(ERROR_CONSEM);
 4115         }
 4116 #endif /* !SVR4 */
 4117         else if (PUSH_FAILS(ptyfd, "ldterm")) {
 4118         SysError(ERROR_LDTERM);
 4119         }
 4120 #ifdef SVR4         /* from Sony */
 4121         else if (PUSH_FAILS(ptyfd, "ttcompat")) {
 4122         SysError(ERROR_TTCOMPAT);
 4123         }
 4124 #endif /* SVR4 */
 4125 #endif /* I_PUSH */
 4126         ttyfd = ptyfd;
 4127 #ifndef __MVS__
 4128         close_fd(screen->respond);
 4129 #endif /* __MVS__ */
 4130 
 4131 #ifdef TTYSIZE_STRUCT
 4132         /* tell tty how big window is */
 4133 #if OPT_TEK4014
 4134         if (TEK4014_ACTIVE(xw)) {
 4135         setup_winsize(ts, TDefaultRows, TDefaultCols,
 4136                   TFullHeight(TekScreenOf(tekWidget)),
 4137                   TFullWidth(TekScreenOf(tekWidget)));
 4138         } else
 4139 #endif /* OPT_TEK4014 */
 4140         {
 4141         setup_winsize(ts, MaxRows(screen), MaxCols(screen),
 4142                   FullHeight(screen), FullWidth(screen));
 4143         }
 4144         trace_winsize(ts, "initial tty size");
 4145 #endif /* TTYSIZE_STRUCT */
 4146 
 4147 #endif /* USE_USG_PTYS */
 4148 
 4149         (void) pgrp;    /* not all branches use this variable */
 4150 
 4151 #if OPT_PTY_HANDSHAKE       /* warning, goes for a long ways */
 4152         if (resource.ptyHandshake) {
 4153         char *ptr;
 4154 
 4155         /* close parent's sides of the pipes */
 4156         close(cp_pipe[0]);
 4157         close(pc_pipe[1]);
 4158 
 4159         /* Make sure that our sides of the pipes are not in the
 4160          * 0, 1, 2 range so that we don't fight with stdin, out
 4161          * or err.
 4162          */
 4163         if (cp_pipe[1] <= 2) {
 4164             if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
 4165             IGNORE_RC(close(cp_pipe[1]));
 4166             cp_pipe[1] = i;
 4167             }
 4168         }
 4169         if (pc_pipe[0] <= 2) {
 4170             if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
 4171             IGNORE_RC(close(pc_pipe[0]));
 4172             pc_pipe[0] = i;
 4173             }
 4174         }
 4175 
 4176         /* we don't need the socket, or the pty master anymore */
 4177         close(ConnectionNumber(screen->display));
 4178 #ifndef __MVS__
 4179         if (screen->respond >= 0)
 4180             close(screen->respond);
 4181 #endif /* __MVS__ */
 4182 
 4183         /* Now is the time to set up our process group and
 4184          * open up the pty slave.
 4185          */
 4186 #ifdef USE_SYSV_PGRP
 4187 #if defined(CRAY) && (OSMAJORVERSION > 5)
 4188         IGNORE_RC(setsid());
 4189 #else
 4190         IGNORE_RC(setpgrp());
 4191 #endif
 4192 #endif /* USE_SYSV_PGRP */
 4193 
 4194 #if defined(__QNX__) && !defined(__QNXNTO__)
 4195         qsetlogin(getlogin(), ttydev);
 4196 #endif
 4197         if (ttyfd >= 0) {
 4198 #ifdef __MVS__
 4199             if (ttyGetAttr(ttyfd, &gio) == 0) {
 4200             gio.c_cflag &= ~(HUPCL | PARENB);
 4201             ttySetAttr(ttyfd, &gio);
 4202             }
 4203 #else /* !__MVS__ */
 4204             close_fd(ttyfd);
 4205 #endif /* __MVS__ */
 4206         }
 4207 
 4208         for (;;) {
 4209 #if USE_NO_DEV_TTY
 4210             if (!no_dev_tty
 4211             && (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
 4212             ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
 4213             close_fd(ttyfd);
 4214             }
 4215 #endif /* USE_NO_DEV_TTY */
 4216 #ifdef CSRG_BASED
 4217             IGNORE_RC(revoke(ttydev));
 4218 #endif
 4219             if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
 4220             TRACE_GET_TTYSIZE(ttyfd, "after open");
 4221             TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
 4222             TRACE_GET_TTYSIZE(ttyfd, "after SET_TTYSIZE fixup");
 4223 #if defined(CRAY) && defined(TCSETCTTY)
 4224             /* make /dev/tty work */
 4225             ioctl(ttyfd, TCSETCTTY, 0);
 4226 #endif
 4227 #if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
 4228             /* make /dev/tty work */
 4229             ioctl(ttyfd, TIOCSCTTY, 0);
 4230 #endif
 4231 #ifdef USE_SYSV_PGRP
 4232             /* We need to make sure that we are actually
 4233              * the process group leader for the pty.  If
 4234              * we are, then we should now be able to open
 4235              * /dev/tty.
 4236              */
 4237             if ((i = open("/dev/tty", O_RDWR)) >= 0) {
 4238                 /* success! */
 4239                 close(i);
 4240                 break;
 4241             }
 4242 #else /* USE_SYSV_PGRP */
 4243             break;
 4244 #endif /* USE_SYSV_PGRP */
 4245             }
 4246             perror("open ttydev");
 4247 #ifdef TIOCSCTTY
 4248             ioctl(ttyfd, TIOCSCTTY, 0);
 4249 #endif
 4250             /* let our master know that the open failed */
 4251             handshake.status = PTY_BAD;
 4252             handshake.error = errno;
 4253             copy_handshake(handshake, ttydev);
 4254             TRACE_HANDSHAKE("writing", &handshake);
 4255             IGNORE_RC(write(cp_pipe[1],
 4256                     (const char *) &handshake,
 4257                     sizeof(handshake)));
 4258 
 4259             /* get reply from parent */
 4260             i = (int) read(pc_pipe[0], (char *) &handshake,
 4261                    sizeof(handshake));
 4262             if (i <= 0) {
 4263             /* parent terminated */
 4264             exit(1);
 4265             }
 4266 
 4267             if (handshake.status == PTY_NOMORE) {
 4268             /* No more ptys, let's shutdown. */
 4269             exit(1);
 4270             }
 4271 
 4272             /* We have a new pty to try */
 4273             if (ttyfd >= 0)
 4274             close(ttyfd);
 4275             free(ttydev);
 4276             handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
 4277             ttydev = x_strdup(handshake.buffer);
 4278         }
 4279 
 4280         /* use the same tty name that everyone else will use
 4281          * (from ttyname)
 4282          */
 4283         if ((ptr = ttyname(ttyfd)) != 0) {
 4284             free(ttydev);
 4285             ttydev = x_strdup(ptr);
 4286         }
 4287         }
 4288 #endif /* OPT_PTY_HANDSHAKE -- from near fork */
 4289 
 4290         set_pty_permissions(screen->uid,
 4291                 (unsigned) screen->gid,
 4292                 (resource.messages
 4293                  ? 0622U
 4294                  : 0600U));
 4295 
 4296         /*
 4297          * set up the tty modes
 4298          */
 4299         {
 4300 #ifdef TERMIO_STRUCT
 4301 #if defined(umips) || defined(CRAY) || defined(linux)
 4302         /* If the control tty had its modes screwed around with,
 4303            eg. by lineedit in the shell, or emacs, etc. then tio
 4304            will have bad values.  Let's just get termio from the
 4305            new tty and tailor it.  */
 4306         if (ttyGetAttr(ttyfd, &tio) == -1)
 4307             SysError(ERROR_TIOCGETP);
 4308         tio.c_lflag |= ECHOE;
 4309 #endif /* umips */
 4310         /* Now is also the time to change the modes of the
 4311          * child pty.
 4312          */
 4313         /* input: nl->nl, don't ignore cr, cr->nl */
 4314         UIntClr(tio.c_iflag, (INLCR | IGNCR));
 4315         tio.c_iflag |= ICRNL;
 4316 #if OPT_WIDE_CHARS && defined(IUTF8)
 4317 #if OPT_LUIT_PROG
 4318         if (command_to_exec_with_luit == 0)
 4319 #endif
 4320             if (screen->utf8_mode)
 4321             tio.c_iflag |= IUTF8;
 4322 #endif
 4323         /* output: cr->cr, nl is not return, no delays, ln->cr/nl */
 4324 #ifndef USE_POSIX_TERMIOS
 4325         UIntClr(tio.c_oflag,
 4326             (OCRNL
 4327              | ONLRET
 4328              | NLDLY
 4329              | CRDLY
 4330              | TABDLY
 4331              | BSDLY
 4332              | VTDLY
 4333              | FFDLY));
 4334 #endif /* USE_POSIX_TERMIOS */
 4335         tio.c_oflag |= D_TIO_FLAGS;
 4336 #ifndef USE_POSIX_TERMIOS
 4337 # if defined(Lynx) && !defined(CBAUD)
 4338 #  define CBAUD V_CBAUD
 4339 # endif
 4340         UIntClr(tio.c_cflag, CBAUD);
 4341 #ifdef BAUD_0
 4342         /* baud rate is 0 (don't care) */
 4343 #elif defined(HAVE_TERMIO_C_ISPEED)
 4344         tio.c_ispeed = tio.c_ospeed = line_speed;
 4345 #else /* !BAUD_0 */
 4346         tio.c_cflag |= line_speed;
 4347 #endif /* !BAUD_0 */
 4348 #else /* USE_POSIX_TERMIOS */
 4349         cfsetispeed(&tio, line_speed);
 4350         cfsetospeed(&tio, line_speed);
 4351 #ifdef __MVS__
 4352         /* turn off bits that can't be set from the slave side */
 4353         tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
 4354 #endif /* __MVS__ */
 4355         /* Clear CLOCAL so that SIGHUP is sent to us
 4356            when the xterm ends */
 4357         tio.c_cflag &= (unsigned) ~CLOCAL;
 4358 #endif /* USE_POSIX_TERMIOS */
 4359         /* enable signals, canonical processing (erase, kill, etc),
 4360          * echo
 4361          */
 4362         tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
 4363 #ifdef ECHOKE
 4364         tio.c_lflag |= ECHOKE | IEXTEN;
 4365 #endif
 4366 #ifdef ECHOCTL
 4367         tio.c_lflag |= ECHOCTL | IEXTEN;
 4368 #endif
 4369         for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
 4370             if (validTtyChar(tio, nn)) {
 4371             int sysMode = ttyChars[nn].sysMode;
 4372 #ifdef __MVS__
 4373             if (tio.c_cc[sysMode] != 0) {
 4374                 switch (sysMode) {
 4375                 case VEOL:
 4376                 case VEOF:
 4377                 continue;
 4378                 }
 4379             }
 4380 #endif
 4381             tio.c_cc[sysMode] = (cc_t) ttyChars[nn].myDefault;
 4382             }
 4383         }
 4384 
 4385         if (override_tty_modes) {
 4386             TRACE(("applying termios ttyModes\n"));
 4387             for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
 4388             if (validTtyChar(tio, nn)) {
 4389                 TMODE(ttyChars[nn].myMode,
 4390                   tio.c_cc[ttyChars[nn].sysMode]);
 4391             } else if (isTabMode(nn)) {
 4392                 unsigned tmp = (unsigned) tio.c_oflag;
 4393                 tmp = tmp & (unsigned) ~TABDLY;
 4394                 tmp |= (unsigned) ttyModes[ttyChars[nn].myMode].value;
 4395                 tio.c_oflag = tmp;
 4396             }
 4397             }
 4398 #ifdef HAS_LTCHARS
 4399             /* both SYSV and BSD have ltchars */
 4400             TMODE(XTTYMODE_susp, ltc.t_suspc);
 4401             TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
 4402             TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
 4403             TMODE(XTTYMODE_flush, ltc.t_flushc);
 4404             TMODE(XTTYMODE_weras, ltc.t_werasc);
 4405             TMODE(XTTYMODE_lnext, ltc.t_lnextc);
 4406 #endif
 4407         }
 4408 #ifdef HAS_LTCHARS
 4409 #ifdef __hpux
 4410         /* ioctl chokes when the "reserved" process group controls
 4411          * are not set to _POSIX_VDISABLE */
 4412         ltc.t_rprntc = _POSIX_VDISABLE;
 4413         ltc.t_rprntc = _POSIX_VDISABLE;
 4414         ltc.t_flushc = _POSIX_VDISABLE;
 4415         ltc.t_werasc = _POSIX_VDISABLE;
 4416         ltc.t_lnextc = _POSIX_VDISABLE;
 4417 #endif /* __hpux */
 4418         if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
 4419             HsSysError(ERROR_TIOCSETC);
 4420 #endif /* HAS_LTCHARS */
 4421 #ifdef TIOCLSET
 4422         if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
 4423             HsSysError(ERROR_TIOCLSET);
 4424 #endif /* TIOCLSET */
 4425         if (ttySetAttr(ttyfd, &tio) == -1)
 4426             HsSysError(ERROR_TIOCSETP);
 4427 
 4428         /* ignore errors here - some platforms don't work */
 4429         UIntClr(tio.c_cflag, CSIZE);
 4430         if (screen->input_eight_bits)
 4431             tio.c_cflag |= CS8;
 4432         else
 4433             tio.c_cflag |= CS7;
 4434         (void) ttySetAttr(ttyfd, &tio);
 4435 
 4436 #else /* !TERMIO_STRUCT */
 4437         sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
 4438         sg.sg_flags |= ECHO | CRMOD;
 4439         /* make sure speed is set on pty so that editors work right */
 4440         sg.sg_ispeed = line_speed;
 4441         sg.sg_ospeed = line_speed;
 4442         /* reset t_brkc to default value */
 4443         tc.t_brkc = -1;
 4444 #ifdef LPASS8
 4445         if (screen->input_eight_bits)
 4446             lmode |= LPASS8;
 4447         else
 4448             lmode &= ~(LPASS8);
 4449 #endif
 4450 #ifdef sony
 4451         jmode &= ~KM_KANJI;
 4452 #endif /* sony */
 4453 
 4454         ltc = d_ltc;
 4455 
 4456         if (override_tty_modes) {
 4457             TRACE(("applying sgtty ttyModes\n"));
 4458             TMODE(XTTYMODE_intr, tc.t_intrc);
 4459             TMODE(XTTYMODE_quit, tc.t_quitc);
 4460             TMODE(XTTYMODE_erase, sg.sg_erase);
 4461             TMODE(XTTYMODE_kill, sg.sg_kill);
 4462             TMODE(XTTYMODE_eof, tc.t_eofc);
 4463             TMODE(XTTYMODE_start, tc.t_startc);
 4464             TMODE(XTTYMODE_stop, tc.t_stopc);
 4465             TMODE(XTTYMODE_brk, tc.t_brkc);
 4466             /* both SYSV and BSD have ltchars */
 4467             TMODE(XTTYMODE_susp, ltc.t_suspc);
 4468             TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
 4469             TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
 4470             TMODE(XTTYMODE_flush, ltc.t_flushc);
 4471             TMODE(XTTYMODE_weras, ltc.t_werasc);
 4472             TMODE(XTTYMODE_lnext, ltc.t_lnextc);
 4473             if (ttyModes[XTTYMODE_tabs].set
 4474             || ttyModes[XTTYMODE__tabs].set) {
 4475             sg.sg_flags &= ~XTABS;
 4476             if (ttyModes[XTTYMODE__tabs].set.set)
 4477                 sg.sg_flags |= XTABS;
 4478             }
 4479         }
 4480 
 4481         if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
 4482             HsSysError(ERROR_TIOCSETP);
 4483         if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
 4484             HsSysError(ERROR_TIOCSETC);
 4485         if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
 4486             HsSysError(ERROR_TIOCSETD);
 4487         if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
 4488             HsSysError(ERROR_TIOCSLTC);
 4489         if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
 4490             HsSysError(ERROR_TIOCLSET);
 4491 #ifdef sony
 4492         if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
 4493             HsSysError(ERROR_TIOCKSET);
 4494         if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
 4495             HsSysError(ERROR_TIOCKSETC);
 4496 #endif /* sony */
 4497 #endif /* TERMIO_STRUCT */
 4498 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
 4499         if (Console) {
 4500 #ifdef TIOCCONS
 4501             int on = 1;
 4502             if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
 4503             xtermPerror("cannot open console");
 4504 #endif
 4505 #ifdef SRIOCSREDIR
 4506             int fd = open("/dev/console", O_RDWR);
 4507             if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
 4508             xtermPerror("cannot open console");
 4509             IGNORE_RC(close(fd));
 4510 #endif
 4511         }
 4512 #endif /* TIOCCONS */
 4513         }
 4514 
 4515         signal(SIGCHLD, SIG_DFL);
 4516 #ifdef USE_SYSV_SIGHUP
 4517         /* watch out for extra shells (I don't understand either) */
 4518         signal(SIGHUP, SIG_DFL);
 4519 #else
 4520         signal(SIGHUP, SIG_IGN);
 4521 #endif
 4522         /* restore various signals to their defaults */
 4523         signal(SIGINT, SIG_DFL);
 4524         signal(SIGQUIT, SIG_DFL);
 4525         signal(SIGTERM, SIG_DFL);
 4526 
 4527         /*
 4528          * If we're not asked to let the parent process set the terminal's
 4529          * erase mode, or if we had the ttyModes erase resource, then set
 4530          * the terminal's erase mode from our best guess.
 4531          */
 4532 #if OPT_INITIAL_ERASE
 4533         TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
 4534            initial_erase,
 4535            setInitialErase ? "YES" : "NO",
 4536            resource.ptyInitialErase,
 4537            override_tty_modes,
 4538            ttyModes[XTTYMODE_erase].set));
 4539         if (setInitialErase) {
 4540 #if OPT_TRACE
 4541         int old_erase;
 4542 #endif
 4543 #ifdef TERMIO_STRUCT
 4544         if (ttyGetAttr(ttyfd, &tio) == -1)
 4545             tio = d_tio;
 4546 #if OPT_TRACE
 4547         old_erase = tio.c_cc[VERASE];
 4548 #endif
 4549         tio.c_cc[VERASE] = (cc_t) initial_erase;
 4550         TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
 4551 #else /* !TERMIO_STRUCT */
 4552         if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
 4553             sg = d_sg;
 4554 #if OPT_TRACE
 4555         old_erase = sg.sg_erase;
 4556 #endif
 4557         sg.sg_erase = initial_erase;
 4558         rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
 4559 #endif /* TERMIO_STRUCT */
 4560         TRACE(("%s setting erase to %d (was %d)\n",
 4561                rc ? "FAIL" : "OK", initial_erase, old_erase));
 4562         }
 4563 #endif
 4564 
 4565         xtermCopyEnv(environ);
 4566 
 4567         /*
 4568          * standards.freedesktop.org/startup-notification-spec/
 4569          * notes that this variable is used when a "reliable" mechanism is
 4570          * not available; in practice it must be unset to avoid confusing
 4571          * GTK applications.
 4572          */
 4573         xtermUnsetenv("DESKTOP_STARTUP_ID");
 4574         /*
 4575          * We set this temporarily to work around poor design of Xcursor.
 4576          * Unset it here to avoid confusion.
 4577          */
 4578         xtermUnsetenv("XCURSOR_PATH");
 4579 
 4580         xtermSetenv("TERM", resource.term_name);
 4581         if (!resource.term_name)
 4582         *get_tcap_buffer(xw) = 0;
 4583 
 4584         sprintf(buf, "%lu",
 4585             ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
 4586         xtermSetenv("WINDOWID", buf);
 4587 
 4588         /* put the display into the environment of the shell */
 4589         xtermSetenv("DISPLAY", XDisplayString(screen->display));
 4590 
 4591         xtermSetenv("XTERM_VERSION", xtermVersion());
 4592         xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
 4593 
 4594         /*
 4595          * For debugging only, add environment variables that can be used
 4596          * in scripts to selectively kill xterm's parent or child
 4597          * processes.
 4598          */
 4599 #if OPT_TRACE
 4600         sprintf(buf, "%lu", (unsigned long) xterm_parent);
 4601         xtermSetenv("XTERM_PARENT", buf);
 4602         sprintf(buf, "%lu", (unsigned long) getpid());
 4603         xtermSetenv("XTERM_CHILD", buf);
 4604 #endif
 4605 
 4606         signal(SIGTERM, SIG_DFL);
 4607 
 4608         /* this is the time to go and set up stdin, out, and err
 4609          */
 4610         {
 4611 #if defined(CRAY) && (OSMAJORVERSION >= 6)
 4612         close_fd(ttyfd);
 4613 
 4614         IGNORE_RC(close(0));
 4615 
 4616         if (open("/dev/tty", O_RDWR)) {
 4617             SysError(ERROR_OPDEVTTY);
 4618         }
 4619         IGNORE_RC(close(1));
 4620         IGNORE_RC(close(2));
 4621         dup(0);
 4622         dup(0);
 4623 #else
 4624         /* dup the tty */
 4625         for (i = 0; i <= 2; i++)
 4626             if (i != ttyfd) {
 4627             IGNORE_RC(close(i));
 4628             IGNORE_RC(dup(ttyfd));
 4629             }
 4630 #ifndef ATT
 4631         /* and close the tty */
 4632         if (ttyfd > 2)
 4633             close_fd(ttyfd);
 4634 #endif
 4635 #endif /* CRAY */
 4636         }
 4637 
 4638 #if !defined(USE_SYSV_PGRP)
 4639 #ifdef TIOCSCTTY
 4640         setsid();
 4641         ioctl(0, TIOCSCTTY, 0);
 4642 #endif
 4643         ioctl(0, TIOCSPGRP, (char *) &pgrp);
 4644         setpgrp(0, 0);
 4645         close(open(ttydev, O_WRONLY));
 4646         setpgrp(0, pgrp);
 4647 #if defined(__QNX__)
 4648         tcsetpgrp(0, pgrp /*setsid() */ );
 4649 #endif
 4650 #endif /* !USE_SYSV_PGRP */
 4651 
 4652 #ifdef Lynx
 4653         {
 4654         TERMIO_STRUCT t;
 4655         if (ttyGetAttr(0, &t) >= 0) {
 4656             /* this gets lost somewhere on our way... */
 4657             t.c_oflag |= OPOST;
 4658             ttySetAttr(0, &t);
 4659         }
 4660         }
 4661 #endif
 4662 
 4663 #ifdef HAVE_UTMP
 4664         login_name = NULL;
 4665         if (x_getpwuid(screen->uid, &pw)) {
 4666         login_name = x_getlogin(screen->uid, &pw);
 4667         }
 4668         if (login_name != NULL) {
 4669         xtermSetenv("LOGNAME", login_name); /* for POSIX */
 4670         }
 4671 #ifndef USE_UTEMPTER
 4672 #ifdef USE_UTMP_SETGID
 4673         setEffectiveGroup(save_egid);
 4674         TRACE_IDS;
 4675 #endif
 4676 #ifdef USE_SYSV_UTMP
 4677         /* Set up our utmp entry now.  We need to do it here
 4678          * for the following reasons:
 4679          *   - It needs to have our correct process id (for
 4680          *     login).
 4681          *   - If our parent was to set it after the fork(),
 4682          *     it might make it out before we need it.
 4683          *   - We need to do it before we go and change our
 4684          *     user and group id's.
 4685          */
 4686         (void) call_setutent();
 4687         init_utmp(DEAD_PROCESS, &utmp);
 4688 
 4689         /* position to entry in utmp file */
 4690         /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
 4691         utret = find_utmp(&utmp);
 4692         if (utret == 0) {
 4693         (void) call_setutent();
 4694         init_utmp(USER_PROCESS, &utmp);
 4695         utret = find_utmp(&utmp);
 4696         if (utret == 0) {
 4697             (void) call_setutent();
 4698         }
 4699         }
 4700 #if OPT_TRACE
 4701         if (!utret)
 4702         TRACE(("getutid: NULL\n"));
 4703         else
 4704         TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
 4705                (int) utret->ut_pid, utret->ut_type, utret->ut_user,
 4706                (int) sizeof(utret->ut_line), utret->ut_line,
 4707                (int) sizeof(utret->ut_id), utret->ut_id));
 4708 #endif
 4709 
 4710         /* set up the new entry */
 4711         utmp.ut_type = USER_PROCESS;
 4712 #ifdef HAVE_UTMP_UT_XSTATUS
 4713         utmp.ut_xstatus = 2;
 4714 #endif
 4715         copy_filled(utmp.ut_user,
 4716             (login_name != NULL) ? login_name : "????",
 4717             sizeof(utmp.ut_user));
 4718         /* why are we copying this string again?  (see above) */
 4719         copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
 4720         copy_filled(utmp.ut_line,
 4721             my_pty_name(ttydev), sizeof(utmp.ut_line));
 4722 
 4723 #ifdef HAVE_UTMP_UT_HOST
 4724         SetUtmpHost(utmp.ut_host, screen);
 4725 #endif
 4726 #ifdef HAVE_UTMP_UT_SYSLEN
 4727         SetUtmpSysLen(utmp);
 4728 #endif
 4729 
 4730         copy_filled(utmp.ut_name,
 4731             (login_name) ? login_name : "????",
 4732             sizeof(utmp.ut_name));
 4733 
 4734         utmp.ut_pid = getpid();
 4735 #if defined(HAVE_UTMP_UT_XTIME)
 4736 #if defined(HAVE_UTMP_UT_SESSION)
 4737         utmp.ut_session = getsid(0);
 4738 #endif
 4739         utmp.ut_xtime = time((time_t *) 0);
 4740         utmp.ut_tv.tv_usec = 0;
 4741 #else
 4742         utmp.ut_time = time((time_t *) 0);
 4743 #endif
 4744 
 4745         /* write out the entry */
 4746         if (!resource.utmpInhibit) {
 4747         errno = 0;
 4748         call_pututline(&utmp);
 4749         TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
 4750                (int) sizeof(utmp.ut_id), utmp.ut_id,
 4751                (int) sizeof(utmp.ut_line), utmp.ut_line,
 4752                (long) utmp.ut_pid,
 4753                errno, (errno != 0) ? strerror(errno) : ""));
 4754         }
 4755 #ifdef WTMP
 4756 #if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
 4757         if (xw->misc.login_shell)
 4758         updwtmpx(WTMPX_FILE, &utmp);
 4759 #elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
 4760         if (xw->misc.login_shell)
 4761         call_updwtmp(etc_wtmp, &utmp);
 4762 #else
 4763         if (xw->misc.login_shell &&
 4764         (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
 4765         IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
 4766         close(i);
 4767         }
 4768 #endif
 4769 #endif
 4770         /* close the file */
 4771         (void) call_endutent();
 4772 
 4773 #else /* USE_SYSV_UTMP */
 4774         /* We can now get our ttyslot!  We can also set the initial
 4775          * utmp entry.
 4776          */
 4777         tslot = ttyslot();
 4778         added_utmp_entry = False;
 4779         {
 4780         if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
 4781             (i = open(etc_utmp, O_WRONLY)) >= 0) {
 4782             memset(&utmp, 0, sizeof(utmp));
 4783             copy_filled(utmp.ut_line,
 4784                 my_pty_name(ttydev),
 4785                 sizeof(utmp.ut_line));
 4786             copy_filled(utmp.ut_name, login_name,
 4787                 sizeof(utmp.ut_name));
 4788 #ifdef HAVE_UTMP_UT_HOST
 4789             SetUtmpHost(utmp.ut_host, screen);
 4790 #endif
 4791 #ifdef HAVE_UTMP_UT_SYSLEN
 4792             SetUtmpSysLen(utmp);
 4793 #endif
 4794 
 4795             utmp.ut_time = time((time_t *) 0);
 4796             lseek(i, (long) (tslot * sizeof(utmp)), 0);
 4797             IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
 4798             close(i);
 4799             added_utmp_entry = True;
 4800 #if defined(WTMP)
 4801             if (xw->misc.login_shell &&
 4802             (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
 4803             int status;
 4804             status = write(i, (char *) &utmp, sizeof(utmp));
 4805             status = close(i);
 4806             }
 4807 #elif defined(MNX_LASTLOG)
 4808             if (xw->misc.login_shell &&
 4809             (i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
 4810             lseek(i, (long) (screen->uid *
 4811                      sizeof(utmp)), 0);
 4812             IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
 4813             close(i);
 4814             }
 4815 #endif /* WTMP or MNX_LASTLOG */
 4816         } else
 4817             tslot = -tslot;
 4818         }
 4819 
 4820         /* Let's pass our ttyslot to our parent so that it can
 4821          * clean up after us.
 4822          */
 4823 #if OPT_PTY_HANDSHAKE
 4824         if (resource.ptyHandshake) {
 4825         handshake.tty_slot = tslot;
 4826         }
 4827 #endif /* OPT_PTY_HANDSHAKE */
 4828 #endif /* USE_SYSV_UTMP */
 4829 
 4830 #ifdef USE_LASTLOGX
 4831         if (xw->misc.login_shell) {
 4832         memset(&lastlogx, 0, sizeof(lastlogx));
 4833         copy_filled(lastlogx.ll_line,
 4834                 my_pty_name(ttydev),
 4835                 sizeof(lastlogx.ll_line));
 4836         X_GETTIMEOFDAY(&lastlogx.ll_tv);
 4837         SetUtmpHost(lastlogx.ll_host, screen);
 4838         updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
 4839         }
 4840 #endif
 4841 
 4842 #ifdef USE_LASTLOG
 4843         if (xw->misc.login_shell &&
 4844         (i = open(etc_lastlog, O_WRONLY)) >= 0) {
 4845         size_t size = sizeof(struct lastlog);
 4846         off_t offset = (off_t) ((size_t) screen->uid * size);
 4847 
 4848         memset(&lastlog, 0, size);
 4849         copy_filled(lastlog.ll_line,
 4850                 my_pty_name(ttydev),
 4851                 sizeof(lastlog.ll_line));
 4852         SetUtmpHost(lastlog.ll_host, screen);
 4853         lastlog.ll_time = time((time_t *) 0);
 4854         if (lseek(i, offset, 0) != (off_t) (-1)) {
 4855             IGNORE_RC(write(i, (char *) &lastlog, size));
 4856         }
 4857         close(i);
 4858         }
 4859 #endif /* USE_LASTLOG */
 4860 
 4861 #if defined(USE_UTMP_SETGID)
 4862         disableSetGid();
 4863         TRACE_IDS;
 4864 #endif
 4865 
 4866 #if OPT_PTY_HANDSHAKE
 4867         /* Let our parent know that we set up our utmp entry
 4868          * so that it can clean up after us.
 4869          */
 4870         if (resource.ptyHandshake) {
 4871         handshake.status = UTMP_ADDED;
 4872         handshake.error = 0;
 4873         copy_handshake(handshake, ttydev);
 4874         TRACE_HANDSHAKE("writing", &handshake);
 4875         IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
 4876         }
 4877 #endif /* OPT_PTY_HANDSHAKE */
 4878 #endif /* USE_UTEMPTER */
 4879 #endif /* HAVE_UTMP */
 4880 
 4881         IGNORE_RC(setgid(screen->gid));
 4882         TRACE_IDS;
 4883 #ifdef HAVE_INITGROUPS
 4884         if (geteuid() == 0 && OkPasswd(&pw)) {
 4885         if (initgroups(login_name, pw.pw_gid)) {
 4886             perror("initgroups failed");
 4887             SysError(ERROR_INIGROUPS);
 4888         }
 4889         }
 4890 #endif
 4891         if (setuid(screen->uid)) {
 4892         SysError(ERROR_SETUID);
 4893         }
 4894         TRACE_IDS;
 4895 #if OPT_PTY_HANDSHAKE
 4896         if (resource.ptyHandshake) {
 4897         /* mark the pipes as close on exec */
 4898         (void) fcntl(cp_pipe[1], F_SETFD, 1);
 4899         (void) fcntl(pc_pipe[0], F_SETFD, 1);
 4900 
 4901         /* We are at the point where we are going to
 4902          * exec our shell (or whatever).  Let our parent
 4903          * know we arrived safely.
 4904          */
 4905         handshake.status = PTY_GOOD;
 4906         handshake.error = 0;
 4907         copy_handshake(handshake, ttydev);
 4908         TRACE_HANDSHAKE("writing", &handshake);
 4909         IGNORE_RC(write(cp_pipe[1],
 4910                 (const char *) &handshake,
 4911                 sizeof(handshake)));
 4912 
 4913         if (resource.wait_for_map) {
 4914             i = (int) read(pc_pipe[0], (char *) &handshake,
 4915                    sizeof(handshake));
 4916             if (i != sizeof(handshake) ||
 4917             handshake.status != PTY_EXEC) {
 4918             /* some very bad problem occurred */
 4919             exit(ERROR_PTY_EXEC);
 4920             }
 4921             if (handshake.rows > 0 && handshake.cols > 0) {
 4922             TRACE(("handshake read ttysize: %dx%d\n",
 4923                    handshake.rows, handshake.cols));
 4924             set_max_row(screen, handshake.rows);
 4925             set_max_col(screen, handshake.cols);
 4926 #ifdef TTYSIZE_STRUCT
 4927             got_handshake_size = True;
 4928             setup_winsize(ts, MaxRows(screen), MaxCols(screen),
 4929                       FullHeight(screen), FullWidth(screen));
 4930             trace_winsize(ts, "got handshake");
 4931 #endif /* TTYSIZE_STRUCT */
 4932             }
 4933         }
 4934         }
 4935 #endif /* OPT_PTY_HANDSHAKE */
 4936 
 4937 #ifdef USE_SYSV_ENVVARS
 4938         {
 4939         char numbuf[12];
 4940         sprintf(numbuf, "%d", MaxCols(screen));
 4941         xtermSetenv("COLUMNS", numbuf);
 4942         sprintf(numbuf, "%d", MaxRows(screen));
 4943         xtermSetenv("LINES", numbuf);
 4944         }
 4945 #ifdef HAVE_UTMP
 4946         if (OkPasswd(&pw)) {    /* SVR4 doesn't provide these */
 4947         if (!x_getenv("HOME"))
 4948             xtermSetenv("HOME", pw.pw_dir);
 4949         if (!x_getenv("SHELL"))
 4950             xtermSetenv("SHELL", pw.pw_shell);
 4951         }
 4952 #endif /* HAVE_UTMP */
 4953 #else /* USE_SYSV_ENVVARS */
 4954         if (*(newtc = get_tcap_buffer(xw)) != '\0') {
 4955         resize_termcap(xw);
 4956         if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
 4957             remove_termcap_entry(newtc, "ti=");
 4958             remove_termcap_entry(newtc, "te=");
 4959         }
 4960         /*
 4961          * work around broken termcap entries */
 4962         if (resource.useInsertMode) {
 4963             remove_termcap_entry(newtc, "ic=");
 4964             /* don't get duplicates */
 4965             remove_termcap_entry(newtc, "im=");
 4966             remove_termcap_entry(newtc, "ei=");
 4967             remove_termcap_entry(newtc, "mi");
 4968             if (*newtc)
 4969             strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
 4970         }
 4971         if (*newtc) {
 4972 #if OPT_INITIAL_ERASE
 4973             unsigned len;
 4974             remove_termcap_entry(newtc, TERMCAP_ERASE "=");
 4975             len = (unsigned) strlen(newtc);
 4976             if (len != 0 && newtc[len - 1] == ':')
 4977             len--;
 4978             sprintf(newtc + len, ":%s=\\%03o:",
 4979                 TERMCAP_ERASE,
 4980                 CharOf(initial_erase));
 4981 #endif
 4982             xtermSetenv("TERMCAP", newtc);
 4983         }
 4984         }
 4985 #endif /* USE_SYSV_ENVVARS */
 4986 #ifdef OWN_TERMINFO_ENV
 4987         xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
 4988 #endif
 4989 
 4990 #if OPT_PTY_HANDSHAKE
 4991         /*
 4992          * Need to reset after all the ioctl bashing we did above.
 4993          *
 4994          * If we expect the waitForMap logic to set the handshake-size,
 4995          * use that to prevent races.
 4996          */
 4997         TRACE(("should we reset screensize after pty-handshake?\n"));
 4998         TRACE(("... ptyHandshake      :%d\n", resource.ptyHandshake));
 4999         TRACE(("... ptySttySize       :%d\n", resource.ptySttySize));
 5000         TRACE(("... got_handshake_size:%d\n", got_handshake_size));
 5001         TRACE(("... wait_for_map0     :%d\n", resource.wait_for_map0));
 5002         if (resource.ptyHandshake
 5003         && resource.ptySttySize
 5004         && (got_handshake_size || !resource.wait_for_map0)) {
 5005 #ifdef TTYSIZE_STRUCT
 5006         TRACE_RC(i, SET_TTYSIZE(0, ts));
 5007         trace_winsize(ts, "ptyHandshake SET_TTYSIZE");
 5008 #endif /* TTYSIZE_STRUCT */
 5009         }
 5010 #endif /* OPT_PTY_HANDSHAKE */
 5011         signal(SIGHUP, SIG_DFL);
 5012 
 5013         /*
 5014          * If we have an explicit shell to run, make that set $SHELL.
 5015          * Next, allow an existing setting of $SHELL, for absolute paths.
 5016          * Otherwise, if $SHELL is not set, determine it from the user's
 5017          * password information, if possible.
 5018          *
 5019          * Incidentally, our setting of $SHELL tells luit to use that
 5020          * program rather than choosing between $SHELL and "/bin/sh".
 5021          */
 5022         if (validShell(explicit_shname)) {
 5023         xtermSetenv("SHELL", explicit_shname);
 5024         } else if (validProgram(shell_path = x_getenv("SHELL"))) {
 5025         if (!validShell(shell_path)) {
 5026             xtermUnsetenv("SHELL");
 5027         }
 5028         } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
 5029                || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
 5030         shell_path = resetShell(shell_path);
 5031         } else if (validShell(shell_path)) {
 5032         xtermSetenv("SHELL", shell_path);
 5033         } else {
 5034         shell_path = resetShell(shell_path);
 5035         }
 5036 
 5037         /*
 5038          * Set $XTERM_SHELL, which is not necessarily a valid shell, but
 5039          * is executable.
 5040          */
 5041         if (validProgram(explicit_shname)) {
 5042         shell_path = explicit_shname;
 5043         } else if (shell_path == 0) {
 5044         /* this could happen if the explicit shname lost a race */
 5045         shell_path = resetShell(shell_path);
 5046         }
 5047         xtermSetenv("XTERM_SHELL", shell_path);
 5048 
 5049         shname = x_basename(shell_path);
 5050         TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
 5051 
 5052 #if OPT_LUIT_PROG
 5053         /*
 5054          * Use two copies of command_to_exec, in case luit is not actually
 5055          * there, or refuses to run.  In that case we will fall-through to
 5056          * to command that the user gave anyway.
 5057          */
 5058         if (command_to_exec_with_luit && command_to_exec) {
 5059         char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
 5060         xtermSetenv("XTERM_SHELL", myShell);
 5061         free(myShell);
 5062         TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
 5063         execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
 5064         xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
 5065         xtermWarning("cannot support your locale.\n");
 5066         }
 5067 #endif
 5068         if (command_to_exec) {
 5069         char *myShell = xtermFindShell(*command_to_exec, False);
 5070         xtermSetenv("XTERM_SHELL", myShell);
 5071         free(myShell);
 5072         TRACE_ARGV("spawning command", command_to_exec);
 5073         execvp(*command_to_exec, command_to_exec);
 5074         if (command_to_exec[1] == 0)
 5075             execlp(shell_path, shname, "-c", command_to_exec[0],
 5076                (void *) 0);
 5077         xtermPerror("Can't execvp %s", *command_to_exec);
 5078         }
 5079 #ifdef USE_SYSV_SIGHUP
 5080         /* fix pts sh hanging around */
 5081         signal(SIGHUP, SIG_DFL);
 5082 #endif
 5083 
 5084         if ((shname_minus = malloc(strlen(shname) + 2)) != 0) {
 5085         (void) strcpy(shname_minus, "-");
 5086         (void) strcat(shname_minus, shname);
 5087         } else {
 5088         static char default_minus[] = "-sh";
 5089         shname_minus = default_minus;
 5090         }
 5091 #ifndef TERMIO_STRUCT
 5092         ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
 5093              ? NTTYDISC
 5094              : 0);
 5095         ioctl(0, TIOCSETD, (char *) &ldisc);
 5096 #endif /* !TERMIO_STRUCT */
 5097 
 5098 #ifdef USE_LOGIN_DASH_P
 5099         if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
 5100         execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
 5101 #endif
 5102 
 5103 #if OPT_LUIT_PROG
 5104         if (command_to_exec_with_luit) {
 5105         if (xw->misc.login_shell) {
 5106             char *params[4];
 5107             params[0] = x_strdup("-argv0");
 5108             params[1] = shname_minus;
 5109             params[2] = NULL;
 5110             x_appendargv(command_to_exec_with_luit
 5111                  + command_length_with_luit,
 5112                  params);
 5113         }
 5114         TRACE_ARGV("final luit command", command_to_exec_with_luit);
 5115         execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
 5116         /* Exec failed. */
 5117         xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
 5118         }
 5119 #endif
 5120         execlp(shell_path,
 5121            (xw->misc.login_shell ? shname_minus : shname),
 5122            (void *) 0);
 5123 
 5124         /* Exec failed. */
 5125         xtermPerror("Could not exec %s", shell_path);
 5126         IGNORE_RC(sleep(5));
 5127         free(shell_path);
 5128         exit(ERROR_EXEC);
 5129     }
 5130     /* end if in child after fork */
 5131 #if OPT_PTY_HANDSHAKE
 5132     if (resource.ptyHandshake) {
 5133         /* Parent process.  Let's handle handshaked requests to our
 5134          * child process.
 5135          */
 5136 
 5137         /* close childs's sides of the pipes */
 5138         close(cp_pipe[1]);
 5139         close(pc_pipe[0]);
 5140 
 5141         for (done = 0; !done;) {
 5142         if (read(cp_pipe[0],
 5143              (char *) &handshake,
 5144              sizeof(handshake)) <= 0) {
 5145             /* Our child is done talking to us.  If it terminated
 5146              * due to an error, we will catch the death of child
 5147              * and clean up.
 5148              */
 5149             break;
 5150         }
 5151 
 5152         TRACE_HANDSHAKE("read", &handshake);
 5153         switch (handshake.status) {
 5154         case PTY_GOOD:
 5155             /* Success!  Let's free up resources and
 5156              * continue.
 5157              */
 5158             done = 1;
 5159             break;
 5160 
 5161         case PTY_BAD:
 5162             /* The open of the pty failed!  Let's get
 5163              * another one.
 5164              */
 5165             IGNORE_RC(close(screen->respond));
 5166             if (get_pty(&screen->respond, XDisplayString(screen->display))) {
 5167             /* no more ptys! */
 5168             xtermPerror("child process can find no available ptys");
 5169             handshake.status = PTY_NOMORE;
 5170             TRACE_HANDSHAKE("writing", &handshake);
 5171             IGNORE_RC(write(pc_pipe[1],
 5172                     (const char *) &handshake,
 5173                     sizeof(handshake)));
 5174             exit(ERROR_PTYS);
 5175             }
 5176             handshake.status = PTY_NEW;
 5177             copy_handshake(handshake, ttydev);
 5178             TRACE_HANDSHAKE("writing", &handshake);
 5179             IGNORE_RC(write(pc_pipe[1],
 5180                     (const char *) &handshake,
 5181                     sizeof(handshake)));
 5182             break;
 5183 
 5184         case PTY_FATALERROR:
 5185             errno = handshake.error;
 5186             close(cp_pipe[0]);
 5187             close(pc_pipe[1]);
 5188             SysError(handshake.fatal_error);
 5189             /*NOTREACHED */
 5190 
 5191         case UTMP_ADDED:
 5192             /* The utmp entry was set by our slave.  Remember
 5193              * this so that we can reset it later.
 5194              */
 5195             added_utmp_entry = True;
 5196 #ifndef USE_SYSV_UTMP
 5197             tslot = handshake.tty_slot;
 5198 #endif /* USE_SYSV_UTMP */
 5199             free(ttydev);
 5200             handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
 5201             ttydev = x_strdup(handshake.buffer);
 5202             break;
 5203         case PTY_NEW:
 5204         case PTY_NOMORE:
 5205         case UTMP_TTYSLOT:
 5206         case PTY_EXEC:
 5207         default:
 5208             xtermWarning("unexpected handshake status %d\n",
 5209                  (int) handshake.status);
 5210         }
 5211         }
 5212         /* close our sides of the pipes */
 5213         if (!resource.wait_for_map) {
 5214         close(cp_pipe[0]);
 5215         close(pc_pipe[1]);
 5216         }
 5217     }
 5218 #endif /* OPT_PTY_HANDSHAKE */
 5219     }
 5220 
 5221     /* end if no slave */
 5222     /*
 5223      * still in parent (xterm process)
 5224      */
 5225 #ifdef USE_SYSV_SIGHUP
 5226     /* hung sh problem? */
 5227     signal(SIGHUP, SIG_DFL);
 5228 #else
 5229     signal(SIGHUP, SIG_IGN);
 5230 #endif
 5231 
 5232 /*
 5233  * Unfortunately, System V seems to have trouble divorcing the child process
 5234  * from the process group of xterm.  This is a problem because hitting the
 5235  * INTR or QUIT characters on the keyboard will cause xterm to go away if we
 5236  * don't ignore the signals.  This is annoying.
 5237  */
 5238 
 5239 #if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
 5240     signal(SIGINT, SIG_IGN);
 5241 
 5242 #ifndef SYSV
 5243     /* hung shell problem */
 5244     signal(SIGQUIT, SIG_IGN);
 5245 #endif
 5246     signal(SIGTERM, SIG_IGN);
 5247 #elif defined(SYSV) || defined(__osf__)
 5248     /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
 5249      * then our pgrp and pid will be the same.  If we were spawned by
 5250      * a jobcontrol dumb shell (like /bin/sh), then we will be in our
 5251      * parent's pgrp, and we must ignore keyboard signals, or we will
 5252      * tank on everything.
 5253      */
 5254     if (getpid() == getpgrp()) {
 5255     (void) signal(SIGINT, Exit);
 5256     (void) signal(SIGQUIT, Exit);
 5257     (void) signal(SIGTERM, Exit);
 5258     } else {
 5259     (void) signal(SIGINT, SIG_IGN);
 5260     (void) signal(SIGQUIT, SIG_IGN);
 5261     (void) signal(SIGTERM, SIG_IGN);
 5262     }
 5263     (void) signal(SIGPIPE, Exit);
 5264 #else /* SYSV */
 5265     signal(SIGINT, Exit);
 5266     signal(SIGQUIT, Exit);
 5267     signal(SIGTERM, Exit);
 5268     signal(SIGPIPE, Exit);
 5269 #endif /* USE_SYSV_SIGNALS and not SIGTSTP */
 5270 #ifdef NO_LEAKS
 5271     if (ok_termcap != True)
 5272     free(TermName);
 5273 #endif
 5274 
 5275     return 0;
 5276 }               /* end spawnXTerm */
 5277 
 5278 void
 5279 Exit(int n)
 5280 {
 5281     XtermWidget xw = term;
 5282     TScreen *screen = TScreenOf(xw);
 5283 
 5284 #ifdef USE_UTEMPTER
 5285     DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
 5286     if (!resource.utmpInhibit && added_utmp_entry) {
 5287     TRACE(("...calling removeFromUtmp\n"));
 5288     UTEMPTER_DEL();
 5289     }
 5290 #elif defined(HAVE_UTMP)
 5291 #ifdef USE_SYSV_UTMP
 5292     struct UTMP_STR utmp;
 5293     struct UTMP_STR *utptr;
 5294 
 5295     DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
 5296     /* don't do this more than once */
 5297     if (xterm_exiting) {
 5298     exit(n);
 5299     }
 5300     xterm_exiting = True;
 5301 
 5302 #ifdef PUCC_PTYD
 5303     closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
 5304 #endif /* PUCC_PTYD */
 5305 
 5306     /* cleanup the utmp entry we forged earlier */
 5307     if (!resource.utmpInhibit
 5308 #if OPT_PTY_HANDSHAKE       /* without handshake, no way to know */
 5309     && (resource.ptyHandshake && added_utmp_entry)
 5310 #endif /* OPT_PTY_HANDSHAKE */
 5311     ) {
 5312 #if defined(USE_UTMP_SETGID)
 5313     setEffectiveGroup(save_egid);
 5314     TRACE_IDS;
 5315 #endif
 5316     init_utmp(USER_PROCESS, &utmp);
 5317     (void) call_setutent();
 5318 
 5319     /*
 5320      * We could use getutline() if we didn't support old systems.
 5321      */
 5322     while ((utptr = find_utmp(&utmp)) != 0) {
 5323         if (utptr->ut_pid == screen->pid) {
 5324         utptr->ut_type = DEAD_PROCESS;
 5325 #if defined(HAVE_UTMP_UT_XTIME)
 5326 #if defined(HAVE_UTMP_UT_SESSION)
 5327         utptr->ut_session = getsid(0);
 5328 #endif
 5329         utptr->ut_xtime = time((time_t *) 0);
 5330         utptr->ut_tv.tv_usec = 0;
 5331 #else
 5332         *utptr->ut_user = 0;
 5333         utptr->ut_time = time((