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