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