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