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