main.c revision ad37e533
1/* $XTermId: main.c,v 1.877 2021/03/21 22:09:06 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 = argv[0]; 2225 2226#ifdef HAVE_POSIX_SAVED_IDS 2227 save_euid = geteuid(); 2228 save_egid = getegid(); 2229#endif 2230 2231 save_ruid = getuid(); 2232 save_rgid = getgid(); 2233 2234#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID) 2235#if defined(DISABLE_SETUID) 2236 disableSetUid(); 2237#endif 2238#if defined(DISABLE_SETGID) 2239 disableSetGid(); 2240#endif 2241 TRACE_IDS; 2242#endif 2243 2244 /* extra length in case longer tty name like /dev/ttyq255 */ 2245 ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80); 2246#ifdef USE_PTY_DEVICE 2247 ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80); 2248 if (!ttydev || !ptydev) 2249#else 2250 if (!ttydev) 2251#endif 2252 { 2253 xtermWarning("unable to allocate memory for ttydev or ptydev\n"); 2254 exit(1); 2255 } 2256 strcpy(ttydev, TTYDEV); 2257#ifdef USE_PTY_DEVICE 2258 strcpy(ptydev, PTYDEV); 2259#endif 2260 2261#if defined(USE_UTMP_SETGID) 2262 get_pty(NULL, NULL); 2263 disableSetUid(); 2264 disableSetGid(); 2265 TRACE_IDS; 2266#define get_pty(pty, from) really_get_pty(pty, from) 2267#endif 2268 2269 /* Do these first, since we may not be able to open the display */ 2270 TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList)); 2271 TRACE_ARGV("Before XtOpenApplication", argv); 2272 if (argc > 1) { 2273 XrmOptionDescRec *option_ptr; 2274 char *option_value; 2275 int n; 2276 Bool quit = False; 2277 2278 for (n = 1; n < argc; n++) { 2279 if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) { 2280 if (argv[n] == 0) { 2281 break; 2282 } else if (isOption(argv[n])) { 2283 Syntax(argv[n]); 2284 } else if (explicit_shname != 0) { 2285 xtermWarning("Explicit shell already was %s\n", explicit_shname); 2286 Syntax(argv[n]); 2287 } 2288 explicit_shname = xtermFindShell(argv[n], True); 2289 if (explicit_shname == 0) 2290 exit(0); 2291 TRACE(("...explicit shell %s\n", explicit_shname)); 2292 } else if (!strcmp(option_ptr->option, "-e")) { 2293 command_to_exec = (argv + n + 1); 2294 if (!command_to_exec[0]) 2295 Syntax(argv[n]); 2296 break; 2297 } else if (!strcmp(option_ptr->option, "-version")) { 2298 Version(); 2299 quit = True; 2300 } else if (!strcmp(option_ptr->option, "-help")) { 2301 Help(); 2302 quit = True; 2303 } else if (!strcmp(option_ptr->option, "-baudrate")) { 2304 NeedParam(option_ptr, option_value); 2305 if ((line_speed = lookup_baudrate(option_value)) == 0) { 2306 Help(); 2307 quit = True; 2308 } 2309 } else if (!strcmp(option_ptr->option, "-class")) { 2310 NeedParam(option_ptr, option_value); 2311 free(my_class); 2312 if ((my_class = x_strdup(option_value)) == 0) { 2313 Help(); 2314 quit = True; 2315 } 2316 } else if (!strcmp(option_ptr->option, "-into")) { 2317 char *endPtr; 2318 NeedParam(option_ptr, option_value); 2319 winToEmbedInto = (Window) strtol(option_value, &endPtr, 0); 2320 if (!FullS2L(option_value, endPtr)) { 2321 Help(); 2322 quit = True; 2323 } 2324 } 2325 } 2326 if (quit) 2327 exit(0); 2328 /* 2329 * If there is anything left unparsed, and we're not using "-e", 2330 * then give up. 2331 */ 2332 if (n < argc && !command_to_exec) { 2333 Syntax(argv[n]); 2334 } 2335 } 2336 2337 /* This dumped core on HP-UX 9.05 with X11R5 */ 2338#if OPT_I18N_SUPPORT 2339 XtSetLanguageProc(NULL, NULL, NULL); 2340#endif 2341 2342 /* enable Xft support in Xaw3DXft */ 2343#if defined(HAVE_LIB_XAW3DXFT) 2344 GET_XAW3DXFT_DATA(xaw3dxft_data); 2345 xaw3dxft_data->encoding = -1; 2346#endif 2347 2348#ifdef TERMIO_STRUCT /* { */ 2349 /* Initialization is done here rather than above in order 2350 * to prevent any assumptions about the order of the contents 2351 * of the various terminal structures (which may change from 2352 * implementation to implementation). 2353 */ 2354 memset(&d_tio, 0, sizeof(d_tio)); 2355 d_tio.c_iflag = ICRNL | IXON; 2356 d_tio.c_oflag = TAB3 | D_TIO_FLAGS; 2357 { 2358 Cardinal nn; 2359 2360 /* fill in default-values */ 2361 for (nn = 0; nn < XtNumber(ttyChars); ++nn) { 2362 if (validTtyChar(d_tio, nn)) { 2363 d_tio.c_cc[ttyChars[nn].sysMode] = 2364 (cc_t) ttyChars[nn].myDefault; 2365 } 2366 } 2367 } 2368#if defined(macII) || defined(ATT) || defined(CRAY) /* { */ 2369 d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL; 2370 d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK; 2371#ifdef ECHOKE 2372 d_tio.c_lflag |= ECHOKE | IEXTEN; 2373#endif 2374#ifdef ECHOCTL 2375 d_tio.c_lflag |= ECHOCTL | IEXTEN; 2376#endif 2377#ifndef USE_TERMIOS /* { */ 2378 d_tio.c_line = 0; 2379#endif /* } */ 2380#ifdef HAS_LTCHARS /* { */ 2381 d_ltc.t_suspc = CSUSP; /* t_suspc */ 2382 d_ltc.t_dsuspc = CDSUSP; /* t_dsuspc */ 2383 d_ltc.t_rprntc = CRPRNT; 2384 d_ltc.t_flushc = CFLUSH; 2385 d_ltc.t_werasc = CWERASE; 2386 d_ltc.t_lnextc = CLNEXT; 2387#endif /* } HAS_LTCHARS */ 2388#ifdef TIOCLSET /* { */ 2389 d_lmode = 0; 2390#endif /* } TIOCLSET */ 2391#else /* }{ else !macII, ATT, CRAY */ 2392#ifndef USE_POSIX_TERMIOS 2393#ifdef BAUD_0 /* { */ 2394 d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL; 2395#else /* }{ !BAUD_0 */ 2396 d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL; 2397#endif /* } !BAUD_0 */ 2398#else /* USE_POSIX_TERMIOS */ 2399 d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL; 2400 cfsetispeed(&d_tio, line_speed); 2401 cfsetospeed(&d_tio, line_speed); 2402#endif 2403 d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK; 2404#ifdef ECHOKE 2405 d_tio.c_lflag |= ECHOKE | IEXTEN; 2406#endif 2407#ifdef ECHOCTL 2408 d_tio.c_lflag |= ECHOCTL | IEXTEN; 2409#endif 2410#ifndef USE_POSIX_TERMIOS 2411#ifdef NTTYDISC 2412 d_tio.c_line = NTTYDISC; 2413#else 2414 d_tio.c_line = 0; 2415#endif 2416#endif /* USE_POSIX_TERMIOS */ 2417#ifdef __sgi 2418 d_tio.c_cflag &= ~(HUPCL | PARENB); 2419 d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR; 2420#endif 2421#ifdef __MVS__ 2422 d_tio.c_cflag &= ~(HUPCL | PARENB); 2423#endif 2424 { 2425 Cardinal nn; 2426 int i; 2427 2428 /* try to inherit tty settings */ 2429 for (i = 0; i <= 2; i++) { 2430 TERMIO_STRUCT deftio; 2431 if (ttyGetAttr(i, &deftio) == 0) { 2432 for (nn = 0; nn < XtNumber(ttyChars); ++nn) { 2433 if (validTtyChar(d_tio, nn)) { 2434 d_tio.c_cc[ttyChars[nn].sysMode] = 2435 deftio.c_cc[ttyChars[nn].sysMode]; 2436 } 2437 } 2438 break; 2439 } 2440 } 2441 } 2442#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS) /* { */ 2443 d_tio.c_cc[VMIN] = 1; 2444 d_tio.c_cc[VTIME] = 0; 2445#endif /* } */ 2446#ifdef HAS_LTCHARS /* { */ 2447 d_ltc.t_suspc = CharOf('\000'); /* t_suspc */ 2448 d_ltc.t_dsuspc = CharOf('\000'); /* t_dsuspc */ 2449 d_ltc.t_rprntc = CharOf('\377'); /* reserved... */ 2450 d_ltc.t_flushc = CharOf('\377'); 2451 d_ltc.t_werasc = CharOf('\377'); 2452 d_ltc.t_lnextc = CharOf('\377'); 2453#endif /* } HAS_LTCHARS */ 2454 2455#ifdef TIOCLSET /* { */ 2456 d_lmode = 0; 2457#endif /* } TIOCLSET */ 2458#endif /* } macII, ATT, CRAY */ 2459#endif /* } TERMIO_STRUCT */ 2460 2461 /* Init the Toolkit. */ 2462 { 2463#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER) 2464 setEffectiveGroup(save_rgid); 2465 setEffectiveUser(save_ruid); 2466 TRACE_IDS; 2467#endif 2468 toplevel = xtermOpenApplication(&app_con, 2469 my_class, 2470 optionDescList, 2471 XtNumber(optionDescList), 2472 &argc, argv, 2473 fallback_resources, 2474 sessionShellWidgetClass, 2475 NULL, 0); 2476 2477 XtGetApplicationResources(toplevel, (XtPointer) &resource, 2478 application_resources, 2479 XtNumber(application_resources), NULL, 0); 2480 TRACE_XRES(); 2481#ifdef HAVE_LIB_XCURSOR 2482 if (!strcmp(resource.cursorTheme, "none")) { 2483 TRACE(("startup with no cursorTheme\n")); 2484 init_colored_cursor(XtDisplay(toplevel)); 2485 } else { 2486 const char *theme = resource.cursorTheme; 2487 if (IsEmpty(theme)) 2488 theme = "default"; 2489 TRACE(("startup with \"%s\" cursorTheme\n", theme)); 2490 xtermSetenv("XCURSOR_THEME", theme); 2491 } 2492#endif 2493#if USE_DOUBLE_BUFFER 2494 if (resource.buffered_fps <= 0) 2495 resource.buffered_fps = DEF_BUFFER_RATE; 2496 if (resource.buffered_fps > 100) 2497 resource.buffered_fps = 100; 2498#endif 2499#if OPT_MAXIMIZE 2500 resource.fullscreen = extendedBoolean(resource.fullscreen_s, 2501 tblFullscreen, 2502 esLAST); 2503#endif 2504 VTInitTranslations(); 2505#if OPT_PTY_HANDSHAKE 2506 resource.wait_for_map0 = resource.wait_for_map; 2507#endif 2508 2509#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) 2510#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID) 2511#if !defined(DISABLE_SETUID) 2512 setEffectiveUser(save_euid); 2513#endif 2514#if !defined(DISABLE_SETGID) 2515 setEffectiveGroup(save_egid); 2516#endif 2517 TRACE_IDS; 2518#endif 2519#endif 2520 } 2521 2522 /* 2523 * ICCCM delete_window. 2524 */ 2525 XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs)); 2526 2527 /* 2528 * fill in terminal modes 2529 */ 2530 if (resource.tty_modes) { 2531 int n = parse_tty_modes(resource.tty_modes); 2532 if (n < 0) { 2533 xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes); 2534 } else if (n > 0) { 2535 override_tty_modes = True; 2536 } 2537 } 2538 initZIconBeep(); 2539 hold_screen = resource.hold_screen ? 1 : 0; 2540 if (resource.icon_geometry != NULL) { 2541 int scr, junk; 2542 int ix, iy; 2543 Arg args[2]; 2544 2545 for (scr = 0; /* yyuucchh */ 2546 XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr); 2547 scr++) ; 2548 2549 args[0].name = XtNiconX; 2550 args[1].name = XtNiconY; 2551 XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "", 2552 0, 0, 0, 0, 0, &ix, &iy, &junk, &junk); 2553 args[0].value = (XtArgVal) ix; 2554 args[1].value = (XtArgVal) iy; 2555 XtSetValues(toplevel, args, 2); 2556 } 2557 2558 XtSetValues(toplevel, ourTopLevelShellArgs, 2559 number_ourTopLevelShellArgs); 2560 2561#if OPT_WIDE_CHARS 2562 /* seems as good a place as any */ 2563 init_classtab(); 2564#endif 2565 2566 /* Parse the rest of the command line */ 2567 TRACE_ARGV("After XtOpenApplication", argv); 2568 for (argc--, argv++; argc > 0; argc--, argv++) { 2569 if (!isOption(*argv)) { 2570#ifdef VMS 2571 Syntax(*argv); 2572#else 2573 if (argc > 1) 2574 Syntax(*argv); 2575 continue; 2576#endif 2577 } 2578 2579 TRACE(("parsing %s\n", argv[0])); 2580 switch (argv[0][1]) { 2581 case 'C': 2582#if defined(TIOCCONS) || defined(SRIOCSREDIR) 2583#ifndef __sgi 2584 { 2585 struct stat sbuf; 2586 2587 /* Must be owner and have read/write permission. 2588 xdm cooperates to give the console the right user. */ 2589 if (!stat("/dev/console", &sbuf) && 2590 (sbuf.st_uid == save_ruid) && 2591 !access("/dev/console", R_OK | W_OK)) { 2592 Console = True; 2593 } else 2594 Console = False; 2595 } 2596#else /* __sgi */ 2597 Console = True; 2598#endif /* __sgi */ 2599#endif /* TIOCCONS */ 2600 continue; 2601 case 'S': 2602 if (!ParseSccn(*argv + 2)) 2603 Syntax(*argv); 2604 continue; 2605#ifdef DEBUG 2606 case 'D': 2607 debug = True; 2608 continue; 2609#endif /* DEBUG */ 2610 case 'b': 2611 if (strcmp(argv[0], "-baudrate")) 2612 Syntax(*argv); 2613 argc--; 2614 argv++; 2615 continue; 2616 case 'c': 2617 if (strcmp(argv[0], "-class")) 2618 Syntax(*argv); 2619 argc--; 2620 argv++; 2621 continue; 2622 case 'e': 2623 if (strcmp(argv[0], "-e")) 2624 Syntax(*argv); 2625 command_to_exec = (argv + 1); 2626 break; 2627 case 'i': 2628 if (strcmp(argv[0], "-into")) 2629 Syntax(*argv); 2630 argc--; 2631 argv++; 2632 continue; 2633 2634 default: 2635 Syntax(*argv); 2636 } 2637 break; 2638 } 2639 2640 SetupMenus(toplevel, &form_top, &menu_top, &menu_high); 2641 2642 term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass, 2643 form_top, 2644#if OPT_TOOLBAR 2645 XtNmenuBar, menu_top, 2646 XtNresizable, True, 2647 XtNfromVert, menu_top, 2648 XtNleft, XawChainLeft, 2649 XtNright, XawChainRight, 2650 XtNtop, XawChainTop, 2651 XtNbottom, XawChainBottom, 2652 XtNmenuHeight, menu_high, 2653#endif 2654 (XtPointer) 0); 2655 decode_keyboard_type(term, &resource); 2656 2657 screen = TScreenOf(term); 2658 screen->inhibit = 0; 2659 2660#ifdef ALLOWLOGGING 2661 if (term->misc.logInhibit) 2662 screen->inhibit |= I_LOG; 2663#endif 2664 if (term->misc.signalInhibit) 2665 screen->inhibit |= I_SIGNAL; 2666#if OPT_TEK4014 2667 if (term->misc.tekInhibit) 2668 screen->inhibit |= I_TEK; 2669#endif 2670 2671 /* 2672 * We might start by showing the tek4014 window. 2673 */ 2674#if OPT_TEK4014 2675 if (screen->inhibit & I_TEK) 2676 TEK4014_ACTIVE(term) = False; 2677 2678 if (TEK4014_ACTIVE(term) && !TekInit()) 2679 SysError(ERROR_INIT); 2680#endif 2681 2682 /* 2683 * Start the toolbar at this point, after the first window has been setup. 2684 */ 2685#if OPT_TOOLBAR 2686 ShowToolbar(resource.toolBar); 2687#endif 2688 2689 xtermOpenSession(); 2690 2691 /* 2692 * Set title and icon name if not specified 2693 */ 2694 if (command_to_exec) { 2695 Arg args[2]; 2696 2697 if (!resource.title) { 2698 if (command_to_exec) { 2699 resource.title = x_basename(command_to_exec[0]); 2700 } /* else not reached */ 2701 } 2702 2703 if (!resource.icon_name) 2704 resource.icon_name = resource.title; 2705 XtSetArg(args[0], XtNtitle, resource.title); 2706 XtSetArg(args[1], XtNiconName, resource.icon_name); 2707 2708 TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n", 2709 resource.title, 2710 resource.icon_name, 2711 NonNull(resource.icon_hint), 2712 *command_to_exec)); 2713 2714 XtSetValues(toplevel, args, 2); 2715 } 2716#if OPT_LUIT_PROG 2717 if (term->misc.callfilter) { 2718 char **split_filter = x_splitargs(term->misc.localefilter); 2719 unsigned count_split = x_countargv(split_filter); 2720 unsigned count_exec = x_countargv(command_to_exec); 2721 unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0); 2722 2723 command_to_exec_with_luit = TypeCallocN(char *, 2724 (count_split 2725 + count_exec 2726 + count_using 2727 + 8)); 2728 if (command_to_exec_with_luit == NULL) 2729 SysError(ERROR_LUMALLOC); 2730 2731 x_appendargv(command_to_exec_with_luit, split_filter); 2732 if (count_using) { 2733 char *encoding_opt[4]; 2734 encoding_opt[0] = x_strdup("-encoding"); 2735 encoding_opt[1] = term->misc.locale_str; 2736 encoding_opt[2] = 0; 2737 x_appendargv(command_to_exec_with_luit, encoding_opt); 2738 } 2739 command_length_with_luit = x_countargv(command_to_exec_with_luit); 2740 if (count_exec) { 2741 static char *fixup_shell[] = 2742 {(char *) "sh", (char *) "-c", 0}; 2743 char *delimiter[2]; 2744 delimiter[0] = x_strdup("--"); 2745 delimiter[1] = 0; 2746 x_appendargv(command_to_exec_with_luit, delimiter); 2747 if (complex_command(command_to_exec)) { 2748 x_appendargv(command_to_exec_with_luit, fixup_shell); 2749 } 2750 x_appendargv(command_to_exec_with_luit, command_to_exec); 2751 } 2752 TRACE_ARGV("luit command", command_to_exec_with_luit); 2753 xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit); 2754 } 2755#endif 2756 2757 if_DEBUG({ 2758 /* Set up stderr properly. Opening this log file cannot be 2759 done securely by a privileged xterm process (although we try), 2760 so the debug feature is disabled by default. */ 2761 char dbglogfile[TIMESTAMP_LEN + 20]; 2762 int i = -1; 2763 timestamp_filename(dbglogfile, "xterm.debug.log."); 2764 if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) { 2765 i = open(dbglogfile, O_WRONLY | O_TRUNC); 2766 } 2767 if (i >= 0) { 2768 dup2(i, 2); 2769 2770 /* mark this file as close on exec */ 2771 (void) fcntl(i, F_SETFD, 1); 2772 } 2773 }); 2774 2775 spawnXTerm(term, line_speed); 2776 2777#ifndef VMS 2778 /* Child process is out there, let's catch its termination */ 2779 2780#ifdef USE_POSIX_SIGNALS 2781 (void) posix_signal(SIGCHLD, reapchild); 2782#else 2783 (void) signal(SIGCHLD, reapchild); 2784#endif 2785 /* Realize procs have now been executed */ 2786 2787 if (am_slave >= 0) { /* Write window id so master end can read and use */ 2788 char buf[80]; 2789 2790 buf[0] = '\0'; 2791 sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU()))); 2792 IGNORE_RC(write(screen->respond, buf, strlen(buf))); 2793 } 2794#ifdef AIXV3 2795#if (OSMAJORVERSION < 4) 2796 /* In AIXV3, xterms started from /dev/console have CLOCAL set. 2797 * This means we need to clear CLOCAL so that SIGHUP gets sent 2798 * to the slave-pty process when xterm exits. 2799 */ 2800 2801 { 2802 TERMIO_STRUCT tio; 2803 2804 if (ttyGetAttr(screen->respond, &tio) == -1) 2805 SysError(ERROR_TIOCGETP); 2806 2807 tio.c_cflag &= ~(CLOCAL); 2808 2809 if (ttySetAttr(screen->respond, &tio) == -1) 2810 SysError(ERROR_TIOCSETP); 2811 } 2812#endif 2813#endif 2814#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__) || defined(__minix) 2815 if (0 > (mode = fcntl(screen->respond, F_GETFL, 0))) 2816 SysError(ERROR_F_GETFL); 2817#ifdef O_NDELAY 2818 mode |= O_NDELAY; 2819#else 2820 mode |= O_NONBLOCK; 2821#endif /* O_NDELAY */ 2822 if (fcntl(screen->respond, F_SETFL, mode)) 2823 SysError(ERROR_F_SETFL); 2824#else /* !USE_ANY_SYSV_TERMIO */ 2825 mode = 1; 2826 if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1) 2827 SysError(ERROR_FIONBIO); 2828#endif /* USE_ANY_SYSV_TERMIO, etc */ 2829 2830 /* The erase character is used to delete the current completion */ 2831#if OPT_DABBREV 2832#ifdef TERMIO_STRUCT 2833 screen->dabbrev_erase_char = d_tio.c_cc[VERASE]; 2834#else 2835 screen->dabbrev_erase_char = d_sg.sg_erase; 2836#endif 2837 TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char)); 2838#endif 2839 2840 FD_ZERO(&pty_mask); 2841 FD_ZERO(&X_mask); 2842 FD_ZERO(&Select_mask); 2843 FD_SET(screen->respond, &pty_mask); 2844 FD_SET(ConnectionNumber(screen->display), &X_mask); 2845 FD_SET(screen->respond, &Select_mask); 2846 FD_SET(ConnectionNumber(screen->display), &Select_mask); 2847 max_plus1 = ((screen->respond < ConnectionNumber(screen->display)) 2848 ? (1 + ConnectionNumber(screen->display)) 2849 : (1 + screen->respond)); 2850 2851#endif /* !VMS */ 2852 if_DEBUG({ 2853 TRACE(("debugging on pid %d\n", (int) getpid())); 2854 }); 2855 XSetErrorHandler(xerror); 2856 XSetIOErrorHandler(xioerror); 2857#if OPT_SESSION_MGT 2858 IceSetIOErrorHandler(ice_error); 2859#endif 2860 2861 initPtyData(&VTbuffer); 2862#ifdef ALLOWLOGGING 2863 if (term->misc.log_on) { 2864 StartLog(term); 2865 } 2866#endif 2867 2868 xtermEmbedWindow(winToEmbedInto); 2869#if OPT_COLOR_RES 2870 TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n", 2871 term->misc.re_verse0 ? "reverse" : "normal", 2872 NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource), 2873 NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource))); 2874 2875 if (term->misc.re_verse0) { 2876 if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource) 2877 && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) { 2878 TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground); 2879 TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground); 2880 } else { 2881 ReverseVideo(term); 2882 } 2883 term->misc.re_verse = True; 2884 update_reversevideo(); 2885 TRACE(("updated reverseVideo after rv %s fg %s, bg %s\n", 2886 term->misc.re_verse ? "reverse" : "normal", 2887 NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource), 2888 NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource))); 2889 } 2890#endif /* OPT_COLOR_RES */ 2891 2892#if OPT_MAXIMIZE 2893 if (resource.maximized) 2894 RequestMaximize(term, True); 2895#endif 2896 for (;;) { 2897#if OPT_TEK4014 2898 if (TEK4014_ACTIVE(term)) 2899 TekRun(); 2900 else 2901#endif 2902 VTRun(term); 2903 } 2904} 2905 2906#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) 2907#define USE_OPENPTY 1 2908static int opened_tty = -1; 2909#endif 2910 2911/* 2912 * This function opens up a pty master and stuffs its value into pty. 2913 * 2914 * If it finds one, it returns a value of 0. If it does not find one, 2915 * it returns a value of !0. This routine is designed to be re-entrant, 2916 * so that if a pty master is found and later, we find that the slave 2917 * has problems, we can re-enter this function and get another one. 2918 */ 2919static int 2920get_pty(int *pty, char *from GCC_UNUSED) 2921{ 2922 int result = 1; 2923 2924#if defined(USE_OPENPTY) 2925 result = openpty(pty, &opened_tty, ttydev, NULL, NULL); 2926 if (opened_tty >= 0) { 2927 close(opened_tty); 2928 opened_tty = -1; 2929 } 2930#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY) 2931 if ((*pty = posix_openpt(O_RDWR)) >= 0) { 2932 char *name = ptsname(*pty); 2933 if (name != 0) { 2934 strcpy(ttydev, name); 2935 result = 0; 2936 } 2937 } 2938#ifdef USE_PTY_SEARCH 2939 if (result) { 2940 result = pty_search(pty); 2941 } 2942#endif 2943#elif defined(PUCC_PTYD) 2944 result = ((*pty = openrpty(ttydev, ptydev, 2945 (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), 2946 save_ruid, from)) < 0); 2947#elif defined(__QNXNTO__) 2948 result = pty_search(pty); 2949#else 2950#if defined(USE_USG_PTYS) || defined(__CYGWIN__) 2951#if defined(__MVS__) 2952 result = pty_search(pty); 2953#else 2954 result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0); 2955#endif 2956#if defined(SVR4) || defined(__SCO__) 2957 if (!result) 2958 strcpy(ttydev, ptsname(*pty)); 2959#endif 2960 2961#elif defined(AIXV3) 2962 2963 if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) { 2964 strcpy(ttydev, ttyname(*pty)); 2965 result = 0; 2966 } 2967#elif defined(__convex__) 2968 2969 char *pty_name; 2970 extern char *getpty(void); 2971 2972 while ((pty_name = getpty()) != NULL) { 2973 if ((*pty = open(pty_name, O_RDWR)) >= 0) { 2974 strcpy(ptydev, pty_name); 2975 strcpy(ttydev, pty_name); 2976 *x_basename(ttydev) = 't'; 2977 result = 0; 2978 break; 2979 } 2980 } 2981 2982#elif defined(sequent) 2983 2984 result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0); 2985 2986#elif defined(__sgi) && (OSMAJORVERSION >= 4) 2987 2988 char *tty_name; 2989 2990 tty_name = _getpty(pty, O_RDWR, 0622, 0); 2991 if (tty_name != 0) { 2992 strcpy(ttydev, tty_name); 2993 result = 0; 2994 } 2995#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV)) 2996 2997 struct stat fstat_buf; 2998 2999 *pty = open("/dev/ptc", O_RDWR); 3000 if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) { 3001 result = 0; 3002 sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev)); 3003 } 3004#elif defined(__hpux) 3005 3006 /* 3007 * Use the clone device if it works, otherwise use pty_search logic. 3008 */ 3009 if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) { 3010 char *name = ptsname(*pty); 3011 if (name != 0) { 3012 strcpy(ttydev, name); 3013 result = 0; 3014 } else { /* permissions, or other unexpected problem */ 3015 close(*pty); 3016 *pty = -1; 3017 result = pty_search(pty); 3018 } 3019 } else { 3020 result = pty_search(pty); 3021 } 3022 3023#else 3024 3025 result = pty_search(pty); 3026 3027#endif 3028#endif 3029 3030 TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n", 3031 ttydev != 0 ? ttydev : "?", 3032 ptydev != 0 ? ptydev : "?", 3033 result ? "FAIL" : "OK", 3034 pty != 0 ? *pty : -1)); 3035 return result; 3036} 3037 3038static void 3039set_pty_permissions(uid_t uid, unsigned gid, unsigned mode) 3040{ 3041#ifdef USE_TTY_GROUP 3042 struct group *ttygrp; 3043 3044 if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) { 3045 gid = (unsigned) ttygrp->gr_gid; 3046 mode &= 0660U; 3047 } 3048 endgrent(); 3049#endif /* USE_TTY_GROUP */ 3050 3051 TRACE_IDS; 3052 set_owner(ttydev, (unsigned) uid, gid, mode); 3053} 3054 3055#ifdef get_pty /* USE_UTMP_SETGID */ 3056#undef get_pty 3057/* 3058 * Call the real get_pty() before relinquishing root-setuid, caching the 3059 * result. 3060 */ 3061static int 3062get_pty(int *pty, char *from) 3063{ 3064 static int m_pty = -1; 3065 int result = -1; 3066 3067 if (pty == NULL) { 3068 result = really_get_pty(&m_pty, from); 3069 3070 seteuid(0); 3071 set_pty_permissions(save_ruid, save_rgid, 0600U); 3072 seteuid(save_ruid); 3073 TRACE_IDS; 3074 3075 } else if (m_pty != -1) { 3076 *pty = m_pty; 3077 result = 0; 3078 } else { 3079 result = -1; 3080 } 3081 TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n", 3082 ttydev != 0 ? ttydev : "?", 3083 ptydev != 0 ? ptydev : "?", 3084 result ? "FAIL" : "OK", 3085 pty != 0 ? *pty : -1)); 3086#ifdef USE_OPENPTY 3087 if (opened_tty >= 0) { 3088 close(opened_tty); 3089 opened_tty = -1; 3090 } 3091#endif 3092 return result; 3093} 3094#endif 3095 3096/* 3097 * Called from get_pty to iterate over likely pseudo terminals 3098 * we might allocate. Used on those systems that do not have 3099 * a functional interface for allocating a pty. 3100 * Returns 0 if found a pty, 1 if fails. 3101 */ 3102#ifdef USE_PTY_SEARCH 3103static int 3104pty_search(int *pty) 3105{ 3106 static int devindex = 0, letter = 0; 3107 3108#if defined(CRAY) || defined(__MVS__) 3109 while (devindex < MAXPTTYS) { 3110 sprintf(ttydev, TTYFORMAT, devindex); 3111 sprintf(ptydev, PTYFORMAT, devindex); 3112 devindex++; 3113 3114 TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev)); 3115 if ((*pty = open(ptydev, O_RDWR)) >= 0) { 3116 return 0; 3117 } 3118 } 3119#else /* CRAY || __MVS__ */ 3120 while (PTYCHAR1[letter]) { 3121 ttydev[strlen(ttydev) - 2] = 3122 ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter]; 3123 3124 while (PTYCHAR2[devindex]) { 3125 ttydev[strlen(ttydev) - 1] = 3126 ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex]; 3127 devindex++; 3128 3129 TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev)); 3130 if ((*pty = open(ptydev, O_RDWR)) >= 0) { 3131#ifdef sun 3132 /* Need to check the process group of the pty. 3133 * If it exists, then the slave pty is in use, 3134 * and we need to get another one. 3135 */ 3136 int pgrp_rtn; 3137 if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) { 3138 close(*pty); 3139 continue; 3140 } 3141#endif /* sun */ 3142 return 0; 3143 } 3144 } 3145 devindex = 0; 3146 letter++; 3147 } 3148#endif /* CRAY else */ 3149 /* 3150 * We were unable to allocate a pty master! Return an error 3151 * condition and let our caller terminate cleanly. 3152 */ 3153 return 1; 3154} 3155#endif /* USE_PTY_SEARCH */ 3156 3157/* 3158 * The only difference in /etc/termcap between 4014 and 4015 is that 3159 * the latter has support for switching character sets. We support the 3160 * 4015 protocol, but ignore the character switches. Therefore, we 3161 * choose 4014 over 4015. 3162 * 3163 * Features of the 4014 over the 4012: larger (19") screen, 12-bit 3164 * graphics addressing (compatible with 4012 10-bit addressing), 3165 * special point plot mode, incremental plot mode (not implemented in 3166 * later Tektronix terminals), and 4 character sizes. 3167 * All of these are supported by xterm. 3168 */ 3169 3170#if OPT_TEK4014 3171static const char *const tekterm[] = 3172{ 3173 "tek4014", 3174 "tek4015", /* 4014 with APL character set support */ 3175 "tek4012", /* 4010 with lower case */ 3176 "tek4013", /* 4012 with APL character set support */ 3177 "tek4010", /* small screen, upper-case only */ 3178 "dumb", 3179 0 3180}; 3181#endif 3182 3183/* The VT102 is a VT100 with the Advanced Video Option included standard. 3184 * It also adds Escape sequences for insert/delete character/line. 3185 * The VT220 adds 8-bit character sets, selective erase. 3186 * The VT320 adds a 25th status line, terminal state interrogation. 3187 * The VT420 has up to 48 lines on the screen. 3188 */ 3189 3190static const char *const vtterm[] = 3191{ 3192#ifdef USE_X11TERM 3193 "x11term", /* for people who want special term name */ 3194#endif 3195 DFT_TERMTYPE, /* for people who want special term name */ 3196 "xterm", /* the preferred name, should be fastest */ 3197 "vt102", 3198 "vt100", 3199 "ansi", 3200 "dumb", 3201 0 3202}; 3203 3204/* ARGSUSED */ 3205static void 3206hungtty(int i GCC_UNUSED) 3207{ 3208 DEBUG_MSG("handle:hungtty\n"); 3209 siglongjmp(env, 1); 3210} 3211 3212#if OPT_PTY_HANDSHAKE 3213#define NO_FDS {-1, -1} 3214 3215static int cp_pipe[2] = NO_FDS; /* this pipe is used for child to parent transfer */ 3216static int pc_pipe[2] = NO_FDS; /* this pipe is used for parent to child transfer */ 3217 3218typedef enum { /* c == child, p == parent */ 3219 PTY_BAD, /* c->p: can't open pty slave for some reason */ 3220 PTY_FATALERROR, /* c->p: we had a fatal error with the pty */ 3221 PTY_GOOD, /* c->p: we have a good pty, let's go on */ 3222 PTY_NEW, /* p->c: here is a new pty slave, try this */ 3223 PTY_NOMORE, /* p->c; no more pty's, terminate */ 3224 UTMP_ADDED, /* c->p: utmp entry has been added */ 3225 UTMP_TTYSLOT, /* c->p: here is my ttyslot */ 3226 PTY_EXEC /* p->c: window has been mapped the first time */ 3227} status_t; 3228 3229#define HANDSHAKE_LEN 1024 3230 3231typedef struct { 3232 status_t status; 3233 int error; 3234 int fatal_error; 3235 int tty_slot; 3236 int rows; 3237 int cols; 3238 char buffer[HANDSHAKE_LEN]; 3239} handshake_t; 3240 3241/* the buffer is large enough that we can always have a trailing null */ 3242#define copy_handshake(dst, src) \ 3243 strncpy(dst.buffer, src, (size_t)HANDSHAKE_LEN - 1)[HANDSHAKE_LEN - 1] = '\0' 3244 3245#if OPT_TRACE 3246static void 3247trace_handshake(const char *tag, handshake_t * data) 3248{ 3249 const char *status = "?"; 3250 switch (data->status) { 3251 case PTY_BAD: 3252 status = "PTY_BAD"; 3253 break; 3254 case PTY_FATALERROR: 3255 status = "PTY_FATALERROR"; 3256 break; 3257 case PTY_GOOD: 3258 status = "PTY_GOOD"; 3259 break; 3260 case PTY_NEW: 3261 status = "PTY_NEW"; 3262 break; 3263 case PTY_NOMORE: 3264 status = "PTY_NOMORE"; 3265 break; 3266 case UTMP_ADDED: 3267 status = "UTMP_ADDED"; 3268 break; 3269 case UTMP_TTYSLOT: 3270 status = "UTMP_TTYSLOT"; 3271 break; 3272 case PTY_EXEC: 3273 status = "PTY_EXEC"; 3274 break; 3275 } 3276 TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n", 3277 tag, 3278 status, 3279 data->error, 3280 data->fatal_error, 3281 data->buffer)); 3282} 3283#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data) 3284#else 3285#define TRACE_HANDSHAKE(tag, data) /* nothing */ 3286#endif 3287 3288/* HsSysError() 3289 * 3290 * This routine does the equivalent of a SysError but it handshakes 3291 * over the errno and error exit to the master process so that it can 3292 * display our error message and exit with our exit code so that the 3293 * user can see it. 3294 */ 3295 3296static void 3297HsSysError(int error) 3298{ 3299 handshake_t handshake; 3300 3301 memset(&handshake, 0, sizeof(handshake)); 3302 handshake.status = PTY_FATALERROR; 3303 handshake.error = errno; 3304 handshake.fatal_error = error; 3305 copy_handshake(handshake, ttydev); 3306 3307 if (resource.ptyHandshake && (cp_pipe[1] >= 0)) { 3308 TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n", 3309 handshake.error, 3310 handshake.fatal_error, 3311 handshake.buffer)); 3312 TRACE_HANDSHAKE("writing", &handshake); 3313 IGNORE_RC(write(cp_pipe[1], 3314 (const char *) &handshake, 3315 sizeof(handshake))); 3316 } else { 3317 xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n", 3318 handshake.error, 3319 handshake.fatal_error, 3320 handshake.buffer); 3321 fprintf(stderr, "%s\n", SysErrorMsg(handshake.error)); 3322 fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error)); 3323 } 3324 exit(error); 3325} 3326 3327void 3328first_map_occurred(void) 3329{ 3330 if (resource.wait_for_map) { 3331 if (pc_pipe[1] >= 0) { 3332 handshake_t handshake; 3333 TScreen *screen = TScreenOf(term); 3334 3335 memset(&handshake, 0, sizeof(handshake)); 3336 handshake.status = PTY_EXEC; 3337 handshake.rows = screen->max_row; 3338 handshake.cols = screen->max_col; 3339 3340 TRACE(("first_map_occurred: %dx%d\n", MaxRows(screen), MaxCols(screen))); 3341 TRACE_HANDSHAKE("writing", &handshake); 3342 IGNORE_RC(write(pc_pipe[1], 3343 (const char *) &handshake, 3344 sizeof(handshake))); 3345 close(cp_pipe[0]); 3346 close(pc_pipe[1]); 3347 } 3348 resource.wait_for_map = False; 3349 } 3350} 3351#else 3352/* 3353 * temporary hack to get xterm working on att ptys 3354 */ 3355static void 3356HsSysError(int error) 3357{ 3358 xtermWarning("fatal pty error %d (errno=%d) on tty %s\n", 3359 error, errno, ttydev); 3360 exit(error); 3361} 3362#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */ 3363 3364#ifndef VMS 3365static void 3366set_owner(char *device, unsigned uid, unsigned gid, unsigned mode) 3367{ 3368 int why; 3369 3370 TRACE_IDS; 3371 TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n", 3372 device, (int) uid, (int) gid, (unsigned) mode)); 3373 3374 if (chown(device, (uid_t) uid, (gid_t) gid) < 0) { 3375 why = errno; 3376 if (why != ENOENT 3377 && save_ruid == 0) { 3378 xtermPerror("Cannot chown %s to %ld,%ld", 3379 device, (long) uid, (long) gid); 3380 } 3381 TRACE(("...chown failed: %s\n", strerror(why))); 3382 } else if (chmod(device, (mode_t) mode) < 0) { 3383 why = errno; 3384 if (why != ENOENT) { 3385 struct stat sb; 3386 if (stat(device, &sb) < 0) { 3387 xtermPerror("Cannot chmod %s to %03o", 3388 device, (unsigned) mode); 3389 } else if (mode != (sb.st_mode & 0777U)) { 3390 xtermPerror("Cannot chmod %s to %03lo currently %03lo", 3391 device, 3392 (unsigned long) mode, 3393 (unsigned long) (sb.st_mode & 0777U)); 3394 TRACE(("...stat uid=%d, gid=%d, mode=%#o\n", 3395 (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode)); 3396 } 3397 } 3398 TRACE(("...chmod failed: %s\n", strerror(why))); 3399 } 3400} 3401 3402/* 3403 * utmp data may not be null-terminated; even if it is, there may be garbage 3404 * after the null. This fills the unused part of the result with nulls. 3405 */ 3406static void 3407copy_filled(char *target, const char *source, size_t len) 3408{ 3409 size_t used = 0; 3410 while (used < len) { 3411 if ((target[used] = source[used]) == 0) 3412 break; 3413 ++used; 3414 } 3415 while (used < len) { 3416 target[used++] = '\0'; 3417 } 3418} 3419 3420#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER) 3421/* 3422 * getutid() only looks at ut_type and ut_id. 3423 * But we'll also check ut_line in find_utmp(). 3424 */ 3425static void 3426init_utmp(int type, struct UTMP_STR *tofind) 3427{ 3428 memset(tofind, 0, sizeof(*tofind)); 3429 tofind->ut_type = (short) type; 3430 copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id)); 3431 copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line)); 3432} 3433 3434/* 3435 * We could use getutline() if we didn't support old systems. 3436 */ 3437static struct UTMP_STR * 3438find_utmp(struct UTMP_STR *tofind) 3439{ 3440 struct UTMP_STR *result; 3441 struct UTMP_STR limited; 3442 struct UTMP_STR working; 3443 3444 for (;;) { 3445 memset(&working, 0, sizeof(working)); 3446 working.ut_type = tofind->ut_type; 3447 copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id)); 3448#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5) 3449 working.ut_type = 0; 3450#endif 3451 if ((result = call_getutid(&working)) == 0) 3452 break; 3453 copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line)); 3454 if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line))) 3455 break; 3456 /* 3457 * Solaris, IRIX64 and HPUX manpages say to fill the static area 3458 * pointed to by the return-value to zeros if searching for multiple 3459 * occurrences. Otherwise it will continue to return the same value. 3460 */ 3461 memset(result, 0, sizeof(*result)); 3462 } 3463 return result; 3464} 3465#endif /* HAVE_UTMP... */ 3466 3467#define close_fd(fd) close(fd), fd = -1 3468 3469#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1))) 3470#define USE_NO_DEV_TTY 1 3471#else 3472#define USE_NO_DEV_TTY 0 3473#endif 3474 3475static int 3476same_leaf(char *a, char *b) 3477{ 3478 char *p = x_basename(a); 3479 char *q = x_basename(b); 3480 return !strcmp(p, q); 3481} 3482 3483/* 3484 * "good enough" (inode wouldn't port to Cygwin) 3485 */ 3486static int 3487same_file(const char *a, const char *b) 3488{ 3489 struct stat asb; 3490 struct stat bsb; 3491 int result = 0; 3492 3493 if ((stat(a, &asb) == 0) 3494 && (stat(b, &bsb) == 0) 3495 && ((asb.st_mode & S_IFMT) == S_IFREG) 3496 && ((bsb.st_mode & S_IFMT) == S_IFREG) 3497 && (asb.st_mtime == bsb.st_mtime) 3498 && (asb.st_size == bsb.st_size)) { 3499 result = 1; 3500 } 3501 return result; 3502} 3503 3504static int 3505findValidShell(const char *haystack, const char *needle) 3506{ 3507 int result = -1; 3508 int count = -1; 3509 const char *s, *t; 3510 size_t have; 3511 size_t want = strlen(needle); 3512 3513 TRACE(("findValidShell:\n%s\n", NonNull(haystack))); 3514 3515 for (s = haystack; (s != 0) && (*s != '\0'); s = t) { 3516 ++count; 3517 if ((t = strchr(s, '\n')) == 0) { 3518 t = s + strlen(s); 3519 } 3520 have = (size_t) (t - s); 3521 3522 if ((have >= want) && (*s != '#')) { 3523 char *p = malloc(have + 1); 3524 3525 if (p != 0) { 3526 char *q; 3527 3528 memcpy(p, s, have); 3529 p[have] = '\0'; 3530 if ((q = x_strtrim(p)) != 0) { 3531 TRACE(("...test %s\n", q)); 3532 if (!strcmp(q, needle)) { 3533 result = count; 3534 } else if (same_leaf(q, (char *) needle) && 3535 same_file(q, needle)) { 3536 result = count; 3537 } 3538 free(q); 3539 } 3540 free(p); 3541 } 3542 if (result >= 0) 3543 break; 3544 } 3545 while (*t == '\n') { 3546 ++t; 3547 } 3548 } 3549 return result; 3550} 3551 3552static int 3553ourValidShell(const char *pathname) 3554{ 3555 return findValidShell(x_strtrim(resource.valid_shells), pathname); 3556} 3557 3558#if defined(HAVE_GETUSERSHELL) && defined(HAVE_ENDUSERSHELL) 3559static Boolean 3560validShell(const char *pathname) 3561{ 3562 int result = -1; 3563 3564 if (validProgram(pathname)) { 3565 char *q; 3566 int count = -1; 3567 3568 TRACE(("validShell:getusershell\n")); 3569 while ((q = getusershell()) != 0) { 3570 ++count; 3571 TRACE(("...test \"%s\"\n", q)); 3572 if (!strcmp(q, pathname)) { 3573 result = count; 3574 break; 3575 } 3576 } 3577 endusershell(); 3578 3579 if (result < 0) 3580 result = ourValidShell(pathname); 3581 } 3582 3583 TRACE(("validShell %s ->%d\n", NonNull(pathname), result)); 3584 return (result >= 0); 3585} 3586#else 3587/* 3588 * Only set $SHELL for paths found in the standard location. 3589 */ 3590static Boolean 3591validShell(const char *pathname) 3592{ 3593 int result = -1; 3594 const char *ok_shells = "/etc/shells"; 3595 char *blob; 3596 struct stat sb; 3597 size_t rc; 3598 FILE *fp; 3599 3600 if (validProgram(pathname)) { 3601 3602 TRACE(("validShell:%s\n", ok_shells)); 3603 3604 if (stat(ok_shells, &sb) == 0 3605 && (sb.st_mode & S_IFMT) == S_IFREG 3606 && ((size_t) sb.st_size > 0) 3607 && ((size_t) sb.st_size < (((size_t) ~0) - 2)) 3608 && (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) { 3609 3610 if ((fp = fopen(ok_shells, "r")) != 0) { 3611 rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp); 3612 fclose(fp); 3613 3614 if (rc == (size_t) sb.st_size) { 3615 blob[rc] = '\0'; 3616 result = findValidShell(blob, pathname); 3617 } 3618 } 3619 free(blob); 3620 } 3621 if (result < 0) 3622 result = ourValidShell(pathname); 3623 } 3624 TRACE(("validShell %s ->%d\n", NonNull(pathname), result)); 3625 return (result > 0); 3626} 3627#endif 3628 3629static char * 3630resetShell(char *oldPath) 3631{ 3632 char *newPath = x_strdup("/bin/sh"); 3633 char *envPath = getenv("SHELL"); 3634 free(oldPath); 3635 if (!IsEmpty(envPath)) 3636 xtermSetenv("SHELL", newPath); 3637 return newPath; 3638} 3639 3640/* 3641 * Inits pty and tty and forks a login process. 3642 * Does not close fd Xsocket. 3643 * If slave, the pty named in passedPty is already open for use 3644 */ 3645static int 3646spawnXTerm(XtermWidget xw, unsigned line_speed) 3647{ 3648 TScreen *screen = TScreenOf(xw); 3649 Cardinal nn; 3650#if OPT_PTY_HANDSHAKE 3651 Bool got_handshake_size = False; 3652 handshake_t handshake; 3653 int done; 3654#endif 3655#if OPT_INITIAL_ERASE 3656 int initial_erase = VAL_INITIAL_ERASE; 3657 Bool setInitialErase; 3658#endif 3659 int rc = 0; 3660 int ttyfd = -1; 3661 Bool ok_termcap; 3662 char *newtc; 3663 3664#ifdef TERMIO_STRUCT 3665 TERMIO_STRUCT tio; 3666#ifdef __MVS__ 3667 TERMIO_STRUCT gio; 3668#endif /* __MVS__ */ 3669#ifdef TIOCLSET 3670 unsigned lmode; 3671#endif /* TIOCLSET */ 3672#ifdef HAS_LTCHARS 3673 struct ltchars ltc; 3674#endif /* HAS_LTCHARS */ 3675#else /* !TERMIO_STRUCT */ 3676 int ldisc = 0; 3677 int discipline; 3678 unsigned lmode; 3679 struct tchars tc; 3680 struct ltchars ltc; 3681 struct sgttyb sg; 3682#ifdef sony 3683 int jmode; 3684 struct jtchars jtc; 3685#endif /* sony */ 3686#endif /* TERMIO_STRUCT */ 3687 3688 char *shell_path = 0; 3689 char *shname, *shname_minus; 3690 int i; 3691#if USE_NO_DEV_TTY 3692 int no_dev_tty = False; 3693#endif 3694 const char *const *envnew; /* new environment */ 3695 char buf[64]; 3696 char *TermName = NULL; 3697#ifdef TTYSIZE_STRUCT 3698 TTYSIZE_STRUCT ts; 3699#endif 3700 struct passwd pw; 3701 char *login_name = NULL; 3702#ifndef USE_UTEMPTER 3703#ifdef HAVE_UTMP 3704 struct UTMP_STR utmp; 3705#ifdef USE_SYSV_UTMP 3706 struct UTMP_STR *utret = NULL; 3707#endif 3708#ifdef USE_LASTLOG 3709 struct lastlog lastlog; 3710#endif 3711#ifdef USE_LASTLOGX 3712 struct lastlogx lastlogx; 3713#endif /* USE_LASTLOG */ 3714#endif /* HAVE_UTMP */ 3715#endif /* !USE_UTEMPTER */ 3716 3717#if OPT_TRACE 3718 unsigned long xterm_parent = (unsigned long) getpid(); 3719#endif 3720 3721 /* Noisy compilers (suppress some unused-variable warnings) */ 3722 (void) rc; 3723#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER) 3724 (void) utret; 3725#endif 3726 3727 screen->uid = save_ruid; 3728 screen->gid = save_rgid; 3729 3730#ifdef SIGTTOU 3731 /* so that TIOCSWINSZ || TIOCSIZE doesn't block */ 3732 signal(SIGTTOU, SIG_IGN); 3733#endif 3734 3735#if OPT_PTY_HANDSHAKE 3736 memset(&handshake, 0, sizeof(handshake)); 3737#endif 3738 3739 if (am_slave >= 0) { 3740 screen->respond = am_slave; 3741 set_pty_id(ttydev, passedPty); 3742#ifdef USE_PTY_DEVICE 3743 set_pty_id(ptydev, passedPty); 3744#endif 3745 if (xtermResetIds(screen) < 0) 3746 exit(1); 3747 } else { 3748 Bool tty_got_hung; 3749 3750 /* 3751 * Sometimes /dev/tty hangs on open (as in the case of a pty 3752 * that has gone away). Simply make up some reasonable 3753 * defaults. 3754 */ 3755 3756 if (!sigsetjmp(env, 1)) { 3757 signal(SIGALRM, hungtty); 3758 alarm(2); /* alarm(1) might return too soon */ 3759 ttyfd = open("/dev/tty", O_RDWR); 3760 alarm(0); 3761 tty_got_hung = False; 3762 } else { 3763 tty_got_hung = True; 3764 ttyfd = -1; 3765 errno = ENXIO; 3766 } 3767 shell_path = 0; 3768 memset(&pw, 0, sizeof(pw)); 3769#if OPT_PTY_HANDSHAKE 3770 got_handshake_size = False; 3771#endif /* OPT_PTY_HANDSHAKE */ 3772#if OPT_INITIAL_ERASE 3773 initial_erase = VAL_INITIAL_ERASE; 3774#endif 3775 signal(SIGALRM, SIG_DFL); 3776 3777 /* 3778 * Check results and ignore current control terminal if 3779 * necessary. ENXIO is what is normally returned if there is 3780 * no controlling terminal, but some systems (e.g. SunOS 4.0) 3781 * seem to return EIO. Solaris 2.3 is said to return EINVAL. 3782 * Cygwin returns ENOENT. FreeBSD can return ENOENT, especially 3783 * if xterm is run within a jail. 3784 */ 3785#if USE_NO_DEV_TTY 3786 no_dev_tty = False; 3787#endif 3788 if (ttyfd < 0) { 3789 if (tty_got_hung || errno == ENXIO || errno == EIO || 3790 errno == ENOENT || 3791#ifdef ENODEV 3792 errno == ENODEV || 3793#endif 3794 errno == EINVAL || errno == ENOTTY || errno == EACCES) { 3795#if USE_NO_DEV_TTY 3796 no_dev_tty = True; 3797#endif 3798#ifdef HAS_LTCHARS 3799 ltc = d_ltc; 3800#endif /* HAS_LTCHARS */ 3801#ifdef TIOCLSET 3802 lmode = d_lmode; 3803#endif /* TIOCLSET */ 3804#ifdef TERMIO_STRUCT 3805 tio = d_tio; 3806#else /* !TERMIO_STRUCT */ 3807 sg = d_sg; 3808 tc = d_tc; 3809 discipline = d_disipline; 3810#ifdef sony 3811 jmode = d_jmode; 3812 jtc = d_jtc; 3813#endif /* sony */ 3814#endif /* TERMIO_STRUCT */ 3815 } else { 3816 SysError(ERROR_OPDEVTTY); 3817 } 3818 } else { 3819 3820 /* Get a copy of the current terminal's state, 3821 * if we can. Some systems (e.g., SVR4 and MacII) 3822 * may not have a controlling terminal at this point 3823 * if started directly from xdm or xinit, 3824 * in which case we just use the defaults as above. 3825 */ 3826#ifdef HAS_LTCHARS 3827 if (ioctl(ttyfd, TIOCGLTC, <c) == -1) 3828 ltc = d_ltc; 3829#endif /* HAS_LTCHARS */ 3830#ifdef TIOCLSET 3831 if (ioctl(ttyfd, TIOCLGET, &lmode) == -1) 3832 lmode = d_lmode; 3833#endif /* TIOCLSET */ 3834#ifdef TERMIO_STRUCT 3835 rc = ttyGetAttr(ttyfd, &tio); 3836 if (rc == -1) 3837 tio = d_tio; 3838#else /* !TERMIO_STRUCT */ 3839 rc = ioctl(ttyfd, TIOCGETP, (char *) &sg); 3840 if (rc == -1) 3841 sg = d_sg; 3842 if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1) 3843 tc = d_tc; 3844 if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1) 3845 discipline = d_disipline; 3846#ifdef sony 3847 if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1) 3848 jmode = d_jmode; 3849 if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1) 3850 jtc = d_jtc; 3851#endif /* sony */ 3852#endif /* TERMIO_STRUCT */ 3853 3854 /* 3855 * If ptyInitialErase is set, we want to get the pty's 3856 * erase value. Just in case that will fail, first get 3857 * the value from /dev/tty, so we will have something 3858 * at least. 3859 */ 3860#if OPT_INITIAL_ERASE 3861 if (resource.ptyInitialErase) { 3862#ifdef TERMIO_STRUCT 3863 initial_erase = tio.c_cc[VERASE]; 3864#else /* !TERMIO_STRUCT */ 3865 initial_erase = sg.sg_erase; 3866#endif /* TERMIO_STRUCT */ 3867 TRACE(("%s initial_erase:%d (from /dev/tty)\n", 3868 rc == 0 ? "OK" : "FAIL", 3869 initial_erase)); 3870 } 3871#endif 3872#ifdef __MVS__ 3873 if (ttyGetAttr(ttyfd, &gio) == 0) { 3874 gio.c_cflag &= ~(HUPCL | PARENB); 3875 ttySetAttr(ttyfd, &gio); 3876 } 3877#endif /* __MVS__ */ 3878 3879 close_fd(ttyfd); 3880 } 3881 3882 if (get_pty(&screen->respond, XDisplayString(screen->display))) { 3883 SysError(ERROR_PTYS); 3884 } 3885 TRACE_GET_TTYSIZE(screen->respond, "after get_pty"); 3886#if OPT_INITIAL_ERASE 3887 if (resource.ptyInitialErase) { 3888#ifdef TERMIO_STRUCT 3889 TERMIO_STRUCT my_tio; 3890 rc = ttyGetAttr(screen->respond, &my_tio); 3891 if (rc == 0) 3892 initial_erase = my_tio.c_cc[VERASE]; 3893#else /* !TERMIO_STRUCT */ 3894 struct sgttyb my_sg; 3895 rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg); 3896 if (rc == 0) 3897 initial_erase = my_sg.sg_erase; 3898#endif /* TERMIO_STRUCT */ 3899 TRACE(("%s initial_erase:%d (from pty)\n", 3900 (rc == 0) ? "OK" : "FAIL", 3901 initial_erase)); 3902 } 3903#endif /* OPT_INITIAL_ERASE */ 3904 } 3905 3906 /* avoid double MapWindow requests */ 3907 XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False); 3908 3909 wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", 3910 False); 3911 3912 if (!TEK4014_ACTIVE(xw)) 3913 VTInit(xw); /* realize now so know window size for tty driver */ 3914#if defined(TIOCCONS) || defined(SRIOCSREDIR) 3915 if (Console) { 3916 /* 3917 * Inform any running xconsole program 3918 * that we are going to steal the console. 3919 */ 3920 XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255); 3921 mit_console = XInternAtom(screen->display, mit_console_name, False); 3922 /* the user told us to be the console, so we can use CurrentTime */ 3923 XtOwnSelection(SHELL_OF(CURRENT_EMU()), 3924 mit_console, CurrentTime, 3925 ConvertConsoleSelection, NULL, NULL); 3926 } 3927#endif 3928#if OPT_TEK4014 3929 if (TEK4014_ACTIVE(xw)) { 3930 envnew = tekterm; 3931 } else 3932#endif 3933 { 3934 envnew = vtterm; 3935 } 3936 3937 /* 3938 * This used to exit if no termcap entry was found for the specified 3939 * terminal name. That's a little unfriendly, so instead we'll allow 3940 * the program to proceed (but not to set $TERMCAP) if the termcap 3941 * entry is not found. 3942 */ 3943 ok_termcap = True; 3944 if (!get_termcap(xw, TermName = resource.term_name)) { 3945 const char *last = NULL; 3946 char *next; 3947 3948 TermName = x_strdup(*envnew); 3949 ok_termcap = False; 3950 while (*envnew != NULL) { 3951 if (last == NULL || strcmp(last, *envnew)) { 3952 next = x_strdup(*envnew); 3953 if (get_termcap(xw, next)) { 3954 free(TermName); 3955 TermName = next; 3956 ok_termcap = True + 1; 3957 break; 3958 } else { 3959 free(next); 3960 } 3961 } 3962 last = *envnew; 3963 envnew++; 3964 } 3965 } 3966 if (ok_termcap) { 3967 resource.term_name = x_strdup(TermName); 3968 resize_termcap(xw); 3969 } 3970 3971 /* 3972 * Check if ptyInitialErase is not set. If so, we rely on the termcap 3973 * (or terminfo) to tell us what the erase mode should be set to. 3974 */ 3975#if OPT_INITIAL_ERASE 3976 TRACE(("resource ptyInitialErase is %sset\n", 3977 resource.ptyInitialErase ? "" : "not ")); 3978 setInitialErase = False; 3979 if (override_tty_modes && ttyModes[XTTYMODE_erase].set) { 3980 initial_erase = ttyModes[XTTYMODE_erase].value; 3981 setInitialErase = True; 3982 } else if (resource.ptyInitialErase) { 3983 /* EMPTY */ ; 3984 } else if (ok_termcap) { 3985 char *s = get_tcap_erase(xw); 3986 TRACE(("...extracting initial_erase value from termcap\n")); 3987 if (s != 0) { 3988 char *save = s; 3989 initial_erase = decode_keyvalue(&s, True); 3990 setInitialErase = True; 3991 free(save); 3992 } 3993 } 3994 TRACE(("...initial_erase:%d\n", initial_erase)); 3995 3996 TRACE(("resource backarrowKeyIsErase is %sset\n", 3997 resource.backarrow_is_erase ? "" : "not ")); 3998 if (resource.backarrow_is_erase) { /* see input.c */ 3999 if (initial_erase == ANSI_DEL) { 4000 UIntClr(xw->keyboard.flags, MODE_DECBKM); 4001 } else { 4002 xw->keyboard.flags |= MODE_DECBKM; 4003 xw->keyboard.reset_DECBKM = 1; 4004 } 4005 TRACE(("...sets DECBKM %s\n", 4006 (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off")); 4007 } else { 4008 xw->keyboard.reset_DECBKM = 2; 4009 } 4010#endif /* OPT_INITIAL_ERASE */ 4011 4012#ifdef TTYSIZE_STRUCT 4013 /* tell tty how big window is */ 4014#if OPT_TEK4014 4015 if (TEK4014_ACTIVE(xw)) { 4016 setup_winsize(ts, TDefaultRows, TDefaultCols, 4017 TFullHeight(TekScreenOf(tekWidget)), 4018 TFullWidth(TekScreenOf(tekWidget))); 4019 } else 4020#endif 4021 { 4022 setup_winsize(ts, MaxRows(screen), MaxCols(screen), 4023 FullHeight(screen), FullWidth(screen)); 4024 } 4025 TRACE_RC(i, SET_TTYSIZE(screen->respond, ts)); 4026 TRACE(("spawn SET_TTYSIZE %dx%d return %d\n", 4027 TTYSIZE_ROWS(ts), 4028 TTYSIZE_COLS(ts), i)); 4029#endif /* TTYSIZE_STRUCT */ 4030 4031#if !defined(USE_OPENPTY) 4032#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT) 4033 /* 4034 * utempter checks the ownership of the device; some implementations 4035 * set ownership in grantpt - do this first. 4036 */ 4037 grantpt(screen->respond); 4038#endif 4039#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT) 4040 unlockpt(screen->respond); 4041 TRACE_GET_TTYSIZE(screen->respond, "after unlockpt"); 4042#endif 4043#endif /* !USE_OPENPTY */ 4044 4045 added_utmp_entry = False; 4046#if defined(USE_UTEMPTER) 4047#undef UTMP 4048 if ((xw->misc.login_shell || !command_to_exec) && !resource.utmpInhibit) { 4049 struct UTMP_STR dummy; 4050 4051 /* Note: utempter may trim it anyway */ 4052 SetUtmpHost(dummy.ut_host, screen); 4053 TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n", 4054 ttydev, dummy.ut_host, screen->respond)); 4055 UTEMPTER_ADD(ttydev, dummy.ut_host, screen->respond); 4056 added_utmp_entry = True; 4057 } 4058#endif 4059 4060 if (am_slave < 0) { 4061#if OPT_PTY_HANDSHAKE 4062 if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe))) 4063 SysError(ERROR_FORK); 4064#endif 4065 TRACE(("Forking...\n")); 4066 if ((screen->pid = fork()) == -1) 4067 SysError(ERROR_FORK); 4068 4069 if (screen->pid == 0) { 4070#ifdef USE_USG_PTYS 4071 int ptyfd = -1; 4072 char *pty_name; 4073#endif 4074 /* 4075 * now in child process 4076 */ 4077#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__) 4078 int pgrp = setsid(); /* variable may not be used... */ 4079#else 4080 int pgrp = getpid(); 4081#endif 4082 TRACE_CHILD 4083 4084#ifdef USE_USG_PTYS 4085#ifdef HAVE_SETPGID 4086 setpgid(0, 0); 4087#else 4088 setpgrp(); 4089#endif 4090 unlockpt(screen->respond); 4091 TRACE_GET_TTYSIZE(screen->respond, "after unlockpt"); 4092 if ((pty_name = ptsname(screen->respond)) == 0) { 4093 SysError(ERROR_PTSNAME); 4094 } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) { 4095 SysError(ERROR_OPPTSNAME); 4096 } 4097#ifdef I_PUSH 4098 else if (PUSH_FAILS(ptyfd, "ptem")) { 4099 SysError(ERROR_PTEM); 4100 } 4101#if !defined(SVR4) && !(defined(SYSV) && defined(i386)) 4102 else if (!x_getenv("CONSEM") 4103 && PUSH_FAILS(ptyfd, "consem")) { 4104 SysError(ERROR_CONSEM); 4105 } 4106#endif /* !SVR4 */ 4107 else if (PUSH_FAILS(ptyfd, "ldterm")) { 4108 SysError(ERROR_LDTERM); 4109 } 4110#ifdef SVR4 /* from Sony */ 4111 else if (PUSH_FAILS(ptyfd, "ttcompat")) { 4112 SysError(ERROR_TTCOMPAT); 4113 } 4114#endif /* SVR4 */ 4115#endif /* I_PUSH */ 4116 ttyfd = ptyfd; 4117#ifndef __MVS__ 4118 close_fd(screen->respond); 4119#endif /* __MVS__ */ 4120 4121#ifdef TTYSIZE_STRUCT 4122 /* tell tty how big window is */ 4123#if OPT_TEK4014 4124 if (TEK4014_ACTIVE(xw)) { 4125 setup_winsize(ts, TDefaultRows, TDefaultCols, 4126 TFullHeight(TekScreenOf(tekWidget)), 4127 TFullWidth(TekScreenOf(tekWidget))); 4128 } else 4129#endif /* OPT_TEK4014 */ 4130 { 4131 setup_winsize(ts, MaxRows(screen), MaxCols(screen), 4132 FullHeight(screen), FullWidth(screen)); 4133 } 4134 trace_winsize(ts, "initial tty size"); 4135#endif /* TTYSIZE_STRUCT */ 4136 4137#endif /* USE_USG_PTYS */ 4138 4139 (void) pgrp; /* not all branches use this variable */ 4140 4141#if OPT_PTY_HANDSHAKE /* warning, goes for a long ways */ 4142 if (resource.ptyHandshake) { 4143 char *ptr; 4144 4145 /* close parent's sides of the pipes */ 4146 close(cp_pipe[0]); 4147 close(pc_pipe[1]); 4148 4149 /* Make sure that our sides of the pipes are not in the 4150 * 0, 1, 2 range so that we don't fight with stdin, out 4151 * or err. 4152 */ 4153 if (cp_pipe[1] <= 2) { 4154 if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) { 4155 IGNORE_RC(close(cp_pipe[1])); 4156 cp_pipe[1] = i; 4157 } 4158 } 4159 if (pc_pipe[0] <= 2) { 4160 if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) { 4161 IGNORE_RC(close(pc_pipe[0])); 4162 pc_pipe[0] = i; 4163 } 4164 } 4165 4166 /* we don't need the socket, or the pty master anymore */ 4167 close(ConnectionNumber(screen->display)); 4168#ifndef __MVS__ 4169 if (screen->respond >= 0) 4170 close(screen->respond); 4171#endif /* __MVS__ */ 4172 4173 /* Now is the time to set up our process group and 4174 * open up the pty slave. 4175 */ 4176#ifdef USE_SYSV_PGRP 4177#if defined(CRAY) && (OSMAJORVERSION > 5) 4178 IGNORE_RC(setsid()); 4179#else 4180 IGNORE_RC(setpgrp()); 4181#endif 4182#endif /* USE_SYSV_PGRP */ 4183 4184#if defined(__QNX__) && !defined(__QNXNTO__) 4185 qsetlogin(getlogin(), ttydev); 4186#endif 4187 if (ttyfd >= 0) { 4188#ifdef __MVS__ 4189 if (ttyGetAttr(ttyfd, &gio) == 0) { 4190 gio.c_cflag &= ~(HUPCL | PARENB); 4191 ttySetAttr(ttyfd, &gio); 4192 } 4193#else /* !__MVS__ */ 4194 close_fd(ttyfd); 4195#endif /* __MVS__ */ 4196 } 4197 4198 for (;;) { 4199#if USE_NO_DEV_TTY 4200 if (!no_dev_tty 4201 && (ttyfd = open("/dev/tty", O_RDWR)) >= 0) { 4202 ioctl(ttyfd, TIOCNOTTY, (char *) NULL); 4203 close_fd(ttyfd); 4204 } 4205#endif /* USE_NO_DEV_TTY */ 4206#ifdef CSRG_BASED 4207 IGNORE_RC(revoke(ttydev)); 4208#endif 4209 if ((ttyfd = open(ttydev, O_RDWR)) >= 0) { 4210 TRACE_GET_TTYSIZE(ttyfd, "after open"); 4211 TRACE_RC(i, SET_TTYSIZE(ttyfd, ts)); 4212 TRACE_GET_TTYSIZE(ttyfd, "after SET_TTYSIZE fixup"); 4213#if defined(CRAY) && defined(TCSETCTTY) 4214 /* make /dev/tty work */ 4215 ioctl(ttyfd, TCSETCTTY, 0); 4216#endif 4217#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY) 4218 /* make /dev/tty work */ 4219 ioctl(ttyfd, TIOCSCTTY, 0); 4220#endif 4221#ifdef USE_SYSV_PGRP 4222 /* We need to make sure that we are actually 4223 * the process group leader for the pty. If 4224 * we are, then we should now be able to open 4225 * /dev/tty. 4226 */ 4227 if ((i = open("/dev/tty", O_RDWR)) >= 0) { 4228 /* success! */ 4229 close(i); 4230 break; 4231 } 4232#else /* USE_SYSV_PGRP */ 4233 break; 4234#endif /* USE_SYSV_PGRP */ 4235 } 4236 perror("open ttydev"); 4237#ifdef TIOCSCTTY 4238 ioctl(ttyfd, TIOCSCTTY, 0); 4239#endif 4240 /* let our master know that the open failed */ 4241 handshake.status = PTY_BAD; 4242 handshake.error = errno; 4243 copy_handshake(handshake, ttydev); 4244 TRACE_HANDSHAKE("writing", &handshake); 4245 IGNORE_RC(write(cp_pipe[1], 4246 (const char *) &handshake, 4247 sizeof(handshake))); 4248 4249 /* get reply from parent */ 4250 i = (int) read(pc_pipe[0], (char *) &handshake, 4251 sizeof(handshake)); 4252 if (i <= 0) { 4253 /* parent terminated */ 4254 exit(1); 4255 } 4256 4257 if (handshake.status == PTY_NOMORE) { 4258 /* No more ptys, let's shutdown. */ 4259 exit(1); 4260 } 4261 4262 /* We have a new pty to try */ 4263 if (ttyfd >= 0) 4264 close(ttyfd); 4265 free(ttydev); 4266 handshake.buffer[HANDSHAKE_LEN - 1] = '\0'; 4267 ttydev = x_strdup(handshake.buffer); 4268 } 4269 4270 /* use the same tty name that everyone else will use 4271 * (from ttyname) 4272 */ 4273 if ((ptr = ttyname(ttyfd)) != 0) { 4274 free(ttydev); 4275 ttydev = x_strdup(ptr); 4276 } 4277 } 4278#endif /* OPT_PTY_HANDSHAKE -- from near fork */ 4279 4280 set_pty_permissions(screen->uid, 4281 (unsigned) screen->gid, 4282 (resource.messages 4283 ? 0622U 4284 : 0600U)); 4285 4286 /* 4287 * set up the tty modes 4288 */ 4289 { 4290#ifdef TERMIO_STRUCT 4291#if defined(umips) || defined(CRAY) || defined(linux) 4292 /* If the control tty had its modes screwed around with, 4293 eg. by lineedit in the shell, or emacs, etc. then tio 4294 will have bad values. Let's just get termio from the 4295 new tty and tailor it. */ 4296 if (ttyGetAttr(ttyfd, &tio) == -1) 4297 SysError(ERROR_TIOCGETP); 4298 tio.c_lflag |= ECHOE; 4299#endif /* umips */ 4300 /* Now is also the time to change the modes of the 4301 * child pty. 4302 */ 4303 /* input: nl->nl, don't ignore cr, cr->nl */ 4304 UIntClr(tio.c_iflag, (INLCR | IGNCR)); 4305 tio.c_iflag |= ICRNL; 4306#if OPT_WIDE_CHARS && defined(IUTF8) 4307#if OPT_LUIT_PROG 4308 if (command_to_exec_with_luit == 0) 4309#endif 4310 if (screen->utf8_mode) 4311 tio.c_iflag |= IUTF8; 4312#endif 4313 /* output: cr->cr, nl is not return, no delays, ln->cr/nl */ 4314#ifndef USE_POSIX_TERMIOS 4315 UIntClr(tio.c_oflag, 4316 (OCRNL 4317 | ONLRET 4318 | NLDLY 4319 | CRDLY 4320 | TABDLY 4321 | BSDLY 4322 | VTDLY 4323 | FFDLY)); 4324#endif /* USE_POSIX_TERMIOS */ 4325 tio.c_oflag |= D_TIO_FLAGS; 4326#ifndef USE_POSIX_TERMIOS 4327# if defined(Lynx) && !defined(CBAUD) 4328# define CBAUD V_CBAUD 4329# endif 4330 UIntClr(tio.c_cflag, CBAUD); 4331#ifdef BAUD_0 4332 /* baud rate is 0 (don't care) */ 4333#elif defined(HAVE_TERMIO_C_ISPEED) 4334 tio.c_ispeed = tio.c_ospeed = line_speed; 4335#else /* !BAUD_0 */ 4336 tio.c_cflag |= line_speed; 4337#endif /* !BAUD_0 */ 4338#else /* USE_POSIX_TERMIOS */ 4339 cfsetispeed(&tio, line_speed); 4340 cfsetospeed(&tio, line_speed); 4341#ifdef __MVS__ 4342 /* turn off bits that can't be set from the slave side */ 4343 tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND); 4344#endif /* __MVS__ */ 4345 /* Clear CLOCAL so that SIGHUP is sent to us 4346 when the xterm ends */ 4347 tio.c_cflag &= (unsigned) ~CLOCAL; 4348#endif /* USE_POSIX_TERMIOS */ 4349 /* enable signals, canonical processing (erase, kill, etc), 4350 * echo 4351 */ 4352 tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK; 4353#ifdef ECHOKE 4354 tio.c_lflag |= ECHOKE | IEXTEN; 4355#endif 4356#ifdef ECHOCTL 4357 tio.c_lflag |= ECHOCTL | IEXTEN; 4358#endif 4359 for (nn = 0; nn < XtNumber(ttyChars); ++nn) { 4360 if (validTtyChar(tio, nn)) { 4361 int sysMode = ttyChars[nn].sysMode; 4362#ifdef __MVS__ 4363 if (tio.c_cc[sysMode] != 0) { 4364 switch (sysMode) { 4365 case VEOL: 4366 case VEOF: 4367 continue; 4368 } 4369 } 4370#endif 4371 tio.c_cc[sysMode] = (cc_t) ttyChars[nn].myDefault; 4372 } 4373 } 4374 4375 if (override_tty_modes) { 4376 TRACE(("applying termios ttyModes\n")); 4377 for (nn = 0; nn < XtNumber(ttyChars); ++nn) { 4378 if (validTtyChar(tio, nn)) { 4379 TMODE(ttyChars[nn].myMode, 4380 tio.c_cc[ttyChars[nn].sysMode]); 4381 } else if (isTabMode(nn)) { 4382 unsigned tmp = (unsigned) tio.c_oflag; 4383 tmp = tmp & (unsigned) ~TABDLY; 4384 tmp |= (unsigned) ttyModes[ttyChars[nn].myMode].value; 4385 tio.c_oflag = tmp; 4386 } 4387 } 4388#ifdef HAS_LTCHARS 4389 /* both SYSV and BSD have ltchars */ 4390 TMODE(XTTYMODE_susp, ltc.t_suspc); 4391 TMODE(XTTYMODE_dsusp, ltc.t_dsuspc); 4392 TMODE(XTTYMODE_rprnt, ltc.t_rprntc); 4393 TMODE(XTTYMODE_flush, ltc.t_flushc); 4394 TMODE(XTTYMODE_weras, ltc.t_werasc); 4395 TMODE(XTTYMODE_lnext, ltc.t_lnextc); 4396#endif 4397 } 4398#ifdef HAS_LTCHARS 4399#ifdef __hpux 4400 /* ioctl chokes when the "reserved" process group controls 4401 * are not set to _POSIX_VDISABLE */ 4402 ltc.t_rprntc = _POSIX_VDISABLE; 4403 ltc.t_rprntc = _POSIX_VDISABLE; 4404 ltc.t_flushc = _POSIX_VDISABLE; 4405 ltc.t_werasc = _POSIX_VDISABLE; 4406 ltc.t_lnextc = _POSIX_VDISABLE; 4407#endif /* __hpux */ 4408 if (ioctl(ttyfd, TIOCSLTC, <c) == -1) 4409 HsSysError(ERROR_TIOCSETC); 4410#endif /* HAS_LTCHARS */ 4411#ifdef TIOCLSET 4412 if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1) 4413 HsSysError(ERROR_TIOCLSET); 4414#endif /* TIOCLSET */ 4415 if (ttySetAttr(ttyfd, &tio) == -1) 4416 HsSysError(ERROR_TIOCSETP); 4417 4418 /* ignore errors here - some platforms don't work */ 4419 UIntClr(tio.c_cflag, CSIZE); 4420 if (screen->input_eight_bits) 4421 tio.c_cflag |= CS8; 4422 else 4423 tio.c_cflag |= CS7; 4424 (void) ttySetAttr(ttyfd, &tio); 4425 4426#else /* !TERMIO_STRUCT */ 4427 sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW); 4428 sg.sg_flags |= ECHO | CRMOD; 4429 /* make sure speed is set on pty so that editors work right */ 4430 sg.sg_ispeed = line_speed; 4431 sg.sg_ospeed = line_speed; 4432 /* reset t_brkc to default value */ 4433 tc.t_brkc = -1; 4434#ifdef LPASS8 4435 if (screen->input_eight_bits) 4436 lmode |= LPASS8; 4437 else 4438 lmode &= ~(LPASS8); 4439#endif 4440#ifdef sony 4441 jmode &= ~KM_KANJI; 4442#endif /* sony */ 4443 4444 ltc = d_ltc; 4445 4446 if (override_tty_modes) { 4447 TRACE(("applying sgtty ttyModes\n")); 4448 TMODE(XTTYMODE_intr, tc.t_intrc); 4449 TMODE(XTTYMODE_quit, tc.t_quitc); 4450 TMODE(XTTYMODE_erase, sg.sg_erase); 4451 TMODE(XTTYMODE_kill, sg.sg_kill); 4452 TMODE(XTTYMODE_eof, tc.t_eofc); 4453 TMODE(XTTYMODE_start, tc.t_startc); 4454 TMODE(XTTYMODE_stop, tc.t_stopc); 4455 TMODE(XTTYMODE_brk, tc.t_brkc); 4456 /* both SYSV and BSD have ltchars */ 4457 TMODE(XTTYMODE_susp, ltc.t_suspc); 4458 TMODE(XTTYMODE_dsusp, ltc.t_dsuspc); 4459 TMODE(XTTYMODE_rprnt, ltc.t_rprntc); 4460 TMODE(XTTYMODE_flush, ltc.t_flushc); 4461 TMODE(XTTYMODE_weras, ltc.t_werasc); 4462 TMODE(XTTYMODE_lnext, ltc.t_lnextc); 4463 if (ttyModes[XTTYMODE_tabs].set 4464 || ttyModes[XTTYMODE__tabs].set) { 4465 sg.sg_flags &= ~XTABS; 4466 if (ttyModes[XTTYMODE__tabs].set.set) 4467 sg.sg_flags |= XTABS; 4468 } 4469 } 4470 4471 if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1) 4472 HsSysError(ERROR_TIOCSETP); 4473 if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1) 4474 HsSysError(ERROR_TIOCSETC); 4475 if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1) 4476 HsSysError(ERROR_TIOCSETD); 4477 if (ioctl(ttyfd, TIOCSLTC, (char *) <c) == -1) 4478 HsSysError(ERROR_TIOCSLTC); 4479 if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1) 4480 HsSysError(ERROR_TIOCLSET); 4481#ifdef sony 4482 if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1) 4483 HsSysError(ERROR_TIOCKSET); 4484 if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1) 4485 HsSysError(ERROR_TIOCKSETC); 4486#endif /* sony */ 4487#endif /* TERMIO_STRUCT */ 4488#if defined(TIOCCONS) || defined(SRIOCSREDIR) 4489 if (Console) { 4490#ifdef TIOCCONS 4491 int on = 1; 4492 if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1) 4493 xtermPerror("cannot open console"); 4494#endif 4495#ifdef SRIOCSREDIR 4496 int fd = open("/dev/console", O_RDWR); 4497 if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1) 4498 xtermPerror("cannot open console"); 4499 IGNORE_RC(close(fd)); 4500#endif 4501 } 4502#endif /* TIOCCONS */ 4503 } 4504 4505 signal(SIGCHLD, SIG_DFL); 4506#ifdef USE_SYSV_SIGHUP 4507 /* watch out for extra shells (I don't understand either) */ 4508 signal(SIGHUP, SIG_DFL); 4509#else 4510 signal(SIGHUP, SIG_IGN); 4511#endif 4512 /* restore various signals to their defaults */ 4513 signal(SIGINT, SIG_DFL); 4514 signal(SIGQUIT, SIG_DFL); 4515 signal(SIGTERM, SIG_DFL); 4516 4517 /* 4518 * If we're not asked to let the parent process set the terminal's 4519 * erase mode, or if we had the ttyModes erase resource, then set 4520 * the terminal's erase mode from our best guess. 4521 */ 4522#if OPT_INITIAL_ERASE 4523 TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n", 4524 initial_erase, 4525 setInitialErase ? "YES" : "NO", 4526 resource.ptyInitialErase, 4527 override_tty_modes, 4528 ttyModes[XTTYMODE_erase].set)); 4529 if (setInitialErase) { 4530#if OPT_TRACE 4531 int old_erase; 4532#endif 4533#ifdef TERMIO_STRUCT 4534 if (ttyGetAttr(ttyfd, &tio) == -1) 4535 tio = d_tio; 4536#if OPT_TRACE 4537 old_erase = tio.c_cc[VERASE]; 4538#endif 4539 tio.c_cc[VERASE] = (cc_t) initial_erase; 4540 TRACE_RC(rc, ttySetAttr(ttyfd, &tio)); 4541#else /* !TERMIO_STRUCT */ 4542 if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1) 4543 sg = d_sg; 4544#if OPT_TRACE 4545 old_erase = sg.sg_erase; 4546#endif 4547 sg.sg_erase = initial_erase; 4548 rc = ioctl(ttyfd, TIOCSETP, (char *) &sg); 4549#endif /* TERMIO_STRUCT */ 4550 TRACE(("%s setting erase to %d (was %d)\n", 4551 rc ? "FAIL" : "OK", initial_erase, old_erase)); 4552 } 4553#endif 4554 4555 xtermCopyEnv(environ); 4556 4557 /* 4558 * standards.freedesktop.org/startup-notification-spec/ 4559 * notes that this variable is used when a "reliable" mechanism is 4560 * not available; in practice it must be unset to avoid confusing 4561 * GTK applications. 4562 */ 4563 xtermUnsetenv("DESKTOP_STARTUP_ID"); 4564 /* 4565 * We set this temporarily to work around poor design of Xcursor. 4566 * Unset it here to avoid confusion. 4567 */ 4568 xtermUnsetenv("XCURSOR_PATH"); 4569 4570 xtermSetenv("TERM", resource.term_name); 4571 if (!resource.term_name) 4572 *get_tcap_buffer(xw) = 0; 4573 4574 sprintf(buf, "%lu", 4575 ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU())))); 4576 xtermSetenv("WINDOWID", buf); 4577 4578 /* put the display into the environment of the shell */ 4579 xtermSetenv("DISPLAY", XDisplayString(screen->display)); 4580 4581 xtermSetenv("XTERM_VERSION", xtermVersion()); 4582 xtermSetenv("XTERM_LOCALE", xtermEnvLocale()); 4583 4584 /* 4585 * For debugging only, add environment variables that can be used 4586 * in scripts to selectively kill xterm's parent or child 4587 * processes. 4588 */ 4589#if OPT_TRACE 4590 sprintf(buf, "%lu", (unsigned long) xterm_parent); 4591 xtermSetenv("XTERM_PARENT", buf); 4592 sprintf(buf, "%lu", (unsigned long) getpid()); 4593 xtermSetenv("XTERM_CHILD", buf); 4594#endif 4595 4596 signal(SIGTERM, SIG_DFL); 4597 4598 /* this is the time to go and set up stdin, out, and err 4599 */ 4600 { 4601#if defined(CRAY) && (OSMAJORVERSION >= 6) 4602 close_fd(ttyfd); 4603 4604 IGNORE_RC(close(0)); 4605 4606 if (open("/dev/tty", O_RDWR)) { 4607 SysError(ERROR_OPDEVTTY); 4608 } 4609 IGNORE_RC(close(1)); 4610 IGNORE_RC(close(2)); 4611 dup(0); 4612 dup(0); 4613#else 4614 /* dup the tty */ 4615 for (i = 0; i <= 2; i++) 4616 if (i != ttyfd) { 4617 IGNORE_RC(close(i)); 4618 IGNORE_RC(dup(ttyfd)); 4619 } 4620#ifndef ATT 4621 /* and close the tty */ 4622 if (ttyfd > 2) 4623 close_fd(ttyfd); 4624#endif 4625#endif /* CRAY */ 4626 } 4627 4628#if !defined(USE_SYSV_PGRP) 4629#ifdef TIOCSCTTY 4630 setsid(); 4631 ioctl(0, TIOCSCTTY, 0); 4632#endif 4633 ioctl(0, TIOCSPGRP, (char *) &pgrp); 4634 setpgrp(0, 0); 4635 close(open(ttydev, O_WRONLY)); 4636 setpgrp(0, pgrp); 4637#if defined(__QNX__) 4638 tcsetpgrp(0, pgrp /*setsid() */ ); 4639#endif 4640#endif /* !USE_SYSV_PGRP */ 4641 4642#ifdef Lynx 4643 { 4644 TERMIO_STRUCT t; 4645 if (ttyGetAttr(0, &t) >= 0) { 4646 /* this gets lost somewhere on our way... */ 4647 t.c_oflag |= OPOST; 4648 ttySetAttr(0, &t); 4649 } 4650 } 4651#endif 4652 4653#ifdef HAVE_UTMP 4654 login_name = NULL; 4655 if (x_getpwuid(screen->uid, &pw)) { 4656 login_name = x_getlogin(screen->uid, &pw); 4657 } 4658 if (login_name != NULL) { 4659 xtermSetenv("LOGNAME", login_name); /* for POSIX */ 4660 } 4661#ifndef USE_UTEMPTER 4662#ifdef USE_UTMP_SETGID 4663 setEffectiveGroup(save_egid); 4664 TRACE_IDS; 4665#endif 4666#ifdef USE_SYSV_UTMP 4667 /* Set up our utmp entry now. We need to do it here 4668 * for the following reasons: 4669 * - It needs to have our correct process id (for 4670 * login). 4671 * - If our parent was to set it after the fork(), 4672 * it might make it out before we need it. 4673 * - We need to do it before we go and change our 4674 * user and group id's. 4675 */ 4676 (void) call_setutent(); 4677 init_utmp(DEAD_PROCESS, &utmp); 4678 4679 /* position to entry in utmp file */ 4680 /* Test return value: beware of entries left behind: PSz 9 Mar 00 */ 4681 utret = find_utmp(&utmp); 4682 if (utret == 0) { 4683 (void) call_setutent(); 4684 init_utmp(USER_PROCESS, &utmp); 4685 utret = find_utmp(&utmp); 4686 if (utret == 0) { 4687 (void) call_setutent(); 4688 } 4689 } 4690#if OPT_TRACE 4691 if (!utret) 4692 TRACE(("getutid: NULL\n")); 4693 else 4694 TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n", 4695 (int) utret->ut_pid, utret->ut_type, utret->ut_user, 4696 (int) sizeof(utret->ut_line), utret->ut_line, 4697 (int) sizeof(utret->ut_id), utret->ut_id)); 4698#endif 4699 4700 /* set up the new entry */ 4701 utmp.ut_type = USER_PROCESS; 4702#ifdef HAVE_UTMP_UT_XSTATUS 4703 utmp.ut_xstatus = 2; 4704#endif 4705 copy_filled(utmp.ut_user, 4706 (login_name != NULL) ? login_name : "????", 4707 sizeof(utmp.ut_user)); 4708 /* why are we copying this string again? (see above) */ 4709 copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id)); 4710 copy_filled(utmp.ut_line, 4711 my_pty_name(ttydev), sizeof(utmp.ut_line)); 4712 4713#ifdef HAVE_UTMP_UT_HOST 4714 SetUtmpHost(utmp.ut_host, screen); 4715#endif 4716#ifdef HAVE_UTMP_UT_SYSLEN 4717 SetUtmpSysLen(utmp); 4718#endif 4719 4720 copy_filled(utmp.ut_name, 4721 (login_name) ? login_name : "????", 4722 sizeof(utmp.ut_name)); 4723 4724 utmp.ut_pid = getpid(); 4725#if defined(HAVE_UTMP_UT_XTIME) 4726#if defined(HAVE_UTMP_UT_SESSION) 4727 utmp.ut_session = getsid(0); 4728#endif 4729 utmp.ut_xtime = time((time_t *) 0); 4730 utmp.ut_tv.tv_usec = 0; 4731#else 4732 utmp.ut_time = time((time_t *) 0); 4733#endif 4734 4735 /* write out the entry */ 4736 if (!resource.utmpInhibit) { 4737 errno = 0; 4738 call_pututline(&utmp); 4739 TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n", 4740 (int) sizeof(utmp.ut_id), utmp.ut_id, 4741 (int) sizeof(utmp.ut_line), utmp.ut_line, 4742 (long) utmp.ut_pid, 4743 errno, (errno != 0) ? strerror(errno) : "")); 4744 } 4745#ifdef WTMP 4746#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__)) 4747 if (xw->misc.login_shell) 4748 updwtmpx(WTMPX_FILE, &utmp); 4749#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) 4750 if (xw->misc.login_shell) 4751 call_updwtmp(etc_wtmp, &utmp); 4752#else 4753 if (xw->misc.login_shell && 4754 (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 4755 IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp))); 4756 close(i); 4757 } 4758#endif 4759#endif 4760 /* close the file */ 4761 (void) call_endutent(); 4762 4763#else /* USE_SYSV_UTMP */ 4764 /* We can now get our ttyslot! We can also set the initial 4765 * utmp entry. 4766 */ 4767 tslot = ttyslot(); 4768 added_utmp_entry = False; 4769 { 4770 if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit && 4771 (i = open(etc_utmp, O_WRONLY)) >= 0) { 4772 memset(&utmp, 0, sizeof(utmp)); 4773 copy_filled(utmp.ut_line, 4774 my_pty_name(ttydev), 4775 sizeof(utmp.ut_line)); 4776 copy_filled(utmp.ut_name, login_name, 4777 sizeof(utmp.ut_name)); 4778#ifdef HAVE_UTMP_UT_HOST 4779 SetUtmpHost(utmp.ut_host, screen); 4780#endif 4781#ifdef HAVE_UTMP_UT_SYSLEN 4782 SetUtmpSysLen(utmp); 4783#endif 4784 4785 utmp.ut_time = time((time_t *) 0); 4786 lseek(i, (long) (tslot * sizeof(utmp)), 0); 4787 IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp))); 4788 close(i); 4789 added_utmp_entry = True; 4790#if defined(WTMP) 4791 if (xw->misc.login_shell && 4792 (i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 4793 int status; 4794 status = write(i, (char *) &utmp, sizeof(utmp)); 4795 status = close(i); 4796 } 4797#elif defined(MNX_LASTLOG) 4798 if (xw->misc.login_shell && 4799 (i = open(_U_LASTLOG, O_WRONLY)) >= 0) { 4800 lseek(i, (long) (screen->uid * 4801 sizeof(utmp)), 0); 4802 IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp))); 4803 close(i); 4804 } 4805#endif /* WTMP or MNX_LASTLOG */ 4806 } else 4807 tslot = -tslot; 4808 } 4809 4810 /* Let's pass our ttyslot to our parent so that it can 4811 * clean up after us. 4812 */ 4813#if OPT_PTY_HANDSHAKE 4814 if (resource.ptyHandshake) { 4815 handshake.tty_slot = tslot; 4816 } 4817#endif /* OPT_PTY_HANDSHAKE */ 4818#endif /* USE_SYSV_UTMP */ 4819 4820#ifdef USE_LASTLOGX 4821 if (xw->misc.login_shell) { 4822 memset(&lastlogx, 0, sizeof(lastlogx)); 4823 copy_filled(lastlogx.ll_line, 4824 my_pty_name(ttydev), 4825 sizeof(lastlogx.ll_line)); 4826 X_GETTIMEOFDAY(&lastlogx.ll_tv); 4827 SetUtmpHost(lastlogx.ll_host, screen); 4828 updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx); 4829 } 4830#endif 4831 4832#ifdef USE_LASTLOG 4833 if (xw->misc.login_shell && 4834 (i = open(etc_lastlog, O_WRONLY)) >= 0) { 4835 size_t size = sizeof(struct lastlog); 4836 off_t offset = (off_t) ((size_t) screen->uid * size); 4837 4838 memset(&lastlog, 0, size); 4839 copy_filled(lastlog.ll_line, 4840 my_pty_name(ttydev), 4841 sizeof(lastlog.ll_line)); 4842 SetUtmpHost(lastlog.ll_host, screen); 4843 lastlog.ll_time = time((time_t *) 0); 4844 if (lseek(i, offset, 0) != (off_t) (-1)) { 4845 IGNORE_RC(write(i, (char *) &lastlog, size)); 4846 } 4847 close(i); 4848 } 4849#endif /* USE_LASTLOG */ 4850 4851#if defined(USE_UTMP_SETGID) 4852 disableSetGid(); 4853 TRACE_IDS; 4854#endif 4855 4856#if OPT_PTY_HANDSHAKE 4857 /* Let our parent know that we set up our utmp entry 4858 * so that it can clean up after us. 4859 */ 4860 if (resource.ptyHandshake) { 4861 handshake.status = UTMP_ADDED; 4862 handshake.error = 0; 4863 copy_handshake(handshake, ttydev); 4864 TRACE_HANDSHAKE("writing", &handshake); 4865 IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake))); 4866 } 4867#endif /* OPT_PTY_HANDSHAKE */ 4868#endif /* USE_UTEMPTER */ 4869#endif /* HAVE_UTMP */ 4870 4871 IGNORE_RC(setgid(screen->gid)); 4872 TRACE_IDS; 4873#ifdef HAVE_INITGROUPS 4874 if (geteuid() == 0 && OkPasswd(&pw)) { 4875 if (initgroups(login_name, pw.pw_gid)) { 4876 perror("initgroups failed"); 4877 SysError(ERROR_INIGROUPS); 4878 } 4879 } 4880#endif 4881 if (setuid(screen->uid)) { 4882 SysError(ERROR_SETUID); 4883 } 4884 TRACE_IDS; 4885#if OPT_PTY_HANDSHAKE 4886 if (resource.ptyHandshake) { 4887 /* mark the pipes as close on exec */ 4888 (void) fcntl(cp_pipe[1], F_SETFD, 1); 4889 (void) fcntl(pc_pipe[0], F_SETFD, 1); 4890 4891 /* We are at the point where we are going to 4892 * exec our shell (or whatever). Let our parent 4893 * know we arrived safely. 4894 */ 4895 handshake.status = PTY_GOOD; 4896 handshake.error = 0; 4897 copy_handshake(handshake, ttydev); 4898 TRACE_HANDSHAKE("writing", &handshake); 4899 IGNORE_RC(write(cp_pipe[1], 4900 (const char *) &handshake, 4901 sizeof(handshake))); 4902 4903 if (resource.wait_for_map) { 4904 i = (int) read(pc_pipe[0], (char *) &handshake, 4905 sizeof(handshake)); 4906 if (i != sizeof(handshake) || 4907 handshake.status != PTY_EXEC) { 4908 /* some very bad problem occurred */ 4909 exit(ERROR_PTY_EXEC); 4910 } 4911 if (handshake.rows > 0 && handshake.cols > 0) { 4912 TRACE(("handshake read ttysize: %dx%d\n", 4913 handshake.rows, handshake.cols)); 4914 set_max_row(screen, handshake.rows); 4915 set_max_col(screen, handshake.cols); 4916#ifdef TTYSIZE_STRUCT 4917 got_handshake_size = True; 4918 setup_winsize(ts, MaxRows(screen), MaxCols(screen), 4919 FullHeight(screen), FullWidth(screen)); 4920 trace_winsize(ts, "got handshake"); 4921#endif /* TTYSIZE_STRUCT */ 4922 } 4923 } 4924 } 4925#endif /* OPT_PTY_HANDSHAKE */ 4926 4927#ifdef USE_SYSV_ENVVARS 4928 { 4929 char numbuf[12]; 4930 sprintf(numbuf, "%d", MaxCols(screen)); 4931 xtermSetenv("COLUMNS", numbuf); 4932 sprintf(numbuf, "%d", MaxRows(screen)); 4933 xtermSetenv("LINES", numbuf); 4934 } 4935#ifdef HAVE_UTMP 4936 if (OkPasswd(&pw)) { /* SVR4 doesn't provide these */ 4937 if (!x_getenv("HOME")) 4938 xtermSetenv("HOME", pw.pw_dir); 4939 if (!x_getenv("SHELL")) 4940 xtermSetenv("SHELL", pw.pw_shell); 4941 } 4942#endif /* HAVE_UTMP */ 4943#else /* USE_SYSV_ENVVARS */ 4944 if (*(newtc = get_tcap_buffer(xw)) != '\0') { 4945 resize_termcap(xw); 4946 if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) { 4947 remove_termcap_entry(newtc, "ti="); 4948 remove_termcap_entry(newtc, "te="); 4949 } 4950 /* 4951 * work around broken termcap entries */ 4952 if (resource.useInsertMode) { 4953 remove_termcap_entry(newtc, "ic="); 4954 /* don't get duplicates */ 4955 remove_termcap_entry(newtc, "im="); 4956 remove_termcap_entry(newtc, "ei="); 4957 remove_termcap_entry(newtc, "mi"); 4958 if (*newtc) 4959 strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:"); 4960 } 4961 if (*newtc) { 4962#if OPT_INITIAL_ERASE 4963 unsigned len; 4964 remove_termcap_entry(newtc, TERMCAP_ERASE "="); 4965 len = (unsigned) strlen(newtc); 4966 if (len != 0 && newtc[len - 1] == ':') 4967 len--; 4968 sprintf(newtc + len, ":%s=\\%03o:", 4969 TERMCAP_ERASE, 4970 CharOf(initial_erase)); 4971#endif 4972 xtermSetenv("TERMCAP", newtc); 4973 } 4974 } 4975#endif /* USE_SYSV_ENVVARS */ 4976#ifdef OWN_TERMINFO_ENV 4977 xtermSetenv("TERMINFO", OWN_TERMINFO_DIR); 4978#endif 4979 4980#if OPT_PTY_HANDSHAKE 4981 /* 4982 * Need to reset after all the ioctl bashing we did above. 4983 * 4984 * If we expect the waitForMap logic to set the handshake-size, 4985 * use that to prevent races. 4986 */ 4987 TRACE(("should we reset screensize after pty-handshake?\n")); 4988 TRACE(("... ptyHandshake :%d\n", resource.ptyHandshake)); 4989 TRACE(("... ptySttySize :%d\n", resource.ptySttySize)); 4990 TRACE(("... got_handshake_size:%d\n", got_handshake_size)); 4991 TRACE(("... wait_for_map0 :%d\n", resource.wait_for_map0)); 4992 if (resource.ptyHandshake 4993 && resource.ptySttySize 4994 && (got_handshake_size || !resource.wait_for_map0)) { 4995#ifdef TTYSIZE_STRUCT 4996 TRACE_RC(i, SET_TTYSIZE(0, ts)); 4997 trace_winsize(ts, "ptyHandshake SET_TTYSIZE"); 4998#endif /* TTYSIZE_STRUCT */ 4999 } 5000#endif /* OPT_PTY_HANDSHAKE */ 5001 signal(SIGHUP, SIG_DFL); 5002 5003 /* 5004 * If we have an explicit shell to run, make that set $SHELL. 5005 * Next, allow an existing setting of $SHELL, for absolute paths. 5006 * Otherwise, if $SHELL is not set, determine it from the user's 5007 * password information, if possible. 5008 * 5009 * Incidentally, our setting of $SHELL tells luit to use that 5010 * program rather than choosing between $SHELL and "/bin/sh". 5011 */ 5012 if (validShell(explicit_shname)) { 5013 xtermSetenv("SHELL", explicit_shname); 5014 } else if (validProgram(shell_path = x_getenv("SHELL"))) { 5015 if (!validShell(shell_path)) { 5016 xtermUnsetenv("SHELL"); 5017 } 5018 } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw)) 5019 || *(shell_path = x_strdup(pw.pw_shell)) == 0) { 5020 shell_path = resetShell(shell_path); 5021 } else if (validShell(shell_path)) { 5022 xtermSetenv("SHELL", shell_path); 5023 } else { 5024 shell_path = resetShell(shell_path); 5025 } 5026 5027 /* 5028 * Set $XTERM_SHELL, which is not necessarily a valid shell, but 5029 * is executable. 5030 */ 5031 if (validProgram(explicit_shname)) { 5032 shell_path = explicit_shname; 5033 } else if (shell_path == 0) { 5034 /* this could happen if the explicit shname lost a race */ 5035 shell_path = resetShell(shell_path); 5036 } 5037 xtermSetenv("XTERM_SHELL", shell_path); 5038 5039 shname = x_basename(shell_path); 5040 TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname)); 5041 5042#if OPT_LUIT_PROG 5043 /* 5044 * Use two copies of command_to_exec, in case luit is not actually 5045 * there, or refuses to run. In that case we will fall-through to 5046 * to command that the user gave anyway. 5047 */ 5048 if (command_to_exec_with_luit && command_to_exec) { 5049 char *myShell = xtermFindShell(*command_to_exec_with_luit, False); 5050 xtermSetenv("XTERM_SHELL", myShell); 5051 free(myShell); 5052 TRACE_ARGV("spawning luit command", command_to_exec_with_luit); 5053 execvp(*command_to_exec_with_luit, command_to_exec_with_luit); 5054 xtermPerror("Can't execvp %s", *command_to_exec_with_luit); 5055 xtermWarning("cannot support your locale.\n"); 5056 } 5057#endif 5058 if (command_to_exec) { 5059 char *myShell = xtermFindShell(*command_to_exec, False); 5060 xtermSetenv("XTERM_SHELL", myShell); 5061 free(myShell); 5062 TRACE_ARGV("spawning command", command_to_exec); 5063 execvp(*command_to_exec, command_to_exec); 5064 if (command_to_exec[1] == 0) 5065 execlp(shell_path, shname, "-c", command_to_exec[0], 5066 (void *) 0); 5067 xtermPerror("Can't execvp %s", *command_to_exec); 5068 } 5069#ifdef USE_SYSV_SIGHUP 5070 /* fix pts sh hanging around */ 5071 signal(SIGHUP, SIG_DFL); 5072#endif 5073 5074 if ((shname_minus = malloc(strlen(shname) + 2)) != 0) { 5075 (void) strcpy(shname_minus, "-"); 5076 (void) strcat(shname_minus, shname); 5077 } else { 5078 static char default_minus[] = "-sh"; 5079 shname_minus = default_minus; 5080 } 5081#ifndef TERMIO_STRUCT 5082 ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3) 5083 ? NTTYDISC 5084 : 0); 5085 ioctl(0, TIOCSETD, (char *) &ldisc); 5086#endif /* !TERMIO_STRUCT */ 5087 5088#ifdef USE_LOGIN_DASH_P 5089 if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry) 5090 execl(bin_login, "login", "-p", "-f", login_name, (void *) 0); 5091#endif 5092 5093#if OPT_LUIT_PROG 5094 if (command_to_exec_with_luit) { 5095 if (xw->misc.login_shell) { 5096 char *params[4]; 5097 params[0] = x_strdup("-argv0"); 5098 params[1] = shname_minus; 5099 params[2] = NULL; 5100 x_appendargv(command_to_exec_with_luit 5101 + command_length_with_luit, 5102 params); 5103 } 5104 TRACE_ARGV("final luit command", command_to_exec_with_luit); 5105 execvp(*command_to_exec_with_luit, command_to_exec_with_luit); 5106 /* Exec failed. */ 5107 xtermPerror("Can't execvp %s", *command_to_exec_with_luit); 5108 } 5109#endif 5110 execlp(shell_path, 5111 (xw->misc.login_shell ? shname_minus : shname), 5112 (void *) 0); 5113 5114 /* Exec failed. */ 5115 xtermPerror("Could not exec %s", shell_path); 5116 IGNORE_RC(sleep(5)); 5117 free(shell_path); 5118 exit(ERROR_EXEC); 5119 } 5120 /* end if in child after fork */ 5121#if OPT_PTY_HANDSHAKE 5122 if (resource.ptyHandshake) { 5123 /* Parent process. Let's handle handshaked requests to our 5124 * child process. 5125 */ 5126 5127 /* close childs's sides of the pipes */ 5128 close(cp_pipe[1]); 5129 close(pc_pipe[0]); 5130 5131 for (done = 0; !done;) { 5132 if (read(cp_pipe[0], 5133 (char *) &handshake, 5134 sizeof(handshake)) <= 0) { 5135 /* Our child is done talking to us. If it terminated 5136 * due to an error, we will catch the death of child 5137 * and clean up. 5138 */ 5139 break; 5140 } 5141 5142 TRACE_HANDSHAKE("read", &handshake); 5143 switch (handshake.status) { 5144 case PTY_GOOD: 5145 /* Success! Let's free up resources and 5146 * continue. 5147 */ 5148 done = 1; 5149 break; 5150 5151 case PTY_BAD: 5152 /* The open of the pty failed! Let's get 5153 * another one. 5154 */ 5155 IGNORE_RC(close(screen->respond)); 5156 if (get_pty(&screen->respond, XDisplayString(screen->display))) { 5157 /* no more ptys! */ 5158 xtermPerror("child process can find no available ptys"); 5159 handshake.status = PTY_NOMORE; 5160 TRACE_HANDSHAKE("writing", &handshake); 5161 IGNORE_RC(write(pc_pipe[1], 5162 (const char *) &handshake, 5163 sizeof(handshake))); 5164 exit(ERROR_PTYS); 5165 } 5166 handshake.status = PTY_NEW; 5167 copy_handshake(handshake, ttydev); 5168 TRACE_HANDSHAKE("writing", &handshake); 5169 IGNORE_RC(write(pc_pipe[1], 5170 (const char *) &handshake, 5171 sizeof(handshake))); 5172 break; 5173 5174 case PTY_FATALERROR: 5175 errno = handshake.error; 5176 close(cp_pipe[0]); 5177 close(pc_pipe[1]); 5178 SysError(handshake.fatal_error); 5179 /*NOTREACHED */ 5180 5181 case UTMP_ADDED: 5182 /* The utmp entry was set by our slave. Remember 5183 * this so that we can reset it later. 5184 */ 5185 added_utmp_entry = True; 5186#ifndef USE_SYSV_UTMP 5187 tslot = handshake.tty_slot; 5188#endif /* USE_SYSV_UTMP */ 5189 free(ttydev); 5190 handshake.buffer[HANDSHAKE_LEN - 1] = '\0'; 5191 ttydev = x_strdup(handshake.buffer); 5192 break; 5193 case PTY_NEW: 5194 case PTY_NOMORE: 5195 case UTMP_TTYSLOT: 5196 case PTY_EXEC: 5197 default: 5198 xtermWarning("unexpected handshake status %d\n", 5199 (int) handshake.status); 5200 } 5201 } 5202 /* close our sides of the pipes */ 5203 if (!resource.wait_for_map) { 5204 close(cp_pipe[0]); 5205 close(pc_pipe[1]); 5206 } 5207 } 5208#endif /* OPT_PTY_HANDSHAKE */ 5209 } 5210 5211 /* end if no slave */ 5212 /* 5213 * still in parent (xterm process) 5214 */ 5215#ifdef USE_SYSV_SIGHUP 5216 /* hung sh problem? */ 5217 signal(SIGHUP, SIG_DFL); 5218#else 5219 signal(SIGHUP, SIG_IGN); 5220#endif 5221 5222/* 5223 * Unfortunately, System V seems to have trouble divorcing the child process 5224 * from the process group of xterm. This is a problem because hitting the 5225 * INTR or QUIT characters on the keyboard will cause xterm to go away if we 5226 * don't ignore the signals. This is annoying. 5227 */ 5228 5229#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) 5230 signal(SIGINT, SIG_IGN); 5231 5232#ifndef SYSV 5233 /* hung shell problem */ 5234 signal(SIGQUIT, SIG_IGN); 5235#endif 5236 signal(SIGTERM, SIG_IGN); 5237#elif defined(SYSV) || defined(__osf__) 5238 /* if we were spawned by a jobcontrol smart shell (like ksh or csh), 5239 * then our pgrp and pid will be the same. If we were spawned by 5240 * a jobcontrol dumb shell (like /bin/sh), then we will be in our 5241 * parent's pgrp, and we must ignore keyboard signals, or we will 5242 * tank on everything. 5243 */ 5244 if (getpid() == getpgrp()) { 5245 (void) signal(SIGINT, Exit); 5246 (void) signal(SIGQUIT, Exit); 5247 (void) signal(SIGTERM, Exit); 5248 } else { 5249 (void) signal(SIGINT, SIG_IGN); 5250 (void) signal(SIGQUIT, SIG_IGN); 5251 (void) signal(SIGTERM, SIG_IGN); 5252 } 5253 (void) signal(SIGPIPE, Exit); 5254#else /* SYSV */ 5255 signal(SIGINT, Exit); 5256 signal(SIGQUIT, Exit); 5257 signal(SIGTERM, Exit); 5258 signal(SIGPIPE, Exit); 5259#endif /* USE_SYSV_SIGNALS and not SIGTSTP */ 5260#ifdef NO_LEAKS 5261 if (ok_termcap != True) 5262 free(TermName); 5263#endif 5264 5265 return 0; 5266} /* end spawnXTerm */ 5267 5268void 5269Exit(int n) 5270{ 5271 XtermWidget xw = term; 5272 TScreen *screen = TScreenOf(xw); 5273 5274#ifdef USE_UTEMPTER 5275 DEBUG_MSG("handle:Exit USE_UTEMPTER\n"); 5276 if (!resource.utmpInhibit && added_utmp_entry) { 5277 TRACE(("...calling removeFromUtmp\n")); 5278 UTEMPTER_DEL(); 5279 } 5280#elif defined(HAVE_UTMP) 5281#ifdef USE_SYSV_UTMP 5282 struct UTMP_STR utmp; 5283 struct UTMP_STR *utptr; 5284 5285 DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n"); 5286 /* don't do this more than once */ 5287 if (xterm_exiting) { 5288 exit(n); 5289 } 5290 xterm_exiting = True; 5291 5292#ifdef PUCC_PTYD 5293 closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond); 5294#endif /* PUCC_PTYD */ 5295 5296 /* cleanup the utmp entry we forged earlier */ 5297 if (!resource.utmpInhibit 5298#if OPT_PTY_HANDSHAKE /* without handshake, no way to know */ 5299 && (resource.ptyHandshake && added_utmp_entry) 5300#endif /* OPT_PTY_HANDSHAKE */ 5301 ) { 5302#if defined(USE_UTMP_SETGID) 5303 setEffectiveGroup(save_egid); 5304 TRACE_IDS; 5305#endif 5306 init_utmp(USER_PROCESS, &utmp); 5307 (void) call_setutent(); 5308 5309 /* 5310 * We could use getutline() if we didn't support old systems. 5311 */ 5312 while ((utptr = find_utmp(&utmp)) != 0) { 5313 if (utptr->ut_pid == screen->pid) { 5314 utptr->ut_type = DEAD_PROCESS; 5315#if defined(HAVE_UTMP_UT_XTIME) 5316#if defined(HAVE_UTMP_UT_SESSION) 5317 utptr->ut_session = getsid(0); 5318#endif 5319 utptr->ut_xtime = time((time_t *) 0); 5320 utptr->ut_tv.tv_usec = 0; 5321#else 5322 *utptr->ut_user = 0; 5323 utptr->ut_time = time((time_t *) 0); 5324#endif 5325 (void) call_pututline(utptr); 5326#ifdef WTMP 5327#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__)) 5328 if (xw->misc.login_shell) 5329 updwtmpx(WTMPX_FILE, utptr); 5330#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) 5331 copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line)); 5332 if (xw->misc.login_shell) 5333 call_updwtmp(etc_wtmp, utptr); 5334#else 5335 /* set wtmp entry if wtmp file exists */ 5336 if (xw->misc.login_shell) { 5337 int fd; 5338 if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 5339 IGNORE_RC(write(fd, utptr, sizeof(*utptr))); 5340 close(fd); 5341 } 5342 } 5343#endif 5344#endif 5345 break; 5346 } 5347 memset(utptr, 0, sizeof(*utptr)); /* keep searching */ 5348 } 5349 (void) call_endutent(); 5350#ifdef USE_UTMP_SETGID 5351 disableSetGid(); 5352 TRACE_IDS; 5353#endif 5354 } 5355#else /* not USE_SYSV_UTMP */ 5356 int wfd; 5357 struct utmp utmp; 5358 5359 DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n"); 5360 if (!resource.utmpInhibit && added_utmp_entry && 5361 (am_slave < 0 && tslot > 0)) { 5362#if defined(USE_UTMP_SETGID) 5363 setEffectiveGroup(save_egid); 5364 TRACE_IDS; 5365#endif 5366 if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) { 5367 memset(&utmp, 0, sizeof(utmp)); 5368 lseek(wfd, (long) (tslot * sizeof(utmp)), 0); 5369 IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp))); 5370 close(wfd); 5371 } 5372#ifdef WTMP 5373 if (xw->misc.login_shell && 5374 (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) { 5375 copy_filled(utmp.ut_line, 5376 my_pty_name(ttydev), 5377 sizeof(utmp.ut_line)); 5378 utmp.ut_time = time((time_t *) 0); 5379 IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp))); 5380 close(wfd); 5381 } 5382#endif /* WTMP */ 5383#ifdef USE_UTMP_SETGID 5384 disableSetGid(); 5385 TRACE_IDS; 5386#endif 5387 } 5388#endif /* USE_SYSV_UTMP */ 5389#endif /* HAVE_UTMP */ 5390 5391 cleanup_colored_cursor(); 5392 5393 /* 5394 * Flush pending data before releasing ownership, so nobody else can write 5395 * in the middle of the data. 5396 */ 5397 ttyFlush(screen->respond); 5398 5399#ifdef USE_PTY_SEARCH 5400 if (am_slave < 0) { 5401 TRACE_IDS; 5402 /* restore ownership of tty and pty */ 5403 set_owner(ttydev, 0, 0, 0666U); 5404#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux)) 5405 set_owner(ptydev, 0, 0, 0666U); 5406#endif 5407 } 5408#endif 5409 5410 /* 5411 * Close after releasing ownership to avoid race condition: other programs 5412 * grabbing it, and *then* having us release ownership.... 5413 */ 5414 close(screen->respond); /* close explicitly to avoid race with slave side */ 5415#ifdef ALLOWLOGGING 5416 if (screen->logging) 5417 CloseLog(xw); 5418#endif 5419 5420 xtermPrintOnXError(xw, n); 5421 5422#ifdef NO_LEAKS 5423 if (n == 0) { 5424 Display *dpy = TScreenOf(xw)->display; 5425 5426 TRACE(("Freeing memory leaks\n")); 5427 5428 if (toplevel) { 5429 XtDestroyWidget(toplevel); 5430 TRACE(("destroyed top-level widget\n")); 5431 } 5432 sortedOpts(0, 0, 0); 5433 noleaks_charproc(); 5434 noleaks_ptydata(); 5435#if OPT_GRAPHICS 5436 noleaks_graphics(); 5437#endif 5438#if OPT_WIDE_CHARS 5439 noleaks_CharacterClass(); 5440#endif 5441 /* XrmSetDatabase(dpy, 0); increases leaks ;-) */ 5442 XtCloseDisplay(dpy); 5443 XtDestroyApplicationContext(app_con); 5444 xtermCloseSession(); 5445 TRACE(("closed display\n")); 5446 5447 TRACE_CLOSE(); 5448 } 5449#endif 5450 5451 exit(n); 5452} 5453 5454/* ARGSUSED */ 5455static void 5456resize_termcap(XtermWidget xw) 5457{ 5458 char *newtc = get_tcap_buffer(xw); 5459 5460#ifndef USE_SYSV_ENVVARS 5461 if (!TEK4014_ACTIVE(xw) && *newtc) { 5462 TScreen *screen = TScreenOf(xw); 5463 char *ptr1, *ptr2; 5464 size_t i; 5465 int li_first = 0; 5466 char *temp; 5467 char oldtc[TERMCAP_SIZE]; 5468 5469 strcpy(oldtc, newtc); 5470 TRACE(("resize %s\n", oldtc)); 5471 if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) { 5472 strcat(oldtc, "co#80:"); 5473 ptr1 = x_strindex(oldtc, "co#"); 5474 } 5475 if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) { 5476 strcat(oldtc, "li#24:"); 5477 ptr2 = x_strindex(oldtc, "li#"); 5478 } 5479 if (ptr1 > ptr2) { 5480 li_first++; 5481 temp = ptr1; 5482 ptr1 = ptr2; 5483 ptr2 = temp; 5484 } 5485 ptr1 += 3; 5486 ptr2 += 3; 5487 strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc)); 5488 temp = newtc + i; 5489 sprintf(temp, "%d", (li_first 5490 ? MaxRows(screen) 5491 : MaxCols(screen))); 5492 temp += strlen(temp); 5493 if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) { 5494 strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1)); 5495 temp += i; 5496 sprintf(temp, "%d", (li_first 5497 ? MaxCols(screen) 5498 : MaxRows(screen))); 5499 if ((ptr2 = strchr(ptr2, ':')) != 0) { 5500 strcat(temp, ptr2); 5501 } 5502 } 5503 TRACE((" ==> %s\n", newtc)); 5504 TRACE((" new size %dx%d\n", MaxRows(screen), MaxCols(screen))); 5505 } 5506#endif /* USE_SYSV_ENVVARS */ 5507} 5508 5509#endif /* ! VMS */ 5510 5511/* 5512 * Does a non-blocking wait for a child process. If the system 5513 * doesn't support non-blocking wait, do nothing. 5514 * Returns the pid of the child, or 0 or -1 if none or error. 5515 */ 5516int 5517nonblocking_wait(void) 5518{ 5519#ifdef USE_POSIX_WAIT 5520 pid_t pid; 5521 5522 pid = waitpid(-1, NULL, WNOHANG); 5523#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) 5524 /* cannot do non-blocking wait */ 5525 int pid = 0; 5526#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */ 5527#if defined(Lynx) 5528 int status; 5529#else 5530 union wait status; 5531#endif 5532 int pid; 5533 5534 pid = wait3(&status, WNOHANG, (struct rusage *) NULL); 5535#endif /* USE_POSIX_WAIT else */ 5536 return pid; 5537} 5538 5539#ifndef VMS 5540 5541/* ARGSUSED */ 5542static void 5543reapchild(int n GCC_UNUSED) 5544{ 5545 int olderrno = errno; 5546 int pid; 5547 5548 DEBUG_MSG("handle:reapchild\n"); 5549 5550 pid = wait(NULL); 5551 5552#ifdef USE_SYSV_SIGNALS 5553 /* cannot re-enable signal before waiting for child 5554 * because then SVR4 loops. Sigh. HP-UX 9.01 too. 5555 */ 5556 (void) signal(SIGCHLD, reapchild); 5557#endif 5558 5559 do { 5560 if (pid == TScreenOf(term)->pid) { 5561 DEBUG_MSG("Exiting\n"); 5562 if (hold_screen) 5563 caught_intr = True; 5564 else 5565 need_cleanup = True; 5566 } 5567 } while ((pid = nonblocking_wait()) > 0); 5568 5569 errno = olderrno; 5570} 5571#endif /* !VMS */ 5572 5573static void 5574remove_termcap_entry(char *buf, const char *str) 5575{ 5576 char *base = buf; 5577 char *first = base; 5578 int count = 0; 5579 size_t len = strlen(str); 5580 5581 TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf)); 5582 5583 while (*buf != 0) { 5584 if (!count && !strncmp(buf, str, len)) { 5585 while (*buf != 0) { 5586 if (*buf == '\\') 5587 buf++; 5588 else if (*buf == ':') 5589 break; 5590 if (*buf != 0) 5591 buf++; 5592 } 5593 while ((*first++ = *buf++) != 0) { 5594 ; 5595 } 5596 TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base)); 5597 return; 5598 } else if (*buf == '\\') { 5599 buf++; 5600 } else if (*buf == ':') { 5601 first = buf; 5602 count = 0; 5603 } else if (!isspace(CharOf(*buf))) { 5604 count++; 5605 } 5606 if (*buf != 0) 5607 buf++; 5608 } 5609 TRACE(("...cannot remove\n")); 5610} 5611 5612/* 5613 * parse_tty_modes accepts lines of the following form: 5614 * 5615 * [SETTING] ... 5616 * 5617 * where setting consists of the words in the ttyModes[] array followed by a 5618 * character or ^char. 5619 */ 5620static int 5621parse_tty_modes(char *s) 5622{ 5623 int c; 5624 Cardinal j, k; 5625 int count = 0; 5626 Boolean found; 5627 5628 TRACE(("parse_tty_modes\n")); 5629 for (;;) { 5630 size_t len; 5631 5632 while (*s && isspace(CharOf(*s))) { 5633 s++; 5634 } 5635 if (!*s) { 5636 return count; 5637 } 5638 5639 for (len = 0; s[len] && !isspace(CharOf(s[len])); ++len) { 5640 ; 5641 } 5642 found = False; 5643 for (j = 0; j < XtNumber(ttyModes); ++j) { 5644 if (len == ttyModes[j].len 5645 && strncmp(s, 5646 ttyModes[j].name, 5647 ttyModes[j].len) == 0) { 5648 found = True; 5649 break; 5650 } 5651 } 5652 if (!found) { 5653 return -1; 5654 } 5655 5656 s += ttyModes[j].len; 5657 while (*s && isspace(CharOf(*s))) { 5658 s++; 5659 } 5660 5661 /* check if this needs a parameter */ 5662 found = False; 5663 for (k = 0, c = 0; k < XtNumber(ttyChars); ++k) { 5664 if ((int) j == ttyChars[k].myMode) { 5665 if (ttyChars[k].sysMode < 0) { 5666 found = True; 5667 c = ttyChars[k].myDefault; 5668 } 5669 break; 5670 } 5671 } 5672 5673 if (!found) { 5674 if (!*s 5675 || (c = decode_keyvalue(&s, False)) == -1) { 5676 return -1; 5677 } 5678 } 5679 ttyModes[j].value = c; 5680 ttyModes[j].set = 1; 5681 count++; 5682 TRACE(("...parsed #%d: %s=%#x\n", count, ttyModes[j].name, c)); 5683 } 5684} 5685 5686#ifndef VMS /* don't use pipes on OpenVMS */ 5687int 5688GetBytesAvailable(int fd) 5689{ 5690#if defined(FIONREAD) 5691 int arg; 5692 ioctl(fd, FIONREAD, (char *) &arg); 5693 return (int) arg; 5694#elif defined(__CYGWIN__) 5695 fd_set set; 5696 struct timeval select_timeout = 5697 {0, 0}; 5698 5699 FD_ZERO(&set); 5700 FD_SET(fd, &set); 5701 if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0) 5702 return 1; 5703 else 5704 return 0; 5705#elif defined(FIORDCK) 5706 return (ioctl(fd, FIORDCHK, NULL)); 5707#else /* !FIORDCK */ 5708 struct pollfd pollfds[1]; 5709 5710 pollfds[0].fd = fd; 5711 pollfds[0].events = POLLIN; 5712 return poll(pollfds, 1, 0); 5713#endif 5714} 5715#endif /* !VMS */ 5716 5717/* Utility function to try to hide system differences from 5718 everybody who used to call killpg() */ 5719 5720int 5721kill_process_group(int pid, int sig) 5722{ 5723 TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig)); 5724#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX) 5725 return kill(-pid, sig); 5726#else 5727 return killpg(pid, sig); 5728#endif 5729} 5730 5731#if OPT_EBCDIC 5732int 5733A2E(int x) 5734{ 5735 char c; 5736 c = x; 5737 __atoe_l(&c, 1); 5738 return c; 5739} 5740 5741int 5742E2A(int x) 5743{ 5744 char c; 5745 c = x; 5746 __etoa_l(&c, 1); 5747 return c; 5748} 5749#endif 5750 5751#if defined(__QNX__) && !defined(__QNXNTO__) 5752#include <sys/types.h> 5753#include <sys/proc_msg.h> 5754#include <sys/kernel.h> 5755#include <string.h> 5756#include <errno.h> 5757 5758struct _proc_session ps; 5759struct _proc_session_reply rps; 5760 5761int 5762qsetlogin(char *login, char *ttyname) 5763{ 5764 int v = getsid(getpid()); 5765 5766 memset(&ps, 0, sizeof(ps)); 5767 memset(&rps, 0, sizeof(rps)); 5768 5769 ps.type = _PROC_SESSION; 5770 ps.subtype = _PROC_SUB_ACTION1; 5771 ps.sid = v; 5772 strcpy(ps.name, login); 5773 5774 Send(1, &ps, &rps, sizeof(ps), sizeof(rps)); 5775 5776 if (rps.status < 0) 5777 return (rps.status); 5778 5779 ps.type = _PROC_SESSION; 5780 ps.subtype = _PROC_SUB_ACTION2; 5781 ps.sid = v; 5782 sprintf(ps.name, "//%d%s", getnid(), ttyname); 5783 Send(1, &ps, &rps, sizeof(ps), sizeof(rps)); 5784 5785 return (rps.status); 5786} 5787#endif 5788 5789#ifdef __minix 5790int 5791setpgrp(void) 5792{ 5793 return 0; 5794} 5795 5796void 5797_longjmp(jmp_buf _env, int _val) 5798{ 5799 longjmp(_env, _val); 5800} 5801#endif 5802