main.c revision a5ae21e4
1/* $XTermId: main.c,v 1.882 2021/09/16 19:49:13 tom Exp $ */ 2 3/* 4 * Copyright 2002-2020,2021 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 * 32 * Copyright 1987, 1988 X Consortium 33 * 34 * Permission to use, copy, modify, distribute, and sell this software and its 35 * documentation for any purpose is hereby granted without fee, provided that 36 * the above copyright notice appear in all copies and that both that 37 * copyright notice and this permission notice appear in supporting 38 * documentation. 39 * 40 * The above copyright notice and this permission notice shall be included in 41 * all copies or substantial portions of the Software. 42 * 43 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 47 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 48 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 49 * 50 * Except as contained in this notice, the name of the X Consortium shall not be 51 * used in advertising or otherwise to promote the sale, use or other dealings 52 * in this Software without prior written authorization from the X Consortium. 53 * 54 * Copyright 1987, 1988 by Digital Equipment Corporation, Maynard. 55 * 56 * All Rights Reserved 57 * 58 * Permission to use, copy, modify, and distribute this software and its 59 * documentation for any purpose and without fee is hereby granted, 60 * provided that the above copyright notice appear in all copies and that 61 * both that copyright notice and this permission notice appear in 62 * supporting documentation, and that the name of Digital not be used in 63 * advertising or publicity pertaining to distribution of the software 64 * without specific, written prior permission. 65 * 66 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 67 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 68 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 69 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 70 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 71 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 72 * SOFTWARE. 73 */ 74 75/* 76 * W A R N I N G 77 * 78 * If you think you know what all of this code is doing, you are 79 * probably very mistaken. There be serious and nasty dragons here. 80 * 81 * This client is *not* to be taken as an example of how to write X 82 * Toolkit applications. It is in need of a substantial rewrite, 83 * ideally to create a generic tty widget with several different parsing 84 * widgets so that you can plug 'em together any way you want. Don't 85 * hold your breath, though.... 86 */ 87 88/* main.c */ 89 90#define RES_OFFSET(field) XtOffsetOf(XTERM_RESOURCE, field) 91 92#include <xterm.h> 93#include <version.h> 94#include <graphics.h> 95 96#if OPT_TOOLBAR 97 98#if defined(HAVE_LIB_XAW) 99#include <X11/Xaw/Form.h> 100#elif defined(HAVE_LIB_XAW3D) 101#include <X11/Xaw3d/Form.h> 102#elif defined(HAVE_LIB_XAW3DXFT) 103#include <X11/Xaw3dxft/Form.h> 104#include <X11/Xaw3dxft/Xaw3dXft.h> 105#elif defined(HAVE_LIB_NEXTAW) 106#include <X11/neXtaw/Form.h> 107#elif defined(HAVE_LIB_XAWPLUS) 108#include <X11/XawPlus/Form.h> 109#endif 110 111#else 112 113#if defined(HAVE_LIB_XAW3DXFT) 114#include <X11/Xaw3dxft/Xaw3dXft.h> 115#endif 116 117#endif /* OPT_TOOLBAR */ 118 119#include <pwd.h> 120#include <ctype.h> 121 122#include <data.h> 123#include <error.h> 124#include <menu.h> 125#include <main.h> 126#include <xstrings.h> 127#include <xtermcap.h> 128#include <xterm_io.h> 129 130#if OPT_WIDE_CHARS 131#include <charclass.h> 132#endif 133 134#ifdef __osf__ 135#define USE_SYSV_SIGNALS 136#define WTMP 137#include <pty.h> /* openpty() */ 138#endif 139 140#ifdef __sgi 141#include <grp.h> /* initgroups() */ 142#endif 143 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 2901#if OPT_MAXIMIZE 2902 if (resource.maximized) 2903 RequestMaximize(term, True); 2904#endif 2905 for (;;) { 2906#if OPT_TEK4014 2907 if (TEK4014_ACTIVE(term)) 2908 TekRun(); 2909 else 2910#endif 2911 VTRun(term); 2912 } 2913} 2914 2915#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) 2916#define USE_OPENPTY 1 2917static int opened_tty = -1; 2918#endif 2919 2920/* 2921 * This function opens up a pty master and stuffs its value into pty. 2922 * 2923 * If it finds one, it returns a value of 0. If it does not find one, 2924 * it returns a value of !0. This routine is designed to be re-entrant, 2925 * so that if a pty master is found and later, we find that the slave 2926 * has problems, we can re-enter this function and get another one. 2927 */ 2928static int 2929get_pty(int *pty, char *from GCC_UNUSED) 2930{ 2931 int result = 1; 2932 2933#if defined(USE_OPENPTY) 2934 result = openpty(pty, &opened_tty, ttydev, NULL, NULL); 2935 if (opened_tty >= 0) { 2936 close(opened_tty); 2937 opened_tty = -1; 2938 } 2939#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY) 2940 if ((*pty = posix_openpt(O_RDWR)) >= 0) { 2941 char *name = ptsname(*pty); 2942 if (name != 0) { 2943 strcpy(ttydev, name); 2944 result = 0; 2945 } 2946 } 2947#ifdef USE_PTY_SEARCH 2948 if (result) { 2949 result = pty_search(pty); 2950 } 2951#endif 2952#elif defined(PUCC_PTYD) 2953 result = ((*pty = openrpty(ttydev, ptydev, 2954 (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), 2955 save_ruid, from)) < 0); 2956#elif defined(__QNXNTO__) 2957 result = pty_search(pty); 2958#else 2959#if defined(USE_USG_PTYS) || defined(__CYGWIN__) 2960#if defined(__MVS__) 2961 result = pty_search(pty); 2962#else 2963 result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0); 2964#endif 2965#if defined(SVR4) || defined(__SCO__) 2966 if (!result) 2967 strcpy(ttydev, ptsname(*pty)); 2968#endif 2969 2970#elif defined(AIXV3) 2971 2972 if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) { 2973 strcpy(ttydev, ttyname(*pty)); 2974 result = 0; 2975 } 2976#elif defined(__convex__) 2977 2978 char *pty_name; 2979 extern char *getpty(void); 2980 2981 while ((pty_name = getpty()) != NULL) { 2982 if ((*pty = open(pty_name, O_RDWR)) >= 0) { 2983 strcpy(ptydev, pty_name); 2984 strcpy(ttydev, pty_name); 2985 *x_basename(ttydev) = 't'; 2986 result = 0; 2987 break; 2988 } 2989 } 2990 2991#elif defined(sequent) 2992 2993 result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0); 2994 2995#elif defined(__sgi) && (OSMAJORVERSION >= 4) 2996 2997 char *tty_name; 2998 2999 tty_name = _getpty(pty, O_RDWR, 0622, 0); 3000 if (tty_name != 0) { 3001 strcpy(ttydev, tty_name); 3002 result = 0; 3003 } 3004#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV)) 3005 3006 struct stat fstat_buf; 3007 3008 *pty = open("/dev/ptc", O_RDWR); 3009 if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) { 3010 result = 0; 3011 sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev)); 3012 } 3013#elif defined(__hpux) 3014 3015 /* 3016 * Use the clone device if it works, otherwise use pty_search logic. 3017 */ 3018 if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) { 3019 char *name = ptsname(*pty); 3020 if (name != 0) { 3021 strcpy(ttydev, name); 3022 result = 0; 3023 } else { /* permissions, or other unexpected problem */ 3024 close(*pty); 3025 *pty = -1; 3026 result = pty_search(pty); 3027 } 3028 } else { 3029 result = pty_search(pty); 3030 } 3031 3032#else 3033 3034 result = pty_search(pty); 3035 3036#endif 3037#endif 3038 3039 TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n", 3040 ttydev != 0 ? ttydev : "?", 3041 ptydev != 0 ? ptydev : "?", 3042 result ? "FAIL" : "OK", 3043 pty != 0 ? *pty : -1)); 3044 return result; 3045} 3046 3047static void 3048set_pty_permissions(uid_t uid, unsigned gid, unsigned mode) 3049{ 3050#ifdef USE_TTY_GROUP 3051 struct group *ttygrp; 3052 3053 if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) { 3054 gid = (unsigned) ttygrp->gr_gid; 3055 mode &= 0660U; 3056 } 3057 endgrent(); 3058#endif /* USE_TTY_GROUP */ 3059 3060 TRACE_IDS; 3061 set_owner(ttydev, (unsigned) uid, gid, mode); 3062} 3063 3064#ifdef get_pty /* USE_UTMP_SETGID */ 3065#undef get_pty 3066/* 3067 * Call the real get_pty() before relinquishing root-setuid, caching the 3068 * result. 3069 */ 3070static int 3071get_pty(int *pty, char *from) 3072{ 3073 static int m_pty = -1; 3074 int result = -1; 3075 3076 if (pty == NULL) { 3077 result = really_get_pty(&m_pty, from); 3078 3079 seteuid(0); 3080 set_pty_permissions(save_ruid, save_rgid, 0600U); 3081 seteuid(save_ruid); 3082 TRACE_IDS; 3083 3084 } else if (m_pty != -1) { 3085 *pty = m_pty; 3086 result = 0; 3087 } else { 3088 result = -1; 3089 } 3090 TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n", 3091 ttydev != 0 ? ttydev : "?", 3092 ptydev != 0 ? ptydev : "?", 3093 result ? "FAIL" : "OK", 3094 pty != 0 ? *pty : -1)); 3095#ifdef USE_OPENPTY 3096 if (opened_tty >= 0) { 3097 close(opened_tty); 3098 opened_tty = -1; 3099 } 3100#endif 3101 return result; 3102} 3103#endif 3104 3105/* 3106 * Called from get_pty to iterate over likely pseudo terminals 3107 * we might allocate. Used on those systems that do not have 3108 * a functional interface for allocating a pty. 3109 * Returns 0 if found a pty, 1 if fails. 3110 */ 3111#ifdef USE_PTY_SEARCH 3112static int 3113pty_search(int *pty) 3114{ 3115 static int devindex = 0, letter = 0; 3116 3117#if defined(CRAY) || defined(__MVS__) 3118 while (devindex < MAXPTTYS) { 3119 sprintf(ttydev, TTYFORMAT, devindex); 3120 sprintf(ptydev, PTYFORMAT, devindex); 3121 devindex++; 3122 3123 TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev)); 3124 if ((*pty = open(ptydev, O_RDWR)) >= 0) { 3125 return 0; 3126 } 3127 } 3128#else /* CRAY || __MVS__ */ 3129 while (PTYCHAR1[letter]) { 3130 ttydev[strlen(ttydev) - 2] = 3131 ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter]; 3132 3133 while (PTYCHAR2[devindex]) { 3134 ttydev[strlen(ttydev) - 1] = 3135 ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex]; 3136 devindex++; 3137 3138 TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev)); 3139 if ((*pty = open(ptydev, O_RDWR)) >= 0) { 3140#ifdef sun 3141 /* Need to check the process group of the pty. 3142 * If it exists, then the slave pty is in use, 3143 * and we need to get another one. 3144 */ 3145 int pgrp_rtn; 3146 if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) { 3147 close(*pty); 3148 continue; 3149 } 3150#endif /* sun */ 3151 return 0; 3152 } 3153 } 3154 devindex = 0; 3155 letter++; 3156 } 3157#endif /* CRAY else */ 3158 /* 3159 * We were unable to allocate a pty master! Return an error 3160 * condition and let our caller terminate cleanly. 3161 */ 3162 return 1; 3163} 3164#endif /* USE_PTY_SEARCH */ 3165 3166/* 3167 * The only difference in /etc/termcap between 4014 and 4015 is that 3168 * the latter has support for switching character sets. We support the 3169 * 4015 protocol, but ignore the character switches. Therefore, we 3170 * choose 4014 over 4015. 3171 * 3172 * Features of the 4014 over the 4012: larger (19") screen, 12-bit 3173 * graphics addressing (compatible with 4012 10-bit addressing), 3174 * special point plot mode, incremental plot mode (not implemented in 3175 * later Tektronix terminals), and 4 character sizes. 3176 * All of these are supported by xterm. 3177 */ 3178 3179#if OPT_TEK4014 3180static const char *const tekterm[] = 3181{ 3182 "tek4014", 3183 "tek4015", /* 4014 with APL character set support */ 3184 "tek4012", /* 4010 with lower case */ 3185 "tek4013", /* 4012 with APL character set support */ 3186 "tek4010", /* small screen, upper-case only */ 3187 "dumb", 3188 0 3189}; 3190#endif 3191 3192/* The VT102 is a VT100 with the Advanced Video Option included standard. 3193 * It also adds Escape sequences for insert/delete character/line. 3194 * The VT220 adds 8-bit character sets, selective erase. 3195 * The VT320 adds a 25th status line, terminal state interrogation. 3196 * The VT420 has up to 48 lines on the screen. 3197 */ 3198 3199static const char *const vtterm[] = 3200{ 3201#ifdef USE_X11TERM 3202 "x11term", /* for people who want special term name */ 3203#endif 3204 DFT_TERMTYPE, /* for people who want special term name */ 3205 "xterm", /* the preferred name, should be fastest */ 3206 "vt102", 3207 "vt100", 3208 "ansi", 3209 "dumb", 3210 0 3211}; 3212 3213/* ARGSUSED */ 3214static void 3215hungtty(int i GCC_UNUSED) 3216{ 3217 DEBUG_MSG("handle:hungtty\n"); 3218 siglongjmp(env, 1); 3219} 3220 3221#if OPT_PTY_HANDSHAKE 3222#define NO_FDS {-1, -1} 3223 3224static int cp_pipe[2] = NO_FDS; /* this pipe is used for child to parent transfer */ 3225static int pc_pipe[2] = NO_FDS; /* this pipe is used for parent to child transfer */ 3226 3227typedef enum { /* c == child, p == parent */ 3228 PTY_BAD, /* c->p: can't open pty slave for some reason */ 3229 PTY_FATALERROR, /* c->p: we had a fatal error with the pty */ 3230 PTY_GOOD, /* c->p: we have a good pty, let's go on */ 3231 PTY_NEW, /* p->c: here is a new pty slave, try this */ 3232 PTY_NOMORE, /* p->c; no more pty's, terminate */ 3233 UTMP_ADDED, /* c->p: utmp entry has been added */ 3234 UTMP_TTYSLOT, /* c->p: here is my ttyslot */ 3235 PTY_EXEC /* p->c: window has been mapped the first time */ 3236} status_t; 3237 3238#define HANDSHAKE_LEN 1024 3239 3240typedef struct { 3241 status_t status; 3242 int error; 3243 int fatal_error; 3244 int tty_slot; 3245 int rows; 3246 int cols; 3247 char buffer[HANDSHAKE_LEN]; 3248} handshake_t; 3249 3250/* the buffer is large enough that we can always have a trailing null */ 3251#define copy_handshake(dst, src) \ 3252 strncpy(dst.buffer, src, (size_t)HANDSHAKE_LEN - 1)[HANDSHAKE_LEN - 1] = '\0' 3253 3254#if OPT_TRACE 3255static void 3256trace_handshake(const char *tag, handshake_t * data) 3257{ 3258 const char *status = "?"; 3259 switch (data->status) { 3260 case PTY_BAD: 3261 status = "PTY_BAD"; 3262 break; 3263 case PTY_FATALERROR: 3264 status = "PTY_FATALERROR"; 3265 break; 3266 case PTY_GOOD: 3267 status = "PTY_GOOD"; 3268 break; 3269 case PTY_NEW: 3270 status = "PTY_NEW"; 3271 break; 3272 case PTY_NOMORE: 3273 status = "PTY_NOMORE"; 3274 break; 3275 case UTMP_ADDED: 3276 status = "UTMP_ADDED"; 3277 break; 3278 case UTMP_TTYSLOT: 3279 status = "UTMP_TTYSLOT"; 3280 break; 3281 case PTY_EXEC: 3282 status = "PTY_EXEC"; 3283 break; 3284 } 3285 TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n", 3286 tag, 3287 status, 3288 data->error, 3289 data->fatal_error, 3290 data->buffer)); 3291} 3292#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data) 3293#else 3294#define TRACE_HANDSHAKE(tag, data) /* nothing */ 3295#endif 3296 3297/* HsSysError() 3298 * 3299 * This routine does the equivalent of a SysError but it handshakes 3300 * over the errno and error exit to the master process so that it can 3301 * display our error message and exit with our exit code so that the 3302 * user can see it. 3303 */ 3304 3305static void 3306HsSysError(int error) 3307{ 3308 handshake_t handshake; 3309 3310 memset(&handshake, 0, sizeof(handshake)); 3311 handshake.status = PTY_FATALERROR; 3312 handshake.error = errno; 3313 handshake.fatal_error = error; 3314 copy_handshake(handshake, ttydev); 3315 3316 if (resource.ptyHandshake && (cp_pipe[1] >= 0)) { 3317 TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n", 3318 handshake.error, 3319 handshake.fatal_error, 3320 handshake.buffer)); 3321 TRACE_HANDSHAKE("writing", &handshake); 3322 IGNORE_RC(write(cp_pipe[1], 3323 (const char *) &handshake, 3324 sizeof(handshake))); 3325 } else { 3326 xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n", 3327 handshake.error, 3328 handshake.fatal_error, 3329 handshake.buffer); 3330 fprintf(stderr, "%s\n", SysErrorMsg(handshake.error)); 3331 fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error)); 3332 } 3333 exit(error); 3334} 3335 3336void 3337first_map_occurred(void) 3338{ 3339 if (resource.wait_for_map) { 3340 if (pc_pipe[1] >= 0) { 3341 handshake_t handshake; 3342 TScreen *screen = TScreenOf(term); 3343 3344 memset(&handshake, 0, sizeof(handshake)); 3345 handshake.status = PTY_EXEC; 3346 handshake.rows = screen->max_row; 3347 handshake.cols = screen->max_col; 3348 3349 TRACE(("first_map_occurred: %dx%d\n", MaxRows(screen), MaxCols(screen))); 3350 TRACE_HANDSHAKE("writing", &handshake); 3351 IGNORE_RC(write(pc_pipe[1], 3352 (const char *) &handshake, 3353 sizeof(handshake))); 3354 close(cp_pipe[0]); 3355 close(pc_pipe[1]); 3356 } 3357 resource.wait_for_map = False; 3358 } 3359} 3360#else 3361/* 3362 * temporary hack to get xterm working on att ptys 3363 */ 3364static void 3365HsSysError(int error) 3366{ 3367 xtermWarning("fatal pty error %d (errno=%d) on tty %s\n", 3368 error, errno, ttydev); 3369 exit(error); 3370} 3371#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */ 3372 3373#ifndef VMS 3374static void 3375set_owner(char *device, unsigned uid, unsigned gid, unsigned mode) 3376{ 3377 int why; 3378 3379 TRACE_IDS; 3380 TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n", 3381 device, (int) uid, (int) gid, (unsigned) mode)); 3382 3383 if (chown(device, (uid_t) uid, (gid_t) gid) < 0) { 3384 why = errno; 3385 if (why != ENOENT 3386 && save_ruid == 0) { 3387 xtermPerror("Cannot chown %s to %ld,%ld", 3388 device, (long) uid, (long) gid); 3389 } 3390 TRACE(("...chown failed: %s\n", strerror(why))); 3391 } else if (chmod(device, (mode_t) mode) < 0) { 3392 why = errno; 3393 if (why != ENOENT) { 3394 struct stat sb; 3395 if (stat(device, &sb) < 0) { 3396 xtermPerror("Cannot chmod %s to %03o", 3397 device, (unsigned) mode); 3398 } else if (mode != (sb.st_mode & 0777U)) { 3399 xtermPerror("Cannot chmod %s to %03lo currently %03lo", 3400 device, 3401 (unsigned long) mode, 3402 (unsigned long) (sb.st_mode & 0777U)); 3403 TRACE(("...stat uid=%d, gid=%d, mode=%#o\n", 3404 (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode)); 3405 } 3406 } 3407 TRACE(("...chmod failed: %s\n", strerror(why))); 3408 } 3409} 3410 3411/* 3412 * utmp data may not be null-terminated; even if it is, there may be garbage 3413 * after the null. This fills the unused part of the result with nulls. 3414 */ 3415static void 3416copy_filled(char *target, const char *source, size_t len) 3417{ 3418 size_t used = 0; 3419 while (used < len) { 3420 if ((target[used] = source[used]) == 0) 3421 break; 3422 ++used; 3423 } 3424 while (used < len) { 3425 target[used++] = '\0'; 3426 } 3427} 3428 3429#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER) 3430/* 3431 * getutid() only looks at ut_type and ut_id. 3432 * But we'll also check ut_line in find_utmp(). 3433 */ 3434static void 3435init_utmp(int type, struct UTMP_STR *tofind) 3436{ 3437 memset(tofind, 0, sizeof(*tofind)); 3438 tofind->ut_type = (short) type; 3439 copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id)); 3440 copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line)); 3441} 3442 3443/* 3444 * We could use getutline() if we didn't support old systems. 3445 */ 3446static struct UTMP_STR * 3447find_utmp(struct UTMP_STR *tofind) 3448{ 3449 struct UTMP_STR *result; 3450 struct UTMP_STR limited; 3451 struct UTMP_STR working; 3452 3453 for (;;) { 3454 memset(&working, 0, sizeof(working)); 3455 working.ut_type = tofind->ut_type; 3456 copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id)); 3457#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5) 3458 working.ut_type = 0; 3459#endif 3460 if ((result = call_getutid(&working)) == 0) 3461 break; 3462 copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line)); 3463 if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line))) 3464 break; 3465 /* 3466 * Solaris, IRIX64 and HPUX manpages say to fill the static area 3467 * pointed to by the return-value to zeros if searching for multiple 3468 * occurrences. Otherwise it will continue to return the same value. 3469 */ 3470 memset(result, 0, sizeof(*result)); 3471 } 3472 return result; 3473} 3474#endif /* HAVE_UTMP... */ 3475 3476#define close_fd(fd) close(fd), fd = -1 3477 3478#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) 3479#define USE_NO_DEV_TTY 1 3480#else 3481#define USE_NO_DEV_TTY 0 3482#endif 3483 3484static int 3485same_leaf(char *a, char *b) 3486{ 3487 char *p = x_basename(a); 3488 char *q = x_basename(b); 3489 return !strcmp(p, q); 3490} 3491 3492/* 3493 * "good enough" (inode wouldn't port to Cygwin) 3494 */ 3495static int 3496same_file(const char *a, const char *b) 3497{ 3498 struct stat asb; 3499 struct stat bsb; 3500 int result = 0; 3501 3502 if ((stat(a, &asb) == 0) 3503 && (stat(b, &bsb) == 0) 3504 && ((asb.st_mode & S_IFMT) == S_IFREG) 3505 && ((bsb.st_mode & S_IFMT) == S_IFREG) 3506 && (asb.st_mtime == bsb.st_mtime) 3507 && (asb.st_size == bsb.st_size)) { 3508 result = 1; 3509 } 3510 return result; 3511} 3512 3513static int 3514findValidShell(const char *haystack, const char *needle) 3515{ 3516 int result = -1; 3517 int count = -1; 3518 const char *s, *t; 3519 size_t have; 3520 size_t want = strlen(needle); 3521 3522 TRACE(("findValidShell:\n%s\n", NonNull(haystack))); 3523 3524 for (s = haystack; (s != 0) && (*s != '\0'); s = t) { 3525 ++count; 3526 if ((t = strchr(s, '\n')) == 0) { 3527 t = s + strlen(s); 3528 } 3529 have = (size_t) (t - s); 3530 3531 if ((have >= want) && (*s != '#')) { 3532 char *p = malloc(have + 1); 3533 3534 if (p != 0) { 3535 char *q; 3536 3537 memcpy(p, s, have); 3538 p[have] = '\0'; 3539 if ((q = x_strtrim(p)) != 0) { 3540 TRACE(("...test %s\n", q)); 3541 if (!strcmp(q, needle)) { 3542 result = count; 3543 } else if (same_leaf(q, (char *) needle) && 3544 same_file(q, needle)) { 3545 result = count; 3546 } 3547 free(q); 3548 } 3549 free(p); 3550 } 3551 if (result >= 0) 3552 break; 3553 } 3554 while (*t == '\n') { 3555 ++t; 3556 } 3557 } 3558 return result; 3559} 3560 3561static int 3562ourValidShell(const char *pathname) 3563{ 3564 return findValidShell(x_strtrim(resource.valid_shells), pathname); 3565} 3566 3567#if defined(HAVE_GETUSERSHELL) && defined(HAVE_ENDUSERSHELL) 3568static Boolean 3569validShell(const char *pathname) 3570{ 3571 int result = -1; 3572 3573 if (validProgram(pathname)) { 3574 char *q; 3575 int count = -1; 3576 3577 TRACE(("validShell:getusershell\n")); 3578 while ((q = getusershell()) != 0) { 3579 ++count; 3580 TRACE(("...test \"%s\"\n", q)); 3581 if (!strcmp(q, pathname)) { 3582 result = count; 3583 break; 3584 } 3585 } 3586 endusershell(); 3587 3588 if (result < 0) 3589 result = ourValidShell(pathname); 3590 } 3591 3592 TRACE(("validShell %s ->%d\n", NonNull(pathname), result)); 3593 return (result >= 0); 3594} 3595#else 3596/* 3597 * Only set $SHELL for paths found in the standard location. 3598 */ 3599static Boolean 3600validShell(const char *pathname) 3601{ 3602 int result = -1; 3603 const char *ok_shells = "/etc/shells"; 3604 char *blob; 3605 struct stat sb; 3606 size_t rc; 3607 FILE *fp; 3608 3609 if (validProgram(pathname)) { 3610 3611 TRACE(("validShell:%s\n", ok_shells)); 3612 3613 if (stat(ok_shells, &sb) == 0 3614 && (sb.st_mode & S_IFMT) == S_IFREG 3615 && ((size_t) sb.st_size > 0) 3616 && ((size_t) sb.st_size < (((size_t) ~0) - 2)) 3617 && (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) { 3618 3619 if ((fp = fopen(ok_shells, "r")) != 0) { 3620 rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp); 3621 fclose(fp); 3622 3623 if (rc == (size_t) sb.st_size) { 3624 blob[rc] = '\0'; 3625 result = findValidShell(blob, pathname); 3626 } 3627 } 3628 free(blob); 3629 } 3630 if (result < 0) 3631 result = ourValidShell(pathname); 3632 } 3633 TRACE(("validShell %s ->%d\n", NonNull(pathname), result)); 3634 return (result > 0); 3635} 3636#endif 3637 3638static char * 3639resetShell(char *oldPath) 3640{ 3641 char *newPath = x_strdup("/bin/sh"); 3642 char *envPath = getenv("SHELL"); 3643 free(oldPath); 3644 if (!IsEmpty(envPath)) 3645 xtermSetenv("SHELL", newPath); 3646 return newPath; 3647} 3648 3649/* 3650 * Inits pty and tty and forks a login process. 3651 * Does not close fd Xsocket. 3652 * If slave, the pty named in passedPty is already open for use 3653 */ 3654static int 3655spawnXTerm(XtermWidget xw, unsigned line_speed) 3656{ 3657 TScreen *screen = TScreenOf(xw); 3658 Cardinal nn; 3659#if OPT_PTY_HANDSHAKE 3660 Bool got_handshake_size = False; 3661 handshake_t handshake; 3662 int done; 3663#endif 3664#if OPT_INITIAL_ERASE 3665 int initial_erase = VAL_INITIAL_ERASE; 3666 Bool setInitialErase; 3667#endif 3668 int rc = 0; 3669 int ttyfd = -1; 3670 Bool ok_termcap; 3671 char *newtc; 3672 3673#ifdef TERMIO_STRUCT 3674 TERMIO_STRUCT tio; 3675#ifdef __MVS__ 3676 TERMIO_STRUCT gio; 3677#endif /* __MVS__ */ 3678#ifdef TIOCLSET 3679 unsigned lmode; 3680#endif /* TIOCLSET */ 3681#ifdef HAS_LTCHARS 3682 struct ltchars ltc; 3683#endif /* HAS_LTCHARS */ 3684#else /* !TERMIO_STRUCT */ 3685 int ldisc = 0; 3686 int discipline; 3687 unsigned lmode; 3688 struct tchars tc; 3689 struct ltchars ltc; 3690 struct sgttyb sg; 3691#ifdef sony 3692 int jmode; 3693 struct jtchars jtc; 3694#endif /* sony */ 3695#endif /* TERMIO_STRUCT */ 3696 3697 char *shell_path = 0; 3698 char *shname, *shname_minus; 3699 int i; 3700#if USE_NO_DEV_TTY 3701 int no_dev_tty = False; 3702#endif 3703 const char *const *envnew; /* new environment */ 3704 char buf[64]; 3705 char *TermName = NULL; 3706#ifdef TTYSIZE_STRUCT 3707 TTYSIZE_STRUCT ts; 3708#endif 3709 struct passwd pw; 3710 char *login_name = NULL; 3711#ifndef USE_UTEMPTER 3712#ifdef HAVE_UTMP 3713 struct UTMP_STR utmp; 3714#ifdef USE_SYSV_UTMP 3715 struct UTMP_STR *utret = NULL; 3716#endif 3717#ifdef USE_LASTLOG 3718 struct lastlog lastlog; 3719#endif 3720#ifdef USE_LASTLOGX 3721 struct lastlogx lastlogx; 3722#endif /* USE_LASTLOG */ 3723#endif /* HAVE_UTMP */ 3724#endif /* !USE_UTEMPTER */ 3725 3726#if OPT_TRACE 3727 unsigned long xterm_parent = (unsigned long) getpid(); 3728#endif 3729 3730 /* Noisy compilers (suppress some unused-variable warnings) */ 3731 (void) rc; 3732#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER) 3733 (void) utret; 3734#endif 3735 3736 screen->uid = save_ruid; 3737 screen->gid = save_rgid; 3738 3739#ifdef SIGTTOU 3740 /* so that TIOCSWINSZ || TIOCSIZE doesn't block */ 3741 signal(SIGTTOU, SIG_IGN); 3742#endif 3743 3744#if OPT_PTY_HANDSHAKE 3745 memset(&handshake, 0, sizeof(handshake)); 3746#endif 3747 3748 if (am_slave >= 0) { 3749 screen->respond = am_slave; 3750 set_pty_id(ttydev, passedPty); 3751#ifdef USE_PTY_DEVICE 3752 set_pty_id(ptydev, passedPty); 3753#endif 3754 if (xtermResetIds(screen) < 0) 3755 exit(1); 3756 } else { 3757 Bool tty_got_hung; 3758 3759 /* 3760 * Sometimes /dev/tty hangs on open (as in the case of a pty 3761 * that has gone away). Simply make up some reasonable 3762 * defaults. 3763 */ 3764 3765 if (!sigsetjmp(env, 1)) { 3766 signal(SIGALRM, hungtty); 3767 alarm(2); /* alarm(1) might return too soon */ 3768 ttyfd = open("/dev/tty", O_RDWR); 3769 alarm(0); 3770 tty_got_hung = False; 3771 } else { 3772 tty_got_hung = True; 3773 ttyfd = -1; 3774 errno = ENXIO; 3775 } 3776 shell_path = 0; 3777 memset(&pw, 0, sizeof(pw)); 3778#if OPT_PTY_HANDSHAKE 3779 got_handshake_size = False; 3780#endif /* OPT_PTY_HANDSHAKE */ 3781#if OPT_INITIAL_ERASE 3782 initial_erase = VAL_INITIAL_ERASE; 3783#endif 3784 signal(SIGALRM, SIG_DFL); 3785 3786 /* 3787 * Check results and ignore current control terminal if 3788 * necessary. ENXIO is what is normally returned if there is 3789 * no controlling terminal, but some systems (e.g. SunOS 4.0) 3790 * seem to return EIO. Solaris 2.3 is said to return EINVAL. 3791 * Cygwin returns ENOENT. FreeBSD can return ENOENT, especially 3792 * if xterm is run within a jail. 3793 */ 3794#if USE_NO_DEV_TTY 3795 no_dev_tty = False; 3796#endif 3797 if (ttyfd < 0) { 3798 if (tty_got_hung || errno == ENXIO || errno == EIO || 3799 errno == ENOENT || 3800#ifdef ENODEV 3801 errno == ENODEV || 3802#endif 3803 errno == EINVAL || errno == ENOTTY || errno == EACCES) { 3804#if USE_NO_DEV_TTY 3805 no_dev_tty = True; 3806#endif 3807#ifdef HAS_LTCHARS 3808 ltc = d_ltc; 3809#endif /* HAS_LTCHARS */ 3810#ifdef TIOCLSET 3811 lmode = d_lmode; 3812#endif /* TIOCLSET */ 3813#ifdef TERMIO_STRUCT 3814 tio = d_tio; 3815#else /* !TERMIO_STRUCT */ 3816 sg = d_sg; 3817 tc = d_tc; 3818 discipline = d_disipline; 3819#ifdef sony 3820 jmode = d_jmode; 3821 jtc = d_jtc; 3822#endif /* sony */ 3823#endif /* TERMIO_STRUCT */ 3824 } else { 3825 SysError(ERROR_OPDEVTTY); 3826 } 3827 } else { 3828 3829 /* Get a copy of the current terminal's state, 3830 * if we can. Some systems (e.g., SVR4 and MacII) 3831 * may not have a controlling terminal at this point 3832 * if started directly from xdm or xinit, 3833 * in which case we just use the defaults as above. 3834 */ 3835#ifdef HAS_LTCHARS 3836 if (ioctl(ttyfd, TIOCGLTC, <c) == -1) 3837 ltc = d_ltc; 3838#endif /* HAS_LTCHARS */ 3839#ifdef TIOCLSET 3840 if (ioctl(ttyfd, TIOCLGET, &lmode) == -1) 3841 lmode = d_lmode; 3842#endif /* TIOCLSET */ 3843#ifdef TERMIO_STRUCT 3844 rc = ttyGetAttr(ttyfd, &tio); 3845 if (rc == -1) 3846 tio = d_tio; 3847#else /* !TERMIO_STRUCT */ 3848 rc = ioctl(ttyfd, TIOCGETP, (char *) &sg); 3849 if (rc == -1) 3850 sg = d_sg; 3851 if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1) 3852 tc = d_tc; 3853 if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1) 3854 discipline = d_disipline; 3855#ifdef sony 3856 if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1) 3857 jmode = d_jmode; 3858 if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1) 3859 jtc = d_jtc; 3860#endif /* sony */ 3861#endif /* TERMIO_STRUCT */ 3862 3863 /* 3864 * If ptyInitialErase is set, we want to get the pty's 3865 * erase value. Just in case that will fail, first get 3866 * the value from /dev/tty, so we will have something 3867 * at least. 3868 */ 3869#if OPT_INITIAL_ERASE 3870 if (resource.ptyInitialErase) { 3871#ifdef TERMIO_STRUCT 3872 initial_erase = tio.c_cc[VERASE]; 3873#else /* !TERMIO_STRUCT */ 3874 initial_erase = sg.sg_erase; 3875#endif /* TERMIO_STRUCT */ 3876 TRACE(("%s initial_erase:%d (from /dev/tty)\n", 3877 rc == 0 ? "OK" : "FAIL", 3878 initial_erase)); 3879 } 3880#endif 3881#ifdef __MVS__ 3882 if (ttyGetAttr(ttyfd, &gio) == 0) { 3883 gio.c_cflag &= ~(HUPCL | PARENB); 3884 ttySetAttr(ttyfd, &gio); 3885 } 3886#endif /* __MVS__ */ 3887 3888 close_fd(ttyfd); 3889 } 3890 3891 if (get_pty(&screen->respond, XDisplayString(screen->display))) { 3892 SysError(ERROR_PTYS); 3893 } 3894 TRACE_GET_TTYSIZE(screen->respond, "after get_pty"); 3895#if OPT_INITIAL_ERASE 3896 if (resource.ptyInitialErase) { 3897#ifdef TERMIO_STRUCT 3898 TERMIO_STRUCT my_tio; 3899 rc = ttyGetAttr(screen->respond, &my_tio); 3900 if (rc == 0) 3901 initial_erase = my_tio.c_cc[VERASE]; 3902#else /* !TERMIO_STRUCT */ 3903 struct sgttyb my_sg; 3904 rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg); 3905 if (rc == 0) 3906 initial_erase = my_sg.sg_erase; 3907#endif /* TERMIO_STRUCT */ 3908 TRACE(("%s initial_erase:%d (from pty)\n", 3909 (rc == 0) ? "OK" : "FAIL", 3910 initial_erase)); 3911 } 3912#endif /* OPT_INITIAL_ERASE */ 3913 } 3914 3915 /* avoid double MapWindow requests */ 3916 XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False); 3917 3918 wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", 3919 False); 3920 3921 if (!TEK4014_ACTIVE(xw)) 3922 VTInit(xw); /* realize now so know window size for tty driver */ 3923#if defined(TIOCCONS) || defined(SRIOCSREDIR) 3924 if (Console) { 3925 /* 3926 * Inform any running xconsole program 3927 * that we are going to steal the console. 3928 */ 3929 XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255); 3930 mit_console = XInternAtom(screen->display, mit_console_name, False); 3931 /* the user told us to be the console, so we can use CurrentTime */ 3932 XtOwnSelection(SHELL_OF(CURRENT_EMU()), 3933 mit_console, CurrentTime, 3934 ConvertConsoleSelection, NULL, NULL); 3935 } 3936#endif 3937#if OPT_TEK4014 3938 if (TEK4014_ACTIVE(xw)) { 3939 envnew = tekterm; 3940 } else 3941#endif 3942 { 3943 envnew = vtterm; 3944 } 3945 3946 /* 3947 * This used to exit if no termcap entry was found for the specified 3948 * terminal name. That's a little unfriendly, so instead we'll allow 3949 * the program to proceed (but not to set $TERMCAP) if the termcap 3950 * entry is not found. 3951 */ 3952 ok_termcap = True; 3953 if (!get_termcap(xw, TermName = resource.term_name)) { 3954 const char *last = NULL; 3955 char *next; 3956 3957 TermName = x_strdup(*envnew); 3958 ok_termcap = False; 3959 while (*envnew != NULL) { 3960 if (last == NULL || strcmp(last, *envnew)) { 3961 next = x_strdup(*envnew); 3962 if (get_termcap(xw, next)) { 3963 free(TermName); 3964 TermName = next; 3965 ok_termcap = True + 1; 3966 break; 3967 } else { 3968 free(next); 3969 } 3970 } 3971 last = *envnew; 3972 envnew++; 3973 } 3974 } 3975 if (ok_termcap) { 3976 resource.term_name = x_strdup(TermName); 3977 resize_termcap(xw); 3978 } 3979 3980 /* 3981 * Check if ptyInitialErase is not set. If so, we rely on the termcap 3982 * (or terminfo) to tell us what the erase mode should be set to. 3983 */ 3984#if OPT_INITIAL_ERASE 3985 TRACE(("resource ptyInitialErase is %sset\n", 3986 resource.ptyInitialErase ? "" : "not ")); 3987 setInitialErase = False; 3988 if (override_tty_modes && ttyModes[XTTYMODE_erase].set) { 3989 initial_erase = ttyModes[XTTYMODE_erase].value; 3990 setInitialErase = True; 3991 } else if (resource.ptyInitialErase) { 3992 /* EMPTY */ ; 3993 } else if (ok_termcap) { 3994 char *s = get_tcap_erase(xw); 3995 TRACE(("...extracting initial_erase value from termcap\n")); 3996 if (s != 0) { 3997 char *save = s; 3998 initial_erase = decode_keyvalue(&s, True); 3999 setInitialErase = True; 4000 free(save); 4001 } 4002 } 4003 TRACE(("...initial_erase:%d\n", initial_erase)); 4004 4005 TRACE(("resource backarrowKeyIsErase is %sset\n", 4006 resource.backarrow_is_erase ? "" : "not ")); 4007 if (resource.backarrow_is_erase) { /* see input.c */ 4008 if (initial_erase == ANSI_DEL) { 4009 UIntClr(xw->keyboard.flags, MODE_DECBKM); 4010 } else { 4011 xw->keyboard.flags |= MODE_DECBKM; 4012 xw->keyboard.reset_DECBKM = 1; 4013 } 4014 TRACE(("...sets DECBKM %s\n", 4015 (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off")); 4016 } else { 4017 xw->keyboard.reset_DECBKM = 2; 4018 } 4019#endif /* OPT_INITIAL_ERASE */ 4020 4021#ifdef TTYSIZE_STRUCT 4022 /* tell tty how big window is */ 4023#if OPT_TEK4014 4024 if (TEK4014_ACTIVE(xw)) { 4025 setup_winsize(ts, TDefaultRows, TDefaultCols, 4026 TFullHeight(TekScreenOf(tekWidget)), 4027 TFullWidth(TekScreenOf(tekWidget))); 4028 } else 4029#endif 4030 { 4031 setup_winsize(ts, MaxRows(screen), MaxCols(screen), 4032 FullHeight(screen), FullWidth(screen)); 4033 } 4034 TRACE_RC(i, SET_TTYSIZE(screen->respond, ts)); 4035 TRACE(("spawn SET_TTYSIZE %dx%d return %d\n", 4036 TTYSIZE_ROWS(ts), 4037 TTYSIZE_COLS(ts), i)); 4038#endif /* TTYSIZE_STRUCT */ 4039 4040#if !defined(USE_OPENPTY) 4041#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT) 4042 /* 4043 * utempter checks the ownership of the device; some implementations 4044 * set ownership in grantpt - do this first. 4045 */ 4046 grantpt(screen->respond); 4047#endif 4048#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT) 4049 unlockpt(screen->respond); 4050 TRACE_GET_TTYSIZE(screen->respond, "after unlockpt"); 4051#endif 4052#endif /* !USE_OPENPTY */ 4053 4054 added_utmp_entry = False; 4055#if defined(USE_UTEMPTER) 4056#undef UTMP 4057 if ((xw->misc.login_shell || !command_to_exec) && !resource.utmpInhibit) { 4058 struct UTMP_STR dummy; 4059 4060 /* Note: utempter may trim it anyway */ 4061 SetUtmpHost(dummy.ut_host, screen); 4062 TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n", 4063 ttydev, dummy.ut_host, screen->respond)); 4064 UTEMPTER_ADD(ttydev, dummy.ut_host, screen->respond); 4065 added_utmp_entry = True; 4066 } 4067#endif 4068 4069 if (am_slave < 0) { 4070#if OPT_PTY_HANDSHAKE 4071 if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe))) 4072 SysError(ERROR_FORK); 4073#endif 4074 TRACE(("Forking...\n")); 4075 if ((screen->pid = fork()) == -1) 4076 SysError(ERROR_FORK); 4077 4078 if (screen->pid == 0) { 4079#ifdef USE_USG_PTYS 4080 int ptyfd = -1; 4081 char *pty_name; 4082#endif 4083 /* 4084 * now in child process 4085 */ 4086#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__) 4087 int pgrp = setsid(); /* variable may not be used... */ 4088#else 4089 int pgrp = getpid(); 4090#endif 4091 TRACE_CHILD 4092 4093#ifdef USE_USG_PTYS 4094#ifdef HAVE_SETPGID 4095 setpgid(0, 0); 4096#else 4097 setpgrp(); 4098#endif 4099 unlockpt(screen->respond); 4100 TRACE_GET_TTYSIZE(screen->respond, "after unlockpt"); 4101 if ((pty_name = ptsname(screen->respond)) == 0) { 4102 SysError(ERROR_PTSNAME); 4103 } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) { 4104 SysError(ERROR_OPPTSNAME); 4105 } 4106#ifdef I_PUSH 4107 else if (PUSH_FAILS(ptyfd, "ptem")) { 4108 SysError(ERROR_PTEM); 4109 } 4110#if !defined(SVR4) && !(defined(SYSV) && defined(i386)) 4111 else if (!x_getenv("CONSEM") 4112 && PUSH_FAILS(ptyfd, "consem")) { 4113 SysError(ERROR_CONSEM); 4114 } 4115#endif /* !SVR4 */ 4116 else if (PUSH_FAILS(ptyfd, "ldterm")) { 4117 SysError(ERROR_LDTERM); 4118 } 4119#ifdef SVR4 /* from Sony */ 4120 else if (PUSH_FAILS(ptyfd, "ttcompat")) { 4121 SysError(ERROR_TTCOMPAT); 4122 } 4123#endif /* SVR4 */ 4124#endif /* I_PUSH */ 4125 ttyfd = ptyfd; 4126#ifndef __MVS__ 4127 close_fd(screen->respond); 4128#endif /* __MVS__ */ 4129 4130#ifdef TTYSIZE_STRUCT 4131 /* tell tty how big window is */ 4132#if OPT_TEK4014 4133 if (TEK4014_ACTIVE(xw)) { 4134 setup_winsize(ts, TDefaultRows, TDefaultCols, 4135 TFullHeight(TekScreenOf(tekWidget)), 4136 TFullWidth(TekScreenOf(tekWidget))); 4137 } else 4138#endif /* OPT_TEK4014 */ 4139 { 4140 setup_winsize(ts, MaxRows(screen), MaxCols(screen), 4141 FullHeight(screen), FullWidth(screen)); 4142 } 4143 trace_winsize(ts, "initial tty size"); 4144#endif /* TTYSIZE_STRUCT */ 4145 4146#endif /* USE_USG_PTYS */ 4147 4148 (void) pgrp; /* not all branches use this variable */ 4149 4150#if OPT_PTY_HANDSHAKE /* warning, goes for a long ways */ 4151 if (resource.ptyHandshake) { 4152 char *ptr; 4153 4154 /* close parent's sides of the pipes */ 4155 close(cp_pipe[0]); 4156 close(pc_pipe[1]); 4157 4158 /* Make sure that our sides of the pipes are not in the 4159 * 0, 1, 2 range so that we don't fight with stdin, out 4160 * or err. 4161 */ 4162 if (cp_pipe[1] <= 2) { 4163 if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) { 4164 IGNORE_RC(close(cp_pipe[1])); 4165 cp_pipe[1] = i; 4166 } 4167 } 4168 if (pc_pipe[0] <= 2) { 4169 if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) { 4170 IGNORE_RC(close(pc_pipe[0])); 4171 pc_pipe[0] = i; 4172 } 4173 } 4174 4175 /* we don't need the socket, or the pty master anymore */ 4176 close(ConnectionNumber(screen->display)); 4177#ifndef __MVS__ 4178 if (screen->respond >= 0) 4179 close(screen->respond); 4180#endif /* __MVS__ */ 4181 4182 /* Now is the time to set up our process group and 4183 * open up the pty slave. 4184 */ 4185#ifdef USE_SYSV_PGRP 4186#if defined(CRAY) && (OSMAJORVERSION > 5) 4187 IGNORE_RC(setsid()); 4188#else 4189 IGNORE_RC(setpgrp()); 4190#endif 4191#endif /* USE_SYSV_PGRP */ 4192 4193#if defined(__QNX__) && !defined(__QNXNTO__) 4194 qsetlogin(getlogin(), ttydev); 4195#endif 4196 if (ttyfd >= 0) { 4197#ifdef __MVS__ 4198 if (ttyGetAttr(ttyfd, &gio) == 0) { 4199 gio.c_cflag &= ~(HUPCL | PARENB); 4200 ttySetAttr(ttyfd, &gio); 4201 } 4202#else /* !__MVS__ */ 4203 close_fd(ttyfd); 4204#endif /* __MVS__ */ 4205 } 4206 4207 for (;;) { 4208#if USE_NO_DEV_TTY 4209 if (!no_dev_tty 4210 && (ttyfd = open("/dev/tty", O_RDWR)) >= 0) { 4211 ioctl(ttyfd, TIOCNOTTY, (char *) NULL); 4212 close_fd(ttyfd); 4213 } 4214#endif /* USE_NO_DEV_TTY */ 4215#ifdef CSRG_BASED 4216 IGNORE_RC(revoke(ttydev)); 4217#endif 4218 if ((ttyfd = open(ttydev, O_RDWR)) >= 0) { 4219 TRACE_GET_TTYSIZE(ttyfd, "after open"); 4220 TRACE_RC(i, SET_TTYSIZE(ttyfd, ts)); 4221 TRACE_GET_TTYSIZE(ttyfd, "after SET_TTYSIZE fixup"); 4222#if defined(CRAY) && defined(TCSETCTTY) 4223 /* make /dev/tty work */ 4224 ioctl(ttyfd, TCSETCTTY, 0); 4225#endif 4226#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY) 4227 /* make /dev/tty work */ 4228 ioctl(ttyfd, TIOCSCTTY, 0); 4229#endif 4230#ifdef USE_SYSV_PGRP 4231 /* We need to make sure that we are actually 4232 * the process group leader for the pty. If 4233 * we are, then we should now be able to open 4234 * /dev/tty. 4235 */ 4236 if ((i = open("/dev/tty", O_RDWR)) >= 0) { 4237 /* success! */ 4238 close(i); 4239 break; 4240 } 4241#else /* USE_SYSV_PGRP */ 4242 break; 4243#endif /* USE_SYSV_PGRP */ 4244 } 4245 perror("open ttydev"); 4246#ifdef TIOCSCTTY 4247 ioctl(ttyfd, TIOCSCTTY, 0); 4248#endif 4249 /* let our master know that the open failed */ 4250 handshake.status = PTY_BAD; 4251 handshake.error = errno; 4252 copy_handshake(handshake, ttydev); 4253 TRACE_HANDSHAKE("writing", &handshake); 4254 IGNORE_RC(write(cp_pipe[1], 4255 (const char *) &handshake, 4256 sizeof(handshake))); 4257 4258 /* get reply from parent */ 4259 i = (int) read(pc_pipe[0], (char *) &handshake, 4260 sizeof(handshake)); 4261 if (i <= 0) { 4262 /* parent terminated */ 4263 exit(1); 4264 } 4265 4266 if (handshake.status == PTY_NOMORE) { 4267 /* No more ptys, let's shutdown. */ 4268 exit(1); 4269 } 4270 4271 /* We have a new pty to try */ 4272 if (ttyfd >= 0) 4273 close(ttyfd); 4274 free(ttydev); 4275 handshake.buffer[HANDSHAKE_LEN - 1] = '\0'; 4276 ttydev = x_strdup(handshake.buffer); 4277 } 4278 4279 /* use the same tty name that everyone else will use 4280 * (from ttyname) 4281 */ 4282 if ((ptr = ttyname(ttyfd)) != 0) { 4283 free(ttydev); 4284 ttydev = x_strdup(ptr); 4285 } 4286 } 4287#endif /* OPT_PTY_HANDSHAKE -- from near fork */ 4288 4289 set_pty_permissions(screen->uid, 4290 (unsigned) screen->gid, 4291 (resource.messages 4292 ? 0622U 4293 : 0600U)); 4294 4295 /* 4296 * set up the tty modes 4297 */ 4298 { 4299#ifdef TERMIO_STRUCT 4300#if defined(umips) || defined(CRAY) || defined(linux) 4301 /* If the control tty had its modes screwed around with, 4302 eg. by lineedit in the shell, or emacs, etc. then tio 4303 will have bad values. Let's just get termio from the 4304 new tty and tailor it. */ 4305 if (ttyGetAttr(ttyfd, &tio) == -1) 4306 SysError(ERROR_TIOCGETP); 4307 tio.c_lflag |= ECHOE; 4308#endif /* umips */ 4309 /* Now is also the time to change the modes of the 4310 * child pty. 4311 */ 4312 /* input: nl->nl, don't ignore cr, cr->nl */ 4313 UIntClr(tio.c_iflag, (INLCR | IGNCR)); 4314 tio.c_iflag |= ICRNL; 4315#if OPT_WIDE_CHARS && defined(IUTF8) 4316#if OPT_LUIT_PROG 4317 if (command_to_exec_with_luit == 0) 4318#endif 4319 if (screen->utf8_mode) 4320 tio.c_iflag |= IUTF8; 4321#endif 4322 /* output: cr->cr, nl is not return, no delays, ln->cr/nl */ 4323#ifndef USE_POSIX_TERMIOS 4324 UIntClr(tio.c_oflag, 4325 (OCRNL 4326 | ONLRET 4327 | NLDLY 4328 | CRDLY 4329 | TABDLY 4330 | BSDLY 4331 | VTDLY 4332 | FFDLY)); 4333#endif /* USE_POSIX_TERMIOS */ 4334 tio.c_oflag |= D_TIO_FLAGS; 4335#ifndef USE_POSIX_TERMIOS 4336# if defined(Lynx) && !defined(CBAUD) 4337# define CBAUD V_CBAUD 4338# endif 4339 UIntClr(tio.c_cflag, CBAUD); 4340#ifdef BAUD_0 4341 /* baud rate is 0 (don't care) */ 4342#elif defined(HAVE_TERMIO_C_ISPEED) 4343 tio.c_ispeed = tio.c_ospeed = line_speed; 4344#else /* !BAUD_0 */ 4345 tio.c_cflag |= line_speed; 4346#endif /* !BAUD_0 */ 4347#else /* USE_POSIX_TERMIOS */ 4348 cfsetispeed(&tio, line_speed); 4349 cfsetospeed(&tio, line_speed); 4350#ifdef __MVS__ 4351 /* turn off bits that can't be set from the slave side */ 4352 tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND); 4353#endif /* __MVS__ */ 4354 /* Clear CLOCAL so that SIGHUP is sent to us 4355 when the xterm ends */ 4356 tio.c_cflag &= (unsigned) ~CLOCAL; 4357#endif /* USE_POSIX_TERMIOS */ 4358 /* enable signals, canonical processing (erase, kill, etc), 4359 * echo 4360 */ 4361 tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK; 4362#ifdef ECHOKE 4363 tio.c_lflag |= ECHOKE | IEXTEN; 4364#endif 4365#ifdef ECHOCTL 4366 tio.c_lflag |= ECHOCTL | IEXTEN; 4367#endif 4368 for (nn = 0; nn < XtNumber(ttyChars); ++nn) { 4369 if (validTtyChar(tio, nn)) { 4370 int sysMode = ttyChars[nn].sysMode; 4371#ifdef __MVS__ 4372 if (tio.c_cc[sysMode] != 0) { 4373 switch (sysMode) { 4374 case VEOL: 4375 case VEOF: 4376 continue; 4377 } 4378 } 4379#endif 4380 tio.c_cc[sysMode] = (cc_t) ttyChars[nn].myDefault; 4381 } 4382 } 4383 4384 if (override_tty_modes) { 4385 TRACE(("applying termios ttyModes\n")); 4386 for (nn = 0; nn < XtNumber(ttyChars); ++nn) { 4387 if (validTtyChar(tio, nn)) { 4388 TMODE(ttyChars[nn].myMode, 4389 tio.c_cc[ttyChars[nn].sysMode]); 4390 } else if (isTabMode(nn)) { 4391 unsigned tmp = (unsigned) tio.c_oflag; 4392 tmp = tmp & (unsigned) ~TABDLY; 4393 tmp |= (unsigned) ttyModes[ttyChars[nn].myMode].value; 4394 tio.c_oflag = tmp; 4395 } 4396 } 4397#ifdef HAS_LTCHARS 4398 /* both SYSV and BSD have ltchars */ 4399 TMODE(XTTYMODE_susp, ltc.t_suspc); 4400 TMODE(XTTYMODE_dsusp, ltc.t_dsuspc); 4401 TMODE(XTTYMODE_rprnt, ltc.t_rprntc); 4402 TMODE(XTTYMODE_flush, ltc.t_flushc); 4403 TMODE(XTTYMODE_weras, ltc.t_werasc); 4404 TMODE(XTTYMODE_lnext, ltc.t_lnextc); 4405#endif 4406 } 4407#ifdef HAS_LTCHARS 4408#ifdef __hpux 4409 /* ioctl chokes when the "reserved" process group controls 4410 * are not set to _POSIX_VDISABLE */ 4411 ltc.t_rprntc = _POSIX_VDISABLE; 4412 ltc.t_rprntc = _POSIX_VDISABLE; 4413 ltc.t_flushc = _POSIX_VDISABLE; 4414 ltc.t_werasc = _POSIX_VDISABLE; 4415 ltc.t_lnextc = _POSIX_VDISABLE; 4416#endif /* __hpux */ 4417 if (ioctl(ttyfd, TIOCSLTC, <c) == -1) 4418 HsSysError(ERROR_TIOCSETC); 4419#endif /* HAS_LTCHARS */ 4420#ifdef TIOCLSET 4421 if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1) 4422 HsSysError(ERROR_TIOCLSET); 4423#endif /* TIOCLSET */ 4424 if (ttySetAttr(ttyfd, &tio) == -1) 4425 HsSysError(ERROR_TIOCSETP); 4426 4427 /* ignore errors here - some platforms don't work */ 4428 UIntClr(tio.c_cflag, CSIZE); 4429 if (screen->input_eight_bits) 4430 tio.c_cflag |= CS8; 4431 else 4432 tio.c_cflag |= CS7; 4433 (void) ttySetAttr(ttyfd, &tio); 4434 4435#else /* !TERMIO_STRUCT */ 4436 sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW); 4437 sg.sg_flags |= ECHO | CRMOD; 4438 /* make sure speed is set on pty so that editors work right */ 4439 sg.sg_ispeed = line_speed; 4440 sg.sg_ospeed = line_speed; 4441 /* reset t_brkc to default value */ 4442 tc.t_brkc = -1; 4443#ifdef LPASS8 4444 if (screen->input_eight_bits) 4445 lmode |= LPASS8; 4446 else 4447 lmode &= ~(LPASS8); 4448#endif 4449#ifdef sony 4450 jmode &= ~KM_KANJI; 4451#endif /* sony */ 4452 4453 ltc = d_ltc; 4454 4455 if (override_tty_modes) { 4456 TRACE(("applying sgtty ttyModes\n")); 4457 TMODE(XTTYMODE_intr, tc.t_intrc); 4458 TMODE(XTTYMODE_quit, tc.t_quitc); 4459 TMODE(XTTYMODE_erase, sg.sg_erase); 4460 TMODE(XTTYMODE_kill, sg.sg_kill); 4461 TMODE(XTTYMODE_eof, tc.t_eofc); 4462 TMODE(XTTYMODE_start, tc.t_startc); 4463 TMODE(XTTYMODE_stop, tc.t_stopc); 4464 TMODE(XTTYMODE_brk, tc.t_brkc); 4465 /* both SYSV and BSD have ltchars */ 4466 TMODE(XTTYMODE_susp, ltc.t_suspc); 4467 TMODE(XTTYMODE_dsusp, ltc.t_dsuspc); 4468 TMODE(XTTYMODE_rprnt, ltc.t_rprntc); 4469 TMODE(XTTYMODE_flush, ltc.t_flushc); 4470 TMODE(XTTYMODE_weras, ltc.t_werasc); 4471 TMODE(XTTYMODE_lnext, ltc.t_lnextc); 4472 if (ttyModes[XTTYMODE_tabs].set 4473 || ttyModes[XTTYMODE__tabs].set) { 4474 sg.sg_flags &= ~XTABS; 4475 if (ttyModes[XTTYMODE__tabs].set.set) 4476 sg.sg_flags |= XTABS; 4477 } 4478 } 4479 4480 if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1) 4481 HsSysError(ERROR_TIOCSETP); 4482 if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1) 4483 HsSysError(ERROR_TIOCSETC); 4484 if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1) 4485 HsSysError(ERROR_TIOCSETD); 4486 if (ioctl(ttyfd, TIOCSLTC, (char *) <c) == -1) 4487 HsSysError(ERROR_TIOCSLTC); 4488 if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1) 4489 HsSysError(ERROR_TIOCLSET); 4490#ifdef sony 4491 if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1) 4492 HsSysError(ERROR_TIOCKSET); 4493 if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1) 4494 HsSysError(ERROR_TIOCKSETC); 4495#endif /* sony */ 4496#endif /* TERMIO_STRUCT */ 4497#if defined(TIOCCONS) || defined(SRIOCSREDIR) 4498 if (Console) { 4499#ifdef TIOCCONS 4500 int on = 1; 4501 if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1) 4502 xtermPerror("cannot open console"); 4503#endif 4504#ifdef SRIOCSREDIR 4505 int fd = open("/dev/console", O_RDWR); 4506 if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1) 4507 xtermPerror("cannot open console"); 4508 IGNORE_RC(close(fd)); 4509#endif 4510 } 4511#endif /* TIOCCONS */ 4512 } 4513 4514 signal(SIGCHLD, SIG_DFL); 4515#ifdef USE_SYSV_SIGHUP 4516 /* watch out for extra shells (I don't understand either) */ 4517 signal(SIGHUP, SIG_DFL); 4518#else 4519 signal(SIGHUP, SIG_IGN); 4520#endif 4521 /* restore various signals to their defaults */ 4522 signal(SIGINT, SIG_DFL); 4523 signal(SIGQUIT, SIG_DFL); 4524 signal(SIGTERM, SIG_DFL); 4525 4526 /* 4527 * If we're not asked to let the parent process set the terminal's 4528 * erase mode, or if we had the ttyModes erase resource, then set 4529 * the terminal's erase mode from our best guess. 4530 */ 4531#if OPT_INITIAL_ERASE 4532 TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n", 4533 initial_erase, 4534 setInitialErase ? "YES" : "NO", 4535 resource.ptyInitialErase, 4536 override_tty_modes, 4537 ttyModes[XTTYMODE_erase].set)); 4538 if (setInitialErase) { 4539#if OPT_TRACE 4540 int old_erase; 4541#endif 4542#ifdef TERMIO_STRUCT 4543 if (ttyGetAttr(ttyfd, &tio) == -1) 4544 tio = d_tio; 4545#if OPT_TRACE 4546 old_erase = tio.c_cc[VERASE]; 4547#endif 4548 tio.c_cc[VERASE] = (cc_t) initial_erase; 4549 TRACE_RC(rc, ttySetAttr(ttyfd, &tio)); 4550#else /* !TERMIO_STRUCT */ 4551 if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1) 4552 sg = d_sg; 4553#if OPT_TRACE 4554 old_erase = sg.sg_erase; 4555#endif 4556 sg.sg_erase = initial_erase; 4557 rc = ioctl(ttyfd, TIOCSETP, (char *) &sg); 4558#endif /* TERMIO_STRUCT */ 4559 TRACE(("%s setting erase to %d (was %d)\n", 4560 rc ? "FAIL" : "OK", initial_erase, old_erase)); 4561 } 4562#endif 4563 4564 xtermCopyEnv(environ); 4565 4566 /* 4567 * standards.freedesktop.org/startup-notification-spec/ 4568 * notes that this variable is used when a "reliable" mechanism is 4569 * not available; in practice it must be unset to avoid confusing 4570 * GTK applications. 4571 */ 4572 xtermUnsetenv("DESKTOP_STARTUP_ID"); 4573 /* 4574 * We set this temporarily to work around poor design of Xcursor. 4575 * Unset it here to avoid confusion. 4576 */ 4577 xtermUnsetenv("XCURSOR_PATH"); 4578 4579 xtermSetenv("TERM", resource.term_name); 4580 if (!resource.term_name) 4581 *get_tcap_buffer(xw) = 0; 4582 4583 sprintf(buf, "%lu", 4584 ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU())))); 4585 xtermSetenv("WINDOWID", buf); 4586 4587 /* put the display into the environment of the shell */ 4588 xtermSetenv("DISPLAY", XDisplayString(screen->display)); 4589 4590 xtermSetenv("XTERM_VERSION", xtermVersion()); 4591 xtermSetenv("XTERM_LOCALE", xtermEnvLocale()); 4592 4593 /* 4594 * For debugging only, add environment variables that can be used 4595 * in scripts to selectively kill xterm's parent or child 4596 * processes. 4597 */ 4598#if OPT_TRACE 4599 sprintf(buf, "%lu", (unsigned long) xterm_parent); 4600 xtermSetenv("XTERM_PARENT", buf); 4601 sprintf(buf, "%lu", (unsigned long) getpid()); 4602 xtermSetenv("XTERM_CHILD", buf); 4603#endif 4604 4605 signal(SIGTERM, SIG_DFL); 4606 4607 /* this is the time to go and set up stdin, out, and err 4608 */ 4609 { 4610#if defined(CRAY) && (OSMAJORVERSION >= 6) 4611 close_fd(ttyfd); 4612 4613 IGNORE_RC(close(0)); 4614 4615 if (open("/dev/tty", O_RDWR)) { 4616 SysError(ERROR_OPDEVTTY); 4617 } 4618 IGNORE_RC(close(1)); 4619 IGNORE_RC(close(2)); 4620 dup(0); 4621 dup(0); 4622#else 4623 /* dup the tty */ 4624 for (i = 0; i <= 2; i++) 4625 if (i != ttyfd) { 4626 IGNORE_RC(close(i)); 4627 IGNORE_RC(dup(ttyfd)); 4628 } 4629#ifndef ATT 4630 /* and close the tty */ 4631 if (ttyfd > 2) 4632 close_fd(ttyfd); 4633#endif 4634#endif /* CRAY */ 4635 } 4636 4637#if !defined(USE_SYSV_PGRP) 4638#ifdef TIOCSCTTY 4639 setsid(); 4640 ioctl(0, TIOCSCTTY, 0); 4641#endif 4642 ioctl(0, TIOCSPGRP, (char *) &pgrp); 4643 setpgrp(0, 0); 4644 close(open(ttydev, O_WRONLY)); 4645 setpgrp(0, pgrp); 4646#if defined(__QNX__) 4647 tcsetpgrp(0, pgrp /*setsid() */ ); 4648#endif 4649#endif /* !USE_SYSV_PGRP */ 4650 4651#ifdef Lynx 4652 { 4653 TERMIO_STRUCT t; 4654 if (ttyGetAttr(0, &t) >= 0) { 4655 /* this gets lost somewhere on our way... */ 4656 t.c_oflag |= OPOST; 4657 ttySetAttr(0, &t); 4658 } 4659 } 4660#endif 4661 4662#ifdef HAVE_UTMP 4663 login_name = NULL; 4664 if (x_getpwuid(screen->uid, &pw)) { 4665 login_name = x_getlogin(screen->uid, &pw); 4666 } 4667 if (login_name != NULL) { 4668 xtermSetenv("LOGNAME", login_name); /* for POSIX */ 4669 } 4670#ifndef USE_UTEMPTER 4671#ifdef USE_UTMP_SETGID 4672 setEffectiveGroup(save_egid); 4673 TRACE_IDS; 4674#endif 4675#ifdef USE_SYSV_UTMP 4676 /* Set up our utmp entry now. We need to do it here 4677 * for the following reasons: 4678 * - It needs to have our correct process id (for 4679 * login). 4680 * - If our parent was to set it after the fork(), 4681 * it might make it out before we need it. 4682 * - We need to do it before we go and change our 4683 * user and group id's. 4684 */ 4685 (void) call_setutent(); 4686 init_utmp(DEAD_PROCESS, &utmp); 4687 4688 /* position to entry in utmp file */ 4689 /* Test return value: beware of entries left behind: PSz 9 Mar 00 */ 4690 utret = find_utmp(&utmp); 4691 if (utret == 0) { 4692 (void) call_setutent(); 4693 init_utmp(USER_PROCESS, &utmp); 4694 utret = find_utmp(&utmp); 4695 if (utret == 0) { 4696 (void) call_setutent(); 4697 } 4698 } 4699#if OPT_TRACE 4700 if (!utret) 4701 TRACE(("getutid: NULL\n")); 4702 else 4703 TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n", 4704 (int) utret->ut_pid, utret->ut_type, utret->ut_user, 4705 (int) sizeof(utret->ut_line), utret->ut_line, 4706 (int) sizeof(utret->ut_id), utret->ut_id)); 4707#endif 4708 4709 /* set up the new entry */ 4710 utmp.ut_type = USER_PROCESS; 4711#ifdef HAVE_UTMP_UT_XSTATUS 4712 utmp.ut_xstatus = 2; 4713#endif 4714 copy_filled(utmp.ut_user, 4715 (login_name != NULL) ? login_name : "????", 4716 sizeof(utmp.ut_user)); 4717 /* why are we copying this string again? (see above) */ 4718 copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id)); 4719 copy_filled(utmp.ut_line, 4720 my_pty_name(ttydev), sizeof(utmp.ut_line)); 4721 4722#ifdef HAVE_UTMP_UT_HOST 4723 SetUtmpHost(utmp.ut_host, screen); 4724#endif 4725#ifdef HAVE_UTMP_UT_SYSLEN 4726 SetUtmpSysLen(utmp); 4727#endif 4728 4729 copy_filled(utmp.ut_name, 4730 (login_name) ? login_name : "????", 4731 sizeof(utmp.ut_name)); 4732 4733 utmp.ut_pid = getpid(); 4734#if defined(HAVE_UTMP_UT_XTIME) 4735#if defined(HAVE_UTMP_UT_SESSION) 4736 utmp.ut_session = getsid(0); 4737#endif 4738 utmp.ut_xtime = time((time_t *) 0); 4739 utmp.ut_tv.tv_usec = 0; 4740#else 4741 utmp.ut_time = time((time_t *) 0); 4742#endif 4743 4744 /* write out the entry */ 4745 if (!resource.utmpInhibit) { 4746 errno = 0; 4747 call_pututline(&utmp); 4748 TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n", 4749 (int) sizeof(utmp.ut_id), utmp.ut_id, 4750 (int) sizeof(utmp.ut_line), utmp.ut_line, 4751 (long) utmp.ut_pid, 4752 errno, (errno != 0) ? strerror(errno) : "")); 4753 } 4754#ifdef WTMP 4755#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__)) 4756 if (xw->misc.login_shell) 4757 updwtmpx(WTMPX_FILE, &utmp); 4758#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) 4759 if (xw->misc.login_shell) 4760 call_updwtmp(etc_wtmp, &utmp); 4761#else 4762 if (xw->misc.login_shell && 4763 (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 4764 IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp))); 4765 close(i); 4766 } 4767#endif 4768#endif 4769 /* close the file */ 4770 (void) call_endutent(); 4771 4772#else /* USE_SYSV_UTMP */ 4773 /* We can now get our ttyslot! We can also set the initial 4774 * utmp entry. 4775 */ 4776 tslot = ttyslot(); 4777 added_utmp_entry = False; 4778 { 4779 if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit && 4780 (i = open(etc_utmp, O_WRONLY)) >= 0) { 4781 memset(&utmp, 0, sizeof(utmp)); 4782 copy_filled(utmp.ut_line, 4783 my_pty_name(ttydev), 4784 sizeof(utmp.ut_line)); 4785 copy_filled(utmp.ut_name, login_name, 4786 sizeof(utmp.ut_name)); 4787#ifdef HAVE_UTMP_UT_HOST 4788 SetUtmpHost(utmp.ut_host, screen); 4789#endif 4790#ifdef HAVE_UTMP_UT_SYSLEN 4791 SetUtmpSysLen(utmp); 4792#endif 4793 4794 utmp.ut_time = time((time_t *) 0); 4795 lseek(i, (long) (tslot * sizeof(utmp)), 0); 4796 IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp))); 4797 close(i); 4798 added_utmp_entry = True; 4799#if defined(WTMP) 4800 if (xw->misc.login_shell && 4801 (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 4802 int status; 4803 status = write(i, (char *) &utmp, sizeof(utmp)); 4804 status = close(i); 4805 } 4806#elif defined(MNX_LASTLOG) 4807 if (xw->misc.login_shell && 4808 (i = open(_U_LASTLOG, O_WRONLY)) >= 0) { 4809 lseek(i, (long) (screen->uid * 4810 sizeof(utmp)), 0); 4811 IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp))); 4812 close(i); 4813 } 4814#endif /* WTMP or MNX_LASTLOG */ 4815 } else 4816 tslot = -tslot; 4817 } 4818 4819 /* Let's pass our ttyslot to our parent so that it can 4820 * clean up after us. 4821 */ 4822#if OPT_PTY_HANDSHAKE 4823 if (resource.ptyHandshake) { 4824 handshake.tty_slot = tslot; 4825 } 4826#endif /* OPT_PTY_HANDSHAKE */ 4827#endif /* USE_SYSV_UTMP */ 4828 4829#ifdef USE_LASTLOGX 4830 if (xw->misc.login_shell) { 4831 memset(&lastlogx, 0, sizeof(lastlogx)); 4832 copy_filled(lastlogx.ll_line, 4833 my_pty_name(ttydev), 4834 sizeof(lastlogx.ll_line)); 4835 X_GETTIMEOFDAY(&lastlogx.ll_tv); 4836 SetUtmpHost(lastlogx.ll_host, screen); 4837 updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx); 4838 } 4839#endif 4840 4841#ifdef USE_LASTLOG 4842 if (xw->misc.login_shell && 4843 (i = open(etc_lastlog, O_WRONLY)) >= 0) { 4844 size_t size = sizeof(struct lastlog); 4845 off_t offset = (off_t) ((size_t) screen->uid * size); 4846 4847 memset(&lastlog, 0, size); 4848 copy_filled(lastlog.ll_line, 4849 my_pty_name(ttydev), 4850 sizeof(lastlog.ll_line)); 4851 SetUtmpHost(lastlog.ll_host, screen); 4852 lastlog.ll_time = time((time_t *) 0); 4853 if (lseek(i, offset, 0) != (off_t) (-1)) { 4854 IGNORE_RC(write(i, (char *) &lastlog, size)); 4855 } 4856 close(i); 4857 } 4858#endif /* USE_LASTLOG */ 4859 4860#if defined(USE_UTMP_SETGID) 4861 disableSetGid(); 4862 TRACE_IDS; 4863#endif 4864 4865#if OPT_PTY_HANDSHAKE 4866 /* Let our parent know that we set up our utmp entry 4867 * so that it can clean up after us. 4868 */ 4869 if (resource.ptyHandshake) { 4870 handshake.status = UTMP_ADDED; 4871 handshake.error = 0; 4872 copy_handshake(handshake, ttydev); 4873 TRACE_HANDSHAKE("writing", &handshake); 4874 IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake))); 4875 } 4876#endif /* OPT_PTY_HANDSHAKE */ 4877#endif /* USE_UTEMPTER */ 4878#endif /* HAVE_UTMP */ 4879 4880 IGNORE_RC(setgid(screen->gid)); 4881 TRACE_IDS; 4882#ifdef HAVE_INITGROUPS 4883 if (geteuid() == 0 && OkPasswd(&pw)) { 4884 if (initgroups(login_name, pw.pw_gid)) { 4885 perror("initgroups failed"); 4886 SysError(ERROR_INIGROUPS); 4887 } 4888 } 4889#endif 4890 if (setuid(screen->uid)) { 4891 SysError(ERROR_SETUID); 4892 } 4893 TRACE_IDS; 4894#if OPT_PTY_HANDSHAKE 4895 if (resource.ptyHandshake) { 4896 /* mark the pipes as close on exec */ 4897 (void) fcntl(cp_pipe[1], F_SETFD, 1); 4898 (void) fcntl(pc_pipe[0], F_SETFD, 1); 4899 4900 /* We are at the point where we are going to 4901 * exec our shell (or whatever). Let our parent 4902 * know we arrived safely. 4903 */ 4904 handshake.status = PTY_GOOD; 4905 handshake.error = 0; 4906 copy_handshake(handshake, ttydev); 4907 TRACE_HANDSHAKE("writing", &handshake); 4908 IGNORE_RC(write(cp_pipe[1], 4909 (const char *) &handshake, 4910 sizeof(handshake))); 4911 4912 if (resource.wait_for_map) { 4913 i = (int) read(pc_pipe[0], (char *) &handshake, 4914 sizeof(handshake)); 4915 if (i != sizeof(handshake) || 4916 handshake.status != PTY_EXEC) { 4917 /* some very bad problem occurred */ 4918 exit(ERROR_PTY_EXEC); 4919 } 4920 if (handshake.rows > 0 && handshake.cols > 0) { 4921 TRACE(("handshake read ttysize: %dx%d\n", 4922 handshake.rows, handshake.cols)); 4923 set_max_row(screen, handshake.rows); 4924 set_max_col(screen, handshake.cols); 4925#ifdef TTYSIZE_STRUCT 4926 got_handshake_size = True; 4927 setup_winsize(ts, MaxRows(screen), MaxCols(screen), 4928 FullHeight(screen), FullWidth(screen)); 4929 trace_winsize(ts, "got handshake"); 4930#endif /* TTYSIZE_STRUCT */ 4931 } 4932 } 4933 } 4934#endif /* OPT_PTY_HANDSHAKE */ 4935 4936#ifdef USE_SYSV_ENVVARS 4937 { 4938 char numbuf[12]; 4939 sprintf(numbuf, "%d", MaxCols(screen)); 4940 xtermSetenv("COLUMNS", numbuf); 4941 sprintf(numbuf, "%d", MaxRows(screen)); 4942 xtermSetenv("LINES", numbuf); 4943 } 4944#ifdef HAVE_UTMP 4945 if (OkPasswd(&pw)) { /* SVR4 doesn't provide these */ 4946 if (!x_getenv("HOME")) 4947 xtermSetenv("HOME", pw.pw_dir); 4948 if (!x_getenv("SHELL")) 4949 xtermSetenv("SHELL", pw.pw_shell); 4950 } 4951#endif /* HAVE_UTMP */ 4952#else /* USE_SYSV_ENVVARS */ 4953 if (*(newtc = get_tcap_buffer(xw)) != '\0') { 4954 resize_termcap(xw); 4955 if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) { 4956 remove_termcap_entry(newtc, "ti="); 4957 remove_termcap_entry(newtc, "te="); 4958 } 4959 /* 4960 * work around broken termcap entries */ 4961 if (resource.useInsertMode) { 4962 remove_termcap_entry(newtc, "ic="); 4963 /* don't get duplicates */ 4964 remove_termcap_entry(newtc, "im="); 4965 remove_termcap_entry(newtc, "ei="); 4966 remove_termcap_entry(newtc, "mi"); 4967 if (*newtc) 4968 strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:"); 4969 } 4970 if (*newtc) { 4971#if OPT_INITIAL_ERASE 4972 unsigned len; 4973 remove_termcap_entry(newtc, TERMCAP_ERASE "="); 4974 len = (unsigned) strlen(newtc); 4975 if (len != 0 && newtc[len - 1] == ':') 4976 len--; 4977 sprintf(newtc + len, ":%s=\\%03o:", 4978 TERMCAP_ERASE, 4979 CharOf(initial_erase)); 4980#endif 4981 xtermSetenv("TERMCAP", newtc); 4982 } 4983 } 4984#endif /* USE_SYSV_ENVVARS */ 4985#ifdef OWN_TERMINFO_ENV 4986 xtermSetenv("TERMINFO", OWN_TERMINFO_DIR); 4987#endif 4988 4989#if OPT_PTY_HANDSHAKE 4990 /* 4991 * Need to reset after all the ioctl bashing we did above. 4992 * 4993 * If we expect the waitForMap logic to set the handshake-size, 4994 * use that to prevent races. 4995 */ 4996 TRACE(("should we reset screensize after pty-handshake?\n")); 4997 TRACE(("... ptyHandshake :%d\n", resource.ptyHandshake)); 4998 TRACE(("... ptySttySize :%d\n", resource.ptySttySize)); 4999 TRACE(("... got_handshake_size:%d\n", got_handshake_size)); 5000 TRACE(("... wait_for_map0 :%d\n", resource.wait_for_map0)); 5001 if (resource.ptyHandshake 5002 && resource.ptySttySize 5003 && (got_handshake_size || !resource.wait_for_map0)) { 5004#ifdef TTYSIZE_STRUCT 5005 TRACE_RC(i, SET_TTYSIZE(0, ts)); 5006 trace_winsize(ts, "ptyHandshake SET_TTYSIZE"); 5007#endif /* TTYSIZE_STRUCT */ 5008 } 5009#endif /* OPT_PTY_HANDSHAKE */ 5010 signal(SIGHUP, SIG_DFL); 5011 5012 /* 5013 * If we have an explicit shell to run, make that set $SHELL. 5014 * Next, allow an existing setting of $SHELL, for absolute paths. 5015 * Otherwise, if $SHELL is not set, determine it from the user's 5016 * password information, if possible. 5017 * 5018 * Incidentally, our setting of $SHELL tells luit to use that 5019 * program rather than choosing between $SHELL and "/bin/sh". 5020 */ 5021 if (validShell(explicit_shname)) { 5022 xtermSetenv("SHELL", explicit_shname); 5023 } else if (validProgram(shell_path = x_getenv("SHELL"))) { 5024 if (!validShell(shell_path)) { 5025 xtermUnsetenv("SHELL"); 5026 } 5027 } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw)) 5028 || *(shell_path = x_strdup(pw.pw_shell)) == 0) { 5029 shell_path = resetShell(shell_path); 5030 } else if (validShell(shell_path)) { 5031 xtermSetenv("SHELL", shell_path); 5032 } else { 5033 shell_path = resetShell(shell_path); 5034 } 5035 5036 /* 5037 * Set $XTERM_SHELL, which is not necessarily a valid shell, but 5038 * is executable. 5039 */ 5040 if (validProgram(explicit_shname)) { 5041 shell_path = explicit_shname; 5042 } else if (shell_path == 0) { 5043 /* this could happen if the explicit shname lost a race */ 5044 shell_path = resetShell(shell_path); 5045 } 5046 xtermSetenv("XTERM_SHELL", shell_path); 5047 5048 shname = x_basename(shell_path); 5049 TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname)); 5050 5051#if OPT_LUIT_PROG 5052 /* 5053 * Use two copies of command_to_exec, in case luit is not actually 5054 * there, or refuses to run. In that case we will fall-through to 5055 * to command that the user gave anyway. 5056 */ 5057 if (command_to_exec_with_luit && command_to_exec) { 5058 char *myShell = xtermFindShell(*command_to_exec_with_luit, False); 5059 xtermSetenv("XTERM_SHELL", myShell); 5060 free(myShell); 5061 TRACE_ARGV("spawning luit command", command_to_exec_with_luit); 5062 execvp(*command_to_exec_with_luit, command_to_exec_with_luit); 5063 xtermPerror("Can't execvp %s", *command_to_exec_with_luit); 5064 xtermWarning("cannot support your locale.\n"); 5065 } 5066#endif 5067 if (command_to_exec) { 5068 char *myShell = xtermFindShell(*command_to_exec, False); 5069 xtermSetenv("XTERM_SHELL", myShell); 5070 free(myShell); 5071 TRACE_ARGV("spawning command", command_to_exec); 5072 execvp(*command_to_exec, command_to_exec); 5073 if (command_to_exec[1] == 0) 5074 execlp(shell_path, shname, "-c", command_to_exec[0], 5075 (void *) 0); 5076 xtermPerror("Can't execvp %s", *command_to_exec); 5077 } 5078#ifdef USE_SYSV_SIGHUP 5079 /* fix pts sh hanging around */ 5080 signal(SIGHUP, SIG_DFL); 5081#endif 5082 5083 if ((shname_minus = malloc(strlen(shname) + 2)) != 0) { 5084 (void) strcpy(shname_minus, "-"); 5085 (void) strcat(shname_minus, shname); 5086 } else { 5087 static char default_minus[] = "-sh"; 5088 shname_minus = default_minus; 5089 } 5090#ifndef TERMIO_STRUCT 5091 ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3) 5092 ? NTTYDISC 5093 : 0); 5094 ioctl(0, TIOCSETD, (char *) &ldisc); 5095#endif /* !TERMIO_STRUCT */ 5096 5097#ifdef USE_LOGIN_DASH_P 5098 if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry) 5099 execl(bin_login, "login", "-p", "-f", login_name, (void *) 0); 5100#endif 5101 5102#if OPT_LUIT_PROG 5103 if (command_to_exec_with_luit) { 5104 if (xw->misc.login_shell) { 5105 char *params[4]; 5106 params[0] = x_strdup("-argv0"); 5107 params[1] = shname_minus; 5108 params[2] = NULL; 5109 x_appendargv(command_to_exec_with_luit 5110 + command_length_with_luit, 5111 params); 5112 } 5113 TRACE_ARGV("final luit command", command_to_exec_with_luit); 5114 execvp(*command_to_exec_with_luit, command_to_exec_with_luit); 5115 /* Exec failed. */ 5116 xtermPerror("Can't execvp %s", *command_to_exec_with_luit); 5117 } 5118#endif 5119 execlp(shell_path, 5120 (xw->misc.login_shell ? shname_minus : shname), 5121 (void *) 0); 5122 5123 /* Exec failed. */ 5124 xtermPerror("Could not exec %s", shell_path); 5125 IGNORE_RC(sleep(5)); 5126 free(shell_path); 5127 exit(ERROR_EXEC); 5128 } 5129 /* end if in child after fork */ 5130#if OPT_PTY_HANDSHAKE 5131 if (resource.ptyHandshake) { 5132 /* Parent process. Let's handle handshaked requests to our 5133 * child process. 5134 */ 5135 5136 /* close childs's sides of the pipes */ 5137 close(cp_pipe[1]); 5138 close(pc_pipe[0]); 5139 5140 for (done = 0; !done;) { 5141 if (read(cp_pipe[0], 5142 (char *) &handshake, 5143 sizeof(handshake)) <= 0) { 5144 /* Our child is done talking to us. If it terminated 5145 * due to an error, we will catch the death of child 5146 * and clean up. 5147 */ 5148 break; 5149 } 5150 5151 TRACE_HANDSHAKE("read", &handshake); 5152 switch (handshake.status) { 5153 case PTY_GOOD: 5154 /* Success! Let's free up resources and 5155 * continue. 5156 */ 5157 done = 1; 5158 break; 5159 5160 case PTY_BAD: 5161 /* The open of the pty failed! Let's get 5162 * another one. 5163 */ 5164 IGNORE_RC(close(screen->respond)); 5165 if (get_pty(&screen->respond, XDisplayString(screen->display))) { 5166 /* no more ptys! */ 5167 xtermPerror("child process can find no available ptys"); 5168 handshake.status = PTY_NOMORE; 5169 TRACE_HANDSHAKE("writing", &handshake); 5170 IGNORE_RC(write(pc_pipe[1], 5171 (const char *) &handshake, 5172 sizeof(handshake))); 5173 exit(ERROR_PTYS); 5174 } 5175 handshake.status = PTY_NEW; 5176 copy_handshake(handshake, ttydev); 5177 TRACE_HANDSHAKE("writing", &handshake); 5178 IGNORE_RC(write(pc_pipe[1], 5179 (const char *) &handshake, 5180 sizeof(handshake))); 5181 break; 5182 5183 case PTY_FATALERROR: 5184 errno = handshake.error; 5185 close(cp_pipe[0]); 5186 close(pc_pipe[1]); 5187 SysError(handshake.fatal_error); 5188 /*NOTREACHED */ 5189 5190 case UTMP_ADDED: 5191 /* The utmp entry was set by our slave. Remember 5192 * this so that we can reset it later. 5193 */ 5194 added_utmp_entry = True; 5195#ifndef USE_SYSV_UTMP 5196 tslot = handshake.tty_slot; 5197#endif /* USE_SYSV_UTMP */ 5198 free(ttydev); 5199 handshake.buffer[HANDSHAKE_LEN - 1] = '\0'; 5200 ttydev = x_strdup(handshake.buffer); 5201 break; 5202 case PTY_NEW: 5203 case PTY_NOMORE: 5204 case UTMP_TTYSLOT: 5205 case PTY_EXEC: 5206 default: 5207 xtermWarning("unexpected handshake status %d\n", 5208 (int) handshake.status); 5209 } 5210 } 5211 /* close our sides of the pipes */ 5212 if (!resource.wait_for_map) { 5213 close(cp_pipe[0]); 5214 close(pc_pipe[1]); 5215 } 5216 } 5217#endif /* OPT_PTY_HANDSHAKE */ 5218 } 5219 5220 /* end if no slave */ 5221 /* 5222 * still in parent (xterm process) 5223 */ 5224#ifdef USE_SYSV_SIGHUP 5225 /* hung sh problem? */ 5226 signal(SIGHUP, SIG_DFL); 5227#else 5228 signal(SIGHUP, SIG_IGN); 5229#endif 5230 5231/* 5232 * Unfortunately, System V seems to have trouble divorcing the child process 5233 * from the process group of xterm. This is a problem because hitting the 5234 * INTR or QUIT characters on the keyboard will cause xterm to go away if we 5235 * don't ignore the signals. This is annoying. 5236 */ 5237 5238#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) 5239 signal(SIGINT, SIG_IGN); 5240 5241#ifndef SYSV 5242 /* hung shell problem */ 5243 signal(SIGQUIT, SIG_IGN); 5244#endif 5245 signal(SIGTERM, SIG_IGN); 5246#elif defined(SYSV) || defined(__osf__) 5247 /* if we were spawned by a jobcontrol smart shell (like ksh or csh), 5248 * then our pgrp and pid will be the same. If we were spawned by 5249 * a jobcontrol dumb shell (like /bin/sh), then we will be in our 5250 * parent's pgrp, and we must ignore keyboard signals, or we will 5251 * tank on everything. 5252 */ 5253 if (getpid() == getpgrp()) { 5254 (void) signal(SIGINT, Exit); 5255 (void) signal(SIGQUIT, Exit); 5256 (void) signal(SIGTERM, Exit); 5257 } else { 5258 (void) signal(SIGINT, SIG_IGN); 5259 (void) signal(SIGQUIT, SIG_IGN); 5260 (void) signal(SIGTERM, SIG_IGN); 5261 } 5262 (void) signal(SIGPIPE, Exit); 5263#else /* SYSV */ 5264 signal(SIGINT, Exit); 5265 signal(SIGQUIT, Exit); 5266 signal(SIGTERM, Exit); 5267 signal(SIGPIPE, Exit); 5268#endif /* USE_SYSV_SIGNALS and not SIGTSTP */ 5269#ifdef NO_LEAKS 5270 if (ok_termcap != True) 5271 free(TermName); 5272#endif 5273 5274 return 0; 5275} /* end spawnXTerm */ 5276 5277void 5278Exit(int n) 5279{ 5280 XtermWidget xw = term; 5281 TScreen *screen = TScreenOf(xw); 5282 5283#ifdef USE_UTEMPTER 5284 DEBUG_MSG("handle:Exit USE_UTEMPTER\n"); 5285 if (!resource.utmpInhibit && added_utmp_entry) { 5286 TRACE(("...calling removeFromUtmp\n")); 5287 UTEMPTER_DEL(); 5288 } 5289#elif defined(HAVE_UTMP) 5290#ifdef USE_SYSV_UTMP 5291 struct UTMP_STR utmp; 5292 struct UTMP_STR *utptr; 5293 5294 DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n"); 5295 /* don't do this more than once */ 5296 if (xterm_exiting) { 5297 exit(n); 5298 } 5299 xterm_exiting = True; 5300 5301#ifdef PUCC_PTYD 5302 closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond); 5303#endif /* PUCC_PTYD */ 5304 5305 /* cleanup the utmp entry we forged earlier */ 5306 if (!resource.utmpInhibit 5307#if OPT_PTY_HANDSHAKE /* without handshake, no way to know */ 5308 && (resource.ptyHandshake && added_utmp_entry) 5309#endif /* OPT_PTY_HANDSHAKE */ 5310 ) { 5311#if defined(USE_UTMP_SETGID) 5312 setEffectiveGroup(save_egid); 5313 TRACE_IDS; 5314#endif 5315 init_utmp(USER_PROCESS, &utmp); 5316 (void) call_setutent(); 5317 5318 /* 5319 * We could use getutline() if we didn't support old systems. 5320 */ 5321 while ((utptr = find_utmp(&utmp)) != 0) { 5322 if (utptr->ut_pid == screen->pid) { 5323 utptr->ut_type = DEAD_PROCESS; 5324#if defined(HAVE_UTMP_UT_XTIME) 5325#if defined(HAVE_UTMP_UT_SESSION) 5326 utptr->ut_session = getsid(0); 5327#endif 5328 utptr->ut_xtime = time((time_t *) 0); 5329 utptr->ut_tv.tv_usec = 0; 5330#else 5331 *utptr->ut_user = 0; 5332 utptr->ut_time = time((time_t *) 0); 5333#endif 5334 (void) call_pututline(utptr); 5335#ifdef WTMP 5336#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__)) 5337 if (xw->misc.login_shell) 5338 updwtmpx(WTMPX_FILE, utptr); 5339#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) 5340 copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line)); 5341 if (xw->misc.login_shell) 5342 call_updwtmp(etc_wtmp, utptr); 5343#else 5344 /* set wtmp entry if wtmp file exists */ 5345 if (xw->misc.login_shell) { 5346 int fd; 5347 if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 5348 IGNORE_RC(write(fd, utptr, sizeof(*utptr))); 5349 close(fd); 5350 } 5351 } 5352#endif 5353#endif 5354 break; 5355 } 5356 memset(utptr, 0, sizeof(*utptr)); /* keep searching */ 5357 } 5358 (void) call_endutent(); 5359#ifdef USE_UTMP_SETGID 5360 disableSetGid(); 5361 TRACE_IDS; 5362#endif 5363 } 5364#else /* not USE_SYSV_UTMP */ 5365 int wfd; 5366 struct utmp utmp; 5367 5368 DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n"); 5369 if (!resource.utmpInhibit && added_utmp_entry && 5370 (am_slave < 0 && tslot > 0)) { 5371#if defined(USE_UTMP_SETGID) 5372 setEffectiveGroup(save_egid); 5373 TRACE_IDS; 5374#endif 5375 if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) { 5376 memset(&utmp, 0, sizeof(utmp)); 5377 lseek(wfd, (long) (tslot * sizeof(utmp)), 0); 5378 IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp))); 5379 close(wfd); 5380 } 5381#ifdef WTMP 5382 if (xw->misc.login_shell && 5383 (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 5384 copy_filled(utmp.ut_line, 5385 my_pty_name(ttydev), 5386 sizeof(utmp.ut_line)); 5387 utmp.ut_time = time((time_t *) 0); 5388 IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp))); 5389 close(wfd); 5390 } 5391#endif /* WTMP */ 5392#ifdef USE_UTMP_SETGID 5393 disableSetGid(); 5394 TRACE_IDS; 5395#endif 5396 } 5397#endif /* USE_SYSV_UTMP */ 5398#endif /* HAVE_UTMP */ 5399 5400 cleanup_colored_cursor(); 5401 5402 /* 5403 * Flush pending data before releasing ownership, so nobody else can write 5404 * in the middle of the data. 5405 */ 5406 ttyFlush(screen->respond); 5407 5408#ifdef USE_PTY_SEARCH 5409 if (am_slave < 0) { 5410 TRACE_IDS; 5411 /* restore ownership of tty and pty */ 5412 set_owner(ttydev, 0, 0, 0666U); 5413#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux)) 5414 set_owner(ptydev, 0, 0, 0666U); 5415#endif 5416 } 5417#endif 5418 5419 /* 5420 * Close after releasing ownership to avoid race condition: other programs 5421 * grabbing it, and *then* having us release ownership.... 5422 */ 5423 close(screen->respond); /* close explicitly to avoid race with slave side */ 5424#ifdef ALLOWLOGGING 5425 if (screen->logging) 5426 CloseLog(xw); 5427#endif 5428 5429 xtermPrintOnXError(xw, n); 5430 5431#ifdef NO_LEAKS 5432 if (n == 0) { 5433 Display *dpy = TScreenOf(xw)->display; 5434 5435 TRACE(("Freeing memory leaks\n")); 5436 5437 if (toplevel) { 5438 XtDestroyWidget(toplevel); 5439 TRACE(("destroyed top-level widget\n")); 5440 } 5441 sortedOpts(0, 0, 0); 5442 noleaks_charproc(); 5443 noleaks_ptydata(); 5444#if OPT_GRAPHICS 5445 noleaks_graphics(); 5446#endif 5447#if OPT_WIDE_CHARS 5448 noleaks_CharacterClass(); 5449#endif 5450 /* XrmSetDatabase(dpy, 0); increases leaks ;-) */ 5451 XtCloseDisplay(dpy); 5452 XtDestroyApplicationContext(app_con); 5453 xtermCloseSession(); 5454 TRACE(("closed display\n")); 5455 5456 TRACE_CLOSE(); 5457 } 5458#endif 5459 5460 exit(n); 5461} 5462 5463/* ARGSUSED */ 5464static void 5465resize_termcap(XtermWidget xw) 5466{ 5467 char *newtc = get_tcap_buffer(xw); 5468 5469#ifndef USE_SYSV_ENVVARS 5470 if (!TEK4014_ACTIVE(xw) && *newtc) { 5471 TScreen *screen = TScreenOf(xw); 5472 char *ptr1, *ptr2; 5473 size_t i; 5474 int li_first = 0; 5475 char *temp; 5476 char oldtc[TERMCAP_SIZE]; 5477 5478 strcpy(oldtc, newtc); 5479 TRACE(("resize %s\n", oldtc)); 5480 if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) { 5481 strcat(oldtc, "co#80:"); 5482 ptr1 = x_strindex(oldtc, "co#"); 5483 } 5484 if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) { 5485 strcat(oldtc, "li#24:"); 5486 ptr2 = x_strindex(oldtc, "li#"); 5487 } 5488 if (ptr1 > ptr2) { 5489 li_first++; 5490 temp = ptr1; 5491 ptr1 = ptr2; 5492 ptr2 = temp; 5493 } 5494 ptr1 += 3; 5495 ptr2 += 3; 5496 strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc)); 5497 temp = newtc + i; 5498 sprintf(temp, "%d", (li_first 5499 ? MaxRows(screen) 5500 : MaxCols(screen))); 5501 temp += strlen(temp); 5502 if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) { 5503 strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1)); 5504 temp += i; 5505 sprintf(temp, "%d", (li_first 5506 ? MaxCols(screen) 5507 : MaxRows(screen))); 5508 if ((ptr2 = strchr(ptr2, ':')) != 0) { 5509 strcat(temp, ptr2); 5510 } 5511 } 5512 TRACE((" ==> %s\n", newtc)); 5513 TRACE((" new size %dx%d\n", MaxRows(screen), MaxCols(screen))); 5514 } 5515#endif /* USE_SYSV_ENVVARS */ 5516} 5517 5518#endif /* ! VMS */ 5519 5520/* 5521 * Does a non-blocking wait for a child process. If the system 5522 * doesn't support non-blocking wait, do nothing. 5523 * Returns the pid of the child, or 0 or -1 if none or error. 5524 */ 5525int 5526nonblocking_wait(void) 5527{ 5528#ifdef USE_POSIX_WAIT 5529 pid_t pid; 5530 5531 pid = waitpid(-1, NULL, WNOHANG); 5532#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) 5533 /* cannot do non-blocking wait */ 5534 int pid = 0; 5535#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */ 5536#if defined(Lynx) 5537 int status; 5538#else 5539 union wait status; 5540#endif 5541 int pid; 5542 5543 pid = wait3(&status, WNOHANG, (struct rusage *) NULL); 5544#endif /* USE_POSIX_WAIT else */ 5545 return pid; 5546} 5547 5548#ifndef VMS 5549 5550/* ARGSUSED */ 5551static void 5552reapchild(int n GCC_UNUSED) 5553{ 5554 int olderrno = errno; 5555 int pid; 5556 5557 DEBUG_MSG("handle:reapchild\n"); 5558 5559 pid = wait(NULL); 5560 5561#ifdef USE_SYSV_SIGNALS 5562 /* cannot re-enable signal before waiting for child 5563 * because then SVR4 loops. Sigh. HP-UX 9.01 too. 5564 */ 5565 (void) signal(SIGCHLD, reapchild); 5566#endif 5567 5568 do { 5569 if (pid == TScreenOf(term)->pid) { 5570 DEBUG_MSG("Exiting\n"); 5571 if (hold_screen) 5572 caught_intr = True; 5573 else 5574 need_cleanup = True; 5575 } 5576 } while ((pid = nonblocking_wait()) > 0); 5577 5578 errno = olderrno; 5579} 5580#endif /* !VMS */ 5581 5582static void 5583remove_termcap_entry(char *buf, const char *str) 5584{ 5585 char *base = buf; 5586 char *first = base; 5587 int count = 0; 5588 size_t len = strlen(str); 5589 5590 TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf)); 5591 5592 while (*buf != 0) { 5593 if (!count && !strncmp(buf, str, len)) { 5594 while (*buf != 0) { 5595 if (*buf == '\\') 5596 buf++; 5597 else if (*buf == ':') 5598 break; 5599 if (*buf != 0) 5600 buf++; 5601 } 5602 while ((*first++ = *buf++) != 0) { 5603 ; 5604 } 5605 TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base)); 5606 return; 5607 } else if (*buf == '\\') { 5608 buf++; 5609 } else if (*buf == ':') { 5610 first = buf; 5611 count = 0; 5612 } else if (!isspace(CharOf(*buf))) { 5613 count++; 5614 } 5615 if (*buf != 0) 5616 buf++; 5617 } 5618 TRACE(("...cannot remove\n")); 5619} 5620 5621/* 5622 * parse_tty_modes accepts lines of the following form: 5623 * 5624 * [SETTING] ... 5625 * 5626 * where setting consists of the words in the ttyModes[] array followed by a 5627 * character or ^char. 5628 */ 5629static int 5630parse_tty_modes(char *s) 5631{ 5632 int c; 5633 Cardinal j, k; 5634 int count = 0; 5635 Boolean found; 5636 5637 TRACE(("parse_tty_modes\n")); 5638 for (;;) { 5639 size_t len; 5640 5641 while (*s && isspace(CharOf(*s))) { 5642 s++; 5643 } 5644 if (!*s) { 5645 return count; 5646 } 5647 5648 for (len = 0; s[len] && !isspace(CharOf(s[len])); ++len) { 5649 ; 5650 } 5651 found = False; 5652 for (j = 0; j < XtNumber(ttyModes); ++j) { 5653 if (len == ttyModes[j].len 5654 && strncmp(s, 5655 ttyModes[j].name, 5656 ttyModes[j].len) == 0) { 5657 found = True; 5658 break; 5659 } 5660 } 5661 if (!found) { 5662 return -1; 5663 } 5664 5665 s += ttyModes[j].len; 5666 while (*s && isspace(CharOf(*s))) { 5667 s++; 5668 } 5669 5670 /* check if this needs a parameter */ 5671 found = False; 5672 for (k = 0, c = 0; k < XtNumber(ttyChars); ++k) { 5673 if ((int) j == ttyChars[k].myMode) { 5674 if (ttyChars[k].sysMode < 0) { 5675 found = True; 5676 c = ttyChars[k].myDefault; 5677 } 5678 break; 5679 } 5680 } 5681 5682 if (!found) { 5683 if (!*s 5684 || (c = decode_keyvalue(&s, False)) == -1) { 5685 return -1; 5686 } 5687 } 5688 ttyModes[j].value = c; 5689 ttyModes[j].set = 1; 5690 count++; 5691 TRACE(("...parsed #%d: %s=%#x\n", count, ttyModes[j].name, c)); 5692 } 5693} 5694 5695#ifndef VMS /* don't use pipes on OpenVMS */ 5696int 5697GetBytesAvailable(int fd) 5698{ 5699#if defined(FIONREAD) 5700 int arg; 5701 ioctl(fd, FIONREAD, (char *) &arg); 5702 return (int) arg; 5703#elif defined(__CYGWIN__) 5704 fd_set set; 5705 struct timeval select_timeout = 5706 {0, 0}; 5707 5708 FD_ZERO(&set); 5709 FD_SET(fd, &set); 5710 if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0) 5711 return 1; 5712 else 5713 return 0; 5714#elif defined(FIORDCK) 5715 return (ioctl(fd, FIORDCHK, NULL)); 5716#else /* !FIORDCK */ 5717 struct pollfd pollfds[1]; 5718 5719 pollfds[0].fd = fd; 5720 pollfds[0].events = POLLIN; 5721 return poll(pollfds, 1, 0); 5722#endif 5723} 5724#endif /* !VMS */ 5725 5726/* Utility function to try to hide system differences from 5727 everybody who used to call killpg() */ 5728 5729int 5730kill_process_group(int pid, int sig) 5731{ 5732 TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig)); 5733#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX) 5734 return kill(-pid, sig); 5735#else 5736 return killpg(pid, sig); 5737#endif 5738} 5739 5740#if OPT_EBCDIC 5741int 5742A2E(int x) 5743{ 5744 char c; 5745 c = x; 5746 __atoe_l(&c, 1); 5747 return c; 5748} 5749 5750int 5751E2A(int x) 5752{ 5753 char c; 5754 c = x; 5755 __etoa_l(&c, 1); 5756 return c; 5757} 5758#endif 5759 5760#if defined(__QNX__) && !defined(__QNXNTO__) 5761#include <sys/types.h> 5762#include <sys/proc_msg.h> 5763#include <sys/kernel.h> 5764#include <string.h> 5765#include <errno.h> 5766 5767struct _proc_session ps; 5768struct _proc_session_reply rps; 5769 5770int 5771qsetlogin(char *login, char *ttyname) 5772{ 5773 int v = getsid(getpid()); 5774 5775 memset(&ps, 0, sizeof(ps)); 5776 memset(&rps, 0, sizeof(rps)); 5777 5778 ps.type = _PROC_SESSION; 5779 ps.subtype = _PROC_SUB_ACTION1; 5780 ps.sid = v; 5781 strcpy(ps.name, login); 5782 5783 Send(1, &ps, &rps, sizeof(ps), sizeof(rps)); 5784 5785 if (rps.status < 0) 5786 return (rps.status); 5787 5788 ps.type = _PROC_SESSION; 5789 ps.subtype = _PROC_SUB_ACTION2; 5790 ps.sid = v; 5791 sprintf(ps.name, "//%d%s", getnid(), ttyname); 5792 Send(1, &ps, &rps, sizeof(ps), sizeof(rps)); 5793 5794 return (rps.status); 5795} 5796#endif 5797 5798#ifdef __minix 5799int 5800setpgrp(void) 5801{ 5802 return 0; 5803} 5804 5805void 5806_longjmp(jmp_buf _env, int _val) 5807{ 5808 longjmp(_env, _val); 5809} 5810#endif 5811