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