1 #ifndef lint
2 static char *rid="$XConsortium: main.c /main/239 1995/12/10 17:21:49 gildea $";
3 static char *ktermid = "$Id: main.c,v 6.4 1996/07/12 05:01:34 kagotani Rel $";
4 #endif /* lint */
5 
6 /*
7  * 				 W A R N I N G
8  *
9  * If you think you know what all of this code is doing, you are
10  * probably very mistaken.  There be serious and nasty dragons here.
11  *
12  * This client is *not* to be taken as an example of how to write X
13  * Toolkit applications.  It is in need of a substantial rewrite,
14  * ideally to create a generic tty widget with several different parsing
15  * widgets so that you can plug 'em together any way you want.  Don't
16  * hold your breath, though....
17  */
18 
19 /***********************************************************
20 
21 
22 Copyright (c) 1987, 1988  X Consortium
23 
24 Permission is hereby granted, free of charge, to any person obtaining a copy
25 of this software and associated documentation files (the "Software"), to deal
26 in the Software without restriction, including without limitation the rights
27 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
28 copies of the Software, and to permit persons to whom the Software is
29 furnished to do so, subject to the following conditions:
30 
31 The above copyright notice and this permission notice shall be included in
32 all copies or substantial portions of the Software.
33 
34 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
37 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
38 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40 
41 Except as contained in this notice, the name of the X Consortium shall not be
42 used in advertising or otherwise to promote the sale, use or other dealings
43 in this Software without prior written authorization from the X Consortium.
44 
45 
46 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard.
47 
48                         All Rights Reserved
49 
50 Permission to use, copy, modify, and distribute this software and its
51 documentation for any purpose and without fee is hereby granted,
52 provided that the above copyright notice appear in all copies and that
53 both that copyright notice and this permission notice appear in
54 supporting documentation, and that the name of Digital not be used in
55 advertising or publicity pertaining to distribution of the software
56 without specific, written prior permission.
57 
58 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
59 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
60 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
61 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
62 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
63 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64 SOFTWARE.
65 
66 ******************************************************************/
67 
68 
69 /* main.c */
70 
71 #include "ptyx.h"
72 #include <X11/StringDefs.h>
73 #include <X11/Shell.h>
74 
75 #include <X11/Xos.h>
76 #include <X11/cursorfont.h>
77 #include <X11/Xaw/SimpleMenu.h>
78 #ifndef NO_XPOLL_H
79 #include <X11/Xpoll.h>
80 #endif
81 #include <X11/Xlocale.h>
82 #include <pwd.h>
83 #include <ctype.h>
84 #include "data.h"
85 #include "error.h"
86 #include "menu.h"
87 #include "unicode_map.h"
88 #ifdef KEEPALIVE
89 #include <sys/socket.h>
90 #endif /* KEEPALIVE */
91 
92 #ifdef att
93 #define ATT
94 #endif
95 
96 #ifdef __osf__
97 #define USE_SYSV_UTMP
98 #define USE_SYSV_SIGNALS
99 #endif
100 
101 #ifdef SVR4
102 #ifndef SYSV
103 #define SYSV			/* SVR4 is (approx) superset of SVR3 */
104 #endif
105 #define ATT
106 #define USE_SYSV_UTMP
107 #ifndef __sgi
108 #define USE_TERMIOS
109 #endif
110 #define HAS_UTMP_UT_HOST
111 #endif
112 
113 #if defined(SYSV) && defined(i386) && !defined(SVR4)
114 #define USE_SYSV_UTMP
115 #define ATT
116 #define USE_HANDSHAKE
117 static Bool IsPts = False;
118 #endif
119 
120 #if defined(ATT) && !defined(__sgi)
121 #define USE_USG_PTYS
122 #else
123 #define USE_HANDSHAKE
124 #endif
125 
126 #if defined(SYSV) && !defined(SVR4)
127 /* older SYSV systems cannot ignore SIGHUP.
128    Shell hangs, or you get extra shells, or something like that */
129 #define USE_SYSV_SIGHUP
130 #endif
131 
132 #if defined(sony) && defined(bsd43) && !defined(KANJI)
133 #define KANJI
134 #endif
135 
136 #ifdef linux
137 #define USE_SYSV_TERMIO
138 #define USE_SYSV_PGRP
139 #define USE_SYSV_UTMP
140 #define USE_SYSV_SIGNALS
141 #define HAS_UTMP_UT_HOST
142 #define LASTLOG
143 #define WTMP
144 #endif
145 
146 #if defined(__DragonFly__)
147 #define USE_SYSV_UTMP
148 #define WTMP
149 #define WTMPX_FILE "/var/log/wtmpx"
150 #endif
151 
152 /* from xterm-200 */
153 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__INTERIX) || defined(__APPLE__) || defined(__DragonFly__)
154 #ifndef USE_POSIX_TERMIOS
155 #define USE_POSIX_TERMIOS
156 #endif
157 #endif
158 
159 #include <sys/ioctl.h>
160 #include <sys/stat.h>
161 
162 /*
163  * Terminal I/O includes (termio, termios, sgtty headers).
164  */
165 #if defined(USE_POSIX_TERMIOS)
166 #include <termios.h>
167 #elif defined(USE_TERMIOS)
168 #include <termios.h>
169 /* this hacked termios support only works on SYSV */
170 #define USE_SYSV_TERMIO
171 #define termio termios
172 #undef TCGETA
173 #define TCGETA TCGETS
174 #undef TCSETA
175 #define TCSETA TCSETS
176 #else /* USE_TERMIOS */
177 #ifdef SYSV
178 #include <sys/termio.h>
179 #endif /* SYSV */
180 #endif /* USE_TERMIOS else */
181 
182 #ifdef SVR4
183 #undef TIOCSLTC				/* defined, but not useable */
184 #endif
185 
186 #if defined(__sgi) && OSMAJORVERSION >= 5
187 #undef TIOCLSET				/* defined, but not useable */
188 #endif
189 
190 #ifdef SYSV /* { */
191 #ifdef USE_USG_PTYS			/* AT&T SYSV has no ptyio.h */
192 #include <sys/stream.h>			/* get typedef used in ptem.h */
193 #include <sys/stropts.h>		/* for I_PUSH */
194 #ifndef SVR4
195 #include <sys/ptem.h>			/* get struct winsize */
196 #endif
197 #include <poll.h>			/* for POLLIN */
198 #endif /* USE_USG_PTYS */
199 #define USE_SYSV_TERMIO
200 #define USE_SYSV_SIGNALS
201 #define	USE_SYSV_PGRP
202 #define USE_SYSV_ENVVARS		/* COLUMNS/LINES vs. TERMCAP */
203 /*
204  * now get system-specific includes
205  */
206 #ifdef CRAY
207 #define USE_SYSV_UTMP
208 #define HAS_UTMP_UT_HOST
209 #define HAS_BSD_GROUPS
210 #endif
211 #ifdef macII
212 #define USE_SYSV_UTMP
213 #define HAS_UTMP_UT_HOST
214 #define HAS_BSD_GROUPS
215 #include <sys/ttychars.h>
216 #undef USE_SYSV_ENVVARS
217 #undef FIOCLEX
218 #undef FIONCLEX
219 #define setpgrp2 setpgrp
220 #ifndef USE_POSIX_TERMIOS
221 #include <sgtty.h>
222 #endif
223 #include <sys/resource.h>
224 #endif
225 #ifdef sco
226 #define USE_SYSV_UTMP
227 #define USE_POSIX_WAIT
228 #endif /* sco */
229 #ifdef hpux
230 #define HAS_BSD_GROUPS
231 #define USE_SYSV_UTMP
232 #define HAS_UTMP_UT_HOST
233 #define USE_POSIX_WAIT
234 #include <sys/ptyio.h>
235 #endif /* hpux */
236 #ifdef __sgi
237 #define HAS_BSD_GROUPS
238 #include <sys/sysmacros.h>
239 #endif /* __sgi */
240 #ifdef sun
241 #include <sys/strredir.h>
242 #endif
243 #ifdef AIXV3
244 #define USE_SYSV_UTMP
245 #define HAS_UTMP_UT_HOST
246 #endif
247 #else /* } !SYSV { */			/* BSD systems */
248 #if !defined(linux) && !defined(USE_POSIX_TERMIOS)
249 #include <sgtty.h>
250 #endif
251 #include <sys/resource.h>
252 #define HAS_UTMP_UT_HOST
253 #define HAS_BSD_GROUPS
254 #ifdef __osf__
255 #define USE_SYSV_UTMP
256 #define setpgrp setpgid
257 #endif
258 #endif	/* } !SYSV */
259 
260 #if defined(__FreeBSD__) && defined(__amd64__)
261 /* defined, but not useable */
262 #undef TIOCSLTC
263 #undef TIOCLSET
264 #endif
265 
266 #ifdef _POSIX_SOURCE
267 #define USE_POSIX_WAIT
268 #define HAS_POSIX_SAVED_IDS
269 #endif
270 #ifdef SVR4
271 #define USE_POSIX_WAIT
272 #define HAS_POSIX_SAVED_IDS
273 #endif
274 
275 #if !defined(MINIX) && !defined(WIN32)
276 #include <sys/param.h>	/* for NOFILE */
277 #endif
278 
279 #if (BSD >= 199103)
280 #define USE_POSIX_WAIT
281 #define HAS_POSIX_SAVED_IDS
282 #endif
283 
284 #include <stdio.h>
285 #include <errno.h>
286 #include <setjmp.h>
287 
288 #ifdef X_NOT_STDC_ENV
289 extern int errno;
290 #define Time_t long
291 extern Time_t time ();
292 #else
293 #include <time.h>
294 #define Time_t time_t
295 #endif
296 
297 #ifdef hpux
298 #include <sys/utsname.h>
299 #endif /* hpux */
300 
301 #if defined(apollo) && OSMAJORVERSION == 10 && OSMINORVERSION < 4
302 #define ttyslot() 1
303 #endif /* apollo */
304 
305 #if defined(SVR4) || (defined(__FreeBSD__) && __FreeBSD_version >= 900007) || defined(__DragonFly__)
306 #include <utmpx.h>
307 #define setutent setutxent
308 #define getutent getutxent
309 #define getutid getutxid
310 #define endutent endutxent
311 #define pututline pututxline
312 #else
313 #include <utmp.h>
314 #if defined(_CRAY) && OSMAJORVERSION < 8
315 extern struct utmp *getutid __((struct utmp *_Id));
316 #endif
317 #endif
318 
319 #ifdef LASTLOG
320 # if !defined(BSD) || (BSD < 199103)
321 #include <lastlog.h>
322 # endif
323 #endif
324 #include <sys/param.h>	/* for NOFILE */
325 
326 #ifdef  PUCC_PTYD
327 #include <local/openpty.h>
328 int	Ptyfd;
329 #endif /* PUCC_PTYD */
330 
331 #ifdef __FreeBSD__
332 #include <libutil.h>	/* openpty() */
333 #endif
334 
335 #ifdef sequent
336 #define USE_GET_PSEUDOTTY
337 #endif
338 
339 #ifndef UTMP_FILENAME
340 #ifdef UTMP_FILE
341 #define UTMP_FILENAME UTMP_FILE
342 #else
343 #ifdef _PATH_UTMP
344 #define UTMP_FILENAME _PATH_UTMP
345 #else
346 #define UTMP_FILENAME "/etc/utmp"
347 #endif
348 #endif
349 #endif
350 
351 #ifndef LASTLOG_FILENAME
352 #ifdef _PATH_LASTLOG
353 #define LASTLOG_FILENAME _PATH_LASTLOG
354 #else
355 #define LASTLOG_FILENAME "/usr/adm/lastlog"  /* only on BSD systems */
356 #endif
357 #endif
358 
359 #ifndef WTMP_FILENAME
360 #ifdef WTMP_FILE
361 #define WTMP_FILENAME WTMP_FILE
362 #else
363 #ifdef _PATH_WTMP
364 #define WTMP_FILENAME _PATH_WTMP
365 #else
366 #ifdef SYSV
367 #define WTMP_FILENAME "/etc/wtmp"
368 #else
369 #define WTMP_FILENAME "/usr/adm/wtmp"
370 #endif
371 #endif
372 #endif
373 #endif
374 
375 #include <signal.h>
376 
377 #if defined(sco) || defined(ISC)
378 #undef SIGTSTP			/* defined, but not the BSD way */
379 #endif
380 
381 #ifdef SIGTSTP
382 #include <sys/wait.h>
383 #ifdef hpux
384 #include <sys/bsdtty.h>
385 #endif
386 #endif
387 
388 #ifdef SIGNALRETURNSINT
389 #define SIGNAL_T int
390 #define SIGNAL_RETURN return 0
391 #else
392 #define SIGNAL_T void
393 #define SIGNAL_RETURN return
394 #endif
395 
396 SIGNAL_T Exit();
397 
398 #ifndef X_NOT_POSIX
399 #include <unistd.h>
400 #else
401 extern long lseek();
402 #ifdef USG
403 extern unsigned sleep();
404 #else
405 extern void sleep();
406 #endif
407 #endif
408 
409 #ifndef X_NOT_STDC_ENV
410 #include <stdlib.h>
411 #else
412 extern char *malloc();
413 extern char *calloc();
414 extern char *realloc();
415 extern char *getenv();
416 extern void exit();
417 #endif
418 #ifdef X_NOT_POSIX
419 extern char *ttyname();
420 #endif
421 
422 #ifdef __sgi
423 #include <locale.h>
424 #endif
425 
426 #ifdef SYSV
427 extern char *ptsname();
428 #endif
429 
430 extern char *strindex ();
431 extern void HandlePopupMenu();
432 
433 int switchfb[] = {0, 2, 1, 3};
434 
435 static SIGNAL_T reapchild ();
436 
437 static Bool added_utmp_entry = False;
438 
439 static Bool xterm_exiting = False;
440 
441 /*
442 ** Ordinarily it should be okay to omit the assignment in the following
443 ** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
444 ** it? Without the assignment though the compiler will init command_to_exec
445 ** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawn() to
446 ** SEGV.
447 */
448 static char **command_to_exec = NULL;
449 
450 #ifdef USE_SYSV_TERMIO
451 /* The following structures are initialized in main() in order
452 ** to eliminate any assumptions about the internal order of their
453 ** contents.
454 */
455 static struct termio d_tio;
456 #ifdef TIOCSLTC
457 static struct ltchars d_ltc;
458 #endif	/* TIOCSLTC */
459 
460 #ifdef __sgi
461 #undef TIOCLSET /* XXX why is this undef-ed again? */
462 #endif
463 
464 #ifdef TIOCLSET
465 static unsigned int d_lmode;
466 #endif	/* TIOCLSET */
467 
468 #elif defined(USE_POSIX_TERMIOS)
469 static struct termios d_tio;
470 
471 #ifdef TIOCSLTC
472 static struct ltchars d_ltc;
473 #endif /* TIOCSLTC */
474 
475 #ifdef TIOCLSET
476 static unsigned int d_lmode;
477 #endif /* TIOCLSET */
478 
479 #else /* !USE_SYSV_TERMIO && !USE_POSIX_TERMIOS */
480 static struct  sgttyb d_sg = {
481         0, 0, 0177, CKILL, EVENP|ODDP|ECHO|XTABS|CRMOD
482 };
483 static struct  tchars d_tc = {
484         CINTR, CQUIT, CSTART,
485         CSTOP, CEOF, CBRK,
486 };
487 static struct  ltchars d_ltc = {
488         CSUSP, CDSUSP, CRPRNT,
489         CFLUSH, CWERASE, CLNEXT
490 };
491 static int d_disipline = NTTYDISC;
492 #if defined(KTERM) && defined(LPASS8)
493 static long int d_lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH|LPASS8;
494 #else
495 static long int d_lmode = LCRTBS|LCRTERA|LCRTKIL|LCTLECH;
496 #endif
497 #ifdef sony
498 static long int d_jmode = KM_SYSSJIS|KM_ASCII;
499 static struct jtchars d_jtc = {
500 	'J', 'B'
501 };
502 #endif /* sony */
503 #endif /* USE_SYSV_TERMIO */
504 
505 /* allow use of system default characters if defined and reasonable */
506 #ifndef CEOF
507 #define CEOF ('D'&037)
508 #endif
509 #ifndef CSUSP
510 #define CSUSP ('Z'&037)
511 #endif
512 #ifndef CQUIT
513 #define CQUIT ('\\'&037)
514 #endif
515 #ifndef CEOL
516 #define CEOL 0
517 #endif
518 #ifndef CSWTCH
519 #define CSWTCH 0
520 #endif
521 #ifndef CLNEXT
522 #define CLNEXT ('V'&037)
523 #endif
524 #ifndef CWERASE
525 #define CWERASE ('W'&037)
526 #endif
527 #ifndef CRPRNT
528 #define CRPRNT ('R'&037)
529 #endif
530 #ifndef CFLUSH
531 #define CFLUSH ('O'&037)
532 #endif
533 #ifndef CSTOP
534 #define CSTOP ('S'&037)
535 #endif
536 #ifndef CSTART
537 #define CSTART ('Q'&037)
538 #endif
539 
540 static int parse_tty_modes ();
541 /*
542  * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
543  * SVR4 has only termio.c_cc, but it includes everything from ltchars.
544  */
545 static int override_tty_modes = 0;
546 struct _xttymodes {
547     char *name;
548     int len;
549     int set;
550     char value;
551 } ttymodelist[] = {
552 { "intr", 4, 0, '\0' },			/* tchars.t_intrc ; VINTR */
553 #define XTTYMODE_intr 0
554 { "quit", 4, 0, '\0' },			/* tchars.t_quitc ; VQUIT */
555 #define XTTYMODE_quit 1
556 { "erase", 5, 0, '\0' },		/* sgttyb.sg_erase ; VERASE */
557 #define XTTYMODE_erase 2
558 { "kill", 4, 0, '\0' },			/* sgttyb.sg_kill ; VKILL */
559 #define XTTYMODE_kill 3
560 { "eof", 3, 0, '\0' },			/* tchars.t_eofc ; VEOF */
561 #define XTTYMODE_eof 4
562 { "eol", 3, 0, '\0' },			/* VEOL */
563 #define XTTYMODE_eol 5
564 { "swtch", 5, 0, '\0' },		/* VSWTCH */
565 #define XTTYMODE_swtch 6
566 { "start", 5, 0, '\0' },		/* tchars.t_startc */
567 #define XTTYMODE_start 7
568 { "stop", 4, 0, '\0' },			/* tchars.t_stopc */
569 #define XTTYMODE_stop 8
570 { "brk", 3, 0, '\0' },			/* tchars.t_brkc */
571 #define XTTYMODE_brk 9
572 { "susp", 4, 0, '\0' },			/* ltchars.t_suspc ; VSUSP */
573 #define XTTYMODE_susp 10
574 { "dsusp", 5, 0, '\0' },		/* ltchars.t_dsuspc ; VDSUSP */
575 #define XTTYMODE_dsusp 11
576 { "rprnt", 5, 0, '\0' },		/* ltchars.t_rprntc ; VREPRINT */
577 #define XTTYMODE_rprnt 12
578 { "flush", 5, 0, '\0' },		/* ltchars.t_flushc ; VDISCARD */
579 #define XTTYMODE_flush 13
580 { "weras", 5, 0, '\0' },		/* ltchars.t_werasc ; VWERASE */
581 #define XTTYMODE_weras 14
582 { "lnext", 5, 0, '\0' },		/* ltchars.t_lnextc ; VLNEXT */
583 #define XTTYMODE_lnext 15
584 { NULL, 0, 0, '\0' },			/* end of data */
585 };
586 
587 #ifdef USE_SYSV_UTMP
588 #if defined(X_NOT_STDC_ENV) || (defined(AIXV3) && OSMAJORVERSION < 4)
589 extern struct utmp *getutent();
590 extern struct utmp *getutid();
591 extern struct utmp *getutline();
592 extern void pututline();
593 extern void setutent();
594 extern void endutent();
595 extern void utmpname();
596 #endif /* !SVR4 */
597 
598 #ifdef X_NOT_STDC_ENV		/* could remove paragraph unconditionally? */
599 extern struct passwd *getpwent();
600 extern struct passwd *getpwuid();
601 extern struct passwd *getpwnam();
602 extern void setpwent();
603 extern void endpwent();
604 #endif
605 
606 extern struct passwd *fgetpwent();
607 #else	/* not USE_SYSV_UTMP */
608 static char etc_utmp[] = UTMP_FILENAME;
609 #ifdef LASTLOG
610 static char etc_lastlog[] = LASTLOG_FILENAME;
611 #endif
612 #endif	/* USE_SYSV_UTMP */
613 
614 #ifdef WTMP
615 static char etc_wtmp[] = WTMP_FILENAME;
616 #endif
617 
618 /*
619  * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
620  * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
621  * WTMP and LASTLOG.
622  */
623 #ifdef USE_LOGIN_DASH_P
624 #ifndef LOGIN_FILENAME
625 #define LOGIN_FILENAME "/bin/login"
626 #endif
627 static char bin_login[] = LOGIN_FILENAME;
628 #endif
629 
630 static int inhibit;
631 static char passedPty[2];	/* name if pty if slave */
632 
633 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
634 static int Console;
635 #include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
636 #define MIT_CONSOLE_LEN	12
637 #define MIT_CONSOLE "MIT_CONSOLE_"
638 static char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
639 static Atom mit_console;
640 #endif	/* TIOCCONS */
641 
642 #ifndef USE_SYSV_UTMP
643 static int tslot;
644 #endif	/* USE_SYSV_UTMP */
645 static jmp_buf env;
646 
647 char *ProgramName;
648 Boolean sunFunctionKeys;
649 
650 static struct _resource {
651     char *xterm_name;
652     char *icon_geometry;
653     char *title;
654     char *icon_name;
655     char *term_name;
656     char *tty_modes;
657     Boolean utmpInhibit;
658     Boolean sunFunctionKeys;	/* %%% should be widget resource? */
659     Boolean wait_for_map;
660     Boolean useInsertMode;
661 #ifdef __sgi
662     Boolean useLocale;
663 #endif
664 #ifdef KEEPALIVE
665     Boolean keepalive;
666 #endif
667 #ifdef WALLPAPER
668     char *wallpaper;
669 #endif /* WALLPAPER */
670 } resource;
671 
672 /* used by VT (charproc.c) */
673 
674 #define offset(field)	XtOffsetOf(struct _resource, field)
675 
676 static XtResource application_resources[] = {
677     {"name", "Name", XtRString, sizeof(char *),
678 #ifdef KTERM
679 	offset(xterm_name), XtRString, "kterm"},
680 #else /* !KTERM */
681 	offset(xterm_name), XtRString, "xterm"},
682 #endif /* !KTERM */
683     {"iconGeometry", "IconGeometry", XtRString, sizeof(char *),
684 	offset(icon_geometry), XtRString, (caddr_t) NULL},
685     {XtNtitle, XtCTitle, XtRString, sizeof(char *),
686 	offset(title), XtRString, (caddr_t) NULL},
687     {XtNiconName, XtCIconName, XtRString, sizeof(char *),
688 	offset(icon_name), XtRString, (caddr_t) NULL},
689     {"termName", "TermName", XtRString, sizeof(char *),
690 	offset(term_name), XtRString, (caddr_t) NULL},
691     {"ttyModes", "TtyModes", XtRString, sizeof(char *),
692 	offset(tty_modes), XtRString, (caddr_t) NULL},
693     {"utmpInhibit", "UtmpInhibit", XtRBoolean, sizeof (Boolean),
694 	offset(utmpInhibit), XtRString, "false"},
695     {"sunFunctionKeys", "SunFunctionKeys", XtRBoolean, sizeof (Boolean),
696 	offset(sunFunctionKeys), XtRString, "false"},
697     {"waitForMap", "WaitForMap", XtRBoolean, sizeof (Boolean),
698         offset(wait_for_map), XtRString, "false"},
699     {"useInsertMode", "UseInsertMode", XtRBoolean, sizeof (Boolean),
700         offset(useInsertMode), XtRString, "false"},
701 #ifdef __sgi
702     {"useLocale", "UseLocale", XtRBoolean, sizeof(Boolean),
703 	offset(useLocale), XtRString, "true"},
704 #endif
705 #ifdef KEEPALIVE
706     {"keepAlive", "KeepAlive", XtRBoolean, sizeof (Boolean),
707 	offset(keepalive), XtRString, "false"},
708 #endif /* KEEPALIVE */
709 #ifdef WALLPAPER
710     {"wallPaper", "WallPaper", XtRString, sizeof (char *),
711         offset(wallpaper), XtRString, (caddr_t)NULL},
712 #endif /* WALLPAPER */
713 };
714 #undef offset
715 
716 static char *fallback_resources[] = {
717 #ifdef KTERM
718     "KTerm*SimpleMenu*menuLabel.vertSpace: 100",
719     "KTerm*SimpleMenu*HorizontalMargins: 16",
720     "KTerm*SimpleMenu*Sme.height: 16",
721     "KTerm*SimpleMenu*Cursor: left_ptr",
722     "KTerm*mainMenu.Label:  Main Options (no app-defaults)",
723     "KTerm*vtMenu.Label:  VT Options (no app-defaults)",
724     "KTerm*fontMenu.Label:  VT Fonts (no app-defaults)",
725 # ifndef KTERM_NOTEK
726     "KTerm*tekMenu.Label:  Tek Options (no app-defaults)",
727 # endif /* !KTERM_NOTEK */
728 #else /* !KTERM */
729     "XTerm*SimpleMenu*menuLabel.vertSpace: 100",
730     "XTerm*SimpleMenu*HorizontalMargins: 16",
731     "XTerm*SimpleMenu*Sme.height: 16",
732     "XTerm*SimpleMenu*Cursor: left_ptr",
733     "XTerm*mainMenu.Label:  Main Options (no app-defaults)",
734     "XTerm*vtMenu.Label:  VT Options (no app-defaults)",
735     "XTerm*fontMenu.Label:  VT Fonts (no app-defaults)",
736     "XTerm*tekMenu.Label:  Tek Options (no app-defaults)",
737 #endif /* !KTERM */
738     NULL
739 };
740 
741 /* Command line options table.  Only resources are entered here...there is a
742    pass over the remaining options after XrmParseCommand is let loose. */
743 
744 static XrmOptionDescRec optionDescList[] = {
745 {"-geometry",	"*vt100.geometry",XrmoptionSepArg,	(caddr_t) NULL},
746 {"-132",	"*c132",	XrmoptionNoArg,		(caddr_t) "on"},
747 {"+132",	"*c132",	XrmoptionNoArg,		(caddr_t) "off"},
748 {"-ah",		"*alwaysHighlight", XrmoptionNoArg,	(caddr_t) "on"},
749 {"+ah",		"*alwaysHighlight", XrmoptionNoArg,	(caddr_t) "off"},
750 {"-b",		"*internalBorder",XrmoptionSepArg,	(caddr_t) NULL},
751 {"-cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "off"},
752 {"+cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (caddr_t) "on"},
753 {"-cc",		"*charClass",	XrmoptionSepArg,	(caddr_t) NULL},
754 {"-cn",		"*cutNewline",	XrmoptionNoArg,		(caddr_t) "off"},
755 {"+cn",		"*cutNewline",	XrmoptionNoArg,		(caddr_t) "on"},
756 {"-cr",		"*cursorColor",	XrmoptionSepArg,	(caddr_t) NULL},
757 {"-cu",		"*curses",	XrmoptionNoArg,		(caddr_t) "on"},
758 {"+cu",		"*curses",	XrmoptionNoArg,		(caddr_t) "off"},
759 {"-e",		NULL,		XrmoptionSkipLine,	(caddr_t) NULL},
760 #ifndef ENBUG /* kagotani */
761 {"-fn",		"*vt100.font",	XrmoptionSepArg,	(caddr_t) NULL},
762 #endif
763 {"-fb",		"*boldFont",	XrmoptionSepArg,	(caddr_t) NULL},
764 #ifdef KTERM
765 {"-dfl",	"*dynamicFontLoad", XrmoptionNoArg,	(caddr_t) "on"},
766 {"+dfl",	"*dynamicFontLoad", XrmoptionNoArg,	(caddr_t) "off"},
767 {"-fl",		"*fontList",	XrmoptionSepArg,	(caddr_t) NULL},
768 {"-flb",	"*boldFontList", XrmoptionSepArg,	(caddr_t) NULL},
769 {"-fr",		"*romanKanaFont", XrmoptionSepArg,	(caddr_t) NULL},
770 {"-frb",	"*romanKanaBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
771 #ifdef KTERM_MBCS
772 {"-fk",		"*kanjiFont",	XrmoptionSepArg,	(caddr_t) NULL},
773 {"-fkb",	"*kanjiBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
774 {"-fkB",	"*kanjiFont",   XrmoptionSepArg,	(caddr_t) NULL},
775 {"-fkbB",	"*kanjiBoldFont", XrmoptionSepArg,      (caddr_t) NULL},
776 {"-fk@",	"*oldKanjiFont", XrmoptionSepArg,	(caddr_t) NULL},
777 {"-fkb@",	"*oldKanjiBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
778 {"-fk@B",	"*kanji90Font", XrmoptionSepArg,	(caddr_t) NULL},
779 {"-fkb@B",	"*kanji90BoldFont", XrmoptionSepArg,	(caddr_t) NULL},
780 {"-fkD",	"*hojoKanjiFont", XrmoptionSepArg,	(caddr_t) NULL},
781 {"-fkbD",	"*hojoKanjiBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
782 {"-fkO",	"*extOneKanjiFont", XrmoptionSepArg,	(caddr_t) NULL},
783 {"-fkbO",	"*extOneKanjiBoldFont", XrmoptionSepArg,(caddr_t) NULL},
784 {"-fkP",	"*extTwoKanjiFont", XrmoptionSepArg,	(caddr_t) NULL},
785 {"-fkbP",	"*extTwoKanjiBoldFont", XrmoptionSepArg,(caddr_t) NULL},
786 {"-fkQ",	"*ext2004OneKanjiFont", XrmoptionSepArg,(caddr_t) NULL},
787 {"-fkbQ",	"*ext2004OneKanjiBoldFont", XrmoptionSepArg,(caddr_t) NULL},
788 {"-fkC",	"*hanglFont", XrmoptionSepArg,		(caddr_t) NULL},
789 {"-fkbC",	"*hanglBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
790 {"-fkA",	"*hanziFont", XrmoptionSepArg,		(caddr_t) NULL},
791 {"-fkbA",	"*hanziBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
792 {"-fkG",	"*cnsOneFont", XrmoptionSepArg,		(caddr_t) NULL},
793 {"-fkbG",	"*cnsOneBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
794 {"-fkH",	"*cnsTwoFont", XrmoptionSepArg,		(caddr_t) NULL},
795 {"-fkbH",	"*cnsTwoBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
796 {"-fkI",	"*cnsThreeFont", XrmoptionSepArg,	(caddr_t) NULL},
797 {"-fkbI",	"*cnsThreeBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
798 {"-fkJ",	"*cnsFourFont", XrmoptionSepArg,	(caddr_t) NULL},
799 {"-fkbJ",	"*cnsFourBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
800 {"-fkK",	"*cnsFiveFont", XrmoptionSepArg,	(caddr_t) NULL},
801 {"-fkbK",	"*cnsFiveBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
802 {"-fkL",	"*cnsSixFont", XrmoptionSepArg,		(caddr_t) NULL},
803 {"-fkbL",	"*cnsSixBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
804 {"-fkM",	"*cnsSevenFont", XrmoptionSepArg,	(caddr_t) NULL},
805 {"-fkbM",	"*cnsSevenBoldFont", XrmoptionSepArg,	(caddr_t) NULL},
806 #endif /* KTERM_MBCS */
807 #ifdef KTERM_KANJIMODE
808 {"-km",		"*kanjiMode",	XrmoptionSepArg,	(caddr_t) NULL},
809 #endif /* KTERM_KANJIMODE */
810 #ifdef KTERM_XIM
811 { "-xim",	"*openIm",	XrmoptionNoArg,		(caddr_t) "on"},
812 { "+xim",	"*openIm",	XrmoptionNoArg,		(caddr_t) "off"},
813 #endif /* KTERM_XIM */
814 {"-lsp",	"*lineSpace",	XrmoptionSepArg,	(caddr_t) NULL},
815 #endif /* KTERM */
816 {"-j",		"*jumpScroll",	XrmoptionNoArg,		(caddr_t) "on"},
817 {"+j",		"*jumpScroll",	XrmoptionNoArg,		(caddr_t) "off"},
818 #ifdef KEEPALIVE
819 {"-ka",		"*keepAlive",	XrmoptionNoArg,		(caddr_t) "on"},
820 {"+ka",		"*keepAlive",	XrmoptionNoArg,		(caddr_t) "off"},
821 #endif /* KEEPALIVE */
822 /* parse logging options anyway for compatibility */
823 {"-l",		"*logging",	XrmoptionNoArg,		(caddr_t) "on"},
824 {"+l",		"*logging",	XrmoptionNoArg,		(caddr_t) "off"},
825 {"-lf",		"*logFile",	XrmoptionSepArg,	(caddr_t) NULL},
826 {"-ls",		"*loginShell",	XrmoptionNoArg,		(caddr_t) "on"},
827 {"+ls",		"*loginShell",	XrmoptionNoArg,		(caddr_t) "off"},
828 {"-mb",		"*marginBell",	XrmoptionNoArg,		(caddr_t) "on"},
829 {"+mb",		"*marginBell",	XrmoptionNoArg,		(caddr_t) "off"},
830 {"-mc",		"*multiClickTime", XrmoptionSepArg,	(caddr_t) NULL},
831 {"-ms",		"*pointerColor",XrmoptionSepArg,	(caddr_t) NULL},
832 {"-nb",		"*nMarginBell",	XrmoptionSepArg,	(caddr_t) NULL},
833 {"-rw",		"*reverseWrap",	XrmoptionNoArg,		(caddr_t) "on"},
834 {"+rw",		"*reverseWrap",	XrmoptionNoArg,		(caddr_t) "off"},
835 {"-aw",		"*autoWrap",	XrmoptionNoArg,		(caddr_t) "on"},
836 {"+aw",		"*autoWrap",	XrmoptionNoArg,		(caddr_t) "off"},
837 {"-s",		"*multiScroll",	XrmoptionNoArg,		(caddr_t) "on"},
838 {"+s",		"*multiScroll",	XrmoptionNoArg,		(caddr_t) "off"},
839 {"-sb",		"*scrollBar",	XrmoptionNoArg,		(caddr_t) "on"},
840 {"+sb",		"*scrollBar",	XrmoptionNoArg,		(caddr_t) "off"},
841 {"-sf",		"*sunFunctionKeys", XrmoptionNoArg,	(caddr_t) "on"},
842 {"+sf",		"*sunFunctionKeys", XrmoptionNoArg,	(caddr_t) "off"},
843 {"-si",		"*scrollTtyOutput",	XrmoptionNoArg,		(caddr_t) "off"},
844 {"+si",		"*scrollTtyOutput",	XrmoptionNoArg,		(caddr_t) "on"},
845 {"-sk",		"*scrollKey",	XrmoptionNoArg,		(caddr_t) "on"},
846 {"+sk",		"*scrollKey",	XrmoptionNoArg,		(caddr_t) "off"},
847 {"-sl",		"*saveLines",	XrmoptionSepArg,	(caddr_t) NULL},
848 #ifndef KTERM_NOTEK
849 {"-t",		"*tekStartup",	XrmoptionNoArg,		(caddr_t) "on"},
850 {"+t",		"*tekStartup",	XrmoptionNoArg,		(caddr_t) "off"},
851 #endif /* !KTERM_NOTEK */
852 {"-tm",		"*ttyModes",	XrmoptionSepArg,	(caddr_t) NULL},
853 {"-tn",		"*termName",	XrmoptionSepArg,	(caddr_t) NULL},
854 #ifdef __sgi
855 {"-ul",		"*useLocale",	XrmoptionNoArg,		(caddr_t) "on"},
856 {"+ul",		"*useLocale",	XrmoptionNoArg,		(caddr_t) "off"},
857 #endif
858 {"-ut",		"*utmpInhibit",	XrmoptionNoArg,		(caddr_t) "on"},
859 {"+ut",		"*utmpInhibit",	XrmoptionNoArg,		(caddr_t) "off"},
860 {"-im",		"*useInsertMode", XrmoptionNoArg,	(caddr_t) "on"},
861 {"+im",		"*useInsertMode", XrmoptionNoArg,	(caddr_t) "off"},
862 {"-vb",		"*visualBell",	XrmoptionNoArg,		(caddr_t) "on"},
863 {"+vb",		"*visualBell",	XrmoptionNoArg,		(caddr_t) "off"},
864 {"-wf",		"*waitForMap",	XrmoptionNoArg,		(caddr_t) "on"},
865 {"+wf",		"*waitForMap",	XrmoptionNoArg,		(caddr_t) "off"},
866 #ifdef WALLPAPER
867 {"-wp",		"*wallPaper",	XrmoptionSepArg,	(caddr_t) NULL},
868 #endif /* WALLPAPER */
869 /* bogus old compatibility stuff for which there are
870    standard XtAppInitialize options now */
871 #ifndef KTERM_NOTEK
872 {"%",		"*tekGeometry",	XrmoptionStickyArg,	(caddr_t) NULL},
873 #endif /* !KTERM_NOTEK */
874 {"#",		".iconGeometry",XrmoptionStickyArg,	(caddr_t) NULL},
875 {"-T",		"*title",	XrmoptionSepArg,	(caddr_t) NULL},
876 {"-n",		"*iconName",	XrmoptionSepArg,	(caddr_t) NULL},
877 {"-r",		"*reverseVideo",XrmoptionNoArg,		(caddr_t) "on"},
878 {"+r",		"*reverseVideo",XrmoptionNoArg,		(caddr_t) "off"},
879 {"-rv",		"*reverseVideo",XrmoptionNoArg,		(caddr_t) "on"},
880 {"+rv",		"*reverseVideo",XrmoptionNoArg,		(caddr_t) "off"},
881 {"-w",		".borderWidth", XrmoptionSepArg,	(caddr_t) NULL},
882 #ifdef STATUSLINE
883 {"-sn",		"*statusNormal", XrmoptionNoArg,	(caddr_t) "on"},
884 {"+sn",		"*statusNormal", XrmoptionNoArg,	(caddr_t) "off"},
885 {"-st",		"*statusLine",	XrmoptionNoArg,		(caddr_t) "on"},
886 {"+st",		"*statusLine",	XrmoptionNoArg,		(caddr_t) "off"},
887 #endif /* STATUSLINE */
888 };
889 
890 static struct _options {
891   char *opt;
892   char *desc;
893 } options[] = {
894 { "-help",                 "print out this message" },
895 #ifdef KTERM
896 { "-version",              "print out kterm version info" },
897 #endif /* KTERM */
898 { "-display displayname",  "X server to contact" },
899 { "-geometry geom",        "size (in characters) and position" },
900 { "-/+rv",                 "turn on/off reverse video" },
901 { "-bg color",             "background color" },
902 { "-fg color",             "foreground color" },
903 { "-bd color",             "border color" },
904 { "-bw number",            "border width in pixels" },
905 { "-fn fontname",          "normal text font" },
906 { "-iconic",               "start iconic" },
907 { "-name string",          "client instance, icon, and title strings" },
908 { "-title string",         "title string" },
909 { "-xrm resourcestring",   "additional resource specifications" },
910 { "-/+132",                "turn on/off column switch inhibiting" },
911 { "-/+ah",                 "turn on/off always highlight" },
912 { "-b number",             "internal border in pixels" },
913 { "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
914 { "-cc classrange",        "specify additional character classes" },
915 { "-/+cn",                 "turn on/off cut newline inhibit" },
916 { "-cr color",             "text cursor color" },
917 { "-/+cu",                 "turn on/off curses emulation" },
918 { "-fb fontname",          "bold text font" },
919 #ifdef KTERM
920 { "-/+dfl",                "turn on/off dynamic font load" },
921 { "-fl fontlist",          "normal fonts" },
922 { "-flb fontlist",         "bold fonts" },
923 { "-fr fontname",          "normal kana font" },
924 { "-frb fontname",         "bold kana font" },
925 #ifdef KTERM_MBCS
926 { "-fkB fontname",         "normal kanji font" },
927 { "-fkbB fontname",        "bold kanji font" },
928 { "-fk@ fontname",         "normal old kanji font" },
929 { "-fkb@ fontname",        "bold old kanji font" },
930 { "-fk@B fontname",        "normal kanji 1990 font" },
931 { "-fkb@B fontname",       "bold kanji 1990 font" },
932 { "-fkD fontname",         "normal hojo kanji font" },
933 { "-fkbD fontname",        "bold hojo kanji font" },
934 { "-fkO fontname",         "normal extended kanji font 1" },
935 { "-fkbO fontname",        "bold extended kanji font 1" },
936 { "-fkP fontname",         "normal extended kanji font 2" },
937 { "-fkbP fontname",        "bold extended kanji font 2" },
938 { "-fkQ fontname",         "normal extended 2004 kanji font 1" },
939 { "-fkbQ fontname",        "bold extended 2004 kanji font 1" },
940 { "-fkC fontname",         "normal hangl font" },
941 { "-fkbC fontname",        "bold hangl font" },
942 { "-fkA fontname",         "normal hanzi font" },
943 { "-fkbA fontname",        "bold hanzi font" },
944 { "-fkG fontname",         "normal cns font 1" },
945 { "-fkbG fontname",        "bold cns font 1" },
946 { "-fkH fontname",         "normal cns font 2" },
947 { "-fkbH fontname",        "bold cns font 2" },
948 { "-fkI fontname",         "normal cns font 3" },
949 { "-fkbI fontname",        "bold cns font 3" },
950 { "-fkJ fontname",         "normal cns font 4" },
951 { "-fkbJ fontname",        "bold cns font 4" },
952 { "-fkK fontname",         "normal cns font 5" },
953 { "-fkbK fontname",        "bold cns font 5" },
954 { "-fkL fontname",         "normal cns font 6" },
955 { "-fkbL fontname",        "bold cns font 6" },
956 { "-fkM fontname",         "normal cns font 7" },
957 { "-fkbM fontname",        "bold cns font 7" },
958 #endif /* KTERM_MBCS */
959 #ifdef KTERM_KANJIMODE
960 { "-km kanjimode",         "kanji code (jis|euc|sjis|utf8)" },
961 #endif /* KTERM_KANJIMODE */
962 #ifdef KTERM_XIM
963 { "-/+xim",                "open IM at startup time" },
964 #endif /* KTERM_XIM */
965 { "-lsp number",           "number of extra dots between lines" },
966 #endif /* KTERM */
967 { "-/+im",		   "use insert mode for TERMCAP" },
968 { "-/+j",                  "turn on/off jump scroll" },
969 #ifdef KEEPALIVE
970 { "-/+ka",                 "turn on/off keeping connection alive" },
971 #endif /* KEEPALIVE */
972 #ifdef ALLOWLOGGING
973 { "-/+l",                  "turn on/off logging" },
974 { "-lf filename",          "logging filename" },
975 #else
976 { "-/+l",                  "turn on/off logging (not supported)" },
977 { "-lf filename",          "logging filename (not supported)" },
978 #endif
979 { "-/+ls",                 "turn on/off login shell" },
980 { "-/+mb",                 "turn on/off margin bell" },
981 { "-mc milliseconds",      "multiclick time in milliseconds" },
982 { "-ms color",             "pointer color" },
983 { "-nb number",            "margin bell in characters from right end" },
984 { "-/+aw",                 "turn on/off auto wraparound" },
985 { "-/+rw",                 "turn on/off reverse wraparound" },
986 { "-/+s",                  "turn on/off multiscroll" },
987 { "-/+sb",                 "turn on/off scrollbar" },
988 { "-/+sf",                 "turn on/off Sun Function Key escape codes" },
989 { "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
990 { "-/+sk",                 "turn on/off scroll-on-keypress" },
991 { "-sl number",            "number of scrolled lines to save" },
992 #ifdef STATUSLINE
993 { "-/+sn",                 "turn on/off status line norval video" },
994 { "-/+st",                 "turn on/off status line" },
995 #endif /* STATUSLINE */
996 { "-/+t",                  "turn on/off Tek emulation window" },
997 { "-tm string",            "terminal mode keywords and characters" },
998 { "-tn name",              "TERM environment variable name" },
999 #ifdef __sgi
1000 { "-/+ul",                 "use/don't use locale for character input" },
1001 #endif
1002 #ifdef UTMP
1003 { "-/+ut",                 "turn on/off utmp inhibit" },
1004 #else
1005 { "-/+ut",                 "turn on/off utmp inhibit (not supported)" },
1006 #endif
1007 { "-/+vb",                 "turn on/off visual bell" },
1008 { "-/+wf",                 "turn on/off wait for map before command exec" },
1009 #ifdef WALLPAPER
1010 { "-wp filename.xpm",      "wallpaper image filename" },
1011 #endif /* WALLPAPER */
1012 { "-e command args ...",   "command to execute" },
1013 { "%geom",                 "Tek window geometry" },
1014 { "#geom",                 "icon window geometry" },
1015 { "-T string",             "title name for window" },
1016 { "-n string",             "icon name for window" },
1017 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
1018 { "-C",                    "intercept console messages" },
1019 #else
1020 { "-C",                    "intercept console messages (not supported)" },
1021 #endif
1022 { "-Sxxd",                 "slave mode on \"ttyxx\", file descriptor \"d\"" },
1023 { NULL, NULL }};
1024 
1025 static char *message[] = {
1026 "Fonts must be fixed width and, if both normal and bold are specified, must",
1027 "have the same size.  If only a normal font is specified, it will be used for",
1028 "both normal and bold text (by doing overstriking).  The -e option, if given,",
1029 "must be appear at the end of the command line, otherwise the user's default",
1030 "shell will be started.  Options that start with a plus sign (+) restore the",
1031 "default.",
1032 NULL};
1033 
Syntax(badOption)1034 static void Syntax (badOption)
1035     char *badOption;
1036 {
1037     struct _options *opt;
1038     int col;
1039 
1040     fprintf (stderr, "%s:  bad command line option \"%s\"\r\n\n",
1041 	     ProgramName, badOption);
1042 
1043     fprintf (stderr, "usage:  %s", ProgramName);
1044     col = 8 + strlen(ProgramName);
1045     for (opt = options; opt->opt; opt++) {
1046 	int len = 3 + strlen(opt->opt);	 /* space [ string ] */
1047 	if (col + len > 79) {
1048 	    fprintf (stderr, "\r\n   ");  /* 3 spaces */
1049 	    col = 3;
1050 	}
1051 	fprintf (stderr, " [%s]", opt->opt);
1052 	col += len;
1053     }
1054 
1055     fprintf (stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1056 	     ProgramName);
1057     exit (1);
1058 }
1059 
Help()1060 static void Help ()
1061 {
1062     struct _options *opt;
1063     char **cpp;
1064 
1065     fprintf (stderr, "usage:\n        %s [-options ...] [-e command args]\n\n",
1066 	     ProgramName);
1067     fprintf (stderr, "where options include:\n");
1068     for (opt = options; opt->opt; opt++) {
1069 	fprintf (stderr, "    %-28s %s\n", opt->opt, opt->desc);
1070     }
1071 
1072     putc ('\n', stderr);
1073     for (cpp = message; *cpp; cpp++) {
1074 	fputs (*cpp, stderr);
1075 	putc ('\n', stderr);
1076     }
1077     putc ('\n', stderr);
1078 
1079     exit (0);
1080 }
1081 
1082 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
1083 /* ARGSUSED */
1084 static Boolean
ConvertConsoleSelection(w,selection,target,type,value,length,format)1085 ConvertConsoleSelection(w, selection, target, type, value, length, format)
1086     Widget w;
1087     Atom *selection, *target, *type;
1088     XtPointer *value;
1089     unsigned long *length;
1090     int *format;
1091 {
1092     /* we don't save console output, so can't offer it */
1093     return False;
1094 }
1095 #endif /* TIOCCONS */
1096 
1097 #ifdef KTERM
1098 static void
printopt(s)1099 printopt(s)
1100 char *s;
1101 {
1102     static int optcol;
1103 
1104     if (optcol + strlen(s) >= 80) {
1105 	fprintf (stderr, "\n        ");
1106 	optcol = 8;
1107     }
1108     optcol += strlen(s);
1109     fprintf (stderr, "%s", s);
1110 }
1111 
1112 static void
Version()1113 Version()
1114 {
1115     fprintf(stderr, "kterm: version %s\n", KTERM_VERSION);
1116 
1117     printopt("options:");
1118 # ifdef KTERM_MBCS
1119     printopt(" [KTERM_MBCS]");
1120 # endif
1121 # ifdef	KTERM_MBCC
1122     printopt(" [KTERM_MBCC]");
1123 # endif
1124 # ifdef KTERM_KANJIMODE
1125     printopt(" [KTERM_KANJIMODE]");
1126 # endif
1127 # ifdef KTERM_XIM
1128     printopt(" [KTERM_XIM]");
1129 # endif
1130 # ifdef KTERM_KINPUT2
1131     printopt(" [KTERM_KINPUT2]");
1132 # endif
1133 # ifdef	KTERM_COLOR
1134     printopt(" [KTERM_COLOR]");
1135 # endif
1136 # ifdef	KTERM_XAW3D
1137     printopt(" [KTERM_XAW3D]");
1138 # endif
1139 # ifdef	KTERM_NOTEK
1140     printopt(" [KTERM_NOTEK]");
1141 # endif
1142 # ifdef STATUSLINE
1143     printopt(" [STATUSLINE]");
1144 # endif
1145 # ifdef KEEPALIVE
1146     printopt(" [KEEPALIVE]");
1147 # endif
1148 # ifdef WALLPAPER
1149     printopt(" [WALLPAPER]");
1150 # endif
1151     fprintf (stderr, "\n");
1152 
1153     exit (0);
1154 }
1155 #endif /* KTERM */
1156 
1157 extern WidgetClass xtermWidgetClass;
1158 
1159 Arg ourTopLevelShellArgs[] = {
1160 	{ XtNallowShellResize, (XtArgVal) TRUE },
1161 	{ XtNinput, (XtArgVal) TRUE },
1162 };
1163 int number_ourTopLevelShellArgs = 2;
1164 
1165 XtAppContext app_con;
1166 Widget toplevel;
1167 Bool waiting_for_initial_map;
1168 
1169 extern void do_hangup();
1170 extern void xt_error();
1171 
1172 /*
1173  * DeleteWindow(): Action proc to implement ICCCM delete_window.
1174  */
1175 /* ARGSUSED */
1176 void
DeleteWindow(w,event,params,num_params)1177 DeleteWindow(w, event, params, num_params)
1178     Widget w;
1179     XEvent *event;
1180     String *params;
1181     Cardinal *num_params;
1182 {
1183 #ifndef KTERM_NOTEK
1184   if (w == toplevel)
1185     if (term->screen.Tshow)
1186       hide_vt_window();
1187     else
1188       do_hangup(w);
1189   else
1190     if (term->screen.Vshow)
1191       hide_tek_window();
1192     else
1193 #endif /* !KTERM_NOTEK */
1194       do_hangup(w);
1195 }
1196 
1197 /* ARGSUSED */
1198 void
KeyboardMapping(w,event,params,num_params)1199 KeyboardMapping(w, event, params, num_params)
1200     Widget w;
1201     XEvent *event;
1202     String *params;
1203     Cardinal *num_params;
1204 {
1205     switch (event->type) {
1206        case MappingNotify:
1207 	  XRefreshKeyboardMapping(&event->xmapping);
1208 	  break;
1209     }
1210 }
1211 
1212 XtActionsRec actionProcs[] = {
1213     "DeleteWindow", DeleteWindow,
1214     "KeyboardMapping", KeyboardMapping,
1215 };
1216 
1217 Atom wm_delete_window;
1218 extern fd_set Select_mask;
1219 extern fd_set X_mask;
1220 extern fd_set pty_mask;
1221 
1222 #ifdef WALLPAPER
1223 
1224 #include <X11/xpm.h>
1225 
1226 Pixmap BackgroundPixmap = NULL;
1227 Pixmap BackgroundPixmap_shape = NULL;
1228 int BackgroundPixmapIsOn = 0;
1229 static XpmAttributes imageattr;
1230 
1231 void
FillRectangle(display,d,gc,x,y,width,height)1232 FillRectangle(display, d, gc, x, y, width, height)
1233     Display *display;
1234     Drawable d;
1235     GC gc;
1236     int x;
1237     int y;
1238     unsigned int width;
1239     unsigned int height;
1240 {
1241     int sx, sy, dx, dy, w, h;
1242 
1243     if(BackgroundPixmapIsOn){
1244       XClearArea(display, d, x, y, width, height, 0);
1245     }else{
1246       XFillRectangle(display, d, gc, x, y, width, height);
1247     }
1248 }
1249 
1250 void
DrawImageString(screen,ascent,reverse,display,d,gc,x,y,string,length)1251 DrawImageString(screen, ascent, reverse, display, d, gc, x, y, string, length)
1252     TScreen *screen;
1253     int ascent;
1254     int reverse;
1255     Display *display;
1256     Drawable d;
1257     GC gc;
1258     int x;
1259     int y;
1260     char *string;
1261     int length;
1262 {
1263     if (!reverse && (BackgroundPixmapIsOn)){
1264 	FillRectangle(display, d, gc, x, y - ascent, FontWidth(screen) * length, FontHeight(screen));
1265 	XDrawString(display, d, gc, x, y, string, length);
1266     }
1267     else{
1268 	XDrawImageString(display, d, gc, x, y, string, length);
1269     }
1270 }
1271 
1272 void
DrawImageString16(screen,ascent,reverse,display,d,gc,x,y,string,length)1273 DrawImageString16(screen, ascent, reverse, display, d, gc, x, y, string, length)
1274     TScreen *screen;
1275     int ascent;
1276     int reverse;
1277     Display *display;
1278     Drawable d;
1279     GC gc;
1280     int x;
1281     int y;
1282     XChar2b *string;
1283     int length;
1284 {
1285     int i, len = 0;
1286 
1287     for (i = 0; i < length; i++){
1288 	len += (string[i].byte1 == 0x00) ? 1 : 2;
1289     }
1290     if (!reverse && (BackgroundPixmapIsOn)){
1291 	FillRectangle(display, d, gc, x, y - ascent, FontWidth(screen) * len, FontHeight(screen));
1292 	XDrawString16(display, d, gc, x, y, string, length);
1293     }
1294     else{
1295 	XDrawImageString16(display, d, gc, x, y, string, length);
1296     }
1297 }
1298 
1299 #endif /* WALLPAPER */
1300 
main(argc,argv)1301 main (argc, argv)
1302 int argc;
1303 char **argv;
1304 {
1305 	register TScreen *screen;
1306 	int mode;
1307 	char *base_name();
1308 	int xerror(), xioerror();
1309 
1310 	XtSetLanguageProc (NULL, NULL, NULL);
1311 
1312 	ProgramName = argv[0];
1313 
1314 	/* +2 in case longer tty name like /dev/ttyq255 */
1315 	ttydev = (char *) malloc (sizeof(TTYDEV) + 2);
1316 #ifndef __osf__
1317 	ptydev = (char *) malloc (sizeof(PTYDEV) + 2);
1318 	if (!ttydev || !ptydev)
1319 #else
1320 	if (!ttydev)
1321 #endif
1322 	{
1323 	    fprintf (stderr,
1324 	    	     "%s:  unable to allocate memory for ttydev or ptydev\n",
1325 		     ProgramName);
1326 	    exit (1);
1327 	}
1328 	strcpy (ttydev, TTYDEV);
1329 #ifndef __osf__
1330 	strcpy (ptydev, PTYDEV);
1331 #endif
1332 
1333 #if defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)	/* { */
1334 	/* Initialization is done here rather than above in order
1335 	** to prevent any assumptions about the order of the contents
1336 	** of the various terminal structures (which may change from
1337 	** implementation to implementation).
1338 	*/
1339 	d_tio.c_iflag = ICRNL|IXON;
1340 #ifdef TAB3
1341 	d_tio.c_oflag = OPOST|ONLCR|TAB3;
1342 #else
1343 	d_tio.c_oflag = OPOST|ONLCR;
1344 #endif
1345 #if defined(macII) || defined(ATT) || defined(CRAY) /* { */
1346     	d_tio.c_cflag = B9600|CS8|CREAD|PARENB|HUPCL;
1347     	d_tio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1348 #ifdef ECHOKE
1349 	d_tio.c_lflag |= ECHOKE|IEXTEN;
1350 #endif
1351 #ifdef ECHOCTL
1352 	d_tio.c_lflag |= ECHOCTL|IEXTEN;
1353 #endif
1354 
1355 #ifndef USE_TERMIOS /* { */
1356 	d_tio.c_line = 0;
1357 #endif /* } */
1358 
1359 	d_tio.c_cc[VINTR] = CINTR;
1360 	d_tio.c_cc[VQUIT] = CQUIT;
1361 	d_tio.c_cc[VERASE] = CERASE;
1362 	d_tio.c_cc[VKILL] = CKILL;
1363     	d_tio.c_cc[VEOF] = CEOF;
1364 	d_tio.c_cc[VEOL] = CNUL;
1365 	d_tio.c_cc[VEOL2] = CNUL;
1366 	d_tio.c_cc[VSWTCH] = CNUL;
1367 
1368 #ifdef USE_TERMIOS /* { */
1369 	d_tio.c_cc[VSUSP] = CSUSP;
1370 	d_tio.c_cc[VDSUSP] = CDSUSP;
1371 	d_tio.c_cc[VREPRINT] = CRPRNT;
1372 	d_tio.c_cc[VDISCARD] = CFLUSH;
1373 	d_tio.c_cc[VWERASE] = CWERASE;
1374 	d_tio.c_cc[VLNEXT] = CLNEXT;
1375 	d_tio.c_cc[VMIN] = 1;
1376 	d_tio.c_cc[VTIME] = 0;
1377 #endif /* } */
1378 #ifdef TIOCSLTC /* { */
1379         d_ltc.t_suspc = CSUSP;		/* t_suspc */
1380         d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
1381         d_ltc.t_rprntc = CRPRNT;
1382         d_ltc.t_flushc = CFLUSH;
1383         d_ltc.t_werasc = CWERASE;
1384         d_ltc.t_lnextc = CLNEXT;
1385 #endif /* } TIOCSLTC */
1386 #ifdef TIOCLSET /* { */
1387 	d_lmode = 0;
1388 #endif /* } TIOCLSET */
1389 #else  /* }{ else !macII, ATT, CRAY */
1390 #ifndef USE_POSIX_TERMIOS
1391 #ifdef BAUD_0 /* { */
1392     	d_tio.c_cflag = CS8|CREAD|PARENB|HUPCL;
1393 #else	/* }{ !BAUD_0 */
1394     	d_tio.c_cflag = B9600|CS8|CREAD|PARENB|HUPCL;
1395 #endif	/* } !BAUD_0 */
1396 #else /* USE_POSIX_TERMIOS */
1397 	d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
1398 	cfsetispeed(&d_tio, B9600);
1399 	cfsetospeed(&d_tio, B9600);
1400 #endif
1401     	d_tio.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
1402 #ifdef ECHOKE
1403 	d_tio.c_lflag |= ECHOKE|IEXTEN;
1404 #endif
1405 #ifdef ECHOCTL
1406 	d_tio.c_lflag |= ECHOCTL|IEXTEN;
1407 #endif
1408 #ifndef USE_POSIX_TERMIOS
1409 #ifdef NTTYDISC
1410         d_tio.c_line = NTTYDISC;
1411 #else
1412 	d_tio.c_line = 0;
1413 #endif
1414 #endif /* USE_POSIX_TERMIOS */
1415 #ifdef __sgi
1416         d_tio.c_cflag &= ~(HUPCL|PARENB);
1417         d_tio.c_iflag |= BRKINT|ISTRIP|IGNPAR;
1418 #endif
1419 	d_tio.c_cc[VINTR] = 'C' & 0x3f;		/* '^C'	*/
1420 	d_tio.c_cc[VERASE] = 0x7f;		/* DEL	*/
1421 	d_tio.c_cc[VKILL] = 'U' & 0x3f;		/* '^U'	*/
1422 	d_tio.c_cc[VQUIT] = CQUIT;		/* '^\'	*/
1423     	d_tio.c_cc[VEOF] = CEOF;		/* '^D'	*/
1424 	d_tio.c_cc[VEOL] = CEOL;		/* '^@'	*/
1425 	d_tio.c_cc[VMIN] = 1;
1426 	d_tio.c_cc[VTIME] = 0;
1427 #ifdef VSWTCH
1428 	d_tio.c_cc[VSWTCH] = CSWTCH;            /* usually '^Z' */
1429 #endif
1430 #ifdef VLNEXT
1431 	d_tio.c_cc[VLNEXT] = CLNEXT;
1432 #endif
1433 #ifdef VWERASE
1434 	d_tio.c_cc[VWERASE] = CWERASE;
1435 #endif
1436 #ifdef VREPRINT
1437 	d_tio.c_cc[VREPRINT] = CRPRNT;
1438 #endif
1439 #ifdef VRPRNT
1440 	d_tio.c_cc[VRPRNT] = CRPRNT;
1441 #endif
1442 #ifdef VDISCARD
1443 	d_tio.c_cc[VDISCARD] = CFLUSH;
1444 #endif
1445 #ifdef VFLUSHO
1446 	d_tio.c_cc[VFLUSHO] = CFLUSH;
1447 #endif
1448 #ifdef VSTOP
1449 	d_tio.c_cc[VSTOP] = CSTOP;
1450 #endif
1451 #ifdef VSTART
1452 	d_tio.c_cc[VSTART] = CSTART;
1453 #endif
1454 #ifdef VSUSP
1455 	d_tio.c_cc[VSUSP] = CSUSP;
1456 #endif
1457 #ifdef VDSUSP
1458 	d_tio.c_cc[VDSUSP] = CDSUSP;
1459 #endif
1460 	/* now, try to inherit tty settings */
1461 	{
1462 	    int i;
1463 
1464 	    for (i = 0; i <= 2; i++) {
1465 #ifndef USE_POSIX_TERMIOS
1466 		struct termio deftio;
1467 		if (ioctl (i, TCGETA, &deftio) == 0) {
1468 #else
1469 	        struct termios deftio;
1470 	        if (tcgetattr(i, &deftio) == 0) {
1471 #endif
1472 		    d_tio.c_cc[VINTR] = deftio.c_cc[VINTR];
1473 		    d_tio.c_cc[VQUIT] = deftio.c_cc[VQUIT];
1474 		    d_tio.c_cc[VERASE] = deftio.c_cc[VERASE];
1475 		    d_tio.c_cc[VKILL] = deftio.c_cc[VKILL];
1476 		    d_tio.c_cc[VEOF] = deftio.c_cc[VEOF];
1477 		    d_tio.c_cc[VEOL] = deftio.c_cc[VEOL];
1478 #ifdef VSWTCH
1479 		    d_tio.c_cc[VSWTCH] = deftio.c_cc[VSWTCH];
1480 #endif
1481 #ifdef VEOL2
1482 		    d_tio.c_cc[VEOL2] = deftio.c_cc[VEOL2];
1483 #endif
1484 #ifdef VLNEXT
1485 		    d_tio.c_cc[VLNEXT] = deftio.c_cc[VLNEXT];
1486 #endif
1487 #ifdef VWERASE
1488 		    d_tio.c_cc[VWERASE] = deftio.c_cc[VWERASE];
1489 #endif
1490 #ifdef VREPRINT
1491 		    d_tio.c_cc[VREPRINT] = deftio.c_cc[VREPRINT];
1492 #endif
1493 #ifdef VRPRNT
1494 		    d_tio.c_cc[VRPRNT] = deftio.c_cc[VRPRNT];
1495 #endif
1496 #ifdef VDISCARD
1497 		    d_tio.c_cc[VDISCARD] = deftio.c_cc[VDISCARD];
1498 #endif
1499 #ifdef VFLUSHO
1500 		    d_tio.c_cc[VFLUSHO] = deftio.c_cc[VFLUSHO];
1501 #endif
1502 #ifdef VSTOP
1503 		    d_tio.c_cc[VSTOP] = deftio.c_cc[VSTOP];
1504 #endif
1505 #ifdef VSTART
1506 		    d_tio.c_cc[VSTART] = deftio.c_cc[VSTART];
1507 #endif
1508 #ifdef VSUSP
1509 		    d_tio.c_cc[VSUSP] = deftio.c_cc[VSUSP];
1510 #endif
1511 #ifdef VDSUSP
1512 		    d_tio.c_cc[VDSUSP] = deftio.c_cc[VDSUSP];
1513 #endif
1514 		    break;
1515 		}
1516 	    }
1517 	}
1518 #ifdef TIOCSLTC		/* { */
1519 	d_ltc.t_suspc = '\000';	/* t_suspc */
1520 	d_ltc.t_dsuspc = '\000';	/* t_dsuspc */
1521 	d_ltc.t_rprntc = '\377';	/* reserved... */
1522 	d_ltc.t_flushc = '\377';
1523 	d_ltc.t_werasc = '\377';
1524 	d_ltc.t_lnextc = '\377';
1525 #endif /* } TIOCSLTC */
1526 #if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
1527 	d_tio.c_cc[VSUSP] = CSUSP;
1528 	d_tio.c_cc[VDSUSP] = '\000';
1529 	d_tio.c_cc[VREPRINT] = '\377';
1530 	d_tio.c_cc[VDISCARD] = '\377';
1531 	d_tio.c_cc[VWERASE] = '\377';
1532 	d_tio.c_cc[VLNEXT] = '\377';
1533 #endif /* } USE_TERMIOS */
1534 #ifdef TIOCLSET /* { */
1535 	d_lmode = 0;
1536 #endif	/* } TIOCLSET */
1537 #endif  /* } macII, ATT, CRAY */
1538 #endif /* } USE_SYSV_TERMIO || USE_POSIX_TERMIOS */
1539 
1540 	/* Init the Toolkit. */
1541 	XtSetErrorHandler(xt_error);
1542 	{
1543 #ifdef HAS_POSIX_SAVED_IDS
1544 	    uid_t euid = geteuid();
1545 	    gid_t egid = getegid();
1546 	    uid_t ruid = getuid();
1547 	    gid_t rgid = getgid();
1548 
1549 	    if (setegid(rgid) == -1)
1550 		(void) fprintf(stderr, "setegid(%d): %s\n",
1551 			       (int) rgid, strerror(errno));
1552 
1553 	    if (seteuid(ruid) == -1)
1554 		(void) fprintf(stderr, "seteuid(%d): %s\n",
1555 			       (int) ruid, strerror(errno));
1556 #endif
1557 
1558 	    XtSetErrorHandler(xt_error);
1559 #ifdef KTERM
1560 	    toplevel = XtAppInitialize (&app_con, "KTerm",
1561 #else /* !KTERM */
1562 	    toplevel = XtAppInitialize (&app_con, "XTerm",
1563 #endif /* !KTERM */
1564 				    optionDescList, XtNumber(optionDescList),
1565 				    &argc, argv, fallback_resources, NULL, 0);
1566 
1567 	    XtGetApplicationResources(toplevel, (XtPointer) &resource,
1568 				  application_resources,
1569 				  XtNumber(application_resources), NULL, 0);
1570 
1571 #ifdef __sgi
1572 	    if (resource.useLocale)
1573 		setlocale(LC_ALL,"");
1574 #endif
1575 
1576 #ifdef HAS_POSIX_SAVED_IDS
1577 	    if (seteuid(euid) == -1)
1578 		(void) fprintf(stderr, "seteuid(%d): %s\n",
1579 			       (int) euid, strerror(errno));
1580 
1581 	    if (setegid(egid) == -1)
1582 		(void) fprintf(stderr, "setegid(%d): %s\n",
1583 			       (int) egid, strerror(errno));
1584 #endif
1585 	}
1586 
1587 	waiting_for_initial_map = resource.wait_for_map;
1588 
1589 	/*
1590 	 * ICCCM delete_window.
1591 	 */
1592 	XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
1593 
1594 #ifdef KEEPALIVE
1595 	if (resource.keepalive) {
1596 		int on = 1;
1597 		(void)setsockopt(ConnectionNumber(XtDisplay(toplevel)),
1598 				SOL_SOCKET, SO_KEEPALIVE,
1599 				(char *)&on, sizeof(on));
1600 	}
1601 #endif /* KEEPALIVE */
1602 	/*
1603 	 * fill in terminal modes
1604 	 */
1605 	if (resource.tty_modes) {
1606 	    int n = parse_tty_modes (resource.tty_modes, ttymodelist);
1607 	    if (n < 0) {
1608 		fprintf (stderr, "%s:  bad tty modes \"%s\"\n",
1609 			 ProgramName, resource.tty_modes);
1610 	    } else if (n > 0) {
1611 		override_tty_modes = 1;
1612 	    }
1613 	}
1614 
1615 	xterm_name = resource.xterm_name;
1616 	sunFunctionKeys = resource.sunFunctionKeys;
1617 #ifdef KTERM
1618 	if (strcmp(xterm_name, "-") == 0) xterm_name = "kterm";
1619 #else /* KTERM */
1620 	if (strcmp(xterm_name, "-") == 0) xterm_name = "xterm";
1621 #endif /* KTERM */
1622 	if (resource.icon_geometry != NULL) {
1623 	    int scr, junk;
1624 	    int ix, iy;
1625 	    Arg args[2];
1626 
1627 	    for(scr = 0;	/* yyuucchh */
1628 		XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel),scr);
1629 		scr++);
1630 
1631 	    args[0].name = XtNiconX;
1632 	    args[1].name = XtNiconY;
1633 	    XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
1634 		      0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
1635 	    args[0].value = (XtArgVal) ix;
1636 	    args[1].value = (XtArgVal) iy;
1637 	    XtSetValues( toplevel, args, 2);
1638 	}
1639 
1640 	XtSetValues (toplevel, ourTopLevelShellArgs,
1641 		     number_ourTopLevelShellArgs);
1642 
1643 	/* Parse the rest of the command line */
1644 	for (argc--, argv++ ; argc > 0 ; argc--, argv++) {
1645 	    if(**argv != '-') Syntax (*argv);
1646 
1647 	    switch(argv[0][1]) {
1648 	     case 'h':
1649 		Help ();
1650 		/* NOTREACHED */
1651 #ifdef KTERM
1652 	     case 'v':
1653 		Version ();
1654 		/* NOTREACHED */
1655 #endif /* KTERM */
1656 	     case 'C':
1657 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
1658 #ifndef __sgi
1659 		{
1660 		    struct stat sbuf;
1661 
1662 		    /* Must be owner and have read/write permission.
1663 		       xdm cooperates to give the console the right user. */
1664 		    if ( !stat("/dev/console", &sbuf) &&
1665 			 (sbuf.st_uid == getuid()) &&
1666 			 !access("/dev/console", R_OK|W_OK))
1667 		    {
1668 			Console = TRUE;
1669 		    } else
1670 			Console = FALSE;
1671 		}
1672 #else /* __sgi */
1673 		Console = TRUE;
1674 #endif /* __sgi */
1675 #endif	/* TIOCCONS */
1676 		continue;
1677 	     case 'S':
1678 		if (sscanf(*argv + 2, "%c%c%d", passedPty, passedPty+1,
1679 			   &am_slave) != 3)
1680 		    Syntax(*argv);
1681 		continue;
1682 #ifdef DEBUG
1683 	     case 'D':
1684 		debug = TRUE;
1685 		continue;
1686 #endif	/* DEBUG */
1687 	     case 'e':
1688 		if (argc <= 1) Syntax (*argv);
1689 		command_to_exec = ++argv;
1690 		break;
1691 	     default:
1692 		Syntax (*argv);
1693 	    }
1694 	    break;
1695 	}
1696 
1697 	XawSimpleMenuAddGlobalActions (app_con);
1698 	XtRegisterGrabAction (HandlePopupMenu, True,
1699 			      (ButtonPressMask|ButtonReleaseMask),
1700 			      GrabModeAsync, GrabModeAsync);
1701 
1702         term = (XtermWidget) XtCreateManagedWidget(
1703 	    "vt100", xtermWidgetClass, toplevel, NULL, 0);
1704             /* this causes the initialize method to be called */
1705 
1706         screen = &term->screen;
1707 
1708 	if (screen->savelines < 0) screen->savelines = 0;
1709 
1710 	term->flags = 0;
1711 	if (!screen->jumpscroll) {
1712 	    term->flags |= SMOOTHSCROLL;
1713 	    update_jumpscroll();
1714 	}
1715 	if (term->misc.reverseWrap) {
1716 	    term->flags |= REVERSEWRAP;
1717 	    update_reversewrap();
1718 	}
1719 	if (term->misc.autoWrap) {
1720 	    term->flags |= WRAPAROUND;
1721 	    update_autowrap();
1722 	}
1723 	if (term->misc.re_verse) {
1724 	    term->flags |= REVERSE_VIDEO;
1725 	    update_reversevideo();
1726 	}
1727 #ifdef KTERM_KANJIMODE
1728 	if (term->misc.k_m) {
1729 	    switch (term->misc.k_m[0]) {
1730 		case 'e': case 'E': case 'x': case 'X':
1731 		    term->flags |= EUC_KANJI;
1732 		    update_eucmode();
1733 		    break;
1734 		case 's': case 'S': case 'm': case 'M':
1735 		    term->flags |= SJIS_KANJI;
1736 		    update_sjismode();
1737 		    break;
1738 	        case 'u': case 'U':
1739 		    term->flags |= UTF8_KANJI;
1740 		    update_utf8mode();
1741 		    break;
1742 		default:
1743 		    break;
1744 	    }
1745 	    make_unicode_map();
1746 	}
1747 #endif /* KTERM_KANJIMODE */
1748 
1749 	inhibit = 0;
1750 #ifdef ALLOWLOGGING
1751 	if (term->misc.logInhibit) 	    inhibit |= I_LOG;
1752 #endif
1753 	if (term->misc.signalInhibit)		inhibit |= I_SIGNAL;
1754 #ifndef KTERM_NOTEK
1755 	if (term->misc.tekInhibit)			inhibit |= I_TEK;
1756 #endif /* !KTERM_NOTEK */
1757 
1758 	term->initflags = term->flags;
1759 
1760 	if (term->misc.appcursorDefault) {
1761 	    term->keyboard.flags |= CURSOR_APL;
1762 	    update_appcursor();
1763 	}
1764 
1765 	if (term->misc.appkeypadDefault) {
1766 	    term->keyboard.flags |= KYPD_APL;
1767 	    update_appkeypad();
1768 	}
1769 
1770 /*
1771  * Set title and icon name if not specified
1772  */
1773 
1774 	if (command_to_exec) {
1775 	    Arg args[2];
1776 
1777 	    if (!resource.title) {
1778 		if (command_to_exec) {
1779 		    resource.title = base_name (command_to_exec[0]);
1780 		} /* else not reached */
1781 	    }
1782 
1783 	    if (!resource.icon_name)
1784 	      resource.icon_name = resource.title;
1785 	    XtSetArg (args[0], XtNtitle, resource.title);
1786 	    XtSetArg (args[1], XtNiconName, resource.icon_name);
1787 
1788 	    XtSetValues (toplevel, args, 2);
1789 	}
1790 
1791 
1792 #ifndef KTERM_NOTEK
1793 	if(inhibit & I_TEK)
1794 		screen->TekEmu = FALSE;
1795 
1796 	if(screen->TekEmu && !TekInit())
1797 		exit(ERROR_INIT);
1798 #endif /* !KTERM_NOTEK */
1799 
1800 #ifdef DEBUG
1801     {
1802 	/* Set up stderr properly.  Opening this log file cannot be
1803 	 done securely by a privileged xterm process (although we try),
1804 	 so the debug feature is disabled by default. */
1805 	int i = -1;
1806 	if(debug) {
1807 	        creat_as (getuid(), getgid(), "xterm.debug.log", 0666);
1808 		i = open ("xterm.debug.log", O_WRONLY | O_TRUNC, 0666);
1809 	}
1810 	if(i >= 0) {
1811 #if defined(USE_SYSV_TERMIO) && !defined(SVR4) && !defined(linux)
1812 		/* SYSV has another pointer which should be part of the
1813 		** FILE structure but is actually a seperate array.
1814 		*/
1815 		unsigned char *old_bufend;
1816 
1817 		old_bufend = (unsigned char *) _bufend(stderr);
1818 #ifdef hpux
1819 		stderr->__fileH = (i >> 8);
1820 		stderr->__fileL = i;
1821 #else
1822 		stderr->_file = i;
1823 #endif
1824 		_bufend(stderr) = old_bufend;
1825 #else	/* USE_SYSV_TERMIO */
1826 #ifndef linux
1827 		stderr->_file = i;
1828 #else
1829 		setfileno(stderr, i);
1830 #endif
1831 #endif	/* USE_SYSV_TERMIO */
1832 
1833 		/* mark this file as close on exec */
1834 		(void) fcntl(i, F_SETFD, 1);
1835 	}
1836     }
1837 #endif	/* DEBUG */
1838 
1839 	/* open a terminal for client */
1840 	get_terminal ();
1841 	spawn ();
1842 	/* Child process is out there, let's catch its termination */
1843 	signal (SIGCHLD, reapchild);
1844 
1845 	/* Realize procs have now been executed */
1846 
1847 	if (am_slave) { /* Write window id so master end can read and use */
1848 	    char buf[80];
1849 
1850 	    buf[0] = '\0';
1851 #ifdef KTERM_NOTEK
1852 	    sprintf (buf, "%lx\n", XtWindow (XtParent (term)));
1853 #else /* !KTERM_NOTEK */
1854 	    sprintf (buf, "%lx\n",
1855 	    	     screen->TekEmu ? XtWindow (XtParent (tekWidget)) :
1856 				      XtWindow (XtParent (term)));
1857 #endif /* !KTERM_NOTEK */
1858 	    write (screen->respond, buf, strlen (buf));
1859 	}
1860 
1861 #ifdef ALLOWLOGGING
1862 	if (term->misc.log_on) {
1863 		StartLog(screen);
1864 	}
1865 #endif
1866 	screen->inhibit = inhibit;
1867 
1868 #ifdef AIXV3
1869 #if OSMAJORVERSION < 4
1870 	/* In AIXV3, xterms started from /dev/console have CLOCAL set.
1871 	 * This means we need to clear CLOCAL so that SIGHUP gets sent
1872 	 * to the slave-pty process when xterm exits.
1873 	 */
1874 
1875 	{
1876 	    struct termio tio;
1877 
1878 	    if(ioctl(screen->respond, TCGETA, &tio) == -1)
1879 		SysError(ERROR_TIOCGETP);
1880 
1881 	    tio.c_cflag &= ~(CLOCAL);
1882 
1883 	    if (ioctl (screen->respond, TCSETA, &tio) == -1)
1884 		SysError(ERROR_TIOCSETP);
1885 	}
1886 #endif
1887 #endif
1888 #ifdef USE_SYSV_TERMIO
1889 	if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
1890 		Error();
1891 #ifdef O_NDELAY
1892 	mode |= O_NDELAY;
1893 #else
1894 	mode |= O_NONBLOCK;
1895 #endif /* O_NDELAY */
1896 	if (fcntl(screen->respond, F_SETFL, mode))
1897 		Error();
1898 #else	/* USE_SYSV_TERMIO */
1899 	mode = 1;
1900 	if (ioctl (screen->respond, FIONBIO, (char *)&mode) == -1) SysError (ERROR_FIONBIO);
1901 #endif	/* USE_SYSV_TERMIO */
1902 
1903     /* The erase character is used to delete the current completion */
1904 #if OPT_DABBREV
1905 #if defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)
1906     screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
1907 #else
1908     screen->dabbrev_erase_char = d_sg.sg_erase;
1909 #endif
1910 #endif
1911 
1912 	FD_ZERO (&pty_mask);
1913 	FD_ZERO (&X_mask);
1914 	FD_ZERO (&Select_mask);
1915 	FD_SET (screen->respond, &pty_mask);
1916 	FD_SET (ConnectionNumber(screen->display), &X_mask);
1917 	FD_SET (screen->respond, &Select_mask);
1918 	FD_SET (ConnectionNumber(screen->display), &Select_mask);
1919 	max_plus1 = (screen->respond < ConnectionNumber(screen->display)) ?
1920 		(1 + ConnectionNumber(screen->display)) :
1921 		(1 + screen->respond);
1922 
1923 #ifdef DEBUG
1924 	if (debug) printf ("debugging on\n");
1925 #endif	/* DEBUG */
1926 	XSetErrorHandler(xerror);
1927 	XSetIOErrorHandler(xioerror);
1928 #ifdef WALLPAPER
1929 	if (resource.wallpaper){
1930 	    int result;
1931 
1932 	    imageattr.valuemask = XpmColormap;
1933 	    imageattr.x_hotspot = 0;
1934 	    imageattr.y_hotspot = 0;
1935 	    imageattr.depth = DefaultDepth(XtDisplay(toplevel), 0);
1936 	    imageattr.colormap = DefaultColormap(XtDisplay(toplevel), 0);
1937 
1938 	    if ((result =  XpmReadFileToPixmap(XtDisplay(toplevel),
1939 					       XtWindow(toplevel),
1940 					       resource.wallpaper,
1941 					       &BackgroundPixmap,
1942 					       &BackgroundPixmap_shape,
1943 					       &imageattr)) != XpmSuccess){
1944 		fprintf(stderr, "XpmReadFileToImage(\"%s\") : %s\n",
1945 			resource.wallpaper, XpmGetErrorString(result));
1946 	    }
1947 	    else{
1948 	      XSetWindowBackgroundPixmap(XtDisplay(toplevel),
1949 					 XtWindow(toplevel),
1950 					 BackgroundPixmap);
1951 	      if(BackgroundPixmap_shape != NULL)
1952 		XFreePixmap(XtDisplay(toplevel),
1953 			    BackgroundPixmap_shape);
1954 	      XpmFreeAttributes(&imageattr);
1955 	      XSetWindowBackgroundPixmap(XtDisplay(term),
1956 					 XtWindow(term),
1957 					 ParentRelative);
1958 	      XFreePixmap(XtDisplay(toplevel), BackgroundPixmap);
1959 	      BackgroundPixmapIsOn = 1;
1960 	    }
1961 	}
1962 #endif /* WALLPAPER */
1963 	for( ; ; ) {
1964 #ifndef KTERM_NOTEK
1965 		if(screen->TekEmu) {
1966 			TekRun();
1967 		} else
1968 #endif /* !KTERM_NOTEK */
1969 			VTRun();
1970 	}
1971 }
1972 
base_name(name)1973 char *base_name(name)
1974 char *name;
1975 {
1976 	register char *cp;
1977 
1978 	cp = strrchr(name, '/');
1979 	return(cp ? cp + 1 : name);
1980 }
1981 
1982 /* This function opens up a pty master and stuffs its value into pty.
1983  * If it finds one, it returns a value of 0.  If it does not find one,
1984  * it returns a value of !0.  This routine is designed to be re-entrant,
1985  * so that if a pty master is found and later, we find that the slave
1986  * has problems, we can re-enter this function and get another one.
1987  */
1988 
get_pty(pty)1989 get_pty (pty)
1990     int *pty;
1991 {
1992 #if 1
1993     int tty;
1994     return (openpty(pty, &tty, ttydev, NULL, NULL));
1995 #else
1996 #ifdef __osf__
1997     int tty;
1998     return (openpty(pty, &tty, ttydev, NULL, NULL));
1999 #endif
2000 #if defined(SYSV) && defined(i386) && !defined(SVR4)
2001         /*
2002 	  The order of this code is *important*.  On SYSV/386 we want to open
2003 	  a /dev/ttyp? first if at all possible.  If none are available, then
2004 	  we'll try to open a /dev/pts??? device.
2005 
2006 	  The reason for this is because /dev/ttyp? works correctly, where
2007 	  as /dev/pts??? devices have a number of bugs, (won't update
2008 	  screen correcly, will hang -- it more or less works, but you
2009 	  really don't want to use it).
2010 
2011 	  Most importantly, for boxes of this nature, one of the major
2012 	  "features" is that you can emulate a 8086 by spawning off a UNIX
2013 	  program on 80386/80486 in v86 mode.  In other words, you can spawn
2014 	  off multiple MS-DOS environments.  On ISC the program that does
2015 	  this is named "vpix."  The catcher is that "vpix" will *not* work
2016 	  with a /dev/pts??? device, will only work with a /dev/ttyp? device.
2017 
2018 	  Since we can open either a /dev/ttyp? or a /dev/pts??? device,
2019 	  the flag "IsPts" is set here so that we know which type of
2020 	  device we're dealing with in routine spawn().  That's the reason
2021 	  for the "if (IsPts)" statement in spawn(); we have two different
2022 	  device types which need to be handled differently.
2023 	  */
2024         if (pty_search(pty) == 0)
2025 	    return 0;
2026 #endif /* SYSV && i386 && !SVR4 */
2027 #if defined(ATT) && !defined(__sgi)
2028 	if ((*pty = open ("/dev/ptmx", O_RDWR)) < 0) {
2029 	    return 1;
2030 	}
2031 #if defined(SVR4) || defined(i386)
2032 	strcpy(ttydev, ptsname(*pty));
2033 #if defined (SYSV) && defined(i386) && !defined(SVR4)
2034 	IsPts = True;
2035 #endif
2036 #endif
2037 	return 0;
2038 #else /* ATT else */
2039 #ifdef AIXV3
2040 	if ((*pty = open ("/dev/ptc", O_RDWR)) < 0) {
2041 	    return 1;
2042 	}
2043 	strcpy(ttydev, ttyname(*pty));
2044 	return 0;
2045 #endif
2046 #if defined(__sgi) && OSMAJORVERSION >= 4
2047 	{
2048 	    char    *tty_name;
2049 
2050 	    tty_name = _getpty (pty, O_RDWR, 0622, 0);
2051 	    if (tty_name == 0)
2052 		return 1;
2053 	    strcpy (ttydev, tty_name);
2054 	    return 0;
2055 	}
2056 #endif
2057 #ifdef __convex__
2058         {
2059 	    char *pty_name, *getpty();
2060 
2061 	    while ((pty_name = getpty()) != NULL) {
2062 		if ((*pty = open (pty_name, O_RDWR)) >= 0) {
2063 		    strcpy(ptydev, pty_name);
2064 		    strcpy(ttydev, pty_name);
2065 		    ttydev[5] = 't';
2066 		    return 0;
2067 		}
2068 	    }
2069 	    return 1;
2070 	}
2071 #endif /* __convex__ */
2072 #ifdef USE_GET_PSEUDOTTY
2073 	return ((*pty = getpseudotty (&ttydev, &ptydev)) >= 0 ? 0 : 1);
2074 #else
2075 #if (defined(__sgi) && OSMAJORVERSION < 4) || (defined(umips) && defined (SYSTYPE_SYSV))
2076 	struct stat fstat_buf;
2077 
2078 	*pty = open ("/dev/ptc", O_RDWR);
2079 	if (*pty < 0 || (fstat (*pty, &fstat_buf)) < 0) {
2080 	  return(1);
2081 	}
2082 	sprintf (ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
2083 #ifndef __sgi
2084 	sprintf (ptydev, "/dev/ptyq%d", minor(fstat_buf.st_rdev));
2085 	if ((*tty = open (ttydev, O_RDWR)) < 0) {
2086 	  close (*pty);
2087 	  return(1);
2088 	}
2089 #endif /* !__sgi */
2090 	/* got one! */
2091 	return(0);
2092 #else /* __sgi or umips */
2093 
2094 	return pty_search(pty);
2095 
2096 #endif /* __sgi or umips else */
2097 #endif /* USE_GET_PSEUDOTTY else */
2098 #endif /* ATT else */
2099 #endif /* !0 */
2100 }
2101 
2102 /*
2103  * Called from get_pty to iterate over likely pseudo terminals
2104  * we might allocate.  Used on those systems that do not have
2105  * a functional interface for allocating a pty.
2106  * Returns 0 if found a pty, 1 if fails.
2107  */
pty_search(pty)2108 int pty_search(pty)
2109     int *pty;
2110 {
2111     static int devindex, letter = 0;
2112 
2113 #if defined(CRAY) || defined(sco)
2114     for (; devindex < MAXPTTYS; devindex++) {
2115 	sprintf (ttydev, TTYFORMAT, devindex);
2116 	sprintf (ptydev, PTYFORMAT, devindex);
2117 
2118 	if ((*pty = open (ptydev, O_RDWR)) >= 0) {
2119 	    /* We need to set things up for our next entry
2120 	     * into this function!
2121 	     */
2122 	    (void) devindex++;
2123 	    return 0;
2124 	}
2125     }
2126 #else /* CRAY || sco */
2127     while (PTYCHAR1[letter]) {
2128 	ttydev [strlen(ttydev) - 2]  = ptydev [strlen(ptydev) - 2] =
2129 	    PTYCHAR1 [letter];
2130 
2131 	while (PTYCHAR2[devindex]) {
2132 	    ttydev [strlen(ttydev) - 1] = ptydev [strlen(ptydev) - 1] =
2133 		PTYCHAR2 [devindex];
2134 	    /* for next time around loop or next entry to this function */
2135 	    devindex++;
2136 	    if ((*pty = open (ptydev, O_RDWR)) >= 0) {
2137 #ifdef sun
2138 		/* Need to check the process group of the pty.
2139 		 * If it exists, then the slave pty is in use,
2140 		 * and we need to get another one.
2141 		 */
2142 		int pgrp_rtn;
2143 		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
2144 		    close(*pty);
2145 		    continue;
2146 		}
2147 #endif /* sun */
2148 		return 0;
2149 	    }
2150 	}
2151 	devindex = 0;
2152 	(void) letter++;
2153     }
2154 #endif /* CRAY || sco else */
2155     /*
2156      * We were unable to allocate a pty master!  Return an error
2157      * condition and let our caller terminate cleanly.
2158      */
2159     return 1;
2160 }
2161 
get_terminal()2162 get_terminal ()
2163 /*
2164  * sets up X and initializes the terminal structure except for term.buf.fildes.
2165  */
2166 {
2167 	register TScreen *screen = &term->screen;
2168 
2169 	screen->arrow = make_colored_cursor (XC_left_ptr,
2170 					     screen->mousecolor,
2171 					     screen->mousecolorback);
2172 }
2173 
2174 #ifndef KTERM_NOTEK
2175 /*
2176  * The only difference in /etc/termcap between 4014 and 4015 is that
2177  * the latter has support for switching character sets.  We support the
2178  * 4015 protocol, but ignore the character switches.  Therefore, we
2179  * choose 4014 over 4015.
2180  *
2181  * Features of the 4014 over the 4012: larger (19") screen, 12-bit
2182  * graphics addressing (compatible with 4012 10-bit addressing),
2183  * special point plot mode, incremental plot mode (not implemented in
2184  * later Tektronix terminals), and 4 character sizes.
2185  * All of these are supported by xterm.
2186  */
2187 
2188 static char *tekterm[] = {
2189 	"tek4014",
2190 	"tek4015",		/* 4014 with APL character set support */
2191 	"tek4012",		/* 4010 with lower case */
2192 	"tek4013",		/* 4012 with APL character set support */
2193 	"tek4010",		/* small screen, upper-case only */
2194 	"dumb",
2195 	0
2196 };
2197 #endif /* !KTERM_NOTEK */
2198 
2199 /* The VT102 is a VT100 with the Advanced Video Option included standard.
2200  * It also adds Escape sequences for insert/delete character/line.
2201  * The VT220 adds 8-bit character sets, selective erase.
2202  * The VT320 adds a 25th status line, terminal state interrogation.
2203  * The VT420 has up to 48 lines on the screen.
2204  */
2205 
2206 static char *vtterm[] = {
2207 #ifdef KTERM
2208 	"kterm",
2209 #endif
2210 #ifdef USE_X11TERM
2211 	"x11term",		/* for people who want special term name */
2212 #endif
2213 	"xterm",		/* the prefered name, should be fastest */
2214 	"vt102",
2215 	"vt100",
2216 	"ansi",
2217 	"dumb",
2218 	0
2219 };
2220 
2221 /* ARGSUSED */
hungtty(i)2222 SIGNAL_T hungtty(i)
2223 	int i;
2224 {
2225 	longjmp(env, 1);
2226 	SIGNAL_RETURN;
2227 }
2228 
2229 /*
2230  * declared outside USE_HANDSHAKE so HsSysError() callers can use
2231  */
2232 static int pc_pipe[2];	/* this pipe is used for parent to child transfer */
2233 static int cp_pipe[2];	/* this pipe is used for child to parent transfer */
2234 
2235 #ifdef USE_HANDSHAKE
2236 typedef enum {		/* c == child, p == parent                        */
2237 	PTY_BAD,	/* c->p: can't open pty slave for some reason     */
2238 	PTY_FATALERROR,	/* c->p: we had a fatal error with the pty        */
2239 	PTY_GOOD,	/* c->p: we have a good pty, let's go on          */
2240 	PTY_NEW,	/* p->c: here is a new pty slave, try this        */
2241 	PTY_NOMORE,	/* p->c; no more pty's, terminate                 */
2242 	UTMP_ADDED,	/* c->p: utmp entry has been added                */
2243 	UTMP_TTYSLOT,	/* c->p: here is my ttyslot                       */
2244 	PTY_EXEC	/* p->c: window has been mapped the first time    */
2245 } status_t;
2246 
2247 typedef struct {
2248 	status_t status;
2249 	int error;
2250 	int fatal_error;
2251 	int tty_slot;
2252 	int rows;
2253 	int cols;
2254 	char buffer[1024];
2255 } handshake_t;
2256 
2257 /* HsSysError()
2258  *
2259  * This routine does the equivalent of a SysError but it handshakes
2260  * over the errno and error exit to the master process so that it can
2261  * display our error message and exit with our exit code so that the
2262  * user can see it.
2263  */
2264 
2265 void
HsSysError(pf,error)2266 HsSysError(pf, error)
2267 int pf;
2268 int error;
2269 {
2270 	handshake_t handshake;
2271 
2272 	handshake.status = PTY_FATALERROR;
2273 	handshake.error = errno;
2274 	handshake.fatal_error = error;
2275 	strcpy(handshake.buffer, ttydev);
2276 	write(pf, (char *) &handshake, sizeof(handshake));
2277 	exit(error);
2278 }
2279 
first_map_occurred()2280 void first_map_occurred ()
2281 {
2282     handshake_t handshake;
2283     register TScreen *screen = &term->screen;
2284 
2285     handshake.status = PTY_EXEC;
2286     handshake.rows = screen->max_row;
2287     handshake.cols = screen->max_col;
2288     write (pc_pipe[1], (char *) &handshake, sizeof(handshake));
2289     close (cp_pipe[0]);
2290     close (pc_pipe[1]);
2291     waiting_for_initial_map = False;
2292 }
2293 #else
2294 /*
2295  * temporary hack to get xterm working on att ptys
2296  */
2297 void
HsSysError(pf,error)2298 HsSysError(pf, error)
2299     int pf;
2300     int error;
2301 {
2302     fprintf(stderr, "%s: fatal pty error %d (errno=%d) on tty %s\n",
2303 	    xterm_name, error, errno, ttydev);
2304     exit(error);
2305 }
first_map_occurred()2306 void first_map_occurred ()
2307 {
2308     return;
2309 }
2310 #endif /* USE_HANDSHAKE else !USE_HANDSHAKE */
2311 
2312 
spawn()2313 spawn ()
2314 /*
2315  *  Inits pty and tty and forks a login process.
2316  *  Does not close fd Xsocket.
2317  *  If slave, the pty named in passedPty is already open for use
2318  */
2319 {
2320 	extern char *SysErrorMsg();
2321 	register TScreen *screen = &term->screen;
2322 #ifdef USE_HANDSHAKE
2323 	handshake_t handshake;
2324 #else
2325 	int fds[2];
2326 #endif
2327 	int tty = -1;
2328 	int discipline;
2329 	int done;
2330 #ifdef USE_SYSV_TERMIO
2331 	struct termio tio;
2332 	struct termio dummy_tio;
2333 #ifdef TIOCLSET
2334 	unsigned lmode;
2335 #endif	/* TIOCLSET */
2336 #ifdef TIOCSLTC
2337 	struct ltchars ltc;
2338 #endif	/* TIOCSLTC */
2339 	int one = 1;
2340 	int zero = 0;
2341 	int status;
2342 #elif defined(USE_POSIX_TERMIOS)
2343     struct termios tio;
2344 #ifdef TIOCLSET
2345     unsigned lmode;
2346 #endif /* TIOCLSET */
2347 #ifdef TIOCSLTC
2348     struct ltchars ltc;
2349 #endif /* TIOCSLTC */
2350 #else /* !USE_SYSV_TERMIO && !USE_POSIX_TERMIOS */
2351 	unsigned lmode;
2352 	struct tchars tc;
2353 	struct ltchars ltc;
2354 	struct sgttyb sg;
2355 #ifdef sony
2356 	int jmode;
2357 	struct jtchars jtc;
2358 #endif /* sony */
2359 #endif	/* USE_SYSV_TERMIO */
2360 
2361 	char termcap [1024];
2362 	char newtc [1024];
2363 	char *ptr, *shname, *shname_minus;
2364 	int i, no_dev_tty = FALSE;
2365 #ifdef USE_SYSV_TERMIO
2366 	char *dev_tty_name = (char *) 0;
2367 	int fd;			/* for /etc/wtmp */
2368 #endif	/* USE_SYSV_TERMIO */
2369 	char **envnew;		/* new environment */
2370 	int envsize;		/* elements in new environment */
2371 	char buf[64];
2372 	char *TermName = NULL;
2373 	int ldisc = 0;
2374 #if defined(sun) && !defined(SVR4)
2375 #ifdef TIOCSSIZE
2376 	struct ttysize ts;
2377 #endif	/* TIOCSSIZE */
2378 #else	/* not sun */
2379 #ifdef TIOCSWINSZ
2380 	struct winsize ws;
2381 #endif	/* TIOCSWINSZ */
2382 #endif	/* sun */
2383 	struct passwd *pw = NULL;
2384 #ifdef UTMP
2385 #if defined(SVR4) || defined(__DragonFly__)
2386 	struct utmpx utmp;
2387 #else
2388 	struct utmp utmp;
2389 #endif
2390 #ifdef LASTLOG
2391 	struct lastlog lastlog;
2392 #endif	/* LASTLOG */
2393 #endif	/* UTMP */
2394 
2395 	screen->uid = getuid();
2396 	screen->gid = getgid();
2397 
2398 #ifdef linux
2399 	bzero(termcap, sizeof termcap);
2400 	bzero(newtc, sizeof newtc);
2401 #endif
2402 
2403 #ifdef SIGTTOU
2404 	/* so that TIOCSWINSZ || TIOCSIZE doesn't block */
2405 	signal(SIGTTOU,SIG_IGN);
2406 #endif
2407 
2408 	if (am_slave) {
2409 		screen->respond = am_slave;
2410 #ifndef __osf__
2411 		ptydev[strlen(ptydev) - 2] = ttydev[strlen(ttydev) - 2] =
2412 			passedPty[0];
2413 		ptydev[strlen(ptydev) - 1] = ttydev[strlen(ttydev) - 1] =
2414 			passedPty[1];
2415 #endif /* __osf__ */
2416 		setgid (screen->gid);
2417 		setuid (screen->uid);
2418 	} else {
2419 		Bool tty_got_hung = False;
2420 
2421  		/*
2422  		 * Sometimes /dev/tty hangs on open (as in the case of a pty
2423  		 * that has gone away).  Simply make up some reasonable
2424  		 * defaults.
2425  		 */
2426  		signal(SIGALRM, hungtty);
2427  		alarm(2);		/* alarm(1) might return too soon */
2428  		if (! setjmp(env)) {
2429  			tty = open ("/dev/tty", O_RDWR, 0);
2430  			alarm(0);
2431  		} else {
2432 			tty_got_hung = True;
2433  			tty = -1;
2434  			errno = ENXIO;
2435  		}
2436  		signal(SIGALRM, SIG_DFL);
2437 
2438 		/*
2439 		 * Check results and ignore current control terminal if
2440 		 * necessary.  ENXIO is what is normally returned if there is
2441 		 * no controlling terminal, but some systems (e.g. SunOS 4.0)
2442 		 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
2443 		 */
2444  		if (tty < 0) {
2445 			if (tty_got_hung || errno == ENXIO || errno == EIO ||
2446 			    errno == EINVAL || errno == ENOTTY) {
2447 				no_dev_tty = TRUE;
2448 #ifdef TIOCSLTC
2449 				ltc = d_ltc;
2450 #endif	/* TIOCSLTC */
2451 #ifdef TIOCLSET
2452 				lmode = d_lmode;
2453 #endif	/* TIOCLSET */
2454 #if defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)
2455 				tio = d_tio;
2456 #else /* not USE_SYSV_TERMIO and not USE_POSIX_TERMIOS */
2457 				sg = d_sg;
2458 				tc = d_tc;
2459 				discipline = d_disipline;
2460 #ifdef sony
2461 				jmode = d_jmode;
2462 				jtc = d_jtc;
2463 #endif /* sony */
2464 #endif /* USE_SYSV_TERMIO or USE_POSIX_TERMIOS */
2465 			} else {
2466 			    SysError(ERROR_OPDEVTTY);
2467 			}
2468 		} else {
2469 			/* Get a copy of the current terminal's state,
2470 			 * if we can.  Some systems (e.g., SVR4 and MacII)
2471 			 * may not have a controlling terminal at this point
2472 			 * if started directly from xdm or xinit,
2473 			 * in which case we just use the defaults as above.
2474 			 */
2475 #ifdef TIOCSLTC
2476 			if(ioctl(tty, TIOCGLTC, &ltc) == -1)
2477 				ltc = d_ltc;
2478 #endif	/* TIOCSLTC */
2479 #ifdef TIOCLSET
2480 			if(ioctl(tty, TIOCLGET, &lmode) == -1)
2481 				lmode = d_lmode;
2482 #endif	/* TIOCLSET */
2483 #ifdef USE_SYSV_TERMIO
2484 		        if(ioctl(tty, TCGETA, &tio) == -1)
2485 			        tio = d_tio;
2486 
2487 #elif defined(USE_POSIX_TERMIOS)
2488 			if (tcgetattr(tty, &tio) == -1)
2489 			    tio = d_tio;
2490 #else /* !USE_SYSV_TERMIO && !USE_POSIX_TERMIOS */
2491 			if(ioctl(tty, TIOCGETP, (char *)&sg) == -1) {
2492 			        sg = d_sg;
2493 			}
2494 			if(ioctl(tty, TIOCGETC, (char *)&tc) == -1)
2495 			        tc = d_tc;
2496 			if(ioctl(tty, TIOCGETD, (char *)&discipline) == -1)
2497 			        discipline = d_disipline;
2498 #ifdef sony
2499 			if(ioctl(tty, TIOCKGET, (char *)&jmode) == -1)
2500 			        jmode = d_jmode;
2501 			if(ioctl(tty, TIOCKGETC, (char *)&jtc) == -1)
2502 				jtc = d_jtc;
2503 #endif /* sony */
2504 #endif	/* USE_SYSV_TERMIO */
2505 			close (tty);
2506 			/* tty is no longer an open fd! */
2507 			tty = -1;
2508 		}
2509 
2510 #ifdef 	PUCC_PTYD
2511 		if(-1 == (screen->respond = openrpty(ttydev, ptydev,
2512 				(resource.utmpInhibit ?  OPTY_NOP : OPTY_LOGIN),
2513 				getuid(), XDisplayString(screen->display)))) {
2514 #else /* not PUCC_PTYD */
2515 		if (get_pty (&screen->respond)) {
2516 #endif /* PUCC_PTYD */
2517 			/*  no ptys! */
2518 			(void) fprintf(stderr, "%s: no available ptys\n",
2519 				       xterm_name);
2520 			exit (ERROR_PTYS);
2521 #ifdef PUCC_PTYD
2522 		}
2523 #else
2524 		}			/* keep braces balanced for emacs */
2525 #endif
2526 #ifdef PUCC_PTYD
2527 		  else {
2528 			/*
2529 			 *  set the fd of the master in a global var so
2530 			 *  we can undo all this on exit
2531 			 *
2532 			 */
2533 			Ptyfd = screen->respond;
2534 		  }
2535 #endif /* PUCC_PTYD */
2536 	}
2537 
2538 	/* avoid double MapWindow requests */
2539 #ifdef KTERM_NOTEK
2540 	XtSetMappedWhenManaged( XtParent(term), False );
2541 #else /* !KTERM_NOTEK */
2542 	XtSetMappedWhenManaged( screen->TekEmu ? XtParent(tekWidget) :
2543 			        XtParent(term), False );
2544 #endif /* !KTERM_NOTEK */
2545 	wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
2546 				       False);
2547 #ifndef KTERM_NOTEK
2548 	if (!screen->TekEmu)
2549 #endif /* !KTERM_NOTEK */
2550 	    VTInit();		/* realize now so know window size for tty driver */
2551 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
2552 	if (Console) {
2553 	    /*
2554 	     * Inform any running xconsole program
2555 	     * that we are going to steal the console.
2556 	     */
2557 	    XmuGetHostname (mit_console_name + MIT_CONSOLE_LEN, 255);
2558 	    mit_console = XInternAtom(screen->display, mit_console_name, False);
2559 	    /* the user told us to be the console, so we can use CurrentTime */
2560 # ifdef KTERM_NOTEK
2561 	    XtOwnSelection(XtParent(term),
2562 			   mit_console, CurrentTime,
2563 			   ConvertConsoleSelection, NULL, NULL);
2564 # else /* !KTERM_NOTEK */
2565 	    XtOwnSelection(screen->TekEmu ? XtParent(tekWidget) : XtParent(term),
2566 			   mit_console, CurrentTime,
2567 			   ConvertConsoleSelection, NULL, NULL);
2568 # endif /* !KTERM_NOTEK */
2569 	}
2570 #endif
2571 #ifndef KTERM_NOTEK
2572 	if(screen->TekEmu) {
2573 		envnew = tekterm;
2574 		ptr = newtc;
2575 	} else {
2576 #endif /* !KTERM_NOTEK */
2577 		envnew = vtterm;
2578 		ptr = termcap;
2579 #ifndef KTERM_NOTEK
2580 	}
2581 #endif /* !KTERM_NOTEK */
2582 	TermName = NULL;
2583 	if (resource.term_name) {
2584 	    if (tgetent (ptr, resource.term_name) == 1) {
2585 		TermName = resource.term_name;
2586 #ifndef KTERM_NOTEK
2587 		if (!screen->TekEmu)
2588 #endif /* !KTERM_NOTEK */
2589 		    resize (screen, TermName, termcap, newtc);
2590 	    } else {
2591 		fprintf (stderr, "%s:  invalid termcap entry \"%s\".\n",
2592 			 ProgramName, resource.term_name);
2593 	    }
2594 	}
2595 	if (!TermName) {
2596 	    while (*envnew != NULL) {
2597 		if(tgetent(ptr, *envnew) == 1) {
2598 			TermName = *envnew;
2599 #ifndef KTERM_NOTEK
2600 			if(!screen->TekEmu)
2601 #endif /* !KTERM_NOTEK */
2602 			    resize(screen, TermName, termcap, newtc);
2603 			break;
2604 		}
2605 		envnew++;
2606 	    }
2607 	    if (TermName == NULL) {
2608 		fprintf (stderr, "%s:  unable to find usable termcap entry.\n",
2609 			 ProgramName);
2610 		Exit (1);
2611 	    }
2612 	}
2613 
2614 #if defined(sun) && !defined(SVR4)
2615 #ifdef TIOCSSIZE
2616 	/* tell tty how big window is */
2617 #  ifndef KTERM_NOTEK
2618 	if(screen->TekEmu) {
2619 		ts.ts_lines = 38;
2620 		ts.ts_cols = 81;
2621 	} else {
2622 #  endif /* !KTERM_NOTEK */
2623 		ts.ts_lines = screen->max_row + 1;
2624 		ts.ts_cols = screen->max_col + 1;
2625 #  ifndef KTERM_NOTEK
2626 	}
2627 #  endif /* !KTERM_NOTEK */
2628 #endif	/* TIOCSSIZE */
2629 #else	/* not sun */
2630 #ifdef TIOCSWINSZ
2631 	/* tell tty how big window is */
2632 #  ifndef KTERM_NOTEK
2633 	if(screen->TekEmu) {
2634 		ws.ws_row = 38;
2635 		ws.ws_col = 81;
2636 		ws.ws_xpixel = TFullWidth(screen);
2637 		ws.ws_ypixel = TFullHeight(screen);
2638 	} else {
2639 #  endif /* !KTERM_NOTEK */
2640 		ws.ws_row = screen->max_row + 1;
2641 		ws.ws_col = screen->max_col + 1;
2642 		ws.ws_xpixel = FullWidth(screen);
2643 		ws.ws_ypixel = FullHeight(screen);
2644 #  ifndef KTERM_NOTEK
2645 	}
2646 #  endif /* !KTERM_NOTEK */
2647 #endif	/* TIOCSWINSZ */
2648 #endif	/* sun */
2649 
2650 	if (!am_slave) {
2651 #ifdef USE_HANDSHAKE
2652 	    if (pipe(pc_pipe) || pipe(cp_pipe))
2653 		SysError (ERROR_FORK);
2654 #endif
2655 	    if ((screen->pid = fork ()) == -1)
2656 		SysError (ERROR_FORK);
2657 
2658 	    if (screen->pid == 0) {
2659 		/*
2660 		 * now in child process
2661 		 */
2662 		extern char **environ;
2663 #if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__)
2664 		int pgrp = setsid();
2665 #else
2666 		int pgrp = getpid();
2667 #endif
2668 #ifdef USE_SYSV_TERMIO
2669 		char numbuf[12];
2670 #endif	/* USE_SYSV_TERMIO */
2671 #if defined(UTMP) && defined(USE_SYSV_UTMP)
2672 		char* ptyname;
2673 # ifndef __sgi
2674 		char* ptynameptr;
2675 # endif
2676 #endif
2677 
2678 #ifdef USE_USG_PTYS
2679 #if defined(SYSV) && defined(i386) && !defined(SVR4)
2680                 if (IsPts) {	/* SYSV386 supports both, which did we open? */
2681 #endif /* SYSV && i386 && !SVR4 */
2682 		int ptyfd;
2683 
2684 		setpgrp();
2685 		grantpt (screen->respond);
2686 		unlockpt (screen->respond);
2687 		if ((ptyfd = open (ptsname(screen->respond), O_RDWR)) < 0) {
2688 		    SysError (1);
2689 		}
2690 		if (ioctl (ptyfd, I_PUSH, "ptem") < 0) {
2691 		    SysError (2);
2692 		}
2693 #if !defined(SVR4) && !(defined(SYSV) && defined(i386))
2694 		if (!getenv("CONSEM") && ioctl (ptyfd, I_PUSH, "consem") < 0) {
2695 		    SysError (3);
2696 		}
2697 #endif /* !SVR4 */
2698 		if (ioctl (ptyfd, I_PUSH, "ldterm") < 0) {
2699 		    SysError (4);
2700 		}
2701 #ifdef SVR4			/* from Sony */
2702 		if (ioctl (ptyfd, I_PUSH, "ttcompat") < 0) {
2703 		    SysError (5);
2704 		}
2705 #endif /* SVR4 */
2706 		tty = ptyfd;
2707 		close (screen->respond);
2708 #ifdef TIOCSWINSZ
2709                 /* tell tty how big window is */
2710 # ifndef KTERM_NOTEK
2711                 if(screen->TekEmu) {
2712                         ws.ws_row = 24;
2713                         ws.ws_col = 80;
2714                         ws.ws_xpixel = TFullWidth(screen);
2715                         ws.ws_ypixel = TFullHeight(screen);
2716                 } else {
2717 # endif /* !KTERM_NOTEK */
2718                         ws.ws_row = screen->max_row + 1;
2719                         ws.ws_col = screen->max_col + 1;
2720                         ws.ws_xpixel = FullWidth(screen);
2721                         ws.ws_ypixel = FullHeight(screen);
2722 # ifndef KTERM_NOTEK
2723                 }
2724 # endif /* !KTERM_NOTEK */
2725 #endif
2726 #if defined(SYSV) && defined(i386) && !defined(SVR4)
2727                 } else {	/* else pty, not pts */
2728 #endif /* SYSV && i386 && !SVR4 */
2729 #endif /* USE_USG_PTYS */
2730 
2731 #ifdef USE_HANDSHAKE		/* warning, goes for a long ways */
2732 		/* close parent's sides of the pipes */
2733 		close (cp_pipe[0]);
2734 		close (pc_pipe[1]);
2735 
2736 		/* Make sure that our sides of the pipes are not in the
2737 		 * 0, 1, 2 range so that we don't fight with stdin, out
2738 		 * or err.
2739 		 */
2740 		if (cp_pipe[1] <= 2) {
2741 			if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
2742 				(void) close(cp_pipe[1]);
2743 				cp_pipe[1] = i;
2744 			}
2745 		}
2746 		if (pc_pipe[0] <= 2) {
2747 			if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
2748 				(void) close(pc_pipe[0]);
2749 				pc_pipe[0] = i;
2750 			}
2751 		}
2752 
2753 		/* we don't need the socket, or the pty master anymore */
2754 		close (ConnectionNumber(screen->display));
2755 		close (screen->respond);
2756 
2757 		/* Now is the time to set up our process group and
2758 		 * open up the pty slave.
2759 		 */
2760 #ifdef	USE_SYSV_PGRP
2761 #if defined(CRAY) && (OSMAJORVERSION > 5)
2762 		(void) setsid();
2763 #else
2764 		(void) setpgrp();
2765 #endif
2766 #endif /* USE_SYSV_PGRP */
2767 		while (1) {
2768 #ifdef TIOCNOTTY
2769 			if (!no_dev_tty && (tty = open ("/dev/tty", O_RDWR)) >= 0) {
2770 				ioctl (tty, TIOCNOTTY, (char *) NULL);
2771 				close (tty);
2772 			}
2773 #endif /* TIOCNOTTY */
2774 #if (BSD >= 199103)
2775 			(void)revoke(ttydev);
2776 #endif
2777 			if ((tty = open(ttydev, O_RDWR, 0)) >= 0) {
2778 #if 0   /* XXX: xterm does not have the following code. Is it ok? */
2779 			    if (ioctl (tty, TIOCSETP, (char *)&sg) == -1)
2780 				    HsSysError (cp_pipe[1], ERROR_TIOCSETP);
2781 #endif
2782 #if defined(CRAY) && defined(TCSETCTTY)
2783 			    /* make /dev/tty work */
2784 			    ioctl(tty, TCSETCTTY, 0);
2785 #endif
2786 #ifdef	USE_SYSV_PGRP
2787 				/* We need to make sure that we are acutally
2788 				 * the process group leader for the pty.  If
2789 				 * we are, then we should now be able to open
2790 				 * /dev/tty.
2791 				 */
2792 				if ((i = open("/dev/tty", O_RDWR, 0)) >= 0) {
2793 					/* success! */
2794 					close(i);
2795 					break;
2796 				}
2797 #else	/* USE_SYSV_PGRP */
2798 				break;
2799 #endif	/* USE_SYSV_PGRP */
2800 			}
2801 
2802 #ifdef TIOCSCTTY
2803 			ioctl(tty, TIOCSCTTY, 0);
2804 #endif
2805 			/* let our master know that the open failed */
2806 			handshake.status = PTY_BAD;
2807 			handshake.error = errno;
2808 			strcpy(handshake.buffer, ttydev);
2809 			write(cp_pipe[1], (char *) &handshake,
2810 			    sizeof(handshake));
2811 
2812 			/* get reply from parent */
2813 			i = read(pc_pipe[0], (char *) &handshake,
2814 			    sizeof(handshake));
2815 			if (i <= 0) {
2816 				/* parent terminated */
2817 				exit(1);
2818 			}
2819 
2820 			if (handshake.status == PTY_NOMORE) {
2821 				/* No more ptys, let's shutdown. */
2822 				exit(1);
2823 			}
2824 
2825 			/* We have a new pty to try */
2826 			free(ttydev);
2827 			ttydev = malloc((unsigned)
2828 			    (strlen(handshake.buffer) + 1));
2829 			strcpy(ttydev, handshake.buffer);
2830 		}
2831 
2832 		/* use the same tty name that everyone else will use
2833 		** (from ttyname)
2834 		*/
2835 		if (ptr = ttyname(tty))
2836 		{
2837 			/* it may be bigger */
2838 			ttydev = realloc (ttydev, (unsigned) (strlen(ptr) + 1));
2839 			(void) strcpy(ttydev, ptr);
2840 		}
2841 #if defined(SYSV) && defined(i386) && !defined(SVR4)
2842                 } /* end of IsPts else clause */
2843 #endif /* SYSV && i386 && !SVR4 */
2844 
2845 #endif /* USE_HANDSHAKE -- from near fork */
2846 
2847 #ifdef USE_TTY_GROUP
2848 	{
2849 #include <grp.h>
2850 		struct group *ttygrp;
2851 		if (ttygrp = getgrnam("tty")) {
2852 			/* change ownership of tty to real uid, "tty" gid */
2853 			chown (ttydev, screen->uid, ttygrp->gr_gid);
2854 			chmod (ttydev, 0620);
2855 		}
2856 		else {
2857 			/* change ownership of tty to real group and user id */
2858 			chown (ttydev, screen->uid, screen->gid);
2859 			chmod (ttydev, 0622);
2860 		}
2861 		endgrent();
2862 	}
2863 #else /* else !USE_TTY_GROUP */
2864 		/* change ownership of tty to real group and user id */
2865 		chown (ttydev, screen->uid, screen->gid);
2866 
2867 		/* change protection of tty */
2868 		chmod (ttydev, 0622);
2869 #endif /* USE_TTY_GROUP */
2870 
2871 		/*
2872 		 * set up the tty modes
2873 		 */
2874 		{
2875 #if defined(USE_SYSV_TERMIO) || defined(USE_POSIX_TERMIOS)
2876 #if defined(umips) || defined(CRAY) || defined(linux)
2877 		    /* If the control tty had its modes screwed around with,
2878 		       eg. by lineedit in the shell, or emacs, etc. then tio
2879 		       will have bad values.  Let's just get termio from the
2880 		       new tty and tailor it.  */
2881 		    if (ioctl (tty, TCGETA, &tio) == -1)
2882 		      SysError (ERROR_TIOCGETP);
2883 		    tio.c_lflag |= ECHOE;
2884 #endif /* umips */
2885 		    /* Now is also the time to change the modes of the
2886 		     * child pty.
2887 		     */
2888 		    /* input: nl->nl, don't ignore cr, cr->nl */
2889 		    tio.c_iflag &= ~(INLCR|IGNCR);
2890 		    tio.c_iflag |= ICRNL;
2891 		    /* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */
2892 #ifndef USE_POSIX_TERMIOS
2893 		    tio.c_oflag &=
2894 		     ~(OCRNL|ONLRET|NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
2895 #endif /* USE_POSIX_TERMIOS */
2896 		    tio.c_oflag |= ONLCR;
2897 #ifdef OPOST
2898 		    tio.c_oflag |= OPOST;
2899 #endif /* OPOST */
2900 #ifndef USE_POSIX_TERMIOS
2901 #ifdef BAUD_0
2902 		    /* baud rate is 0 (don't care) */
2903 		    tio.c_cflag &= ~(CBAUD);
2904 #else	/* !BAUD_0 */
2905 		    /* baud rate is 9600 (nice default) */
2906 		    tio.c_cflag &= ~(CBAUD);
2907 		    tio.c_cflag |= B9600;
2908 #endif	/* !BAUD_0 */
2909 #else /* USE_POSIX_TERMIOS */
2910 		    cfsetispeed(&tio, B9600);
2911 		    cfsetospeed(&tio, B9600);
2912 		    /* Clear CLOCAL so that SIGHUP is sent to us
2913 		       when the xterm ends */
2914 		    tio.c_cflag &= ~CLOCAL;
2915 #endif /* USE_POSIX_TERMIOS */
2916 		    tio.c_cflag &= ~CSIZE;
2917 		    if (screen->input_eight_bits)
2918 			tio.c_cflag |= CS8;
2919 		    else
2920 			tio.c_cflag |= CS7;
2921 		    /* enable signals, canonical processing (erase, kill, etc),
2922 		    ** echo
2923 		    */
2924 		    tio.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK;
2925 #ifdef ECHOKE
2926 		    tio.c_lflag |= ECHOKE|IEXTEN;
2927 #endif
2928 #ifdef ECHOCTL
2929 		    tio.c_lflag |= ECHOCTL|IEXTEN;
2930 #endif
2931 		    /* reset EOL to default value */
2932 		    tio.c_cc[VEOL] = CEOL;			/* '^@' */
2933 		    /* certain shells (ksh & csh) change EOF as well */
2934 		    tio.c_cc[VEOF] = CEOF;			/* '^D' */
2935 #ifdef VLNEXT
2936 		    tio.c_cc[VLNEXT] = CLNEXT;
2937 #endif
2938 #ifdef VWERASE
2939 		    tio.c_cc[VWERASE] = CWERASE;
2940 #endif
2941 #ifdef VREPRINT
2942 		    tio.c_cc[VREPRINT] = CRPRNT;
2943 #endif
2944 #ifdef VRPRNT
2945 		    tio.c_cc[VRPRNT] = CRPRNT;
2946 #endif
2947 #ifdef VDISCARD
2948 		    tio.c_cc[VDISCARD] = CFLUSH;
2949 #endif
2950 #ifdef VFLUSHO
2951 		    tio.c_cc[VFLUSHO] = CFLUSH;
2952 #endif
2953 #ifdef VSTOP
2954 		    tio.c_cc[VSTOP] = CSTOP;
2955 #endif
2956 #ifdef VSTART
2957 		    tio.c_cc[VSTART] = CSTART;
2958 #endif
2959 #ifdef VSUSP
2960 		    tio.c_cc[VSUSP] = CSUSP;
2961 #endif
2962 #ifdef VDSUSP
2963 		    tio.c_cc[VDSUSP] = CDSUSP;
2964 #endif
2965 #define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value;
2966 		    if (override_tty_modes) {
2967 			/* sysv-specific */
2968 			TMODE (XTTYMODE_intr, tio.c_cc[VINTR]);
2969 			TMODE (XTTYMODE_quit, tio.c_cc[VQUIT]);
2970 			TMODE (XTTYMODE_erase, tio.c_cc[VERASE]);
2971 			TMODE (XTTYMODE_kill, tio.c_cc[VKILL]);
2972 			TMODE (XTTYMODE_eof, tio.c_cc[VEOF]);
2973 			TMODE (XTTYMODE_eol, tio.c_cc[VEOL]);
2974 #ifdef VSWTCH
2975 			TMODE (XTTYMODE_swtch, tio.c_cc[VSWTCH]);
2976 #endif
2977 #ifdef VSUSP
2978 			TMODE (XTTYMODE_susp, tio.c_cc[VSUSP]);
2979 #endif
2980 #ifdef VDSUSP
2981 			TMODE (XTTYMODE_dsusp, tio.c_cc[VDSUSP]);
2982 #endif
2983 #ifdef VREPRINT
2984 			TMODE (XTTYMODE_rprnt, tio.c_cc[VREPRINT]);
2985 #endif
2986 #ifdef VRPRNT
2987 			TMODE (XTTYMODE_rprnt, tio.c_cc[VRPRNT]);
2988 #endif
2989 #ifdef VDISCARD
2990 			TMODE (XTTYMODE_flush, tio.c_cc[VDISCARD]);
2991 #endif
2992 #ifdef VFLUSHO
2993 			TMODE (XTTYMODE_flush, tio.c_cc[VFLUSHO]);
2994 #endif
2995 #ifdef VWERASE
2996 			TMODE (XTTYMODE_weras, tio.c_cc[VWERASE]);
2997 #endif
2998 #ifdef VLNEXT
2999 			TMODE (XTTYMODE_lnext, tio.c_cc[VLNEXT]);
3000 #endif
3001 #ifdef VSTART
3002 			TMODE (XTTYMODE_start, tio.c_cc[VSTART]);
3003 #endif
3004 #ifdef VSTOP
3005 			TMODE (XTTYMODE_stop, tio.c_cc[VSTOP]);
3006 #endif
3007 #ifdef TIOCSLTC
3008 			/* both SYSV and BSD have ltchars */
3009 			TMODE (XTTYMODE_susp, ltc.t_suspc);
3010 			TMODE (XTTYMODE_dsusp, ltc.t_dsuspc);
3011 			TMODE (XTTYMODE_rprnt, ltc.t_rprntc);
3012 			TMODE (XTTYMODE_flush, ltc.t_flushc);
3013 			TMODE (XTTYMODE_weras, ltc.t_werasc);
3014 			TMODE (XTTYMODE_lnext, ltc.t_lnextc);
3015 #endif
3016 		    }
3017 #undef TMODE
3018 
3019 #ifdef TIOCSLTC
3020 		    if (ioctl (tty, TIOCSLTC, &ltc) == -1)
3021 			    HsSysError(cp_pipe[1], ERROR_TIOCSETC);
3022 #endif	/* TIOCSLTC */
3023 #ifdef TIOCLSET
3024 		    if (ioctl (tty, TIOCLSET, (char *)&lmode) == -1)
3025 			    HsSysError(cp_pipe[1], ERROR_TIOCLSET);
3026 #endif	/* TIOCLSET */
3027 #ifndef USE_POSIX_TERMIOS
3028 		    if (ioctl(tty, TCSETA, &tio) == -1)
3029 			HsSysError(cp_pipe[1], ERROR_TIOCSETP);
3030 #else /* USE_POSIX_TERMIOS */
3031 		    if (tcsetattr(tty, TCSANOW, &tio) == -1)
3032 			HsSysError(cp_pipe[1], ERROR_TIOCSETP);
3033 #endif /* USE_POSIX_TERMIOS */
3034 #else	/* USE_SYSV_TERMIO */
3035 #ifdef KTERM
3036 		    sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW
3037 						| EVENP | ODDP);
3038 #else /* !KTERM */
3039 		    sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
3040 #endif /* !KTERM */
3041 		    sg.sg_flags |= ECHO | CRMOD;
3042 		    /* make sure speed is set on pty so that editors work right*/
3043 		    sg.sg_ispeed = B9600;
3044 		    sg.sg_ospeed = B9600;
3045 		    /* reset t_brkc to default value */
3046 		    tc.t_brkc = -1;
3047 #ifdef LPASS8
3048 		    if (screen->input_eight_bits)
3049 			lmode |= LPASS8;
3050 		    else
3051 			lmode &= ~(LPASS8);
3052 #endif
3053 #ifdef sony
3054 		    jmode &= ~KM_KANJI;
3055 # ifdef KTERM_KANJIMODE
3056 		    if (term->misc.k_m) {
3057 			switch (term->misc.k_m[0]) {
3058 			case 'a': case 'A':
3059 				jmode |= KM_ASCII;
3060 				lmode &= ~LPASS8;
3061 				break;
3062 			case 'e': case 'E':
3063 			case 'x': case 'X':
3064 			case 'u': case 'U':
3065 				jmode |= KM_EUC;
3066 				break;
3067 			case 's': case 'S':
3068 			case 'm': case 'M':
3069 				jmode |= KM_SJIS;
3070 				break;
3071 			default:
3072 				jmode |= KM_JIS;
3073 				break;
3074 			}
3075 		    }
3076 # endif /* KTERM_KANJIMODE */
3077 
3078 		    jmode &= ~KM_SYSKANJI;
3079 		    if (ptr = getenv("SYS_CODE")) {
3080 			switch (*ptr) {
3081 			case 's':
3082 			case 'm':
3083 				jmode |= KM_SYSSJIS;
3084 				break;
3085 			case 'e':
3086 				jmode |= KM_SYSEUC;
3087 				break;
3088 			}
3089 		    } else {
3090 			jmode |= KM_SYSSJIS;
3091 		    }
3092 #endif /* sony */
3093 
3094 #define TMODE(ind,var) if (ttymodelist[ind].set) var = ttymodelist[ind].value;
3095 		    if (override_tty_modes) {
3096 			TMODE (XTTYMODE_intr, tc.t_intrc);
3097 			TMODE (XTTYMODE_quit, tc.t_quitc);
3098 			TMODE (XTTYMODE_erase, sg.sg_erase);
3099 			TMODE (XTTYMODE_kill, sg.sg_kill);
3100 			TMODE (XTTYMODE_eof, tc.t_eofc);
3101 			TMODE (XTTYMODE_start, tc.t_startc);
3102 			TMODE (XTTYMODE_stop, tc.t_stopc);
3103 			TMODE (XTTYMODE_brk, tc.t_brkc);
3104 			/* both SYSV and BSD have ltchars */
3105 			TMODE (XTTYMODE_susp, ltc.t_suspc);
3106 			TMODE (XTTYMODE_dsusp, ltc.t_dsuspc);
3107 			TMODE (XTTYMODE_rprnt, ltc.t_rprntc);
3108 			TMODE (XTTYMODE_flush, ltc.t_flushc);
3109 			TMODE (XTTYMODE_weras, ltc.t_werasc);
3110 			TMODE (XTTYMODE_lnext, ltc.t_lnextc);
3111 		    }
3112 #undef TMODE
3113 
3114 		    if (ioctl (tty, TIOCSETP, (char *)&sg) == -1)
3115 			    HsSysError (cp_pipe[1], ERROR_TIOCSETP);
3116 		    if (ioctl (tty, TIOCSETC, (char *)&tc) == -1)
3117 			    HsSysError (cp_pipe[1], ERROR_TIOCSETC);
3118 		    if (ioctl (tty, TIOCSETD, (char *)&discipline) == -1)
3119 			    HsSysError (cp_pipe[1], ERROR_TIOCSETD);
3120 		    if (ioctl (tty, TIOCSLTC, (char *)&ltc) == -1)
3121 			    HsSysError (cp_pipe[1], ERROR_TIOCSLTC);
3122 		    if (ioctl (tty, TIOCLSET, (char *)&lmode) == -1)
3123 			    HsSysError (cp_pipe[1], ERROR_TIOCLSET);
3124 #ifdef sony
3125 		    if (ioctl (tty, TIOCKSET, (char *)&jmode) == -1)
3126 			    HsSysError (cp_pipe[1], ERROR_TIOCKSET);
3127 		    if (ioctl (tty, TIOCKSETC, (char *)&jtc) == -1)
3128 			    HsSysError (cp_pipe[1], ERROR_TIOCKSETC);
3129 #endif /* sony */
3130 #endif	/* !USE_SYSV_TERMIO */
3131 #if defined(TIOCCONS) || defined(SRIOCSREDIR)
3132 		    if (Console) {
3133 #ifdef TIOCCONS
3134 			int on = 1;
3135 			if (ioctl (tty, TIOCCONS, (char *)&on) == -1)
3136 			    fprintf(stderr, "%s: cannot open console\n",
3137 				    xterm_name);
3138 #endif
3139 #ifdef SRIOCSREDIR
3140 			int fd = open("/dev/console",O_RDWR);
3141 			if (fd == -1 || ioctl (fd, SRIOCSREDIR, tty) == -1)
3142 			    fprintf(stderr, "%s: cannot open console\n",
3143 				    xterm_name);
3144 			(void) close (fd);
3145 #endif
3146 		    }
3147 #endif	/* TIOCCONS */
3148 		}
3149 
3150 		signal (SIGCHLD, SIG_DFL);
3151 #ifdef USE_SYSV_SIGHUP
3152 		/* watch out for extra shells (I don't understand either) */
3153 		signal (SIGHUP, SIG_DFL);
3154 #else
3155 		signal (SIGHUP, SIG_IGN);
3156 #endif
3157 		/* restore various signals to their defaults */
3158 		signal (SIGINT, SIG_DFL);
3159 		signal (SIGQUIT, SIG_DFL);
3160 		signal (SIGTERM, SIG_DFL);
3161 
3162 		/* copy the environment before Setenving */
3163 		for (i = 0 ; environ [i] != NULL ; i++)
3164 		    ;
3165 		/* compute number of Setenv() calls below */
3166 		envsize = 1;	/* (NULL terminating entry) */
3167 		envsize += 3;	/* TERM, WINDOWID, DISPLAY */
3168 #ifdef UTMP
3169 		envsize += 1;   /* LOGNAME */
3170 #endif /* UTMP */
3171 #ifdef USE_SYSV_ENVVARS
3172 #ifndef TIOCSWINSZ		/* window size not stored in driver? */
3173 		envsize += 2;	/* COLUMNS, LINES */
3174 #endif /* TIOCSWINSZ */
3175 #ifdef UTMP
3176 		envsize += 2;   /* HOME, SHELL */
3177 #endif /* UTMP */
3178 #else /* USE_SYSV_ENVVARS */
3179 		envsize += 1;	/* TERMCAP */
3180 #endif /* USE_SYSV_ENVVARS */
3181 		envnew = (char **) calloc ((unsigned) i + envsize, sizeof(char *));
3182 		memmove( (char *)envnew, (char *)environ, i * sizeof(char *));
3183 		environ = envnew;
3184 		Setenv ("TERM=", TermName);
3185 		if(!TermName)
3186 			*newtc = 0;
3187 
3188 #ifdef KTERM_NOTEK
3189 		sprintf (buf, "%lu",
3190 			 ((unsigned long) XtWindow (XtParent(term))));
3191 #else /* !KTERM_NOTEK */
3192 		sprintf (buf, "%lu", screen->TekEmu ?
3193 			 ((unsigned long) XtWindow (XtParent(tekWidget))) :
3194 			 ((unsigned long) XtWindow (XtParent(term))));
3195 #endif /* !KTERM_NOTEK */
3196 		Setenv ("WINDOWID=", buf);
3197 		/* put the display into the environment of the shell*/
3198 		Setenv ("DISPLAY=", XDisplayString (screen->display));
3199 
3200 		signal(SIGTERM, SIG_DFL);
3201 
3202 		/* this is the time to go and set up stdin, out, and err
3203 		 */
3204 		{
3205 #if defined(CRAY) && (OSMAJORVERSION >= 6)
3206 		    (void) close(tty);
3207 		    (void) close(0);
3208 
3209 		    if (open ("/dev/tty", O_RDWR)) {
3210 			fprintf(stderr, "cannot open /dev/tty\n");
3211 			exit(1);
3212 		    }
3213 		    (void) close(1);
3214 		    (void) close(2);
3215 		    dup(0);
3216 		    dup(0);
3217 #else
3218 		    /* dup the tty */
3219 		    for (i = 0; i <= 2; i++)
3220 			if (i != tty) {
3221 			    (void) close(i);
3222 			    (void) dup(tty);
3223 			}
3224 
3225 #ifndef ATT
3226 		    /* and close the tty */
3227 		    if (tty > 2)
3228 			(void) close(tty);
3229 #endif
3230 #endif /* CRAY */
3231 		}
3232 
3233 #ifndef	USE_SYSV_PGRP
3234 #ifdef TIOCSCTTY
3235 		setsid();
3236 		ioctl(0, TIOCSCTTY, 0);
3237 #endif
3238 		ioctl(0, TIOCSPGRP, (char *)&pgrp);
3239 #ifndef __osf__
3240 		setpgrp(0,0);
3241 #else
3242 		setpgid(0,0);
3243 #endif
3244 		close(open(ttydev, O_WRONLY, 0));
3245 #ifndef __osf__
3246 		setpgrp (0, pgrp);
3247 #else
3248 		setpgid (0, pgrp);
3249 #endif
3250 #endif /* !USE_SYSV_PGRP */
3251 
3252 #ifdef UTMP
3253 		pw = getpwuid(screen->uid);
3254 		if (pw && pw->pw_name)
3255 		    Setenv ("LOGNAME=", pw->pw_name); /* for POSIX */
3256 #ifdef USE_SYSV_UTMP
3257 		/* Set up our utmp entry now.  We need to do it here
3258 		** for the following reasons:
3259 		**   - It needs to have our correct process id (for
3260 		**     login).
3261 		**   - If our parent was to set it after the fork(),
3262 		**     it might make it out before we need it.
3263 		**   - We need to do it before we go and change our
3264 		**     user and group id's.
3265 		*/
3266 #ifdef CRAY
3267 #define PTYCHARLEN 4
3268 #else
3269 #ifdef __osf__
3270 #define PTYCHARLEN 5
3271 #else
3272 #define PTYCHARLEN 2
3273 #endif
3274 #endif
3275 
3276 		(void) setutent ();
3277 		/* set up entry to search for */
3278 		ptyname = ttydev;
3279 #ifndef __sgi
3280 		if (PTYCHARLEN >= (int)strlen(ptyname))
3281 		    ptynameptr = ptyname;
3282 		else
3283 		    ptynameptr = ptyname + strlen(ptyname) - PTYCHARLEN;
3284 		(void) strncpy(utmp.ut_id, ptynameptr, sizeof (utmp.ut_id));
3285 #else
3286 		(void) strncpy(utmp.ut_id,ptyname + sizeof("/dev/tty")-1,
3287 			       sizeof (utmp.ut_id));
3288 
3289 #endif
3290 		utmp.ut_type = DEAD_PROCESS;
3291 
3292 		/* position to entry in utmp file */
3293 		(void) getutid(&utmp);
3294 
3295 		/* set up the new entry */
3296 		utmp.ut_type = USER_PROCESS;
3297 #ifndef linux
3298 		utmp.ut_exit.e_exit = 2;
3299 #endif
3300 		(void) strncpy(utmp.ut_user,
3301 			       (pw && pw->pw_name) ? pw->pw_name : "????",
3302 			       sizeof(utmp.ut_user));
3303 
3304 #ifndef __sgi
3305 		(void)strncpy(utmp.ut_id, ptynameptr, sizeof(utmp.ut_id));
3306 #else
3307 		(void) strncpy(utmp.ut_id,ptyname + sizeof("/dev/tty")-1,
3308 			       sizeof (utmp.ut_id));
3309 #endif
3310 		(void) strncpy (utmp.ut_line,
3311 			ptyname + strlen("/dev/"), sizeof (utmp.ut_line));
3312 
3313 #ifdef HAS_UTMP_UT_HOST
3314 		(void) strncpy(buf, DisplayString(screen->display),
3315 			       sizeof(buf));
3316 #ifndef linux
3317 	        {
3318 		    char *disfin = strrchr(buf, ':');
3319 		    if (disfin)
3320 			*disfin = '\0';
3321 		}
3322 #endif
3323 		(void) strncpy(utmp.ut_host, buf, sizeof(utmp.ut_host));
3324 #endif
3325 		(void) strncpy(utmp.ut_name, pw->pw_name,
3326 			       sizeof(utmp.ut_name));
3327 
3328 		utmp.ut_pid = getpid();
3329 #if defined(SVR4) || defined(__DragonFly__)
3330 		utmp.ut_session = getsid(0);
3331 		utmp.ut_xtime = time ((Time_t *) 0);
3332 		utmp.ut_tv.tv_usec = 0;
3333 #else
3334 		utmp.ut_time = time ((Time_t *) 0);
3335 #endif
3336 
3337 		/* write out the entry */
3338 		if (!resource.utmpInhibit)
3339 		    (void) pututline(&utmp);
3340 #ifdef WTMP
3341 #if defined(SVR4) || defined(__DragonFly__)
3342 		if (term->misc.login_shell)
3343 		    updwtmpx(WTMPX_FILE, &utmp);
3344 #else
3345 		if (term->misc.login_shell &&
3346 		     (i = open(etc_wtmp, O_WRONLY|O_APPEND)) >= 0) {
3347 		    write(i, (char *)&utmp, sizeof(struct utmp));
3348 		    close(i);
3349 		}
3350 #endif
3351 #endif
3352 		/* close the file */
3353 		(void) endutent();
3354 
3355 #else	/* USE_SYSV_UTMP */
3356 		/* We can now get our ttyslot!  We can also set the initial
3357 		 * UTMP entry.
3358 		 */
3359 		tslot = ttyslot();
3360 		added_utmp_entry = False;
3361 		{
3362 			if (pw && !resource.utmpInhibit &&
3363 			    (i = open(etc_utmp, O_WRONLY)) >= 0) {
3364 				bzero((char *)&utmp, sizeof(struct utmp));
3365 				(void) strncpy(utmp.ut_line,
3366 					       ttydev + strlen("/dev/"),
3367 					       sizeof(utmp.ut_line));
3368 				(void) strncpy(utmp.ut_name, pw->pw_name,
3369 					       sizeof(utmp.ut_name));
3370 #ifdef HAS_UTMP_UT_HOST
3371 				(void) strncpy(utmp.ut_host,
3372 					       XDisplayString (screen->display),
3373 					       sizeof(utmp.ut_host));
3374 #endif
3375 				/* cast needed on Ultrix 4.4 */
3376 				time((Time_t*)&utmp.ut_time);
3377 				lseek(i, (long)(tslot * sizeof(struct utmp)), 0);
3378 				write(i, (char *)&utmp, sizeof(struct utmp));
3379 				close(i);
3380 				added_utmp_entry = True;
3381 #ifdef WTMP
3382 				if (term->misc.login_shell &&
3383 				(i = open(etc_wtmp, O_WRONLY|O_APPEND)) >= 0) {
3384 				    int status;
3385 				    status = write(i, (char *)&utmp,
3386 						   sizeof(struct utmp));
3387 				    status = close(i);
3388 				}
3389 #endif /* WTMP */
3390 #ifdef LASTLOG
3391 				if (term->misc.login_shell &&
3392 				(i = open(etc_lastlog, O_WRONLY)) >= 0) {
3393 				    bzero((char *)&lastlog,
3394 					sizeof (struct lastlog));
3395 				    (void) strncpy(lastlog.ll_line, ttydev +
3396 					sizeof("/dev"),
3397 					sizeof (lastlog.ll_line));
3398 				    (void) strncpy(lastlog.ll_host,
3399 					  XDisplayString (screen->display),
3400 					  sizeof (lastlog.ll_host));
3401 				    time(&lastlog.ll_time);
3402 				    lseek(i, (long)(screen->uid *
3403 					sizeof (struct lastlog)), 0);
3404 				    write(i, (char *)&lastlog,
3405 					sizeof (struct lastlog));
3406 				    close(i);
3407 				}
3408 #endif /* LASTLOG */
3409 			} else
3410 				tslot = -tslot;
3411 		}
3412 
3413 		/* Let's pass our ttyslot to our parent so that it can
3414 		 * clean up after us.
3415 		 */
3416 #ifdef USE_HANDSHAKE
3417 		handshake.tty_slot = tslot;
3418 #endif /* USE_HANDSHAKE */
3419 #endif /* USE_SYSV_UTMP */
3420 
3421 #ifdef USE_HANDSHAKE
3422 		/* Let our parent know that we set up our utmp entry
3423 		 * so that it can clean up after us.
3424 		 */
3425 		handshake.status = UTMP_ADDED;
3426 		handshake.error = 0;
3427 		strcpy(handshake.buffer, ttydev);
3428 		(void)write(cp_pipe[1], (char *)&handshake, sizeof(handshake));
3429 #endif /* USE_HANDSHAKE */
3430 #endif/* UTMP */
3431 
3432 		(void) setgid (screen->gid);
3433 #ifdef HAS_BSD_GROUPS
3434 		if (geteuid() == 0 && pw)
3435 		  initgroups (pw->pw_name, pw->pw_gid);
3436 #endif
3437 		(void) setuid (screen->uid);
3438 
3439 #ifdef USE_HANDSHAKE
3440 		/* mark the pipes as close on exec */
3441 		fcntl(cp_pipe[1], F_SETFD, 1);
3442 		fcntl(pc_pipe[0], F_SETFD, 1);
3443 
3444 		/* We are at the point where we are going to
3445 		 * exec our shell (or whatever).  Let our parent
3446 		 * know we arrived safely.
3447 		 */
3448 		handshake.status = PTY_GOOD;
3449 		handshake.error = 0;
3450 		(void)strcpy(handshake.buffer, ttydev);
3451 		(void)write(cp_pipe[1], (char *)&handshake, sizeof(handshake));
3452 
3453 		if (waiting_for_initial_map) {
3454 		    i = read (pc_pipe[0], (char *) &handshake,
3455 			      sizeof(handshake));
3456 		    if (i != sizeof(handshake) ||
3457 			handshake.status != PTY_EXEC) {
3458 			/* some very bad problem occurred */
3459 			exit (ERROR_PTY_EXEC);
3460 		    }
3461 		    if(handshake.rows > 0 && handshake.cols > 0) {
3462 			screen->max_row = handshake.rows;
3463 			screen->max_col = handshake.cols;
3464 #if defined(sun) && !defined(SVR4)
3465 #ifdef TIOCSSIZE
3466 			ts.ts_lines = screen->max_row + 1;
3467 			ts.ts_cols = screen->max_col + 1;
3468 #endif /* TIOCSSIZE */
3469 #else /* !sun */
3470 #ifdef TIOCSWINSZ
3471 			ws.ws_row = screen->max_row + 1;
3472 			ws.ws_col = screen->max_col + 1;
3473 			ws.ws_xpixel = FullWidth(screen);
3474 			ws.ws_ypixel = FullHeight(screen);
3475 #endif /* TIOCSWINSZ */
3476 #endif /* sun else !sun */
3477 		    }
3478 		}
3479 #endif /* USE_HANDSHAKE */
3480 
3481 #ifdef USE_SYSV_ENVVARS
3482 #ifndef TIOCSWINSZ
3483 		sprintf (numbuf, "%d", screen->max_col + 1);
3484 		Setenv("COLUMNS=", numbuf);
3485 		sprintf (numbuf, "%d", screen->max_row + 1);
3486 		Setenv("LINES=", numbuf);
3487 #endif
3488 #ifdef UTMP
3489 		if (pw) {	/* SVR4 doesn't provide these */
3490 		    if (!getenv("HOME"))
3491 			Setenv("HOME=", pw->pw_dir);
3492 		    if (!getenv("SHELL"))
3493 			Setenv("SHELL=", pw->pw_shell);
3494 		}
3495 #endif /* UTMP */
3496 #else /* USE_SYSV_ENVVAR */
3497 # ifndef KTERM_NOTEK
3498 		if(!screen->TekEmu) {
3499 # endif /* !KTERM_NOTEK */
3500 		    strcpy (termcap, newtc);
3501 		    resize (screen, TermName, termcap, newtc);
3502 # ifndef KTERM_NOTEK
3503 		}
3504 # endif /* !KTERM_NOTEK */
3505 		if (term->misc.titeInhibit) {
3506 		    remove_termcap_entry (newtc, ":ti=");
3507 		    remove_termcap_entry (newtc, ":te=");
3508 		}
3509 		/*
3510 		 * work around broken termcap entries */
3511 		if (resource.useInsertMode)	{
3512 		    remove_termcap_entry (newtc, ":ic=");
3513 		    /* don't get duplicates */
3514 		    remove_termcap_entry (newtc, ":im=");
3515 		    remove_termcap_entry (newtc, ":ei=");
3516 		    remove_termcap_entry (newtc, ":mi");
3517 		    strcat (newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
3518 		}
3519 		Setenv ("TERMCAP=", newtc);
3520 # ifdef sony
3521 		switch (jmode & KM_KANJI) {
3522 		case KM_JIS:
3523 			Setenv ("TTYPE=", "jis");
3524 			break;
3525 		case KM_SJIS:
3526 			Setenv ("TTYPE=", "sjis");
3527 			break;
3528 		case KM_EUC:
3529 			Setenv ("TTYPE=", "euc");
3530 			break;
3531 		case KM_ASCII:
3532 		defaults:
3533 			Setenv ("TTYPE=", "ascii");
3534 			break;
3535 		}
3536 # endif /* sony */
3537 #endif /* USE_SYSV_ENVVAR */
3538 
3539 
3540 		/* need to reset after all the ioctl bashing we did above */
3541 #if defined(sun) && !defined(SVR4)
3542 #ifdef TIOCSSIZE
3543 		ioctl  (0, TIOCSSIZE, &ts);
3544 #endif	/* TIOCSSIZE */
3545 #else	/* not sun */
3546 #ifdef TIOCSWINSZ
3547 		ioctl (0, TIOCSWINSZ, (char *)&ws);
3548 #endif	/* TIOCSWINSZ */
3549 #endif	/* sun */
3550 
3551 		signal(SIGHUP, SIG_DFL);
3552 		if (command_to_exec) {
3553 			execvp(*command_to_exec, command_to_exec);
3554 			/* print error message on screen */
3555 			fprintf(stderr, "%s: Can't execvp %s\n", xterm_name,
3556 			 *command_to_exec);
3557 		}
3558 
3559 #ifdef USE_SYSV_SIGHUP
3560 		/* fix pts sh hanging around */
3561 		signal (SIGHUP, SIG_DFL);
3562 #endif
3563 
3564 #ifdef UTMP
3565 		if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
3566 		 ((pw == NULL && (pw = getpwuid(screen->uid)) == NULL) ||
3567 		 *(ptr = pw->pw_shell) == 0))
3568 #else	/* UTMP */
3569 		if(((ptr = getenv("SHELL")) == NULL || *ptr == 0) &&
3570 		 ((pw = getpwuid(screen->uid)) == NULL ||
3571 		 *(ptr = pw->pw_shell) == 0))
3572 #endif	/* UTMP */
3573 			ptr = "/bin/sh";
3574 		if(shname = strrchr(ptr, '/'))
3575 			shname++;
3576 		else
3577 			shname = ptr;
3578 		shname_minus = malloc(strlen(shname) + 2);
3579 		(void) strcpy(shname_minus, "-");
3580 		(void) strcat(shname_minus, shname);
3581 #if !defined(USE_SYSV_TERMIO) && !defined(USE_POSIX_TERMIOS)
3582 		ldisc = XStrCmp("csh", shname + strlen(shname) - 3) == 0 ?
3583 		 NTTYDISC : 0;
3584 		ioctl(0, TIOCSETD, (char *)&ldisc);
3585 #endif /* !USE_SYSV_TERMIO && !USE_POSIX_TERMIOS */
3586 
3587 #ifdef USE_LOGIN_DASH_P
3588 		if (term->misc.login_shell && pw && added_utmp_entry)
3589 		  execl (bin_login, "login", "-p", "-f", pw->pw_name, 0);
3590 #endif
3591 		execlp (ptr, (term->misc.login_shell ? shname_minus : shname),
3592 			0);
3593 
3594 		/* Exec failed. */
3595 		fprintf (stderr, "%s: Could not exec %s!\n", xterm_name, ptr);
3596 		(void) sleep(5);
3597 		exit(ERROR_EXEC);
3598 	    }				/* end if in child after fork */
3599 
3600 #ifdef USE_HANDSHAKE
3601 	    /* Parent process.  Let's handle handshaked requests to our
3602 	     * child process.
3603 	     */
3604 
3605 	    /* close childs's sides of the pipes */
3606 	    close (cp_pipe[1]);
3607 	    close (pc_pipe[0]);
3608 
3609 	    for (done = 0; !done; ) {
3610 		if (read(cp_pipe[0], (char *) &handshake, sizeof(handshake)) <= 0) {
3611 			/* Our child is done talking to us.  If it terminated
3612 			 * due to an error, we will catch the death of child
3613 			 * and clean up.
3614 			 */
3615 			break;
3616 		}
3617 
3618 		switch(handshake.status) {
3619 		case PTY_GOOD:
3620 			/* Success!  Let's free up resources and
3621 			 * continue.
3622 			 */
3623 			done = 1;
3624 			break;
3625 
3626 		case PTY_BAD:
3627 			/* The open of the pty failed!  Let's get
3628 			 * another one.
3629 			 */
3630 			(void) close(screen->respond);
3631 			if (get_pty(&screen->respond)) {
3632 			    /* no more ptys! */
3633 			    (void) fprintf(stderr,
3634 			      "%s: child process can find no available ptys\n",
3635 			      xterm_name);
3636 			    handshake.status = PTY_NOMORE;
3637 			    write(pc_pipe[1], (char *) &handshake, sizeof(handshake));
3638 			    exit (ERROR_PTYS);
3639 			}
3640 			handshake.status = PTY_NEW;
3641 			(void) strcpy(handshake.buffer, ttydev);
3642 			write(pc_pipe[1], (char *) &handshake, sizeof(handshake));
3643 			break;
3644 
3645 		case PTY_FATALERROR:
3646 			errno = handshake.error;
3647 			close(cp_pipe[0]);
3648 			close(pc_pipe[1]);
3649 			SysError(handshake.fatal_error);
3650 
3651 		case UTMP_ADDED:
3652 			/* The utmp entry was set by our slave.  Remember
3653 			 * this so that we can reset it later.
3654 			 */
3655 			added_utmp_entry = True;
3656 #ifndef	USE_SYSV_UTMP
3657 			tslot = handshake.tty_slot;
3658 #endif	/* USE_SYSV_UTMP */
3659 			free(ttydev);
3660 			ttydev = malloc((unsigned) strlen(handshake.buffer) + 1);
3661 			strcpy(ttydev, handshake.buffer);
3662 			break;
3663 		default:
3664 			fprintf(stderr, "%s: unexpected handshake status %d\n",
3665 			        xterm_name, handshake.status);
3666 		}
3667 	    }
3668 	    /* close our sides of the pipes */
3669 	    if (!waiting_for_initial_map) {
3670 		close (cp_pipe[0]);
3671 		close (pc_pipe[1]);
3672 	    }
3673 #endif /* USE_HANDSHAKE */
3674 	}				/* end if no slave */
3675 
3676 	/*
3677 	 * still in parent (xterm process)
3678 	 */
3679 
3680 #ifdef USE_SYSV_SIGHUP
3681 	/* hung sh problem? */
3682 	signal (SIGHUP, SIG_DFL);
3683 #else
3684 	signal (SIGHUP,SIG_IGN);
3685 #endif
3686 
3687 /*
3688  * Unfortunately, System V seems to have trouble divorcing the child process
3689  * from the process group of xterm.  This is a problem because hitting the
3690  * INTR or QUIT characters on the keyboard will cause xterm to go away if we
3691  * don't ignore the signals.  This is annoying.
3692  */
3693 
3694 #if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
3695 	signal (SIGINT, SIG_IGN);
3696 
3697 #ifndef SYSV
3698 	/* hung shell problem */
3699 	signal (SIGQUIT, SIG_IGN);
3700 #endif
3701 	signal (SIGTERM, SIG_IGN);
3702 #else /* else is bsd or has job control */
3703 #if defined(SYSV) || defined(__osf__)
3704 	/* if we were spawned by a jobcontrol smart shell (like ksh or csh),
3705 	 * then our pgrp and pid will be the same.  If we were spawned by
3706 	 * a jobcontrol dumb shell (like /bin/sh), then we will be in our
3707 	 * parent's pgrp, and we must ignore keyboard signals, or we will
3708 	 * tank on everything.
3709 	 */
3710 	if (getpid() == getpgrp()) {
3711 	    (void) signal(SIGINT, Exit);
3712 	    (void) signal(SIGQUIT, Exit);
3713 	    (void) signal(SIGTERM, Exit);
3714 	} else {
3715 	    (void) signal(SIGINT, SIG_IGN);
3716 	    (void) signal(SIGQUIT, SIG_IGN);
3717 	    (void) signal(SIGTERM, SIG_IGN);
3718 	}
3719 	(void) signal(SIGPIPE, Exit);
3720 #else	/* SYSV */
3721 	signal (SIGINT, Exit);
3722 	signal (SIGQUIT, Exit);
3723 	signal (SIGTERM, Exit);
3724         signal (SIGPIPE, Exit);
3725 #endif	/* SYSV */
3726 #endif /* USE_SYSV_SIGNALS and not SIGTSTP */
3727 
3728 	return 0;
3729 }							/* end spawn */
3730 
3731 SIGNAL_T
Exit(n)3732 Exit(n)
3733 	int n;
3734 {
3735 	register TScreen *screen = &term->screen;
3736         int pty = term->screen.respond;  /* file descriptor of pty */
3737 #ifdef UTMP
3738 #ifdef USE_SYSV_UTMP
3739 #if defined(SVR4) || defined(__DragonFly__)
3740 	struct utmpx utmp;
3741 	struct utmpx *utptr;
3742 #else
3743 	struct utmp utmp;
3744 	struct utmp *utptr;
3745 #endif
3746 	char* ptyname;
3747 	char* ptynameptr;
3748 #if defined(WTMP) && !defined(SVR4)
3749 	int fd;			/* for /etc/wtmp */
3750 	int i;
3751 #endif
3752 
3753 	/* don't do this more than once */
3754 	if (xterm_exiting)
3755 	    SIGNAL_RETURN;
3756 	xterm_exiting = True;
3757 
3758 #ifdef PUCC_PTYD
3759 	closepty(ttydev, ptydev, (resource.utmpInhibit ?  OPTY_NOP : OPTY_LOGIN), Ptyfd);
3760 #endif /* PUCC_PTYD */
3761 
3762 	/* cleanup the utmp entry we forged earlier */
3763 	if (!resource.utmpInhibit
3764 #ifdef USE_HANDSHAKE		/* without handshake, no way to know */
3765 	    && added_utmp_entry
3766 #endif /* USE_HANDSHAKE */
3767 	    ) {
3768 	    ptyname = ttydev;
3769 	    utmp.ut_type = USER_PROCESS;
3770 	    if (PTYCHARLEN >= (int)strlen(ptyname))
3771 		ptynameptr = ptyname;
3772 	    else
3773 		ptynameptr = ptyname + strlen(ptyname) - PTYCHARLEN;
3774 	    (void) strncpy(utmp.ut_id, ptynameptr, sizeof(utmp.ut_id));
3775 	    (void) setutent();
3776 	    utptr = getutid(&utmp);
3777 	    /* write it out only if it exists, and the pid's match */
3778 	    if (utptr && (utptr->ut_pid == screen->pid)) {
3779 		    utptr->ut_type = DEAD_PROCESS;
3780 #if defined(SVR4) || defined(__DragonFly__)
3781 		    utmp.ut_session = getsid(0);
3782 		    utmp.ut_xtime = time ((Time_t *) 0);
3783 		    utmp.ut_tv.tv_usec = 0;
3784 #else
3785 		    utptr->ut_time = time((Time_t *) 0);
3786 #endif
3787 		    (void) pututline(utptr);
3788 #ifdef WTMP
3789 #if defined(SVR4) || defined(__DragonFly__)
3790 		    updwtmpx(WTMPX_FILE, &utmp);
3791 #else
3792 		    /* set wtmp entry if wtmp file exists */
3793 		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
3794 		      i = write(fd, utptr, sizeof(utmp));
3795 		      i = close(fd);
3796 		    }
3797 #endif
3798 #endif
3799 
3800 	    }
3801 	    (void) endutent();
3802 	}
3803 #else	/* not USE_SYSV_UTMP */
3804 	register int wfd;
3805 	register int i;
3806 	struct utmp utmp;
3807 
3808 	if (!resource.utmpInhibit && added_utmp_entry &&
3809 	    (!am_slave && tslot > 0 && (wfd = open(etc_utmp, O_WRONLY)) >= 0)){
3810 		bzero((char *)&utmp, sizeof(struct utmp));
3811 		lseek(wfd, (long)(tslot * sizeof(struct utmp)), 0);
3812 		write(wfd, (char *)&utmp, sizeof(struct utmp));
3813 		close(wfd);
3814 #ifdef WTMP
3815 		if (term->misc.login_shell &&
3816 		    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
3817 			(void) strncpy(utmp.ut_line, ttydev +
3818 			    sizeof("/dev"), sizeof (utmp.ut_line));
3819 			time(&utmp.ut_time);
3820 			i = write(wfd, (char *)&utmp, sizeof(struct utmp));
3821 			i = close(wfd);
3822 		}
3823 #endif /* WTMP */
3824 	}
3825 #endif	/* USE_SYSV_UTMP */
3826 #endif	/* UTMP */
3827         close(pty); /* close explicitly to avoid race with slave side */
3828 #ifdef ALLOWLOGGING
3829 	if(screen->logging)
3830 		CloseLog(screen);
3831 #endif
3832 
3833 	if (!am_slave) {
3834 		/* restore ownership of tty and pty */
3835 		chown (ttydev, 0, 0);
3836 #if (!defined(__sgi) && !defined(__osf__))
3837 		chown (ptydev, 0, 0);
3838 #endif
3839 
3840 		/* restore modes of tty and pty */
3841 		chmod (ttydev, 0666);
3842 #if (!defined(__sgi) && !defined(__osf__))
3843 		chmod (ptydev, 0666);
3844 #endif
3845 	}
3846 	exit(n);
3847 	SIGNAL_RETURN;
3848 }
3849 
3850 /* ARGSUSED */
resize(screen,TermName,oldtc,newtc)3851 resize(screen, TermName, oldtc, newtc)
3852 TScreen *screen;
3853 char *TermName;
3854 register char *oldtc, *newtc;
3855 {
3856 #ifndef USE_SYSV_ENVVARS
3857 	register char *ptr1, *ptr2;
3858 	register int i;
3859 	register int li_first = 0;
3860 	register char *temp;
3861 
3862 	if ((ptr1 = strindex (oldtc, "co#")) == NULL){
3863 		strcat (oldtc, "co#80:");
3864 		ptr1 = strindex (oldtc, "co#");
3865 	}
3866 	if ((ptr2 = strindex (oldtc, "li#")) == NULL){
3867 		strcat (oldtc, "li#24:");
3868 		ptr2 = strindex (oldtc, "li#");
3869 	}
3870 	if(ptr1 > ptr2) {
3871 		li_first++;
3872 		temp = ptr1;
3873 		ptr1 = ptr2;
3874 		ptr2 = temp;
3875 	}
3876 	ptr1 += 3;
3877 	ptr2 += 3;
3878 	strncpy (newtc, oldtc, i = ptr1 - oldtc);
3879 	newtc += i;
3880 	sprintf (newtc, "%d", li_first ? screen->max_row + 1 :
3881 	 screen->max_col + 1);
3882 	newtc += strlen(newtc);
3883 	ptr1 = strchr(ptr1, ':');
3884 	strncpy (newtc, ptr1, i = ptr2 - ptr1);
3885 	newtc += i;
3886 	sprintf (newtc, "%d", li_first ? screen->max_col + 1 :
3887 	 screen->max_row + 1);
3888 	ptr2 = strchr(ptr2, ':');
3889 	strcat (newtc, ptr2);
3890 #endif /* USE_SYSV_ENVVARS */
3891 }
3892 
3893 /*
3894  * Does a non-blocking wait for a child process.  If the system
3895  * doesn't support non-blocking wait, do nothing.
3896  * Returns the pid of the child, or 0 or -1 if none or error.
3897  */
3898 int
nonblocking_wait()3899 nonblocking_wait()
3900 {
3901 #ifdef USE_POSIX_WAIT
3902         pid_t pid;
3903 
3904 	pid = waitpid(-1, NULL, WNOHANG);
3905 #else /* USE_POSIX_WAIT */
3906 #if defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
3907 	/* cannot do non-blocking wait */
3908 	int pid = 0;
3909 #else	/* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
3910 	union wait status;
3911 	register int pid;
3912 
3913 	pid = wait3 (&status, WNOHANG, (struct rusage *)NULL);
3914 #endif /* defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP) */
3915 #endif /* USE_POSIX_WAIT else */
3916 
3917 	return pid;
3918 }
3919 
3920 /* ARGSUSED */
reapchild(n)3921 static SIGNAL_T reapchild (n)
3922     int n;
3923 {
3924     int pid;
3925 
3926     pid = wait(NULL);
3927 
3928 #ifdef USE_SYSV_SIGNALS
3929     /* cannot re-enable signal before waiting for child
3930        because then SVR4 loops.  Sigh.  HP-UX 9.01 too. */
3931     (void) signal(SIGCHLD, reapchild);
3932 #endif
3933 
3934     do {
3935 	if (pid == term->screen.pid) {
3936 #ifdef DEBUG
3937 	    if (debug) fputs ("Exiting\n", stderr);
3938 #endif
3939 	    Cleanup (0);
3940 	}
3941     } while ( (pid=nonblocking_wait()) > 0);
3942 
3943     SIGNAL_RETURN;
3944 }
3945 
3946 /* VARARGS1 */
consolepr(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)3947 consolepr(fmt,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
3948 char *fmt;
3949 {
3950 	extern char *SysErrorMsg();
3951 	int oerrno;
3952 	int f;
3953  	char buf[ BUFSIZ ];
3954 
3955 	oerrno = errno;
3956  	strcpy(buf, "xterm: ");
3957  	sprintf(buf+strlen(buf), fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
3958  	strcat(buf, ": ");
3959  	strcat(buf, SysErrorMsg (oerrno));
3960  	strcat(buf, "\n");
3961 	f = open("/dev/console",O_WRONLY);
3962 	write(f, buf, strlen(buf));
3963 	close(f);
3964 #ifdef TIOCNOTTY
3965 	if ((f = open("/dev/tty", 2)) >= 0) {
3966 		ioctl(f, TIOCNOTTY, (char *)NULL);
3967 		close(f);
3968 	}
3969 #endif	/* TIOCNOTTY */
3970 }
3971 
3972 
remove_termcap_entry(buf,str)3973 remove_termcap_entry (buf, str)
3974     char *buf;
3975     char *str;
3976 {
3977     register char *strinbuf;
3978 
3979     strinbuf = strindex (buf, str);
3980     if (strinbuf) {
3981         register char *colonPtr = strchr(strinbuf+1, ':');
3982         if (colonPtr) {
3983             while (*colonPtr) {
3984                 *strinbuf++ = *colonPtr++;      /* copy down */
3985             }
3986             *strinbuf = '\0';
3987         } else {
3988             strinbuf[1] = '\0';
3989         }
3990     }
3991     return 0;
3992 }
3993 
3994 /*
3995  * parse_tty_modes accepts lines of the following form:
3996  *
3997  *         [SETTING] ...
3998  *
3999  * where setting consists of the words in the modelist followed by a character
4000  * or ^char.
4001  */
parse_tty_modes(s,modelist)4002 static int parse_tty_modes (s, modelist)
4003     char *s;
4004     struct _xttymodes *modelist;
4005 {
4006     struct _xttymodes *mp;
4007     int c;
4008     int count = 0;
4009 
4010     while (1) {
4011 	while (*s && isascii(*s) && isspace(*s)) s++;
4012 	if (!*s) return count;
4013 
4014 	for (mp = modelist; mp->name; mp++) {
4015 	    if (strncmp (s, mp->name, mp->len) == 0) break;
4016 	}
4017 	if (!mp->name) return -1;
4018 
4019 	s += mp->len;
4020 	while (*s && isascii(*s) && isspace(*s)) s++;
4021 	if (!*s) return -1;
4022 
4023 	if (*s == '^') {
4024 	    s++;
4025 	    c = ((*s == '?') ? 0177 : *s & 31);	 /* keep control bits */
4026 	} else {
4027 	    c = *s;
4028 	}
4029 	mp->value = c;
4030 	mp->set = 1;
4031 	count++;
4032 	s++;
4033     }
4034 }
4035 
4036 
GetBytesAvailable(fd)4037 int GetBytesAvailable (fd)
4038     int fd;
4039 {
4040 #ifdef FIONREAD
4041     static long arg;
4042     ioctl (fd, FIONREAD, (char *) &arg);
4043     return (int) arg;
4044 #else
4045 #if defined(KTERM_XAW3D) && defined(FIORDCK)
4046     return ioctl (fd, FIORDCHK, NULL);
4047 #else /* !KTERM_XAW3D || !FIORDCK */
4048     struct pollfd pollfds[1];
4049 
4050     pollfds[0].fd = fd;
4051     pollfds[0].events = POLLIN;
4052     return poll (pollfds, 1, 0);
4053 #endif /* !KTERM_XAW3D || !FIORDCK */
4054 #endif
4055 }
4056 
4057 /* Utility function to try to hide system differences from
4058    everybody who used to call killpg() */
4059 
4060 int
kill_process_group(pid,sig)4061 kill_process_group(pid, sig)
4062     int pid;
4063     int sig;
4064 {
4065 #ifndef X_NOT_POSIX
4066     return kill (-pid, sig);
4067 #else
4068 #if defined(SVR4) || defined(SYSV)
4069     return kill (-pid, sig);
4070 #else
4071     return killpg (pid, sig);
4072 #endif
4073 #endif
4074 }
4075