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, <c) == -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, <c) == -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 *)<c) == -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