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