"Fossies" - the Fresh Open Source Software Archive

Member "xterm-379/main.c" (15 Feb 2023, 159867 Bytes) of package /linux/misc/xterm-379.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: 377_vs_379.

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