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