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