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