main.c revision 0bd37d32
10bd37d32Smrg/* $XTermId: main.c,v 1.727 2013/05/27 22:11:11 tom Exp $ */
20bd37d32Smrg
30bd37d32Smrg/*
40bd37d32Smrg * Copyright 2002-2012,2013 by Thomas E. Dickey
50bd37d32Smrg *
60bd37d32Smrg *                         All Rights Reserved
70bd37d32Smrg *
80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90bd37d32Smrg * copy of this software and associated documentation files (the
100bd37d32Smrg * "Software"), to deal in the Software without restriction, including
110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish,
120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to
130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to
140bd37d32Smrg * the following conditions:
150bd37d32Smrg *
160bd37d32Smrg * The above copyright notice and this permission notice shall be included
170bd37d32Smrg * in all copies or substantial portions of the Software.
180bd37d32Smrg *
190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
260bd37d32Smrg *
270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright
280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the
290bd37d32Smrg * sale, use or other dealings in this Software without prior written
300bd37d32Smrg * authorization.
310bd37d32Smrg *
320bd37d32Smrg * Copyright 1987, 1988  The Open Group
330bd37d32Smrg *
340bd37d32Smrg * Permission to use, copy, modify, distribute, and sell this software and its
350bd37d32Smrg * documentation for any purpose is hereby granted without fee, provided that
360bd37d32Smrg * the above copyright notice appear in all copies and that both that
370bd37d32Smrg * copyright notice and this permission notice appear in supporting
380bd37d32Smrg * documentation.
390bd37d32Smrg *
400bd37d32Smrg * The above copyright notice and this permission notice shall be included in
410bd37d32Smrg * all copies or substantial portions of the Software.
420bd37d32Smrg *
430bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
440bd37d32Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
450bd37d32Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
460bd37d32Smrg * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
470bd37d32Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
480bd37d32Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
490bd37d32Smrg *
500bd37d32Smrg * Except as contained in this notice, the name of The Open Group shall not be
510bd37d32Smrg * used in advertising or otherwise to promote the sale, use or other dealings
520bd37d32Smrg * in this Software without prior written authorization from The Open Group.
530bd37d32Smrg *
540bd37d32Smrg * Copyright 1987, 1988 by Digital Equipment Corporation, Maynard.
550bd37d32Smrg *
560bd37d32Smrg *                         All Rights Reserved
570bd37d32Smrg *
580bd37d32Smrg * Permission to use, copy, modify, and distribute this software and its
590bd37d32Smrg * documentation for any purpose and without fee is hereby granted,
600bd37d32Smrg * provided that the above copyright notice appear in all copies and that
610bd37d32Smrg * both that copyright notice and this permission notice appear in
620bd37d32Smrg * supporting documentation, and that the name of Digital not be used in
630bd37d32Smrg * advertising or publicity pertaining to distribution of the software
640bd37d32Smrg * without specific, written prior permission.
650bd37d32Smrg *
660bd37d32Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
670bd37d32Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
680bd37d32Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
690bd37d32Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
700bd37d32Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
710bd37d32Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
720bd37d32Smrg * SOFTWARE.
730bd37d32Smrg */
74d522f475Smrg
75d522f475Smrg/*
76d522f475Smrg *				 W A R N I N G
77d522f475Smrg *
78d522f475Smrg * If you think you know what all of this code is doing, you are
79d522f475Smrg * probably very mistaken.  There be serious and nasty dragons here.
80d522f475Smrg *
81d522f475Smrg * This client is *not* to be taken as an example of how to write X
82d522f475Smrg * Toolkit applications.  It is in need of a substantial rewrite,
83d522f475Smrg * ideally to create a generic tty widget with several different parsing
84d522f475Smrg * widgets so that you can plug 'em together any way you want.  Don't
85d522f475Smrg * hold your breath, though....
86d522f475Smrg */
87d522f475Smrg
88d522f475Smrg/* main.c */
89d522f475Smrg
90d522f475Smrg#define RES_OFFSET(field)	XtOffsetOf(XTERM_RESOURCE, field)
91d522f475Smrg
92d522f475Smrg#include <xterm.h>
930bd37d32Smrg#include <version.h>
94d522f475Smrg
95d522f475Smrg#include <X11/cursorfont.h>
96d522f475Smrg#include <X11/Xlocale.h>
97d522f475Smrg
98d522f475Smrg#if OPT_TOOLBAR
99d522f475Smrg
100d522f475Smrg#if defined(HAVE_LIB_XAW)
101d522f475Smrg#include <X11/Xaw/Form.h>
102d522f475Smrg#elif defined(HAVE_LIB_XAW3D)
103d522f475Smrg#include <X11/Xaw3d/Form.h>
104d522f475Smrg#elif defined(HAVE_LIB_NEXTAW)
105d522f475Smrg#include <X11/neXtaw/Form.h>
106d522f475Smrg#elif defined(HAVE_LIB_XAWPLUS)
107d522f475Smrg#include <X11/XawPlus/Form.h>
108d522f475Smrg#endif
109d522f475Smrg
110d522f475Smrg#endif /* OPT_TOOLBAR */
111d522f475Smrg
112d522f475Smrg#include <pwd.h>
113d522f475Smrg#include <ctype.h>
114d522f475Smrg
115d522f475Smrg#include <data.h>
116d522f475Smrg#include <error.h>
117d522f475Smrg#include <menu.h>
118d522f475Smrg#include <main.h>
119d522f475Smrg#include <xstrings.h>
120d522f475Smrg#include <xtermcap.h>
121d522f475Smrg#include <xterm_io.h>
122d522f475Smrg
123d522f475Smrg#if OPT_WIDE_CHARS
124d522f475Smrg#include <charclass.h>
125d522f475Smrg#endif
126d522f475Smrg
127d522f475Smrg#ifdef __osf__
128d522f475Smrg#define USE_SYSV_SIGNALS
129d522f475Smrg#define WTMP
130d522f475Smrg#include <pty.h>		/* openpty() */
131d522f475Smrg#endif
132d522f475Smrg
133d522f475Smrg#ifdef __sgi
134d522f475Smrg#include <grp.h>		/* initgroups() */
135d522f475Smrg#endif
136d522f475Smrg
1370bd37d32Smrgstatic void Syntax(char *) GCC_NORETURN;
1380bd37d32Smrgstatic void HsSysError(int) GCC_NORETURN;
139d522f475Smrg
140d522f475Smrg#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE)
141d522f475Smrg#define USE_POSIX_SIGNALS
142d522f475Smrg#endif
143d522f475Smrg
144d522f475Smrg#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
145d522f475Smrg/* older SYSV systems cannot ignore SIGHUP.
146d522f475Smrg   Shell hangs, or you get extra shells, or something like that */
147d522f475Smrg#define USE_SYSV_SIGHUP
148d522f475Smrg#endif
149d522f475Smrg
150d522f475Smrg#if defined(sony) && defined(bsd43) && !defined(KANJI)
151d522f475Smrg#define KANJI
152d522f475Smrg#endif
153d522f475Smrg
154d522f475Smrg#ifdef linux
155d522f475Smrg#define USE_SYSV_PGRP
156d522f475Smrg#define USE_SYSV_SIGNALS
157d522f475Smrg#define WTMP
158d522f475Smrg#ifdef __GLIBC__
159d522f475Smrg#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
160d522f475Smrg#include <pty.h>
161d522f475Smrg#endif
162d522f475Smrg#endif
163d522f475Smrg#endif
164d522f475Smrg
165d522f475Smrg#ifdef __MVS__
166d522f475Smrg#define USE_SYSV_PGRP
167d522f475Smrg#define USE_SYSV_SIGNALS
168d522f475Smrg#endif
169d522f475Smrg
170d522f475Smrg#ifdef __CYGWIN__
171d522f475Smrg#define WTMP
172d522f475Smrg#endif
173d522f475Smrg
174d522f475Smrg#ifdef __SCO__
175d522f475Smrg#ifndef _SVID3
176d522f475Smrg#define _SVID3
177d522f475Smrg#endif
178d522f475Smrg#endif
179d522f475Smrg
180d522f475Smrg#if defined(__GLIBC__) && !defined(linux)
181d522f475Smrg#define USE_SYSV_PGRP
182d522f475Smrg#define WTMP
183d522f475Smrg#define HAS_BSD_GROUPS
184d522f475Smrg#endif
185d522f475Smrg
186d522f475Smrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID)
187d522f475Smrg#include <grp.h>
188d522f475Smrg#endif
189d522f475Smrg
190d522f475Smrg#ifndef TTY_GROUP_NAME
191d522f475Smrg#define TTY_GROUP_NAME "tty"
192d522f475Smrg#endif
193d522f475Smrg
194d522f475Smrg#include <sys/stat.h>
195d522f475Smrg
196d522f475Smrg#ifdef Lynx
197d522f475Smrg#ifndef BSDLY
198d522f475Smrg#define BSDLY	0
199d522f475Smrg#endif
200d522f475Smrg#ifndef VTDLY
201d522f475Smrg#define VTDLY	0
202d522f475Smrg#endif
203d522f475Smrg#ifndef FFDLY
204d522f475Smrg#define FFDLY	0
205d522f475Smrg#endif
206d522f475Smrg#endif
207d522f475Smrg
208d522f475Smrg#ifdef SYSV			/* { */
209d522f475Smrg
210d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
211d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
212d522f475Smrg#include <poll.h>		/* for POLLIN */
213d522f475Smrg#endif /* USE_USG_PTYS */
214d522f475Smrg
215d522f475Smrg#define USE_SYSV_SIGNALS
216d522f475Smrg#define	USE_SYSV_PGRP
217d522f475Smrg
218d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
219d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
220d522f475Smrg#endif
221d522f475Smrg
222d522f475Smrg/*
223d522f475Smrg * now get system-specific includes
224d522f475Smrg */
225d522f475Smrg#ifdef CRAY
226d522f475Smrg#define HAS_BSD_GROUPS
227d522f475Smrg#endif
228d522f475Smrg
229d522f475Smrg#ifdef macII
230d522f475Smrg#define HAS_BSD_GROUPS
231d522f475Smrg#include <sys/ttychars.h>
232d522f475Smrg#undef USE_SYSV_ENVVARS
233d522f475Smrg#undef FIOCLEX
234d522f475Smrg#undef FIONCLEX
235d522f475Smrg#define setpgrp2 setpgrp
236d522f475Smrg#include <sgtty.h>
237d522f475Smrg#include <sys/resource.h>
238d522f475Smrg#endif
239d522f475Smrg
240d522f475Smrg#ifdef __hpux
241d522f475Smrg#define HAS_BSD_GROUPS
242d522f475Smrg#include <sys/ptyio.h>
243d522f475Smrg#endif /* __hpux */
244d522f475Smrg
245d522f475Smrg#ifdef __osf__
246d522f475Smrg#define HAS_BSD_GROUPS
247d522f475Smrg#undef  USE_SYSV_PGRP
248d522f475Smrg#define setpgrp setpgid
249d522f475Smrg#endif
250d522f475Smrg
251d522f475Smrg#ifdef __sgi
252d522f475Smrg#define HAS_BSD_GROUPS
253d522f475Smrg#include <sys/sysmacros.h>
254d522f475Smrg#endif /* __sgi */
255d522f475Smrg
256d522f475Smrg#ifdef sun
257d522f475Smrg#include <sys/strredir.h>
258d522f475Smrg#endif
259d522f475Smrg
260e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
261d522f475Smrg
262d522f475Smrg#ifdef __QNX__
263d522f475Smrg
264d522f475Smrg#ifndef __QNXNTO__
265d522f475Smrg#define ttyslot() 1
266d522f475Smrg#else
267d522f475Smrg#define USE_SYSV_PGRP
268d522f475Smrgextern __inline__
269d522f475Smrgint
270d522f475Smrgttyslot(void)
271d522f475Smrg{
272d522f475Smrg    return 1;			/* yuk */
273d522f475Smrg}
274d522f475Smrg#endif
275d522f475Smrg
276d522f475Smrg#else
277d522f475Smrg
278d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
279d522f475Smrg#define setpgrp setpgid
280d522f475Smrg#endif
281d522f475Smrg
282d522f475Smrg#ifndef linux
283d522f475Smrg#ifndef VMS
284d522f475Smrg#ifndef USE_POSIX_TERMIOS
285d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
286d522f475Smrg#include <sgtty.h>
287d522f475Smrg#endif
288d522f475Smrg#endif /* USE_POSIX_TERMIOS */
289d522f475Smrg#ifdef Lynx
290d522f475Smrg#include <resource.h>
291d522f475Smrg#else
292d522f475Smrg#include <sys/resource.h>
293d522f475Smrg#endif
294d522f475Smrg#ifndef __INTERIX
295d522f475Smrg#define HAS_BSD_GROUPS
296d522f475Smrg#endif
297d522f475Smrg#endif /* !VMS */
298d522f475Smrg#endif /* !linux */
299d522f475Smrg
300d522f475Smrg#endif /* __QNX__ */
301d522f475Smrg
302d522f475Smrg#endif /* } !SYSV */
303d522f475Smrg
304d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
305d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
306d522f475Smrg#ifndef NOFILE
307d522f475Smrg#define NOFILE OPEN_MAX
308d522f475Smrg#endif
309d522f475Smrg#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
310d522f475Smrg#include <sys/param.h>		/* for NOFILE */
311d522f475Smrg#endif
312d522f475Smrg
313d522f475Smrg#if defined(BSD) && (BSD >= 199103)
314d522f475Smrg#define WTMP
315d522f475Smrg#endif
316d522f475Smrg
317d522f475Smrg#include <stdio.h>
318d522f475Smrg
319d522f475Smrg#ifdef __hpux
320d522f475Smrg#include <sys/utsname.h>
321d522f475Smrg#endif /* __hpux */
322d522f475Smrg
323d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
324d522f475Smrg#define ttyslot() 1
325d522f475Smrg#endif /* apollo */
326d522f475Smrg
327d522f475Smrg#if defined(UTMPX_FOR_UTMP)
328d522f475Smrg#define UTMP_STR utmpx
329d522f475Smrg#else
330d522f475Smrg#define UTMP_STR utmp
331d522f475Smrg#endif
332d522f475Smrg
333d522f475Smrg#if defined(USE_UTEMPTER)
334d522f475Smrg#include <utempter.h>
335d522f475Smrg#endif
336d522f475Smrg
337d522f475Smrg#if defined(UTMPX_FOR_UTMP)
338d522f475Smrg
339d522f475Smrg#include <utmpx.h>
340d522f475Smrg
341d522f475Smrg#define call_endutent  endutxent
342d522f475Smrg#define call_getutid   getutxid
343d522f475Smrg#define call_pututline pututxline
344d522f475Smrg#define call_setutent  setutxent
345d522f475Smrg#define call_updwtmp   updwtmpx
346d522f475Smrg
347d522f475Smrg#elif defined(HAVE_UTMP)
348d522f475Smrg
349d522f475Smrg#include <utmp.h>
350d522f475Smrg
351d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
352d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
353d522f475Smrg#endif
354d522f475Smrg
355d522f475Smrg#define call_endutent  endutent
356d522f475Smrg#define call_getutid   getutid
357d522f475Smrg#define call_pututline pututline
358d522f475Smrg#define call_setutent  setutent
359d522f475Smrg#define call_updwtmp   updwtmp
360d522f475Smrg
361d522f475Smrg#endif
362d522f475Smrg
363d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
364d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
365d522f475Smrg#endif
366d522f475Smrg
367d522f475Smrg#ifndef USE_LASTLOGX
368d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
369d522f475Smrg#define USE_LASTLOGX 1
370d522f475Smrg#endif
371d522f475Smrg#endif
372d522f475Smrg
373d522f475Smrg#ifdef  PUCC_PTYD
374d522f475Smrg#include <local/openpty.h>
375d522f475Smrg#endif /* PUCC_PTYD */
376d522f475Smrg
377d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
378d522f475Smrg#include <util.h>		/* openpty() */
379d522f475Smrg#endif
380d522f475Smrg
381956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
382d522f475Smrg#include <libutil.h>		/* openpty() */
383d522f475Smrg#endif
384d522f475Smrg
385d522f475Smrg#if !defined(UTMP_FILENAME)
386d522f475Smrg#if defined(UTMP_FILE)
387d522f475Smrg#define UTMP_FILENAME UTMP_FILE
388d522f475Smrg#elif defined(_PATH_UTMP)
389d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
390d522f475Smrg#else
391d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
392d522f475Smrg#endif
393d522f475Smrg#endif
394d522f475Smrg
395d522f475Smrg#ifndef LASTLOG_FILENAME
396d522f475Smrg#ifdef _PATH_LASTLOG
397d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
398d522f475Smrg#else
399d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
400d522f475Smrg#endif
401d522f475Smrg#endif
402d522f475Smrg
403d522f475Smrg#if !defined(WTMP_FILENAME)
404d522f475Smrg#if defined(WTMP_FILE)
405d522f475Smrg#define WTMP_FILENAME WTMP_FILE
406d522f475Smrg#elif defined(_PATH_WTMP)
407d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
408d522f475Smrg#elif defined(SYSV)
409d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
410d522f475Smrg#else
411d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
412d522f475Smrg#endif
413d522f475Smrg#endif
414d522f475Smrg
415d522f475Smrg#include <signal.h>
416d522f475Smrg
417d522f475Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
418d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
419d522f475Smrg#endif
420d522f475Smrg
421d522f475Smrg#ifdef SIGTSTP
422d522f475Smrg#include <sys/wait.h>
423d522f475Smrg#endif
424d522f475Smrg
425d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
426d522f475Smrg#undef ECHOKE
427d522f475Smrg#undef ECHOCTL
428d522f475Smrg#endif
429d522f475Smrg
430d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
431d522f475Smrg#include <sys/ttydefaults.h>
432d522f475Smrg#endif
433d522f475Smrg
434d522f475Smrg#ifdef X_NOT_POSIX
435d522f475Smrgextern long lseek();
436d522f475Smrg#if defined(USG) || defined(SVR4)
437d522f475Smrgextern unsigned sleep();
438d522f475Smrg#else
439d522f475Smrgextern void sleep();
440d522f475Smrg#endif
441d522f475Smrgextern char *ttyname();
442d522f475Smrg#endif
443d522f475Smrg
444d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
445d522f475Smrgextern char *ptsname(int);
446d522f475Smrg#endif
447d522f475Smrg
448d522f475Smrg#ifndef VMS
4490bd37d32Smrgstatic void reapchild(int /* n */ );
450d522f475Smrgstatic int spawnXTerm(XtermWidget /* xw */ );
45120d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
452d522f475Smrg#ifdef USE_PTY_SEARCH
45320d2c4d2Smrgstatic int pty_search(int * /* pty */ );
454d522f475Smrg#endif
455d522f475Smrg#endif /* ! VMS */
456d522f475Smrg
457d522f475Smrgstatic int get_pty(int *pty, char *from);
45820d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
459d522f475Smrgstatic void set_owner(char *device, uid_t uid, gid_t gid, mode_t mode);
460d522f475Smrg
461d522f475Smrgstatic Bool added_utmp_entry = False;
462d522f475Smrg
463d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
464d522f475Smrgstatic uid_t save_euid;
465d522f475Smrgstatic gid_t save_egid;
466d522f475Smrg#endif
467d522f475Smrg
468d522f475Smrgstatic uid_t save_ruid;
469d522f475Smrgstatic gid_t save_rgid;
470d522f475Smrg
471d522f475Smrg#if defined(USE_UTMP_SETGID)
472d522f475Smrgstatic int really_get_pty(int *pty, char *from);
473d522f475Smrg#endif
474d522f475Smrg
475d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
476d522f475Smrgstatic Bool xterm_exiting = False;
477d522f475Smrg#endif
478d522f475Smrg
479d522f475Smrgstatic char *explicit_shname = NULL;
480d522f475Smrg
481d522f475Smrg/*
482d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
483d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
484d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
485d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
486d522f475Smrg** SEGV.
487d522f475Smrg*/
488d522f475Smrgstatic char **command_to_exec = NULL;
489d522f475Smrg
490d522f475Smrg#if OPT_LUIT_PROG
491d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
4920bd37d32Smrgstatic unsigned command_length_with_luit = 0;
493d522f475Smrg#endif
494d522f475Smrg
495d522f475Smrg#define TERMCAP_ERASE "kb"
496d522f475Smrg#define VAL_INITIAL_ERASE A2E(8)
497d522f475Smrg
498d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
499d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
500d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
501d522f475Smrg * about padding generally store the code in a short, which does not have
502d522f475Smrg * enough bits for the extended values.
503d522f475Smrg */
504d522f475Smrg#ifdef B38400			/* everyone should define this */
505d522f475Smrg#define VAL_LINE_SPEED B38400
506d522f475Smrg#else /* ...but xterm's used this for a long time */
507d522f475Smrg#define VAL_LINE_SPEED B9600
508d522f475Smrg#endif
509d522f475Smrg
510d522f475Smrg/*
511d522f475Smrg * Allow use of system default characters if defined and reasonable.
512d522f475Smrg * These are based on the BSD ttydefaults.h
513d522f475Smrg */
514d522f475Smrg#ifndef CBRK
515d522f475Smrg#define CBRK     0xff		/* was 0 */
516d522f475Smrg#endif
517d522f475Smrg#ifndef CDISCARD
518d522f475Smrg#define CDISCARD CONTROL('O')
519d522f475Smrg#endif
520d522f475Smrg#ifndef CDSUSP
521d522f475Smrg#define CDSUSP   CONTROL('Y')
522d522f475Smrg#endif
523d522f475Smrg#ifndef CEOF
524d522f475Smrg#define CEOF     CONTROL('D')
525d522f475Smrg#endif
526d522f475Smrg#ifndef CEOL
527d522f475Smrg#define CEOL	 0xff		/* was 0 */
528d522f475Smrg#endif
529d522f475Smrg#ifndef CERASE
530d522f475Smrg#define CERASE   0177
531d522f475Smrg#endif
532d522f475Smrg#ifndef CERASE2
533d522f475Smrg#define	CERASE2  CONTROL('H')
534d522f475Smrg#endif
535d522f475Smrg#ifndef CFLUSH
536d522f475Smrg#define CFLUSH   CONTROL('O')
537d522f475Smrg#endif
538d522f475Smrg#ifndef CINTR
539d522f475Smrg#define CINTR    CONTROL('C')
540d522f475Smrg#endif
541d522f475Smrg#ifndef CKILL
542d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
543d522f475Smrg#endif
544d522f475Smrg#ifndef CLNEXT
545d522f475Smrg#define CLNEXT   CONTROL('V')
546d522f475Smrg#endif
547d522f475Smrg#ifndef CNUL
548d522f475Smrg#define CNUL     0
549d522f475Smrg#endif
550d522f475Smrg#ifndef CQUIT
551d522f475Smrg#define CQUIT    CONTROL('\\')
552d522f475Smrg#endif
553d522f475Smrg#ifndef CRPRNT
554d522f475Smrg#define CRPRNT   CONTROL('R')
555d522f475Smrg#endif
556d522f475Smrg#ifndef CREPRINT
557d522f475Smrg#define CREPRINT CRPRNT
558d522f475Smrg#endif
559d522f475Smrg#ifndef CSTART
560d522f475Smrg#define CSTART   CONTROL('Q')
561d522f475Smrg#endif
562d522f475Smrg#ifndef CSTATUS
563d522f475Smrg#define	CSTATUS  CONTROL('T')
564d522f475Smrg#endif
565d522f475Smrg#ifndef CSTOP
566d522f475Smrg#define CSTOP    CONTROL('S')
567d522f475Smrg#endif
568d522f475Smrg#ifndef CSUSP
569d522f475Smrg#define CSUSP    CONTROL('Z')
570d522f475Smrg#endif
571d522f475Smrg#ifndef CSWTCH
572d522f475Smrg#define CSWTCH   0
573d522f475Smrg#endif
574d522f475Smrg#ifndef CWERASE
575d522f475Smrg#define CWERASE  CONTROL('W')
576d522f475Smrg#endif
577d522f475Smrg
578d522f475Smrg#ifdef USE_ANY_SYSV_TERMIO
579d522f475Smrg#define TERMIO_STRUCT struct termio
580d522f475Smrg#define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
581d522f475Smrg#define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
582d522f475Smrg#define ttyFlush(fd)          ioctl(fd, TCFLSH, 1)
583d522f475Smrg#elif defined(USE_POSIX_TERMIOS)
584d522f475Smrg#define TERMIO_STRUCT struct termios
585d522f475Smrg#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
586d522f475Smrg#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
587d522f475Smrg#define ttyFlush(fd)          tcflush(fd, TCOFLUSH)
588d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO */
589d522f475Smrg
590d522f475Smrg#ifndef VMS
591d522f475Smrg#ifdef TERMIO_STRUCT
592d522f475Smrg/* The following structures are initialized in main() in order
593d522f475Smrg** to eliminate any assumptions about the internal order of their
594d522f475Smrg** contents.
595d522f475Smrg*/
596d522f475Smrgstatic TERMIO_STRUCT d_tio;
597d522f475Smrg
598d522f475Smrg#ifdef HAS_LTCHARS
599d522f475Smrgstatic struct ltchars d_ltc;
600d522f475Smrg#endif /* HAS_LTCHARS */
601d522f475Smrg
602d522f475Smrg#ifdef TIOCLSET
603d522f475Smrgstatic unsigned int d_lmode;
604d522f475Smrg#endif /* TIOCLSET */
605d522f475Smrg
606d522f475Smrg#else /* !TERMIO_STRUCT */
607d522f475Smrgstatic struct sgttyb d_sg =
608d522f475Smrg{
609d522f475Smrg    0, 0, 0177, CKILL, (EVENP | ODDP | ECHO | XTABS | CRMOD)
610d522f475Smrg};
611d522f475Smrgstatic struct tchars d_tc =
612d522f475Smrg{
613d522f475Smrg    CINTR, CQUIT, CSTART,
614d522f475Smrg    CSTOP, CEOF, CBRK
615d522f475Smrg};
616d522f475Smrgstatic struct ltchars d_ltc =
617d522f475Smrg{
618d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
619d522f475Smrg    CFLUSH, CWERASE, CLNEXT
620d522f475Smrg};
621d522f475Smrgstatic int d_disipline = NTTYDISC;
622d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
623d522f475Smrg#ifdef sony
624d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
625d522f475Smrgstatic struct jtchars d_jtc =
626d522f475Smrg{
627d522f475Smrg    'J', 'B'
628d522f475Smrg};
629d522f475Smrg#endif /* sony */
630d522f475Smrg#endif /* TERMIO_STRUCT */
631d522f475Smrg#endif /* ! VMS */
632d522f475Smrg
633d522f475Smrg/*
634d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
635d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
636d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
637d522f475Smrg */
638d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
639d522f475Smrgstatic Boolean override_tty_modes = False;
640d522f475Smrg/* *INDENT-OFF* */
641d522f475Smrgstatic struct _xttymodes {
64220d2c4d2Smrg    const char *name;
643d522f475Smrg    size_t len;
644d522f475Smrg    int set;
645d522f475Smrg    int value;
646d522f475Smrg} ttymodelist[] = {
647d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
648d522f475Smrg#define XTTYMODE_intr	0
649d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
650d522f475Smrg#define XTTYMODE_quit	1
651d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
652d522f475Smrg#define XTTYMODE_erase	2
653d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
654d522f475Smrg#define XTTYMODE_kill	3
655d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
656d522f475Smrg#define XTTYMODE_eof	4
657d522f475Smrg    TTYMODE("eol"),		/* VEOL */
658d522f475Smrg#define XTTYMODE_eol	5
659d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
660d522f475Smrg#define XTTYMODE_swtch	6
661d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
662d522f475Smrg#define XTTYMODE_start	7
663d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
664d522f475Smrg#define XTTYMODE_stop	8
665d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
666d522f475Smrg#define XTTYMODE_brk	9
667d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
668d522f475Smrg#define XTTYMODE_susp	10
669d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
670d522f475Smrg#define XTTYMODE_dsusp	11
671d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
672d522f475Smrg#define XTTYMODE_rprnt	12
673d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
674d522f475Smrg#define XTTYMODE_flush	13
675d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
676d522f475Smrg#define XTTYMODE_weras	14
677d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
678d522f475Smrg#define XTTYMODE_lnext	15
679d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
680d522f475Smrg#define XTTYMODE_status	16
681d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
682d522f475Smrg#define XTTYMODE_erase2	17
683d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
684d522f475Smrg#define XTTYMODE_eol2	18
685d522f475Smrg    { NULL,	0, 0, '\0' },	/* end of data */
686d522f475Smrg};
687d522f475Smrg
688d522f475Smrg#define validTtyChar(data, n) \
689d522f475Smrg	    (known_ttyChars[n].sysMode >= 0 && \
690d522f475Smrg	     known_ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
691d522f475Smrg
692d522f475Smrgstatic const struct {
693d522f475Smrg    int sysMode;
694d522f475Smrg    int myMode;
695d522f475Smrg    int myDefault;
696d522f475Smrg} known_ttyChars[] = {
697d522f475Smrg#ifdef VINTR
698d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
699d522f475Smrg#endif
700d522f475Smrg#ifdef VQUIT
701d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
702d522f475Smrg#endif
703d522f475Smrg#ifdef VERASE
704d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
705d522f475Smrg#endif
706d522f475Smrg#ifdef VKILL
707d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
708d522f475Smrg#endif
709d522f475Smrg#ifdef VEOF
710d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
711d522f475Smrg#endif
712d522f475Smrg#ifdef VEOL
713d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
714d522f475Smrg#endif
715d522f475Smrg#ifdef VSWTCH
716d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
717d522f475Smrg#endif
718d522f475Smrg#ifdef VSTART
719d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
720d522f475Smrg#endif
721d522f475Smrg#ifdef VSTOP
722d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
723d522f475Smrg#endif
724d522f475Smrg#ifdef VSUSP
725d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
726d522f475Smrg#endif
727d522f475Smrg#ifdef VDSUSP
728d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
729d522f475Smrg#endif
730d522f475Smrg#ifdef VREPRINT
731d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
732d522f475Smrg#endif
733d522f475Smrg#ifdef VDISCARD
734d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
735d522f475Smrg#endif
736d522f475Smrg#ifdef VWERASE
737d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
738d522f475Smrg#endif
739d522f475Smrg#ifdef VLNEXT
740d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
741d522f475Smrg#endif
742d522f475Smrg#ifdef VSTATUS
743d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
744d522f475Smrg#endif
745d522f475Smrg#ifdef VERASE2
746d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
747d522f475Smrg#endif
748d522f475Smrg#ifdef VEOL2
749d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
750d522f475Smrg#endif
751d522f475Smrg};
752d522f475Smrg/* *INDENT-ON* */
753d522f475Smrg
7540bd37d32Smrg#define TMODE(ind,var) if (ttymodelist[ind].set) var = (cc_t) ttymodelist[ind].value
755d522f475Smrg
756d522f475Smrgstatic int parse_tty_modes(char *s, struct _xttymodes *modelist);
757d522f475Smrg
758d522f475Smrg#ifndef USE_UTEMPTER
759d522f475Smrg#ifdef USE_SYSV_UTMP
760d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
761d522f475Smrgextern struct utmp *getutid();
762d522f475Smrg#endif /* AIXV3 */
763d522f475Smrg
764d522f475Smrg#else /* not USE_SYSV_UTMP */
765d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
766d522f475Smrg#endif /* USE_SYSV_UTMP */
767d522f475Smrg
768d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
769d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
770d522f475Smrg#else
771d522f475Smrg#undef USE_LASTLOG
772d522f475Smrg#endif
773d522f475Smrg
774d522f475Smrg#ifdef WTMP
775d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
776d522f475Smrg#endif
777d522f475Smrg#endif /* !USE_UTEMPTER */
778d522f475Smrg
779d522f475Smrg/*
780d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
781d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
782d522f475Smrg * WTMP and USE_LASTLOG.
783d522f475Smrg */
784d522f475Smrg#ifdef USE_LOGIN_DASH_P
785d522f475Smrg#ifndef LOGIN_FILENAME
786d522f475Smrg#define LOGIN_FILENAME "/bin/login"
787d522f475Smrg#endif
788d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
789d522f475Smrg#endif
790d522f475Smrg
791d522f475Smrgstatic char passedPty[PTYCHARLEN + 1];	/* name if pty if slave */
792d522f475Smrg
793d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
794d522f475Smrgstatic int Console;
795d522f475Smrg#include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
796d522f475Smrg#define MIT_CONSOLE_LEN	12
797d522f475Smrg#define MIT_CONSOLE "MIT_CONSOLE_"
798d522f475Smrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
799d522f475Smrgstatic Atom mit_console;
800d522f475Smrg#endif /* TIOCCONS */
801d522f475Smrg
802d522f475Smrg#ifndef USE_SYSV_UTMP
803d522f475Smrgstatic int tslot;
804d522f475Smrg#endif /* USE_SYSV_UTMP */
805d522f475Smrgstatic sigjmp_buf env;
806d522f475Smrg
807d522f475Smrg#define SetUtmpHost(dst, screen) \
808d522f475Smrg	{ \
809d522f475Smrg	    char host[sizeof(dst) + 1]; \
810d522f475Smrg	    strncpy(host, DisplayString(screen->display), sizeof(host)); \
811d522f475Smrg	    TRACE(("DisplayString(%s)\n", host)); \
812d522f475Smrg	    if (!resource.utmpDisplayId) { \
813d522f475Smrg		char *endptr = strrchr(host, ':'); \
814d522f475Smrg		if (endptr) { \
815d522f475Smrg		    TRACE(("trimming display-id '%s'\n", host)); \
816d522f475Smrg		    *endptr = '\0'; \
817d522f475Smrg		} \
818d522f475Smrg	    } \
819d522f475Smrg	    strncpy(dst, host, sizeof(dst)); \
820d522f475Smrg	}
821d522f475Smrg
822d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
823d522f475Smrg#  define SetUtmpSysLen(utmp) 			   \
824d522f475Smrg	{ \
825d522f475Smrg	    utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
826d522f475Smrg	    utmp.ut_syslen = strlen(utmp.ut_host) + 1; \
827d522f475Smrg	}
828d522f475Smrg#endif
829d522f475Smrg
830d522f475Smrg/* used by VT (charproc.c) */
831d522f475Smrg
832d522f475Smrgstatic XtResource application_resources[] =
833d522f475Smrg{
834d522f475Smrg    Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
835d522f475Smrg    Sres(XtNtitle, XtCTitle, title, NULL),
8360bd37d32Smrg    Sres(XtNiconHint, XtCIconHint, icon_hint, 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"),
849e39b573cSmrg#if OPT_PRINT_ON_EXIT
850e39b573cSmrg    Ires("printModeImmediate", "PrintModeImmediate", printModeNow, 0),
851e39b573cSmrg    Ires("printOptsImmediate", "PrintOptsImmediate", printOptsNow, 9),
852e39b573cSmrg    Sres("printFileImmediate", "PrintFileImmediate", printFileNow, NULL),
853e39b573cSmrg    Ires("printModeOnXError", "PrintModeOnXError", printModeOnXError, 0),
854e39b573cSmrg    Ires("printOptsOnXError", "PrintOptsOnXError", printOptsOnXError, 9),
855e39b573cSmrg    Sres("printFileOnXError", "PrintFileOnXError", printFileOnXError, NULL),
856e39b573cSmrg#endif
857d522f475Smrg#if OPT_SUNPC_KBD
858d522f475Smrg    Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
859d522f475Smrg#endif
860d522f475Smrg#if OPT_HP_FUNC_KEYS
861d522f475Smrg    Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
862d522f475Smrg#endif
863d522f475Smrg#if OPT_SCO_FUNC_KEYS
864d522f475Smrg    Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
865d522f475Smrg#endif
866d522f475Smrg#if OPT_SUN_FUNC_KEYS
867d522f475Smrg    Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
868d522f475Smrg#endif
869d522f475Smrg#if OPT_TCAP_FKEYS
870d522f475Smrg    Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
871d522f475Smrg#endif
872d522f475Smrg#if OPT_INITIAL_ERASE
873d522f475Smrg    Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
874d522f475Smrg    Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
875d522f475Smrg#endif
876d522f475Smrg    Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
877d522f475Smrg#if OPT_ZICONBEEP
878d522f475Smrg    Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
8790bd37d32Smrg    Sres("zIconTitleFormat", "ZIconTitleFormat", zIconFormat, "*** %s"),
880d522f475Smrg#endif
881d522f475Smrg#if OPT_PTY_HANDSHAKE
882d522f475Smrg    Bres("waitForMap", "WaitForMap", wait_for_map, False),
883d522f475Smrg    Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
884d522f475Smrg    Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
885d522f475Smrg#endif
886d522f475Smrg#if OPT_SAME_NAME
887d522f475Smrg    Bres("sameName", "SameName", sameName, True),
888d522f475Smrg#endif
889d522f475Smrg#if OPT_SESSION_MGT
890d522f475Smrg    Bres("sessionMgt", "SessionMgt", sessionMgt, True),
891d522f475Smrg#endif
892d522f475Smrg#if OPT_TOOLBAR
893d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
894d522f475Smrg#endif
895956cc18dSsnj#if OPT_MAXIMIZE
896956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
897a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
898956cc18dSsnj#endif
899d522f475Smrg};
900d522f475Smrg
90120d2c4d2Smrgstatic String fallback_resources[] =
902d522f475Smrg{
903e39b573cSmrg#if OPT_TOOLBAR
904e39b573cSmrg    "*toolBar: false",
905e39b573cSmrg#endif
906d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
907d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
908d522f475Smrg    "*SimpleMenu*Sme.height: 16",
909d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
910d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
911d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
912d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
913d522f475Smrg#if OPT_TEK4014
914d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
915d522f475Smrg#endif
916d522f475Smrg    NULL
917d522f475Smrg};
918d522f475Smrg
919d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
920d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
921d522f475Smrg/* *INDENT-OFF* */
922d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
92320d2c4d2Smrg{"-geometry",	"*vt100.geometry",XrmoptionSepArg,	(XPointer) NULL},
92420d2c4d2Smrg{"-132",	"*c132",	XrmoptionNoArg,		(XPointer) "on"},
92520d2c4d2Smrg{"+132",	"*c132",	XrmoptionNoArg,		(XPointer) "off"},
92620d2c4d2Smrg{"-ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "on"},
92720d2c4d2Smrg{"+ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "off"},
92820d2c4d2Smrg{"-aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "on"},
92920d2c4d2Smrg{"+aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "off"},
930d522f475Smrg#ifndef NO_ACTIVE_ICON
93120d2c4d2Smrg{"-ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "off"},
93220d2c4d2Smrg{"+ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "on"},
933d522f475Smrg#endif /* NO_ACTIVE_ICON */
93420d2c4d2Smrg{"-b",		"*internalBorder",XrmoptionSepArg,	(XPointer) NULL},
93520d2c4d2Smrg{"-bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "on"},
93620d2c4d2Smrg{"+bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "off"},
93720d2c4d2Smrg{"-bcf",	"*cursorOffTime",XrmoptionSepArg,	(XPointer) NULL},
93820d2c4d2Smrg{"-bcn",	"*cursorOnTime",XrmoptionSepArg,	(XPointer) NULL},
93920d2c4d2Smrg{"-bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "off"},
94020d2c4d2Smrg{"+bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "on"},
94120d2c4d2Smrg{"-cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "off"},
94220d2c4d2Smrg{"+cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "on"},
94320d2c4d2Smrg{"-cc",		"*charClass",	XrmoptionSepArg,	(XPointer) NULL},
94420d2c4d2Smrg{"-cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "off"},
94520d2c4d2Smrg{"+cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "on"},
94620d2c4d2Smrg{"-cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "off"},
94720d2c4d2Smrg{"+cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "on"},
94820d2c4d2Smrg{"-cr",		"*cursorColor",	XrmoptionSepArg,	(XPointer) NULL},
94920d2c4d2Smrg{"-cu",		"*curses",	XrmoptionNoArg,		(XPointer) "on"},
95020d2c4d2Smrg{"+cu",		"*curses",	XrmoptionNoArg,		(XPointer) "off"},
95120d2c4d2Smrg{"-dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "off"},
95220d2c4d2Smrg{"+dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "on"},
95320d2c4d2Smrg{"-fb",		"*boldFont",	XrmoptionSepArg,	(XPointer) NULL},
95420d2c4d2Smrg{"-fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"off"},
95520d2c4d2Smrg{"+fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"on"},
95620d2c4d2Smrg{"-fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"off"},
95720d2c4d2Smrg{"+fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"on"},
958d522f475Smrg#ifndef NO_ACTIVE_ICON
95920d2c4d2Smrg{"-fi",		"*iconFont",	XrmoptionSepArg,	(XPointer) NULL},
960d522f475Smrg#endif /* NO_ACTIVE_ICON */
961d522f475Smrg#if OPT_RENDERFONT
96220d2c4d2Smrg{"-fa",		"*faceName",	XrmoptionSepArg,	(XPointer) NULL},
96320d2c4d2Smrg{"-fd",		"*faceNameDoublesize", XrmoptionSepArg,	(XPointer) NULL},
96420d2c4d2Smrg{"-fs",		"*faceSize",	XrmoptionSepArg,	(XPointer) NULL},
965d522f475Smrg#endif
966d522f475Smrg#if OPT_WIDE_CHARS
96720d2c4d2Smrg{"-fw",		"*wideFont",	XrmoptionSepArg,	(XPointer) NULL},
96820d2c4d2Smrg{"-fwb",	"*wideBoldFont", XrmoptionSepArg,	(XPointer) NULL},
969d522f475Smrg#endif
970d522f475Smrg#if OPT_INPUT_METHOD
97120d2c4d2Smrg{"-fx",		"*ximFont",	XrmoptionSepArg,	(XPointer) NULL},
972d522f475Smrg#endif
973d522f475Smrg#if OPT_HIGHLIGHT_COLOR
97420d2c4d2Smrg{"-hc",		"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
97520d2c4d2Smrg{"-hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "on"},
97620d2c4d2Smrg{"+hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "off"},
97720d2c4d2Smrg{"-selfg",	"*highlightTextColor", XrmoptionSepArg,	(XPointer) NULL},
97820d2c4d2Smrg{"-selbg",	"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
979d522f475Smrg#endif
980d522f475Smrg#if OPT_HP_FUNC_KEYS
98120d2c4d2Smrg{"-hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "on"},
98220d2c4d2Smrg{"+hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "off"},
983d522f475Smrg#endif
98420d2c4d2Smrg{"-hold",	"*hold",	XrmoptionNoArg,		(XPointer) "on"},
98520d2c4d2Smrg{"+hold",	"*hold",	XrmoptionNoArg,		(XPointer) "off"},
986d522f475Smrg#if OPT_INITIAL_ERASE
98720d2c4d2Smrg{"-ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "on"},
98820d2c4d2Smrg{"+ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "off"},
989d522f475Smrg#endif
99020d2c4d2Smrg{"-j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "on"},
99120d2c4d2Smrg{"+j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "off"},
992d522f475Smrg#if OPT_C1_PRINT
99320d2c4d2Smrg{"-k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "on"},
99420d2c4d2Smrg{"+k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "off"},
995d522f475Smrg#endif
99620d2c4d2Smrg{"-kt",		"*keyboardType", XrmoptionSepArg,	(XPointer) NULL},
997d522f475Smrg/* parse logging options anyway for compatibility */
99820d2c4d2Smrg{"-l",		"*logging",	XrmoptionNoArg,		(XPointer) "on"},
99920d2c4d2Smrg{"+l",		"*logging",	XrmoptionNoArg,		(XPointer) "off"},
100020d2c4d2Smrg{"-lf",		"*logFile",	XrmoptionSepArg,	(XPointer) NULL},
100120d2c4d2Smrg{"-ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "on"},
100220d2c4d2Smrg{"+ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "off"},
100320d2c4d2Smrg{"-mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "on"},
100420d2c4d2Smrg{"+mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "off"},
100520d2c4d2Smrg{"-mc",		"*multiClickTime", XrmoptionSepArg,	(XPointer) NULL},
100620d2c4d2Smrg{"-mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "off"},
100720d2c4d2Smrg{"+mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "on"},
100820d2c4d2Smrg{"-ms",		"*pointerColor",XrmoptionSepArg,	(XPointer) NULL},
100920d2c4d2Smrg{"-nb",		"*nMarginBell",	XrmoptionSepArg,	(XPointer) NULL},
101020d2c4d2Smrg{"-nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "off"},
101120d2c4d2Smrg{"+nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "on"},
101220d2c4d2Smrg{"-pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "on"},
101320d2c4d2Smrg{"+pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "off"},
101420d2c4d2Smrg{"-rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "on"},
101520d2c4d2Smrg{"+rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "off"},
101620d2c4d2Smrg{"-s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "on"},
101720d2c4d2Smrg{"+s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "off"},
101820d2c4d2Smrg{"-sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "on"},
101920d2c4d2Smrg{"+sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "off"},
1020d522f475Smrg#ifdef SCROLLBAR_RIGHT
102120d2c4d2Smrg{"-leftbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "off"},
102220d2c4d2Smrg{"-rightbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "on"},
102320d2c4d2Smrg#endif
102420d2c4d2Smrg{"-rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "off"},
102520d2c4d2Smrg{"+rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "on"},
102620d2c4d2Smrg{"-sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "on"},
102720d2c4d2Smrg{"+sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "off"},
10280bd37d32Smrg{"-sh",		"*scaleHeight", XrmoptionSepArg,	(XPointer) NULL},
102920d2c4d2Smrg{"-si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "off"},
103020d2c4d2Smrg{"+si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "on"},
103120d2c4d2Smrg{"-sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "on"},
103220d2c4d2Smrg{"+sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "off"},
103320d2c4d2Smrg{"-sl",		"*saveLines",	XrmoptionSepArg,	(XPointer) NULL},
1034d522f475Smrg#if OPT_SUNPC_KBD
103520d2c4d2Smrg{"-sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "on"},
103620d2c4d2Smrg{"+sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "off"},
1037d522f475Smrg#endif
1038d522f475Smrg#if OPT_TEK4014
103920d2c4d2Smrg{"-t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "on"},
104020d2c4d2Smrg{"+t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "off"},
1041d522f475Smrg#endif
104220d2c4d2Smrg{"-ti",		"*decTerminalID",XrmoptionSepArg,	(XPointer) NULL},
104320d2c4d2Smrg{"-tm",		"*ttyModes",	XrmoptionSepArg,	(XPointer) NULL},
104420d2c4d2Smrg{"-tn",		"*termName",	XrmoptionSepArg,	(XPointer) NULL},
1045d522f475Smrg#if OPT_WIDE_CHARS
104620d2c4d2Smrg{"-u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "2"},
104720d2c4d2Smrg{"+u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "0"},
1048d522f475Smrg#endif
1049d522f475Smrg#if OPT_LUIT_PROG
105020d2c4d2Smrg{"-lc",		"*locale",	XrmoptionNoArg,		(XPointer) "on"},
105120d2c4d2Smrg{"+lc",		"*locale",	XrmoptionNoArg,		(XPointer) "off"},
105220d2c4d2Smrg{"-lcc",	"*localeFilter",XrmoptionSepArg,	(XPointer) NULL},
105320d2c4d2Smrg{"-en",		"*locale",	XrmoptionSepArg,	(XPointer) NULL},
105420d2c4d2Smrg#endif
105520d2c4d2Smrg{"-uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "on"},
105620d2c4d2Smrg{"+uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "off"},
105720d2c4d2Smrg{"-ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "off"},
105820d2c4d2Smrg{"+ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "on"},
105920d2c4d2Smrg{"-ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "off"},
106020d2c4d2Smrg{"+ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "on"},
106120d2c4d2Smrg{"-ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "on"},
106220d2c4d2Smrg{"+ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "off"},
106320d2c4d2Smrg{"-im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "on"},
106420d2c4d2Smrg{"+im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "off"},
106520d2c4d2Smrg{"-vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "on"},
106620d2c4d2Smrg{"+vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "off"},
106720d2c4d2Smrg{"-pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "on"},
106820d2c4d2Smrg{"+pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "off"},
1069d522f475Smrg#if OPT_WIDE_CHARS
107020d2c4d2Smrg{"-wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "on"},
107120d2c4d2Smrg{"+wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "off"},
107220d2c4d2Smrg{"-mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "on"},
107320d2c4d2Smrg{"+mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "off"},
107420d2c4d2Smrg{"-cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "on"},
107520d2c4d2Smrg{"+cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "off"},
107620d2c4d2Smrg#endif
107720d2c4d2Smrg{"-wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "on"},
107820d2c4d2Smrg{"+wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "off"},
1079d522f475Smrg#if OPT_ZICONBEEP
108020d2c4d2Smrg{"-ziconbeep",	"*zIconBeep",	XrmoptionSepArg,	(XPointer) NULL},
1081d522f475Smrg#endif
1082d522f475Smrg#if OPT_SAME_NAME
108320d2c4d2Smrg{"-samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "on"},
108420d2c4d2Smrg{"+samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "off"},
1085d522f475Smrg#endif
1086d522f475Smrg#if OPT_SESSION_MGT
108720d2c4d2Smrg{"-sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "on"},
108820d2c4d2Smrg{"+sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "off"},
1089d522f475Smrg#endif
1090d522f475Smrg#if OPT_TOOLBAR
109120d2c4d2Smrg{"-tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "on"},
109220d2c4d2Smrg{"+tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "off"},
1093d522f475Smrg#endif
1094956cc18dSsnj#if OPT_MAXIMIZE
109520d2c4d2Smrg{"-maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "on"},
109620d2c4d2Smrg{"+maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "off"},
1097a1f3da82Smrg{"-fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "on"},
1098a1f3da82Smrg{"+fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "off"},
1099956cc18dSsnj#endif
1100d522f475Smrg/* options that we process ourselves */
110120d2c4d2Smrg{"-help",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
110220d2c4d2Smrg{"-version",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
110320d2c4d2Smrg{"-class",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
110420d2c4d2Smrg{"-e",		NULL,		XrmoptionSkipLine,	(XPointer) NULL},
110520d2c4d2Smrg{"-into",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
1106d522f475Smrg/* bogus old compatibility stuff for which there are
1107d522f475Smrg   standard XtOpenApplication options now */
110820d2c4d2Smrg{"%",		"*tekGeometry",	XrmoptionStickyArg,	(XPointer) NULL},
110920d2c4d2Smrg{"#",		".iconGeometry",XrmoptionStickyArg,	(XPointer) NULL},
111020d2c4d2Smrg{"-T",		".title",	XrmoptionSepArg,	(XPointer) NULL},
111120d2c4d2Smrg{"-n",		"*iconName",	XrmoptionSepArg,	(XPointer) NULL},
111220d2c4d2Smrg{"-r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
111320d2c4d2Smrg{"+r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
111420d2c4d2Smrg{"-rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
111520d2c4d2Smrg{"+rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
111620d2c4d2Smrg{"-w",		".borderWidth", XrmoptionSepArg,	(XPointer) NULL},
1117d522f475Smrg};
1118d522f475Smrg
1119d522f475Smrgstatic OptionHelp xtermOptions[] = {
1120d522f475Smrg{ "-version",              "print the version number" },
1121d522f475Smrg{ "-help",                 "print out this message" },
1122d522f475Smrg{ "-display displayname",  "X server to contact" },
1123d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1124d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1125d522f475Smrg{ "-bg color",             "background color" },
1126d522f475Smrg{ "-fg color",             "foreground color" },
1127d522f475Smrg{ "-bd color",             "border color" },
1128d522f475Smrg{ "-bw number",            "border width in pixels" },
1129d522f475Smrg{ "-fn fontname",          "normal text font" },
1130d522f475Smrg{ "-fb fontname",          "bold text font" },
1131d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1132d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1133d522f475Smrg#if OPT_RENDERFONT
1134d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1135d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1136d522f475Smrg{ "-fs size",              "FreeType font-size" },
1137d522f475Smrg#endif
1138d522f475Smrg#if OPT_WIDE_CHARS
1139d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1140d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1141d522f475Smrg#endif
1142d522f475Smrg#if OPT_INPUT_METHOD
1143d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1144d522f475Smrg#endif
1145d522f475Smrg{ "-iconic",               "start iconic" },
1146d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
1147d522f475Smrg{ "-class string",         "class string (XTerm)" },
1148d522f475Smrg{ "-title string",         "title string" },
1149d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1150d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1151d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1152d522f475Smrg#ifndef NO_ACTIVE_ICON
1153d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1154d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1155d522f475Smrg#endif /* NO_ACTIVE_ICON */
1156d522f475Smrg{ "-b number",             "internal border in pixels" },
1157d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1158d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1159d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1160d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1161d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1162d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1163d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1164d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1165d522f475Smrg{ "-cr color",             "text cursor color" },
1166d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1167d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1168d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1169d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1170d522f475Smrg{ "-selbg color",          "selection background color" },
1171d522f475Smrg{ "-selfg color",          "selection foreground color" },
11720bd37d32Smrg/* -hc is deprecated, not shown in help message */
1173d522f475Smrg#endif
1174d522f475Smrg#if OPT_HP_FUNC_KEYS
1175d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1176d522f475Smrg#endif
1177d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1178d522f475Smrg#if OPT_INITIAL_ERASE
1179d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1180d522f475Smrg#endif
1181d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1182d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1183d522f475Smrg#if OPT_C1_PRINT
1184d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1185d522f475Smrg#endif
1186d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1187d522f475Smrg#ifdef ALLOWLOGGING
1188d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1189d522f475Smrg{ "-lf filename",          "logging filename" },
1190d522f475Smrg#else
1191d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1192d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1193d522f475Smrg#endif
1194d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1195d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1196d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1197d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1198d522f475Smrg{ "-ms color",             "pointer color" },
1199d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
1200d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1201d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1202d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1203d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1204d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1205d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1206d522f475Smrg#ifdef SCROLLBAR_RIGHT
1207d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1208d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1209d522f475Smrg#endif
1210d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1211d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1212d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1213d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1214d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1215d522f475Smrg#if OPT_SUNPC_KBD
1216d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1217d522f475Smrg#endif
1218d522f475Smrg#if OPT_TEK4014
1219d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1220d522f475Smrg#endif
1221d522f475Smrg#if OPT_TOOLBAR
1222d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1223d522f475Smrg#endif
1224d522f475Smrg{ "-ti termid",            "terminal identifier" },
1225d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1226d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1227d522f475Smrg#if OPT_WIDE_CHARS
1228d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1229d522f475Smrg#endif
1230d522f475Smrg#if OPT_LUIT_PROG
1231d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1232d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
12330bd37d32Smrg/* -en is deprecated, not shown in help message */
1234d522f475Smrg#endif
12352eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1236d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1237d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1238d522f475Smrg#ifdef HAVE_UTMP
1239d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1240d522f475Smrg#else
1241d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1242d522f475Smrg#endif
1243d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1244d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
1245d522f475Smrg#if OPT_WIDE_CHARS
1246d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1247d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1248d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1249d522f475Smrg#endif
1250d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1251d522f475Smrg{ "-e command args ...",   "command to execute" },
1252d522f475Smrg#if OPT_TEK4014
1253d522f475Smrg{ "%geom",                 "Tek window geometry" },
1254d522f475Smrg#endif
1255d522f475Smrg{ "#geom",                 "icon window geometry" },
1256d522f475Smrg{ "-T string",             "title name for window" },
1257d522f475Smrg{ "-n string",             "icon name for window" },
1258d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1259d522f475Smrg{ "-C",                    "intercept console messages" },
1260d522f475Smrg#else
1261d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1262d522f475Smrg#endif
1263d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1264d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1265d522f475Smrg#if OPT_ZICONBEEP
1266d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1267d522f475Smrg#endif
1268d522f475Smrg#if OPT_SAME_NAME
1269d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1270d522f475Smrg#endif
1271d522f475Smrg#if OPT_SESSION_MGT
1272d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1273d522f475Smrg#endif
1274956cc18dSsnj#if OPT_MAXIMIZE
1275956cc18dSsnj{"-/+maximized",           "turn on/off maxmize on startup" },
1276a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1277956cc18dSsnj#endif
1278d522f475Smrg{ NULL, NULL }};
1279d522f475Smrg/* *INDENT-ON* */
1280d522f475Smrg
128120d2c4d2Smrgstatic const char *message[] =
1282d522f475Smrg{
1283d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1284d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1285d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1286d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1287d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
1288d522f475Smrg    NULL};
1289d522f475Smrg
1290d522f475Smrg/*
1291d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1292d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1293d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1294d522f475Smrg */
1295d522f475Smrgstatic int
1296d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1297d522f475Smrg{
1298d522f475Smrg    char *string = *ptr;
1299d522f475Smrg    int value = -1;
1300d522f475Smrg
130120d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1302d522f475Smrg    if (*string == '^') {
1303d522f475Smrg	switch (*++string) {
1304d522f475Smrg	case '?':
1305d522f475Smrg	    value = A2E(ANSI_DEL);
1306d522f475Smrg	    break;
1307d522f475Smrg	case '-':
1308d522f475Smrg	    if (!termcap) {
1309d522f475Smrg		errno = 0;
1310d522f475Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
1311d522f475Smrg		value = _POSIX_VDISABLE;
1312d522f475Smrg#endif
1313d522f475Smrg#if defined(_PC_VDISABLE)
1314d522f475Smrg		if (value == -1) {
131520d2c4d2Smrg		    value = (int) fpathconf(0, _PC_VDISABLE);
1316d522f475Smrg		    if (value == -1) {
1317d522f475Smrg			if (errno != 0)
1318d522f475Smrg			    break;	/* skip this (error) */
1319d522f475Smrg			value = 0377;
1320d522f475Smrg		    }
1321d522f475Smrg		}
1322d522f475Smrg#elif defined(VDISABLE)
1323d522f475Smrg		if (value == -1)
1324d522f475Smrg		    value = VDISABLE;
1325d522f475Smrg#endif
1326d522f475Smrg		break;
1327d522f475Smrg	    }
1328d522f475Smrg	    /* FALLTHRU */
1329d522f475Smrg	default:
1330d522f475Smrg	    value = CONTROL(*string);
1331d522f475Smrg	    break;
1332d522f475Smrg	}
1333d522f475Smrg	++string;
1334d522f475Smrg    } else if (termcap && (*string == '\\')) {
1335d522f475Smrg	char *d;
133620d2c4d2Smrg	int temp = (int) strtol(string + 1, &d, 8);
1337d522f475Smrg	if (temp > 0 && d != string) {
1338d522f475Smrg	    value = temp;
1339d522f475Smrg	    string = d;
1340d522f475Smrg	}
1341d522f475Smrg    } else {
1342d522f475Smrg	value = CharOf(*string);
1343d522f475Smrg	++string;
1344d522f475Smrg    }
1345d522f475Smrg    *ptr = string;
134620d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1347d522f475Smrg    return value;
1348d522f475Smrg}
1349d522f475Smrg
1350d522f475Smrgstatic int
13510bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
13520bd37d32Smrg{
13530bd37d32Smrg    int result = -1;
13540bd37d32Smrg    int n;
13550bd37d32Smrg    int ch;
13560bd37d32Smrg
13570bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
13580bd37d32Smrg	if (param[n] == ch) {
13590bd37d32Smrg	    result = n;
13600bd37d32Smrg	} else {
13610bd37d32Smrg	    if (param[n] != '\0')
13620bd37d32Smrg		result = -1;
13630bd37d32Smrg	    break;
13640bd37d32Smrg	}
13650bd37d32Smrg    }
13660bd37d32Smrg
13670bd37d32Smrg    return result;
13680bd37d32Smrg}
13690bd37d32Smrg
13700bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
13710bd37d32Smrgstatic int
13720bd37d32SmrgcountArg(XrmOptionDescRec * item)
1373d522f475Smrg{
13740bd37d32Smrg    int result = 0;
13750bd37d32Smrg
13760bd37d32Smrg    switch (item->argKind) {
13770bd37d32Smrg    case XrmoptionNoArg:
13780bd37d32Smrg	/* FALLTHRU */
13790bd37d32Smrg    case XrmoptionIsArg:
13800bd37d32Smrg	/* FALLTHRU */
13810bd37d32Smrg    case XrmoptionStickyArg:
13820bd37d32Smrg	break;
13830bd37d32Smrg    case XrmoptionSepArg:
13840bd37d32Smrg	/* FALLTHRU */
13850bd37d32Smrg    case XrmoptionResArg:
13860bd37d32Smrg	/* FALLTHRU */
13870bd37d32Smrg    case XrmoptionSkipArg:
13880bd37d32Smrg	result = 1;
13890bd37d32Smrg	break;
13900bd37d32Smrg    case XrmoptionSkipLine:
13910bd37d32Smrg	break;
13920bd37d32Smrg    case XrmoptionSkipNArgs:
13930bd37d32Smrg	result = (int) (long) (item->value);
13940bd37d32Smrg	break;
13950bd37d32Smrg    }
13960bd37d32Smrg    return result;
13970bd37d32Smrg}
13980bd37d32Smrg
13990bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
14000bd37d32Smrg
14010bd37d32Smrg/*
14020bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
14030bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
14040bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
14050bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
14060bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
14070bd37d32Smrg * standard table (something that the X libraries should do).
14080bd37d32Smrg */
14090bd37d32Smrgstatic XrmOptionDescRec *
14100bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
14110bd37d32Smrg{
14120bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
14130bd37d32Smrg    /* *INDENT-OFF* */
14140bd37d32Smrg#define DATA(option,kind) { option, NULL, kind, (XtPointer) NULL }
14150bd37d32Smrg    static XrmOptionDescRec opTable[] = {
14160bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
14170bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
14180bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
14190bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
14200bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
14210bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
14220bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
14230bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
14240bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
14250bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
14260bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
14270bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
14280bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
14290bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
14300bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
14310bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
14320bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
14330bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
14340bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
14350bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
14360bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
14370bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
14380bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
14390bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
14400bd37d32Smrg#endif /* TIOCCONS */
14410bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
14420bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
14430bd37d32Smrg    };
14440bd37d32Smrg#undef DATA
14450bd37d32Smrg    /* *INDENT-ON* */
14460bd37d32Smrg
14470bd37d32Smrg    XrmOptionDescRec *result = 0;
14480bd37d32Smrg    Cardinal inlist;
14490bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
14500bd37d32Smrg    int atbest = -1;
14510bd37d32Smrg    int best = -1;
14520bd37d32Smrg    int test;
14530bd37d32Smrg    Boolean exact = False;
14540bd37d32Smrg    int ambiguous1 = -1;
14550bd37d32Smrg    int ambiguous2 = -1;
14560bd37d32Smrg    char *option;
14570bd37d32Smrg    char *value;
14580bd37d32Smrg
14590bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
14600bd37d32Smrg		 ? &optionDescList[n] \
14610bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
14620bd37d32Smrg
14630bd37d32Smrg    if ((option = argv[*num]) != 0) {
14640bd37d32Smrg	Boolean need_value;
14650bd37d32Smrg	Boolean have_value = False;
14660bd37d32Smrg
14670bd37d32Smrg	TRACE(("parseArg %s\n", option));
14680bd37d32Smrg	if ((value = argv[(*num) + 1]) != 0) {
14690bd37d32Smrg	    have_value = (Boolean) ! isOption(value);
14700bd37d32Smrg	}
14710bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
14720bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
14730bd37d32Smrg
14740bd37d32Smrg	    test = matchArg(check, option);
14750bd37d32Smrg	    if (test < 0)
14760bd37d32Smrg		continue;
14770bd37d32Smrg
14780bd37d32Smrg	    /* check for exact match */
14790bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
14800bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
14810bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
14820bd37d32Smrg			exact = True;
14830bd37d32Smrg			atbest = (int) inlist;
14840bd37d32Smrg			break;
14850bd37d32Smrg		    }
14860bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
14870bd37d32Smrg		    exact = True;
14880bd37d32Smrg		    atbest = (int) inlist;
14890bd37d32Smrg		    break;
14900bd37d32Smrg		}
14910bd37d32Smrg	    }
14920bd37d32Smrg
14930bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
14940bd37d32Smrg
14950bd37d32Smrg	    if (need_value && value != 0) {
14960bd37d32Smrg		;
14970bd37d32Smrg	    } else if (need_value ^ have_value) {
14980bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
14990bd37d32Smrg		continue;
15000bd37d32Smrg	    }
15010bd37d32Smrg
15020bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
15030bd37d32Smrg	    if (test > 0
15040bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
15050bd37d32Smrg		atbest = (int) inlist;
15060bd37d32Smrg		break;
15070bd37d32Smrg	    }
15080bd37d32Smrg	    if (test > best) {
15090bd37d32Smrg		best = test;
15100bd37d32Smrg		atbest = (int) inlist;
15110bd37d32Smrg	    } else if (test == best) {
15120bd37d32Smrg		if (atbest >= 0) {
15130bd37d32Smrg		    if (atbest > 0) {
15140bd37d32Smrg			ambiguous1 = (int) inlist;
15150bd37d32Smrg			ambiguous2 = (int) atbest;
15160bd37d32Smrg		    }
15170bd37d32Smrg		    atbest = -1;
15180bd37d32Smrg		}
15190bd37d32Smrg	    }
15200bd37d32Smrg	}
15210bd37d32Smrg    }
15220bd37d32Smrg
15230bd37d32Smrg    *valuep = 0;
15240bd37d32Smrg    if (atbest >= 0) {
15250bd37d32Smrg	result = ITEM(atbest);
15260bd37d32Smrg	if (!exact) {
15270bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
15280bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
15290bd37d32Smrg			     ITEM(ambiguous1)->option,
15300bd37d32Smrg			     ITEM(ambiguous2)->option);
15310bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
15320bd37d32Smrg		result = 0;
15330bd37d32Smrg	    }
15340bd37d32Smrg	}
15350bd37d32Smrg	if (result != 0) {
15360bd37d32Smrg	    TRACE(("...result %s\n", result->option));
15370bd37d32Smrg	    /* expand abbreviations */
15380bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
15390bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
15400bd37d32Smrg		    argv[*num] = x_strdup(result->option);
15410bd37d32Smrg		}
15420bd37d32Smrg	    }
15430bd37d32Smrg
15440bd37d32Smrg	    /* adjust (*num) to skip option value */
15450bd37d32Smrg	    (*num) += countArg(result);
15460bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
15470bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
15480bd37d32Smrg		*valuep = argv[*num];
15490bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
15500bd37d32Smrg	    }
15510bd37d32Smrg	}
15520bd37d32Smrg    }
15530bd37d32Smrg#undef ITEM
15540bd37d32Smrg    return result;
1555d522f475Smrg}
1556d522f475Smrg
1557d522f475Smrgstatic void
1558d522f475SmrgSyntax(char *badOption)
1559d522f475Smrg{
1560d522f475Smrg    OptionHelp *opt;
1561d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1562d522f475Smrg    int col;
1563d522f475Smrg
15640bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
15650bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1566d522f475Smrg
1567d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1568956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1569d522f475Smrg    for (opt = list; opt->opt; opt++) {
1570956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1571d522f475Smrg	if (col + len > 79) {
1572d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1573d522f475Smrg	    col = 3;
1574d522f475Smrg	}
1575d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1576d522f475Smrg	col += len;
1577d522f475Smrg    }
1578d522f475Smrg
1579d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1580d522f475Smrg	    ProgramName);
1581d522f475Smrg    exit(1);
1582d522f475Smrg}
1583d522f475Smrg
1584d522f475Smrgstatic void
1585d522f475SmrgVersion(void)
1586d522f475Smrg{
1587d522f475Smrg    printf("%s\n", xtermVersion());
1588d522f475Smrg    fflush(stdout);
1589d522f475Smrg}
1590d522f475Smrg
1591d522f475Smrgstatic void
1592d522f475SmrgHelp(void)
1593d522f475Smrg{
1594d522f475Smrg    OptionHelp *opt;
1595d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
159620d2c4d2Smrg    const char **cpp;
1597d522f475Smrg
1598d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1599d522f475Smrg	   xtermVersion(), ProgramName);
1600d522f475Smrg    printf("where options include:\n");
1601d522f475Smrg    for (opt = list; opt->opt; opt++) {
1602d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1603d522f475Smrg    }
1604d522f475Smrg
1605d522f475Smrg    putchar('\n');
1606d522f475Smrg    for (cpp = message; *cpp; cpp++)
1607d522f475Smrg	puts(*cpp);
1608d522f475Smrg    putchar('\n');
1609d522f475Smrg    fflush(stdout);
1610d522f475Smrg}
1611d522f475Smrg
1612d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1613d522f475Smrg/* ARGSUSED */
1614d522f475Smrgstatic Boolean
1615d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1616d522f475Smrg			Atom * selection GCC_UNUSED,
1617d522f475Smrg			Atom * target GCC_UNUSED,
1618d522f475Smrg			Atom * type GCC_UNUSED,
1619d522f475Smrg			XtPointer *value GCC_UNUSED,
1620d522f475Smrg			unsigned long *length GCC_UNUSED,
1621d522f475Smrg			int *format GCC_UNUSED)
1622d522f475Smrg{
1623d522f475Smrg    /* we don't save console output, so can't offer it */
1624d522f475Smrg    return False;
1625d522f475Smrg}
1626d522f475Smrg#endif /* TIOCCONS */
1627d522f475Smrg
1628d522f475Smrg/*
1629d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1630d522f475Smrg */
1631d522f475Smrg/* ARGSUSED */
1632d522f475Smrgstatic void
1633d522f475SmrgDeleteWindow(Widget w,
1634d522f475Smrg	     XEvent * event GCC_UNUSED,
1635d522f475Smrg	     String * params GCC_UNUSED,
1636d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1637d522f475Smrg{
1638d522f475Smrg#if OPT_TEK4014
1639d522f475Smrg    if (w == toplevel) {
1640d522f475Smrg	if (TEK4014_SHOWN(term))
1641d522f475Smrg	    hide_vt_window();
1642d522f475Smrg	else
1643d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
164420d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1645d522f475Smrg	hide_tek_window();
1646d522f475Smrg    else
1647d522f475Smrg#endif
1648d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1649d522f475Smrg}
1650d522f475Smrg
1651d522f475Smrg/* ARGSUSED */
1652d522f475Smrgstatic void
1653d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1654d522f475Smrg		XEvent * event,
1655d522f475Smrg		String * params GCC_UNUSED,
1656d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1657d522f475Smrg{
1658d522f475Smrg    switch (event->type) {
1659d522f475Smrg    case MappingNotify:
1660d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1661d522f475Smrg	break;
1662d522f475Smrg    }
1663d522f475Smrg}
1664d522f475Smrg
1665d522f475Smrgstatic XtActionsRec actionProcs[] =
1666d522f475Smrg{
1667d522f475Smrg    {"DeleteWindow", DeleteWindow},
1668d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1669d522f475Smrg};
1670d522f475Smrg
1671d522f475Smrg/*
1672d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1673d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1674d522f475Smrg * utmp.
1675d522f475Smrg */
1676d522f475Smrgstatic char *
1677d522f475Smrgmy_pty_name(char *device)
1678d522f475Smrg{
1679d522f475Smrg    size_t len = strlen(device);
1680d522f475Smrg    Bool name = False;
1681d522f475Smrg
1682d522f475Smrg    while (len != 0) {
1683d522f475Smrg	int ch = device[len - 1];
1684d522f475Smrg	if (isdigit(ch)) {
1685d522f475Smrg	    len--;
1686d522f475Smrg	} else if (ch == '/') {
1687d522f475Smrg	    if (name)
1688d522f475Smrg		break;
1689d522f475Smrg	    len--;
1690d522f475Smrg	} else if (isalpha(ch)) {
1691d522f475Smrg	    name = True;
1692d522f475Smrg	    len--;
1693d522f475Smrg	} else {
1694d522f475Smrg	    break;
1695d522f475Smrg	}
1696d522f475Smrg    }
1697d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1698d522f475Smrg    return device + len;
1699d522f475Smrg}
1700d522f475Smrg
1701d522f475Smrg/*
1702d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1703d522f475Smrg * last few characters for a utmp identifier.
1704d522f475Smrg */
1705d522f475Smrgstatic char *
1706d522f475Smrgmy_pty_id(char *device)
1707d522f475Smrg{
1708d522f475Smrg    char *name = my_pty_name(device);
1709d522f475Smrg    char *leaf = x_basename(name);
1710d522f475Smrg
1711d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1712956cc18dSsnj	int len = (int) strlen(leaf);
1713d522f475Smrg	if (PTYCHARLEN < len)
1714d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1715d522f475Smrg    }
1716d522f475Smrg    TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
1717d522f475Smrg    return leaf;
1718d522f475Smrg}
1719d522f475Smrg
1720d522f475Smrg/*
1721d522f475Smrg * Set the tty/pty identifier
1722d522f475Smrg */
1723d522f475Smrgstatic void
1724d522f475Smrgset_pty_id(char *device, char *id)
1725d522f475Smrg{
1726d522f475Smrg    char *name = my_pty_name(device);
1727d522f475Smrg    char *leaf = x_basename(name);
1728d522f475Smrg
1729d522f475Smrg    if (name == leaf) {
1730d522f475Smrg	strcpy(my_pty_id(device), id);
1731d522f475Smrg    } else {
1732d522f475Smrg	strcpy(leaf, id);
1733d522f475Smrg    }
1734d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
1735d522f475Smrg}
1736d522f475Smrg
1737d522f475Smrg/*
1738d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
1739d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
1740d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
1741d522f475Smrg * not, fall-thru to the original logic.
1742d522f475Smrg */
1743d522f475Smrgstatic Bool
1744d522f475SmrgParseSccn(char *option)
1745d522f475Smrg{
1746d522f475Smrg    char *leaf = x_basename(option);
1747d522f475Smrg    Bool code = False;
1748d522f475Smrg
1749d522f475Smrg    if (leaf != option) {
1750d522f475Smrg	if (leaf - option > 0
1751d522f475Smrg	    && isdigit(CharOf(*leaf))
1752d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
1753956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
1754d522f475Smrg	    /*
1755d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
1756d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
1757d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
1758d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
1759d522f475Smrg	     */
1760d522f475Smrg	    strncpy(passedPty, option, len);
1761d522f475Smrg	    passedPty[len] = 0;
1762d522f475Smrg	    code = True;
1763d522f475Smrg	}
1764d522f475Smrg    } else {
1765d522f475Smrg	code = (sscanf(option, "%c%c%d",
1766d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
1767d522f475Smrg    }
1768d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
1769d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
1770d522f475Smrg    return code;
1771d522f475Smrg}
1772d522f475Smrg
1773d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
1774d522f475Smrg/*
1775d522f475Smrg * From "man utmp":
1776d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
1777d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
1778d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
1779d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
1780d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
1781d522f475Smrg * ut_time, ut_user and ut_host as well.
1782d522f475Smrg *
1783d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
1784d522f475Smrg * pty implementation allows more than 3 digits.
1785d522f475Smrg */
1786d522f475Smrgstatic char *
1787d522f475Smrgmy_utmp_id(char *device)
1788d522f475Smrg{
1789d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
1790d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
1791d522f475Smrg    static char result[UTIDSIZE + 1];
1792d522f475Smrg
1793d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
1794d522f475Smrg    /*
1795d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
1796d522f475Smrg     * issues, and can use the available space in ut_id differently from the
1797d522f475Smrg     * default convention.
1798d522f475Smrg     *
1799d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
1800d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
1801d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
1802d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
1803d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
1804d522f475Smrg     * last three digits of the device name, regardless of the format of the
1805d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
1806d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
1807d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
1808d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
1809d522f475Smrg     */
1810d522f475Smrg    int len, n;
1811d522f475Smrg
1812d522f475Smrg    len = strlen(device);
1813d522f475Smrg    n = UTIDSIZE;
1814d522f475Smrg    result[n] = '\0';
1815d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
1816d522f475Smrg	result[--n] = device[--len];
1817d522f475Smrg    while (n > 0)
1818d522f475Smrg	result[--n] = '0';
1819d522f475Smrg    result[0] = 'x';
1820d522f475Smrg#else
1821d522f475Smrg    char *name = my_pty_name(device);
1822d522f475Smrg    char *leaf = x_basename(name);
1823d522f475Smrg    size_t len = strlen(leaf);
1824d522f475Smrg
1825d522f475Smrg    if ((UTIDSIZE - 1) < len)
1826d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
1827d522f475Smrg    sprintf(result, "p%s", leaf);
1828d522f475Smrg#endif
1829d522f475Smrg
1830d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
1831d522f475Smrg    return result;
1832d522f475Smrg}
1833d522f475Smrg#endif /* USE_SYSV_UTMP */
1834d522f475Smrg
1835d522f475Smrg#ifdef USE_POSIX_SIGNALS
1836d522f475Smrg
1837d522f475Smrgtypedef void (*sigfunc) (int);
1838d522f475Smrg
1839d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
1840d522f475Smrg   has just been stopped and not actually killed */
1841d522f475Smrg
1842d522f475Smrgstatic sigfunc
1843d522f475Smrgposix_signal(int signo, sigfunc func)
1844d522f475Smrg{
1845d522f475Smrg    struct sigaction act, oact;
1846d522f475Smrg
1847d522f475Smrg    act.sa_handler = func;
1848d522f475Smrg    sigemptyset(&act.sa_mask);
1849d522f475Smrg#ifdef SA_RESTART
1850d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
1851d522f475Smrg#else
1852d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
1853d522f475Smrg#endif
1854d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
1855d522f475Smrg	return (SIG_ERR);
1856d522f475Smrg    return (oact.sa_handler);
1857d522f475Smrg}
1858d522f475Smrg
18590bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
1860d522f475Smrg
1861d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
1862d522f475Smrgstatic void
1863d522f475SmrgdisableSetUid(void)
1864d522f475Smrg{
1865d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
1866d522f475Smrg    if (setuid(save_ruid) == -1) {
18670bd37d32Smrg	xtermWarning("unable to reset uid\n");
1868d522f475Smrg	exit(1);
1869d522f475Smrg    }
1870d522f475Smrg    TRACE_IDS;
1871d522f475Smrg}
1872d522f475Smrg#else
1873d522f475Smrg#define disableSetUid()		/* nothing */
1874d522f475Smrg#endif /* DISABLE_SETUID */
1875d522f475Smrg
1876d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
1877d522f475Smrgstatic void
1878d522f475SmrgdisableSetGid(void)
1879d522f475Smrg{
1880d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
1881d522f475Smrg    if (setegid(save_rgid) == -1) {
18820bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
1883d522f475Smrg	exit(1);
1884d522f475Smrg    }
1885d522f475Smrg    TRACE_IDS;
1886d522f475Smrg}
1887d522f475Smrg#else
1888d522f475Smrg#define disableSetGid()		/* nothing */
1889d522f475Smrg#endif /* DISABLE_SETGID */
1890d522f475Smrg
1891d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
1892d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
1893d522f475Smrgstatic void
1894d522f475SmrgsetEffectiveGroup(gid_t group)
1895d522f475Smrg{
1896d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
1897d522f475Smrg    if (setegid(group) == -1) {
1898d522f475Smrg#ifdef __MVS__
1899d522f475Smrg	if (!(errno == EMVSERR))	/* could happen if _BPX_SHAREAS=REUSE */
1900d522f475Smrg#endif
1901d522f475Smrg	{
19020bd37d32Smrg	    xtermPerror("setegid(%d)", (int) group);
1903d522f475Smrg	}
1904d522f475Smrg    }
1905d522f475Smrg    TRACE_IDS;
1906d522f475Smrg}
1907d522f475Smrg#endif
1908d522f475Smrg
1909d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
1910d522f475Smrgstatic void
1911d522f475SmrgsetEffectiveUser(uid_t user)
1912d522f475Smrg{
1913d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
1914d522f475Smrg    if (seteuid(user) == -1) {
1915d522f475Smrg#ifdef __MVS__
1916d522f475Smrg	if (!(errno == EMVSERR))
1917d522f475Smrg#endif
1918d522f475Smrg	{
19190bd37d32Smrg	    xtermPerror("seteuid(%d)", (int) user);
1920d522f475Smrg	}
1921d522f475Smrg    }
1922d522f475Smrg    TRACE_IDS;
1923d522f475Smrg}
1924d522f475Smrg#endif
1925d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
1926d522f475Smrg
1927d522f475Smrgint
1928d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
1929d522f475Smrg{
1930a1f3da82Smrg#if OPT_MAXIMIZE
1931a1f3da82Smrg#define DATA(name) { #name, es##name }
1932a1f3da82Smrg    static FlagList tblFullscreen[] =
1933a1f3da82Smrg    {
1934a1f3da82Smrg	DATA(Always),
1935a1f3da82Smrg	DATA(Never)
1936a1f3da82Smrg    };
1937a1f3da82Smrg#undef DATA
1938a1f3da82Smrg#endif
1939a1f3da82Smrg
1940d522f475Smrg    Widget form_top, menu_top;
1941d522f475Smrg    Dimension menu_high;
1942d522f475Smrg    TScreen *screen;
1943d522f475Smrg    int mode;
1944d522f475Smrg    char *my_class = DEFCLASS;
1945d522f475Smrg    Window winToEmbedInto = None;
1946d522f475Smrg
1947d522f475Smrg    ProgramName = argv[0];
1948d522f475Smrg
1949d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
1950d522f475Smrg    save_euid = geteuid();
1951d522f475Smrg    save_egid = getegid();
1952d522f475Smrg#endif
1953d522f475Smrg
1954d522f475Smrg    save_ruid = getuid();
1955d522f475Smrg    save_rgid = getgid();
1956d522f475Smrg
1957d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
1958d522f475Smrg#if defined(DISABLE_SETUID)
1959d522f475Smrg    disableSetUid();
1960d522f475Smrg#endif
1961d522f475Smrg#if defined(DISABLE_SETGID)
1962d522f475Smrg    disableSetGid();
1963d522f475Smrg#endif
1964d522f475Smrg    TRACE_IDS;
1965d522f475Smrg#endif
1966d522f475Smrg
1967d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
1968d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
1969d522f475Smrg#ifdef USE_PTY_DEVICE
1970d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
1971d522f475Smrg    if (!ttydev || !ptydev)
1972d522f475Smrg#else
1973d522f475Smrg    if (!ttydev)
1974d522f475Smrg#endif
1975d522f475Smrg    {
19760bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
1977d522f475Smrg	exit(1);
1978d522f475Smrg    }
1979d522f475Smrg    strcpy(ttydev, TTYDEV);
1980d522f475Smrg#ifdef USE_PTY_DEVICE
1981d522f475Smrg    strcpy(ptydev, PTYDEV);
1982d522f475Smrg#endif
1983d522f475Smrg
1984d522f475Smrg#if defined(USE_UTMP_SETGID)
1985d522f475Smrg    get_pty(NULL, NULL);
1986d522f475Smrg    disableSetUid();
1987d522f475Smrg    disableSetGid();
1988d522f475Smrg    TRACE_IDS;
1989d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
1990d522f475Smrg#endif
1991d522f475Smrg
1992d522f475Smrg    /* Do these first, since we may not be able to open the display */
1993d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
1994d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
1995d522f475Smrg    if (argc > 1) {
19960bd37d32Smrg	XrmOptionDescRec *option_ptr;
19970bd37d32Smrg	char *option_value;
1998d522f475Smrg	int n;
1999e39b573cSmrg	Bool quit = False;
2000d522f475Smrg
2001d522f475Smrg	for (n = 1; n < argc; n++) {
20020bd37d32Smrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
20030bd37d32Smrg		if (argv[n] == 0) {
20040bd37d32Smrg		    break;
20050bd37d32Smrg		} else if (isOption(argv[n])) {
20060bd37d32Smrg		    Syntax(argv[n]);
20070bd37d32Smrg		} else if (explicit_shname != 0) {
20080bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
20090bd37d32Smrg		    Syntax(argv[n]);
20100bd37d32Smrg		}
20110bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
20120bd37d32Smrg		if (explicit_shname == 0)
20130bd37d32Smrg		    exit(0);
20140bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
20150bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
20160bd37d32Smrg		command_to_exec = (argv + n + 1);
20170bd37d32Smrg		if (!command_to_exec[0])
20180bd37d32Smrg		    Syntax(argv[n]);
20190bd37d32Smrg		break;
20200bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2021d522f475Smrg		Version();
2022e39b573cSmrg		quit = True;
20230bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2024d522f475Smrg		Help();
2025e39b573cSmrg		quit = True;
20260bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
20270bd37d32Smrg		if ((my_class = x_strdup(option_value)) == 0) {
2028d522f475Smrg		    Help();
2029e39b573cSmrg		    quit = True;
2030d522f475Smrg		}
20310bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
20320bd37d32Smrg		char *endPtr;
20330bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
2034d522f475Smrg	    }
2035d522f475Smrg	}
2036d522f475Smrg	if (quit)
2037d522f475Smrg	    exit(0);
20380bd37d32Smrg	/*
20390bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
20400bd37d32Smrg	 * then give up.
20410bd37d32Smrg	 */
20420bd37d32Smrg	if (n < argc && !command_to_exec) {
20430bd37d32Smrg	    Syntax(argv[n]);
20440bd37d32Smrg	}
2045d522f475Smrg    }
2046d522f475Smrg
20470bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2048d522f475Smrg#if OPT_I18N_SUPPORT
2049d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2050d522f475Smrg#endif
2051d522f475Smrg
2052d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2053d522f475Smrg    /* Initialization is done here rather than above in order
2054d522f475Smrg     * to prevent any assumptions about the order of the contents
2055d522f475Smrg     * of the various terminal structures (which may change from
2056d522f475Smrg     * implementation to implementation).
2057d522f475Smrg     */
2058d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2059d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2060d522f475Smrg#ifdef TAB3
2061d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR | TAB3;
2062d522f475Smrg#else
2063d522f475Smrg#ifdef ONLCR
2064d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR;
2065d522f475Smrg#else
2066d522f475Smrg    d_tio.c_oflag = OPOST;
2067d522f475Smrg#endif
2068d522f475Smrg#endif
2069d522f475Smrg    {
2070d522f475Smrg	Cardinal nn;
2071d522f475Smrg
2072d522f475Smrg	/* fill in default-values */
2073d522f475Smrg	for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2074d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2075d522f475Smrg		d_tio.c_cc[known_ttyChars[nn].sysMode] =
20760bd37d32Smrg		    (cc_t) known_ttyChars[nn].myDefault;
2077d522f475Smrg	    }
2078d522f475Smrg	}
2079d522f475Smrg    }
2080d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
2081d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2082d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2083d522f475Smrg#ifdef ECHOKE
2084d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2085d522f475Smrg#endif
2086d522f475Smrg#ifdef ECHOCTL
2087d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2088d522f475Smrg#endif
2089d522f475Smrg#ifndef USE_TERMIOS		/* { */
2090d522f475Smrg    d_tio.c_line = 0;
2091d522f475Smrg#endif /* } */
2092d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2093d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2094d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2095d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2096d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2097d522f475Smrg    d_ltc.t_werasc = CWERASE;
2098d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2099d522f475Smrg#endif /* } HAS_LTCHARS */
2100d522f475Smrg#ifdef TIOCLSET			/* { */
2101d522f475Smrg    d_lmode = 0;
2102d522f475Smrg#endif /* } TIOCLSET */
2103d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2104d522f475Smrg#ifndef USE_POSIX_TERMIOS
2105d522f475Smrg#ifdef BAUD_0			/* { */
2106d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2107d522f475Smrg#else /* }{ !BAUD_0 */
2108d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2109d522f475Smrg#endif /* } !BAUD_0 */
2110d522f475Smrg#else /* USE_POSIX_TERMIOS */
2111d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2112d522f475Smrg    cfsetispeed(&d_tio, VAL_LINE_SPEED);
2113d522f475Smrg    cfsetospeed(&d_tio, VAL_LINE_SPEED);
2114d522f475Smrg#endif
2115d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2116d522f475Smrg#ifdef ECHOKE
2117d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2118d522f475Smrg#endif
2119d522f475Smrg#ifdef ECHOCTL
2120d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2121d522f475Smrg#endif
2122d522f475Smrg#ifndef USE_POSIX_TERMIOS
2123d522f475Smrg#ifdef NTTYDISC
2124d522f475Smrg    d_tio.c_line = NTTYDISC;
2125d522f475Smrg#else
2126d522f475Smrg    d_tio.c_line = 0;
2127d522f475Smrg#endif
2128d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2129d522f475Smrg#ifdef __sgi
2130d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2131d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2132d522f475Smrg#endif
2133d522f475Smrg#ifdef __MVS__
2134d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2135d522f475Smrg#endif
2136d522f475Smrg    {
2137d522f475Smrg	Cardinal nn;
2138d522f475Smrg	int i;
2139d522f475Smrg
2140d522f475Smrg	/* try to inherit tty settings */
2141d522f475Smrg	for (i = 0; i <= 2; i++) {
2142d522f475Smrg	    TERMIO_STRUCT deftio;
2143d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2144d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2145d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2146d522f475Smrg			d_tio.c_cc[known_ttyChars[nn].sysMode] =
2147d522f475Smrg			    deftio.c_cc[known_ttyChars[nn].sysMode];
2148d522f475Smrg		    }
2149d522f475Smrg		}
2150d522f475Smrg		break;
2151d522f475Smrg	    }
2152d522f475Smrg	}
2153d522f475Smrg    }
2154d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2155d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2156d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2157d522f475Smrg#endif /* } */
2158d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2159d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2160d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2161d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2162d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2163d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2164d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2165d522f475Smrg#endif /* } HAS_LTCHARS */
2166d522f475Smrg
2167d522f475Smrg#ifdef TIOCLSET			/* { */
2168d522f475Smrg    d_lmode = 0;
2169d522f475Smrg#endif /* } TIOCLSET */
2170d522f475Smrg#endif /* } macII, ATT, CRAY */
2171d522f475Smrg#endif /* } TERMIO_STRUCT */
2172d522f475Smrg
2173d522f475Smrg    /* Init the Toolkit. */
2174d522f475Smrg    {
2175d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2176d522f475Smrg	setEffectiveGroup(save_rgid);
2177d522f475Smrg	setEffectiveUser(save_ruid);
2178d522f475Smrg	TRACE_IDS;
2179d522f475Smrg#endif
2180d522f475Smrg
21810bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
21820bd37d32Smrg					my_class,
21830bd37d32Smrg					optionDescList,
21840bd37d32Smrg					XtNumber(optionDescList),
21850bd37d32Smrg					&argc, (String *) argv,
21860bd37d32Smrg					fallback_resources,
21870bd37d32Smrg					sessionShellWidgetClass,
21880bd37d32Smrg					NULL, 0);
2189d522f475Smrg
2190d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2191d522f475Smrg				  application_resources,
2192d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2193d522f475Smrg	TRACE_XRES();
2194a1f3da82Smrg#if OPT_MAXIMIZE
2195a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2196a1f3da82Smrg					      tblFullscreen,
2197a1f3da82Smrg					      XtNumber(tblFullscreen));
2198a1f3da82Smrg#endif
2199e39b573cSmrg	VTInitTranslations();
2200d522f475Smrg#if OPT_PTY_HANDSHAKE
2201d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2202d522f475Smrg#endif
2203d522f475Smrg
2204d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2205d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2206d522f475Smrg#if !defined(DISABLE_SETUID)
2207d522f475Smrg	setEffectiveUser(save_euid);
2208d522f475Smrg#endif
2209d522f475Smrg#if !defined(DISABLE_SETGID)
2210d522f475Smrg	setEffectiveGroup(save_egid);
2211d522f475Smrg#endif
2212d522f475Smrg	TRACE_IDS;
2213d522f475Smrg#endif
2214d522f475Smrg#endif
2215d522f475Smrg    }
2216d522f475Smrg
2217d522f475Smrg    /*
2218d522f475Smrg     * ICCCM delete_window.
2219d522f475Smrg     */
2220d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2221d522f475Smrg
2222d522f475Smrg    /*
2223d522f475Smrg     * fill in terminal modes
2224d522f475Smrg     */
2225d522f475Smrg    if (resource.tty_modes) {
2226d522f475Smrg	int n = parse_tty_modes(resource.tty_modes, ttymodelist);
2227d522f475Smrg	if (n < 0) {
22280bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2229d522f475Smrg	} else if (n > 0) {
2230d522f475Smrg	    override_tty_modes = True;
2231d522f475Smrg	}
2232d522f475Smrg    }
22330bd37d32Smrg    initZIconBeep();
2234d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2235d522f475Smrg    if (resource.icon_geometry != NULL) {
2236d522f475Smrg	int scr, junk;
2237d522f475Smrg	int ix, iy;
2238d522f475Smrg	Arg args[2];
2239d522f475Smrg
2240d522f475Smrg	for (scr = 0;		/* yyuucchh */
2241d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2242d522f475Smrg	     scr++) ;
2243d522f475Smrg
2244d522f475Smrg	args[0].name = XtNiconX;
2245d522f475Smrg	args[1].name = XtNiconY;
2246d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2247d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2248d522f475Smrg	args[0].value = (XtArgVal) ix;
2249d522f475Smrg	args[1].value = (XtArgVal) iy;
2250d522f475Smrg	XtSetValues(toplevel, args, 2);
2251d522f475Smrg    }
2252d522f475Smrg
2253d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2254d522f475Smrg		number_ourTopLevelShellArgs);
2255d522f475Smrg
2256d522f475Smrg#if OPT_WIDE_CHARS
2257d522f475Smrg    /* seems as good a place as any */
2258d522f475Smrg    init_classtab();
2259d522f475Smrg#endif
2260d522f475Smrg
2261d522f475Smrg    /* Parse the rest of the command line */
2262d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2263d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
22640bd37d32Smrg	if (!isOption(*argv)) {
2265d522f475Smrg#ifdef VMS
2266d522f475Smrg	    Syntax(*argv);
2267d522f475Smrg#else
2268d522f475Smrg	    if (argc > 1)
2269d522f475Smrg		Syntax(*argv);
2270d522f475Smrg	    continue;
2271d522f475Smrg#endif
22720bd37d32Smrg	}
2273d522f475Smrg
2274d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2275d522f475Smrg	switch (argv[0][1]) {
2276d522f475Smrg	case 'C':
2277d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2278d522f475Smrg#ifndef __sgi
2279d522f475Smrg	    {
2280d522f475Smrg		struct stat sbuf;
2281d522f475Smrg
2282d522f475Smrg		/* Must be owner and have read/write permission.
2283d522f475Smrg		   xdm cooperates to give the console the right user. */
2284d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2285d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2286d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2287d522f475Smrg		    Console = True;
2288d522f475Smrg		} else
2289d522f475Smrg		    Console = False;
2290d522f475Smrg	    }
2291d522f475Smrg#else /* __sgi */
2292d522f475Smrg	    Console = True;
2293d522f475Smrg#endif /* __sgi */
2294d522f475Smrg#endif /* TIOCCONS */
2295d522f475Smrg	    continue;
2296d522f475Smrg	case 'S':
2297d522f475Smrg	    if (!ParseSccn(*argv + 2))
2298d522f475Smrg		Syntax(*argv);
2299d522f475Smrg	    continue;
2300d522f475Smrg#ifdef DEBUG
2301d522f475Smrg	case 'D':
2302d522f475Smrg	    debug = True;
2303d522f475Smrg	    continue;
2304d522f475Smrg#endif /* DEBUG */
23050bd37d32Smrg	case 'c':
23060bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2307d522f475Smrg		Syntax(*argv);
23080bd37d32Smrg	    argc--, argv++;
2309d522f475Smrg	    continue;
2310d522f475Smrg	case 'e':
23110bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2312d522f475Smrg		Syntax(*argv);
23130bd37d32Smrg	    command_to_exec = (argv + 1);
2314d522f475Smrg	    break;
2315d522f475Smrg	case 'i':
23160bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2317d522f475Smrg		Syntax(*argv);
23180bd37d32Smrg	    argc--, argv++;
2319d522f475Smrg	    continue;
2320d522f475Smrg
2321d522f475Smrg	default:
2322d522f475Smrg	    Syntax(*argv);
2323d522f475Smrg	}
2324d522f475Smrg	break;
2325d522f475Smrg    }
2326d522f475Smrg
2327d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2328d522f475Smrg
2329d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2330d522f475Smrg						 form_top,
2331d522f475Smrg#if OPT_TOOLBAR
2332d522f475Smrg						 XtNmenuBar, menu_top,
2333d522f475Smrg						 XtNresizable, True,
2334d522f475Smrg						 XtNfromVert, menu_top,
2335d522f475Smrg						 XtNleft, XawChainLeft,
2336d522f475Smrg						 XtNright, XawChainRight,
2337d522f475Smrg						 XtNtop, XawChainTop,
2338d522f475Smrg						 XtNbottom, XawChainBottom,
2339d522f475Smrg						 XtNmenuHeight, menu_high,
2340d522f475Smrg#endif
2341d522f475Smrg						 (XtPointer) 0);
2342d522f475Smrg    decode_keyboard_type(term, &resource);
2343d522f475Smrg
2344d522f475Smrg    screen = TScreenOf(term);
2345d522f475Smrg    screen->inhibit = 0;
2346d522f475Smrg
2347d522f475Smrg#ifdef ALLOWLOGGING
2348d522f475Smrg    if (term->misc.logInhibit)
2349d522f475Smrg	screen->inhibit |= I_LOG;
2350d522f475Smrg#endif
2351d522f475Smrg    if (term->misc.signalInhibit)
2352d522f475Smrg	screen->inhibit |= I_SIGNAL;
2353d522f475Smrg#if OPT_TEK4014
2354d522f475Smrg    if (term->misc.tekInhibit)
2355d522f475Smrg	screen->inhibit |= I_TEK;
2356d522f475Smrg#endif
2357d522f475Smrg
2358d522f475Smrg    /*
2359d522f475Smrg     * We might start by showing the tek4014 window.
2360d522f475Smrg     */
2361d522f475Smrg#if OPT_TEK4014
2362d522f475Smrg    if (screen->inhibit & I_TEK)
2363d522f475Smrg	TEK4014_ACTIVE(term) = False;
2364d522f475Smrg
2365d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2366d522f475Smrg	SysError(ERROR_INIT);
2367d522f475Smrg#endif
2368d522f475Smrg
2369d522f475Smrg    /*
2370d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2371d522f475Smrg     */
2372d522f475Smrg#if OPT_TOOLBAR
2373d522f475Smrg    ShowToolbar(resource.toolBar);
2374d522f475Smrg#endif
2375d522f475Smrg
23760bd37d32Smrg    xtermOpenSession();
2377d522f475Smrg
2378d522f475Smrg    /*
2379d522f475Smrg     * Set title and icon name if not specified
2380d522f475Smrg     */
2381d522f475Smrg    if (command_to_exec) {
2382d522f475Smrg	Arg args[2];
2383d522f475Smrg
2384d522f475Smrg	if (!resource.title) {
2385d522f475Smrg	    if (command_to_exec) {
2386d522f475Smrg		resource.title = x_basename(command_to_exec[0]);
2387d522f475Smrg	    }			/* else not reached */
2388d522f475Smrg	}
2389d522f475Smrg
2390d522f475Smrg	if (!resource.icon_name)
2391d522f475Smrg	    resource.icon_name = resource.title;
2392d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2393d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2394d522f475Smrg
23950bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2396d522f475Smrg	       resource.title,
2397d522f475Smrg	       resource.icon_name,
23980bd37d32Smrg	       NonNull(resource.icon_hint),
2399d522f475Smrg	       *command_to_exec));
2400d522f475Smrg
2401d522f475Smrg	XtSetValues(toplevel, args, 2);
2402d522f475Smrg    }
2403d522f475Smrg#if OPT_LUIT_PROG
2404d522f475Smrg    if (term->misc.callfilter) {
24050bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
24060bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
24070bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
24080bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
24090bd37d32Smrg
24100bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
24110bd37d32Smrg						  (count_split
24120bd37d32Smrg						   + count_exec
24130bd37d32Smrg						   + count_using
24140bd37d32Smrg						   + 8));
24150bd37d32Smrg	if (command_to_exec_with_luit == NULL)
24160bd37d32Smrg	    SysError(ERROR_LUMALLOC);
24170bd37d32Smrg
24180bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
24190bd37d32Smrg	if (count_using) {
24200bd37d32Smrg	    char *encoding_opt[4];
24210bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
24220bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
24230bd37d32Smrg	    encoding_opt[2] = 0;
24240bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
24250bd37d32Smrg	}
24260bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
24270bd37d32Smrg	if (count_exec) {
24280bd37d32Smrg	    char *delimiter[2];
24290bd37d32Smrg	    delimiter[0] = x_strdup("--");
24300bd37d32Smrg	    delimiter[1] = 0;
24310bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
24320bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2433d522f475Smrg	}
24340bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
24350bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2436d522f475Smrg    }
2437d522f475Smrg#endif
2438d522f475Smrg
24390bd37d32Smrg    if_DEBUG({
2440d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2441d522f475Smrg	   done securely by a privileged xterm process (although we try),
2442d522f475Smrg	   so the debug feature is disabled by default. */
2443e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2444d522f475Smrg	int i = -1;
24450bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
24460bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
24470bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2448d522f475Smrg	}
2449d522f475Smrg	if (i >= 0) {
2450d522f475Smrg	    dup2(i, 2);
2451d522f475Smrg
2452d522f475Smrg	    /* mark this file as close on exec */
2453d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2454d522f475Smrg	}
24550bd37d32Smrg    });
2456d522f475Smrg
2457d522f475Smrg    spawnXTerm(term);
2458d522f475Smrg
2459d522f475Smrg#ifndef VMS
2460d522f475Smrg    /* Child process is out there, let's catch its termination */
2461d522f475Smrg
2462d522f475Smrg#ifdef USE_POSIX_SIGNALS
2463d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2464d522f475Smrg#else
2465d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2466d522f475Smrg#endif
2467d522f475Smrg    /* Realize procs have now been executed */
2468d522f475Smrg
2469d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2470d522f475Smrg	char buf[80];
2471d522f475Smrg
2472d522f475Smrg	buf[0] = '\0';
2473d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
247420d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2475d522f475Smrg    }
2476d522f475Smrg#ifdef AIXV3
2477d522f475Smrg#if (OSMAJORVERSION < 4)
2478d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2479d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2480d522f475Smrg     * to the slave-pty process when xterm exits.
2481d522f475Smrg     */
2482d522f475Smrg
2483d522f475Smrg    {
2484d522f475Smrg	TERMIO_STRUCT tio;
2485d522f475Smrg
2486d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
2487d522f475Smrg	    SysError(ERROR_TIOCGETP);
2488d522f475Smrg
2489d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
2490d522f475Smrg
2491d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
2492d522f475Smrg	    SysError(ERROR_TIOCSETP);
2493d522f475Smrg    }
2494d522f475Smrg#endif
2495d522f475Smrg#endif
2496d522f475Smrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__)
2497d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
2498d522f475Smrg	SysError(ERROR_F_GETFL);
2499d522f475Smrg#ifdef O_NDELAY
2500d522f475Smrg    mode |= O_NDELAY;
2501d522f475Smrg#else
2502d522f475Smrg    mode |= O_NONBLOCK;
2503d522f475Smrg#endif /* O_NDELAY */
2504d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
2505d522f475Smrg	SysError(ERROR_F_SETFL);
2506d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
2507d522f475Smrg    mode = 1;
2508d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
2509d522f475Smrg	SysError(ERROR_FIONBIO);
2510d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
2511d522f475Smrg
2512d522f475Smrg    /* The erase character is used to delete the current completion */
2513d522f475Smrg#if OPT_DABBREV
2514d522f475Smrg#ifdef TERMIO_STRUCT
2515d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
2516d522f475Smrg#else
2517d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
2518d522f475Smrg#endif
2519d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
2520d522f475Smrg#endif
2521d522f475Smrg
2522d522f475Smrg    FD_ZERO(&pty_mask);
2523d522f475Smrg    FD_ZERO(&X_mask);
2524d522f475Smrg    FD_ZERO(&Select_mask);
2525d522f475Smrg    FD_SET(screen->respond, &pty_mask);
2526d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
2527d522f475Smrg    FD_SET(screen->respond, &Select_mask);
2528d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
2529d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
2530d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
2531d522f475Smrg		 : (1 + screen->respond));
2532d522f475Smrg
2533d522f475Smrg#endif /* !VMS */
25340bd37d32Smrg    if_DEBUG({
25350bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
25360bd37d32Smrg    });
2537d522f475Smrg    XSetErrorHandler(xerror);
2538d522f475Smrg    XSetIOErrorHandler(xioerror);
2539e39b573cSmrg    IceSetIOErrorHandler(ice_error);
2540d522f475Smrg
2541d522f475Smrg    initPtyData(&VTbuffer);
2542d522f475Smrg#ifdef ALLOWLOGGING
2543d522f475Smrg    if (term->misc.log_on) {
254420d2c4d2Smrg	StartLog(term);
2545d522f475Smrg    }
2546d522f475Smrg#endif
2547d522f475Smrg
25480bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
2549d522f475Smrg#if OPT_COLOR_RES
2550a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
2551a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
255220d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
255320d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2554d522f475Smrg
2555a1f3da82Smrg    if (term->misc.re_verse0) {
2556a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
2557a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
2558a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
2559a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
2560a1f3da82Smrg	} else {
2561a1f3da82Smrg	    ReverseVideo(term);
2562a1f3da82Smrg	}
2563a1f3da82Smrg	term->misc.re_verse = True;
2564a1f3da82Smrg	update_reversevideo();
2565a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
2566a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
2567a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
2568a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2569a1f3da82Smrg    }
2570d522f475Smrg#endif /* OPT_COLOR_RES */
2571d522f475Smrg
2572956cc18dSsnj#if OPT_MAXIMIZE
2573956cc18dSsnj    if (resource.maximized)
2574956cc18dSsnj	RequestMaximize(term, True);
2575956cc18dSsnj#endif
2576d522f475Smrg    for (;;) {
2577d522f475Smrg#if OPT_TEK4014
2578d522f475Smrg	if (TEK4014_ACTIVE(term))
2579d522f475Smrg	    TekRun();
2580d522f475Smrg	else
2581d522f475Smrg#endif
2582956cc18dSsnj	    VTRun(term);
2583d522f475Smrg    }
2584d522f475Smrg}
2585d522f475Smrg
2586956cc18dSsnj#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2587d522f475Smrg#define USE_OPENPTY 1
2588d522f475Smrgstatic int opened_tty = -1;
2589d522f475Smrg#endif
2590d522f475Smrg
2591d522f475Smrg/*
2592d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
2593d522f475Smrg *
2594d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
2595d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
2596d522f475Smrg * so that if a pty master is found and later, we find that the slave
2597d522f475Smrg * has problems, we can re-enter this function and get another one.
2598d522f475Smrg */
2599d522f475Smrgstatic int
2600d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
2601d522f475Smrg{
2602d522f475Smrg    int result = 1;
2603d522f475Smrg
26040bd37d32Smrg#if defined(USE_OPENPTY)
26050bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
26060bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
26070bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
26080bd37d32Smrg	char *name = ptsname(*pty);
26090bd37d32Smrg	if (name != 0) {
26100bd37d32Smrg	    strcpy(ttydev, name);
26110bd37d32Smrg	    result = 0;
26120bd37d32Smrg	}
26130bd37d32Smrg    }
26140bd37d32Smrg#ifdef USE_PTY_SEARCH
26150bd37d32Smrg    if (result) {
26160bd37d32Smrg	result = pty_search(pty);
26170bd37d32Smrg    }
26180bd37d32Smrg#endif
26190bd37d32Smrg#elif defined(PUCC_PTYD)
2620d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
2621d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
2622d522f475Smrg			       save_ruid, from)) < 0);
2623d522f475Smrg#elif defined(__QNXNTO__)
2624d522f475Smrg    result = pty_search(pty);
2625d522f475Smrg#else
2626d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
2627d522f475Smrg#ifdef __GLIBC__		/* if __GLIBC__ and USE_USG_PTYS, we know glibc >= 2.1 */
2628d522f475Smrg    /* GNU libc 2 allows us to abstract away from having to know the
2629d522f475Smrg       master pty device name. */
2630d522f475Smrg    if ((*pty = getpt()) >= 0) {
2631d522f475Smrg	char *name = ptsname(*pty);
2632d522f475Smrg	if (name != 0) {	/* if filesystem is trashed, this may be null */
2633d522f475Smrg	    strcpy(ttydev, name);
2634d522f475Smrg	    result = 0;
2635d522f475Smrg	}
2636d522f475Smrg    }
2637d522f475Smrg#elif defined(__MVS__)
2638d522f475Smrg    result = pty_search(pty);
2639d522f475Smrg#else
26400bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
2641d522f475Smrg#endif
26420bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
26430bd37d32Smrg    if (!result)
26440bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
2645d522f475Smrg#endif
2646d522f475Smrg
2647d522f475Smrg#elif defined(AIXV3)
2648d522f475Smrg
2649d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
2650d522f475Smrg	strcpy(ttydev, ttyname(*pty));
2651d522f475Smrg	result = 0;
2652d522f475Smrg    }
2653d522f475Smrg#elif defined(__convex__)
2654d522f475Smrg
2655d522f475Smrg    char *pty_name;
2656d522f475Smrg    extern char *getpty(void);
2657d522f475Smrg
2658d522f475Smrg    while ((pty_name = getpty()) != NULL) {
2659d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
2660d522f475Smrg	    strcpy(ptydev, pty_name);
2661d522f475Smrg	    strcpy(ttydev, pty_name);
2662d522f475Smrg	    *x_basename(ttydev) = 't';
2663d522f475Smrg	    result = 0;
2664d522f475Smrg	    break;
2665d522f475Smrg	}
2666d522f475Smrg    }
2667d522f475Smrg
2668d522f475Smrg#elif defined(sequent)
2669d522f475Smrg
2670d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
2671d522f475Smrg
2672d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
2673d522f475Smrg
2674d522f475Smrg    char *tty_name;
2675d522f475Smrg
2676d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
2677d522f475Smrg    if (tty_name != 0) {
2678d522f475Smrg	strcpy(ttydev, tty_name);
2679d522f475Smrg	result = 0;
2680d522f475Smrg    }
2681d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
2682d522f475Smrg
2683d522f475Smrg    struct stat fstat_buf;
2684d522f475Smrg
2685d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
2686d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
2687d522f475Smrg	result = 0;
2688d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
2689d522f475Smrg    }
2690d522f475Smrg#elif defined(__hpux)
2691d522f475Smrg
2692d522f475Smrg    /*
2693d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
2694d522f475Smrg     */
2695d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
2696d522f475Smrg	char *name = ptsname(*pty);
2697d522f475Smrg	if (name != 0) {
2698d522f475Smrg	    strcpy(ttydev, name);
2699d522f475Smrg	    result = 0;
2700d522f475Smrg	} else {		/* permissions, or other unexpected problem */
2701d522f475Smrg	    close(*pty);
2702d522f475Smrg	    *pty = -1;
2703d522f475Smrg	    result = pty_search(pty);
2704d522f475Smrg	}
2705d522f475Smrg    } else {
2706d522f475Smrg	result = pty_search(pty);
2707d522f475Smrg    }
2708d522f475Smrg
2709d522f475Smrg#else
2710d522f475Smrg
2711d522f475Smrg    result = pty_search(pty);
2712d522f475Smrg
2713d522f475Smrg#endif
2714d522f475Smrg#endif
2715d522f475Smrg
2716d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
2717d522f475Smrg	   ttydev != 0 ? ttydev : "?",
2718d522f475Smrg	   ptydev != 0 ? ptydev : "?",
2719d522f475Smrg	   result ? "FAIL" : "OK",
2720d522f475Smrg	   pty != 0 ? *pty : -1));
2721d522f475Smrg    return result;
2722d522f475Smrg}
2723d522f475Smrg
2724d522f475Smrgstatic void
2725d522f475Smrgset_pty_permissions(uid_t uid, gid_t gid, mode_t mode)
2726d522f475Smrg{
2727d522f475Smrg#ifdef USE_TTY_GROUP
2728d522f475Smrg    struct group *ttygrp;
2729d522f475Smrg
2730d522f475Smrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
2731d522f475Smrg	gid = ttygrp->gr_gid;
2732d522f475Smrg	mode &= 0660U;
2733d522f475Smrg    }
2734d522f475Smrg    endgrent();
2735d522f475Smrg#endif /* USE_TTY_GROUP */
2736d522f475Smrg
2737d522f475Smrg    TRACE_IDS;
2738d522f475Smrg    set_owner(ttydev, uid, gid, mode);
2739d522f475Smrg}
2740d522f475Smrg
2741d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
2742d522f475Smrg#undef get_pty
2743d522f475Smrg/*
2744d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
2745d522f475Smrg * result.
2746d522f475Smrg */
2747d522f475Smrgstatic int
2748d522f475Smrgget_pty(int *pty, char *from)
2749d522f475Smrg{
2750d522f475Smrg    static int m_pty = -1;
2751d522f475Smrg    int result = -1;
2752d522f475Smrg
2753d522f475Smrg    if (pty == NULL) {
2754d522f475Smrg	result = really_get_pty(&m_pty, from);
2755d522f475Smrg
2756d522f475Smrg	seteuid(0);
2757d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
2758d522f475Smrg	seteuid(save_ruid);
2759d522f475Smrg	TRACE_IDS;
2760d522f475Smrg
2761d522f475Smrg#ifdef USE_OPENPTY
2762d522f475Smrg	if (opened_tty >= 0) {
2763d522f475Smrg	    close(opened_tty);
2764d522f475Smrg	    opened_tty = -1;
2765d522f475Smrg	}
2766d522f475Smrg#endif
2767d522f475Smrg    } else if (m_pty != -1) {
2768d522f475Smrg	*pty = m_pty;
2769d522f475Smrg	result = 0;
2770d522f475Smrg    } else {
2771d522f475Smrg	result = -1;
2772d522f475Smrg    }
27730bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
27740bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
27750bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
27760bd37d32Smrg	   result ? "FAIL" : "OK",
27770bd37d32Smrg	   pty != 0 ? *pty : -1));
2778d522f475Smrg    return result;
2779d522f475Smrg}
2780d522f475Smrg#endif
2781d522f475Smrg
2782d522f475Smrg/*
2783d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
2784d522f475Smrg * we might allocate.  Used on those systems that do not have
2785d522f475Smrg * a functional interface for allocating a pty.
2786d522f475Smrg * Returns 0 if found a pty, 1 if fails.
2787d522f475Smrg */
2788d522f475Smrg#ifdef USE_PTY_SEARCH
2789d522f475Smrgstatic int
2790d522f475Smrgpty_search(int *pty)
2791d522f475Smrg{
2792d522f475Smrg    static int devindex = 0, letter = 0;
2793d522f475Smrg
2794d522f475Smrg#if defined(CRAY) || defined(__MVS__)
2795d522f475Smrg    while (devindex < MAXPTTYS) {
2796d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
2797d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
2798d522f475Smrg	devindex++;
2799d522f475Smrg
2800d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2801d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2802d522f475Smrg	    return 0;
2803d522f475Smrg	}
2804d522f475Smrg    }
2805d522f475Smrg#else /* CRAY || __MVS__ */
2806d522f475Smrg    while (PTYCHAR1[letter]) {
2807d522f475Smrg	ttydev[strlen(ttydev) - 2] =
2808d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
2809d522f475Smrg
2810d522f475Smrg	while (PTYCHAR2[devindex]) {
2811d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
2812d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
2813d522f475Smrg	    devindex++;
2814d522f475Smrg
2815d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2816d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2817d522f475Smrg#ifdef sun
2818d522f475Smrg		/* Need to check the process group of the pty.
2819d522f475Smrg		 * If it exists, then the slave pty is in use,
2820d522f475Smrg		 * and we need to get another one.
2821d522f475Smrg		 */
2822d522f475Smrg		int pgrp_rtn;
2823d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
2824d522f475Smrg		    close(*pty);
2825d522f475Smrg		    continue;
2826d522f475Smrg		}
2827d522f475Smrg#endif /* sun */
2828d522f475Smrg		return 0;
2829d522f475Smrg	    }
2830d522f475Smrg	}
2831d522f475Smrg	devindex = 0;
2832d522f475Smrg	letter++;
2833d522f475Smrg    }
2834d522f475Smrg#endif /* CRAY else */
2835d522f475Smrg    /*
2836d522f475Smrg     * We were unable to allocate a pty master!  Return an error
2837d522f475Smrg     * condition and let our caller terminate cleanly.
2838d522f475Smrg     */
2839d522f475Smrg    return 1;
2840d522f475Smrg}
2841d522f475Smrg#endif /* USE_PTY_SEARCH */
2842d522f475Smrg
2843d522f475Smrg/*
2844d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
2845d522f475Smrg * the latter has support for switching character sets.  We support the
2846d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
2847d522f475Smrg * choose 4014 over 4015.
2848d522f475Smrg *
2849d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
2850d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
2851d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
2852d522f475Smrg * later Tektronix terminals), and 4 character sizes.
2853d522f475Smrg * All of these are supported by xterm.
2854d522f475Smrg */
2855d522f475Smrg
2856d522f475Smrg#if OPT_TEK4014
285720d2c4d2Smrgstatic const char *tekterm[] =
2858d522f475Smrg{
2859d522f475Smrg    "tek4014",
2860d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
2861d522f475Smrg    "tek4012",			/* 4010 with lower case */
2862d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
2863d522f475Smrg    "tek4010",			/* small screen, upper-case only */
2864d522f475Smrg    "dumb",
2865d522f475Smrg    0
2866d522f475Smrg};
2867d522f475Smrg#endif
2868d522f475Smrg
2869d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
2870d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
2871d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
2872d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
2873d522f475Smrg * The VT420 has up to 48 lines on the screen.
2874d522f475Smrg */
2875d522f475Smrg
287620d2c4d2Smrgstatic const char *vtterm[] =
2877d522f475Smrg{
2878d522f475Smrg#ifdef USE_X11TERM
2879d522f475Smrg    "x11term",			/* for people who want special term name */
2880d522f475Smrg#endif
2881d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
2882d522f475Smrg    "xterm",			/* the prefered name, should be fastest */
2883d522f475Smrg    "vt102",
2884d522f475Smrg    "vt100",
2885d522f475Smrg    "ansi",
2886d522f475Smrg    "dumb",
2887d522f475Smrg    0
2888d522f475Smrg};
2889d522f475Smrg
2890d522f475Smrg/* ARGSUSED */
28910bd37d32Smrgstatic void
2892d522f475Smrghungtty(int i GCC_UNUSED)
2893d522f475Smrg{
28940bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
2895d522f475Smrg    siglongjmp(env, 1);
2896d522f475Smrg}
2897d522f475Smrg
2898d522f475Smrg#if OPT_PTY_HANDSHAKE
2899d522f475Smrg#define NO_FDS {-1, -1}
2900d522f475Smrg
2901d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
2902d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
2903d522f475Smrg
2904d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
2905d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
2906d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
2907d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
2908d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
2909d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
2910d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
2911d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
2912d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
2913d522f475Smrg} status_t;
2914d522f475Smrg
2915d522f475Smrgtypedef struct {
2916d522f475Smrg    status_t status;
2917d522f475Smrg    int error;
2918d522f475Smrg    int fatal_error;
2919d522f475Smrg    int tty_slot;
2920d522f475Smrg    int rows;
2921d522f475Smrg    int cols;
2922d522f475Smrg    char buffer[1024];
2923d522f475Smrg} handshake_t;
2924d522f475Smrg
2925d522f475Smrg#if OPT_TRACE
2926d522f475Smrgstatic void
2927d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
2928d522f475Smrg{
2929d522f475Smrg    const char *status = "?";
2930d522f475Smrg    switch (data->status) {
2931d522f475Smrg    case PTY_BAD:
2932d522f475Smrg	status = "PTY_BAD";
2933d522f475Smrg	break;
2934d522f475Smrg    case PTY_FATALERROR:
2935d522f475Smrg	status = "PTY_FATALERROR";
2936d522f475Smrg	break;
2937d522f475Smrg    case PTY_GOOD:
2938d522f475Smrg	status = "PTY_GOOD";
2939d522f475Smrg	break;
2940d522f475Smrg    case PTY_NEW:
2941d522f475Smrg	status = "PTY_NEW";
2942d522f475Smrg	break;
2943d522f475Smrg    case PTY_NOMORE:
2944d522f475Smrg	status = "PTY_NOMORE";
2945d522f475Smrg	break;
2946d522f475Smrg    case UTMP_ADDED:
2947d522f475Smrg	status = "UTMP_ADDED";
2948d522f475Smrg	break;
2949d522f475Smrg    case UTMP_TTYSLOT:
2950d522f475Smrg	status = "UTMP_TTYSLOT";
2951d522f475Smrg	break;
2952d522f475Smrg    case PTY_EXEC:
2953d522f475Smrg	status = "PTY_EXEC";
2954d522f475Smrg	break;
2955d522f475Smrg    }
2956d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
2957d522f475Smrg	   tag,
2958d522f475Smrg	   status,
2959d522f475Smrg	   data->error,
2960d522f475Smrg	   data->fatal_error,
2961d522f475Smrg	   data->buffer));
2962d522f475Smrg}
2963d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
2964d522f475Smrg#else
2965d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
2966d522f475Smrg#endif
2967d522f475Smrg
2968d522f475Smrg/* HsSysError()
2969d522f475Smrg *
2970d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
2971d522f475Smrg * over the errno and error exit to the master process so that it can
2972d522f475Smrg * display our error message and exit with our exit code so that the
2973d522f475Smrg * user can see it.
2974d522f475Smrg */
2975d522f475Smrg
2976d522f475Smrgstatic void
2977d522f475SmrgHsSysError(int error)
2978d522f475Smrg{
2979d522f475Smrg    handshake_t handshake;
2980d522f475Smrg
2981d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
2982d522f475Smrg    handshake.status = PTY_FATALERROR;
2983d522f475Smrg    handshake.error = errno;
2984d522f475Smrg    handshake.fatal_error = error;
29850bd37d32Smrg    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
2986d522f475Smrg
2987d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
2988d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
2989d522f475Smrg	       handshake.error,
2990d522f475Smrg	       handshake.fatal_error,
2991d522f475Smrg	       handshake.buffer));
2992d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
299320d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
299420d2c4d2Smrg			(const char *) &handshake,
299520d2c4d2Smrg			sizeof(handshake)));
2996d522f475Smrg    } else {
29970bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
29980bd37d32Smrg		     handshake.error,
29990bd37d32Smrg		     handshake.fatal_error,
30000bd37d32Smrg		     handshake.buffer);
3001d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3002d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3003d522f475Smrg    }
3004d522f475Smrg    exit(error);
3005d522f475Smrg}
3006d522f475Smrg
3007d522f475Smrgvoid
3008d522f475Smrgfirst_map_occurred(void)
3009d522f475Smrg{
3010d522f475Smrg    if (resource.wait_for_map) {
3011d522f475Smrg	handshake_t handshake;
3012d522f475Smrg	TScreen *screen = TScreenOf(term);
3013d522f475Smrg
3014d522f475Smrg	memset(&handshake, 0, sizeof(handshake));
3015d522f475Smrg	handshake.status = PTY_EXEC;
3016d522f475Smrg	handshake.rows = screen->max_row;
3017d522f475Smrg	handshake.cols = screen->max_col;
3018d522f475Smrg
3019d522f475Smrg	if (pc_pipe[1] >= 0) {
3020d522f475Smrg	    TRACE(("first_map_occurred: %dx%d\n", handshake.rows, handshake.cols));
3021d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
302220d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
302320d2c4d2Smrg			    (const char *) &handshake,
302420d2c4d2Smrg			    sizeof(handshake)));
3025d522f475Smrg	    close(cp_pipe[0]);
3026d522f475Smrg	    close(pc_pipe[1]);
3027d522f475Smrg	}
3028d522f475Smrg	resource.wait_for_map = False;
3029d522f475Smrg    }
3030d522f475Smrg}
3031d522f475Smrg#else
3032d522f475Smrg/*
3033d522f475Smrg * temporary hack to get xterm working on att ptys
3034d522f475Smrg */
3035d522f475Smrgstatic void
3036d522f475SmrgHsSysError(int error)
3037d522f475Smrg{
30380bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
30390bd37d32Smrg		 error, errno, ttydev);
3040d522f475Smrg    exit(error);
3041d522f475Smrg}
3042d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3043d522f475Smrg
3044d522f475Smrg#ifndef VMS
3045d522f475Smrgstatic void
3046d522f475Smrgset_owner(char *device, uid_t uid, gid_t gid, mode_t mode)
3047d522f475Smrg{
3048d522f475Smrg    int why;
3049d522f475Smrg
3050d522f475Smrg    TRACE_IDS;
305120d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
30520bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3053d522f475Smrg
3054d522f475Smrg    if (chown(device, uid, gid) < 0) {
3055d522f475Smrg	why = errno;
3056d522f475Smrg	if (why != ENOENT
3057d522f475Smrg	    && save_ruid == 0) {
30580bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
30590bd37d32Smrg			device, (long) uid, (long) gid);
3060d522f475Smrg	}
3061d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3062e39b573cSmrg    } else if (chmod(device, mode) < 0) {
3063d522f475Smrg	why = errno;
3064d522f475Smrg	if (why != ENOENT) {
3065d522f475Smrg	    struct stat sb;
3066d522f475Smrg	    if (stat(device, &sb) < 0) {
30670bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
30680bd37d32Smrg			    device, (unsigned) mode);
3069d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
30700bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
30710bd37d32Smrg			    device,
30720bd37d32Smrg			    (unsigned long) mode,
30730bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3074d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
30750bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3076d522f475Smrg	    }
3077d522f475Smrg	}
3078d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3079d522f475Smrg    }
3080d522f475Smrg}
3081d522f475Smrg
3082d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3083d522f475Smrg/*
3084d522f475Smrg * getutid() only looks at ut_type and ut_id.
3085d522f475Smrg * But we'll also check ut_line in find_utmp().
3086d522f475Smrg */
3087d522f475Smrgstatic void
3088d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3089d522f475Smrg{
3090d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3091d522f475Smrg    tofind->ut_type = type;
3092d522f475Smrg    (void) strncpy(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3093d522f475Smrg    (void) strncpy(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3094d522f475Smrg}
3095d522f475Smrg
3096d522f475Smrg/*
3097d522f475Smrg * We could use getutline() if we didn't support old systems.
3098d522f475Smrg */
3099d522f475Smrgstatic struct UTMP_STR *
3100d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3101d522f475Smrg{
3102d522f475Smrg    struct UTMP_STR *result;
31030bd37d32Smrg    struct UTMP_STR limited;
3104d522f475Smrg    struct UTMP_STR working;
3105d522f475Smrg
3106d522f475Smrg    for (;;) {
3107d522f475Smrg	memset(&working, 0, sizeof(working));
3108d522f475Smrg	working.ut_type = tofind->ut_type;
31090bd37d32Smrg	strncpy(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3110d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3111d522f475Smrg	working.ut_type = 0;
3112d522f475Smrg#endif
3113d522f475Smrg	if ((result = call_getutid(&working)) == 0)
3114d522f475Smrg	    break;
31150bd37d32Smrg	/*
31160bd37d32Smrg	 * ut_line may not be null-terminated, but if it is, there may be
31170bd37d32Smrg	 * garbage after the null.  Use strncpy to ensure that the value
31180bd37d32Smrg	 * we check is null-terminated (if there is enough space in the
31190bd37d32Smrg	 * buffer), and that unused space is nulled.
31200bd37d32Smrg	 */
31210bd37d32Smrg	strncpy(limited.ut_line, result->ut_line, sizeof(result->ut_line));
31220bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3123d522f475Smrg	    break;
3124d522f475Smrg	/*
3125d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3126d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3127d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3128d522f475Smrg	 */
3129d522f475Smrg	memset(result, 0, sizeof(*result));
3130d522f475Smrg    }
3131d522f475Smrg    return result;
3132d522f475Smrg}
3133d522f475Smrg#endif /* HAVE_UTMP... */
3134d522f475Smrg
3135d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3136d522f475Smrg
313720d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
313820d2c4d2Smrg#define USE_NO_DEV_TTY 1
313920d2c4d2Smrg#else
314020d2c4d2Smrg#define USE_NO_DEV_TTY 0
314120d2c4d2Smrg#endif
314220d2c4d2Smrg
3143d522f475Smrg/*
3144d522f475Smrg *  Inits pty and tty and forks a login process.
3145d522f475Smrg *  Does not close fd Xsocket.
3146d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3147d522f475Smrg */
3148d522f475Smrgstatic int
3149d522f475SmrgspawnXTerm(XtermWidget xw)
3150d522f475Smrg{
3151d522f475Smrg    TScreen *screen = TScreenOf(xw);
3152d522f475Smrg    Cardinal nn;
3153d522f475Smrg#if OPT_PTY_HANDSHAKE
3154d522f475Smrg    Bool got_handshake_size = False;
3155d522f475Smrg    handshake_t handshake;
3156d522f475Smrg    int done;
3157d522f475Smrg#endif
3158d522f475Smrg#if OPT_INITIAL_ERASE
3159d522f475Smrg    int initial_erase = VAL_INITIAL_ERASE;
3160d522f475Smrg    Bool setInitialErase;
3161d522f475Smrg#endif
3162d522f475Smrg    int rc = 0;
3163d522f475Smrg    int ttyfd = -1;
3164d522f475Smrg    Bool ok_termcap;
3165d522f475Smrg    char *newtc;
3166d522f475Smrg
3167d522f475Smrg#ifdef TERMIO_STRUCT
3168d522f475Smrg    TERMIO_STRUCT tio;
3169d522f475Smrg#ifdef __MVS__
3170d522f475Smrg    TERMIO_STRUCT gio;
3171d522f475Smrg#endif /* __MVS__ */
3172d522f475Smrg#ifdef TIOCLSET
3173d522f475Smrg    unsigned lmode;
3174d522f475Smrg#endif /* TIOCLSET */
3175d522f475Smrg#ifdef HAS_LTCHARS
3176d522f475Smrg    struct ltchars ltc;
3177d522f475Smrg#endif /* HAS_LTCHARS */
3178d522f475Smrg#else /* !TERMIO_STRUCT */
3179d522f475Smrg    int ldisc = 0;
3180d522f475Smrg    int discipline;
3181d522f475Smrg    unsigned lmode;
3182d522f475Smrg    struct tchars tc;
3183d522f475Smrg    struct ltchars ltc;
3184d522f475Smrg    struct sgttyb sg;
3185d522f475Smrg#ifdef sony
3186d522f475Smrg    int jmode;
3187d522f475Smrg    struct jtchars jtc;
3188d522f475Smrg#endif /* sony */
3189d522f475Smrg#endif /* TERMIO_STRUCT */
3190d522f475Smrg
31910bd37d32Smrg    char *shell_path = 0;
31920bd37d32Smrg    char *shname, *shname_minus;
319320d2c4d2Smrg    int i;
319420d2c4d2Smrg#if USE_NO_DEV_TTY
319520d2c4d2Smrg    int no_dev_tty = False;
319620d2c4d2Smrg#endif
319720d2c4d2Smrg    const char **envnew;	/* new environment */
3198d522f475Smrg    char buf[64];
3199d522f475Smrg    char *TermName = NULL;
3200d522f475Smrg#ifdef TTYSIZE_STRUCT
3201d522f475Smrg    TTYSIZE_STRUCT ts;
3202d522f475Smrg#endif
32030bd37d32Smrg    struct passwd pw;
3204d522f475Smrg    char *login_name = NULL;
3205d522f475Smrg#ifndef USE_UTEMPTER
3206d522f475Smrg#ifdef HAVE_UTMP
3207d522f475Smrg    struct UTMP_STR utmp;
3208d522f475Smrg#ifdef USE_SYSV_UTMP
3209d522f475Smrg    struct UTMP_STR *utret = NULL;
3210d522f475Smrg#endif
3211d522f475Smrg#ifdef USE_LASTLOG
3212d522f475Smrg    struct lastlog lastlog;
3213d522f475Smrg#endif
3214d522f475Smrg#ifdef USE_LASTLOGX
3215d522f475Smrg    struct lastlogx lastlogx;
3216d522f475Smrg#endif /* USE_LASTLOG */
3217d522f475Smrg#endif /* HAVE_UTMP */
3218d522f475Smrg#endif /* !USE_UTEMPTER */
3219d522f475Smrg
3220e39b573cSmrg#if OPT_TRACE
3221e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
3222e39b573cSmrg#endif
3223e39b573cSmrg
3224d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
3225d522f475Smrg    (void) rc;
3226d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3227d522f475Smrg    (void) utret;
3228d522f475Smrg#endif
3229d522f475Smrg
3230d522f475Smrg    screen->uid = save_ruid;
3231d522f475Smrg    screen->gid = save_rgid;
3232d522f475Smrg
3233d522f475Smrg#ifdef SIGTTOU
3234d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
3235d522f475Smrg    signal(SIGTTOU, SIG_IGN);
3236d522f475Smrg#endif
3237d522f475Smrg
3238d522f475Smrg#if OPT_PTY_HANDSHAKE
3239d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3240d522f475Smrg#endif
3241d522f475Smrg
3242d522f475Smrg    if (am_slave >= 0) {
3243d522f475Smrg	screen->respond = am_slave;
3244d522f475Smrg	set_pty_id(ttydev, passedPty);
3245d522f475Smrg#ifdef USE_PTY_DEVICE
3246d522f475Smrg	set_pty_id(ptydev, passedPty);
3247d522f475Smrg#endif
3248d522f475Smrg	if (xtermResetIds(screen) < 0)
3249d522f475Smrg	    exit(1);
3250d522f475Smrg    } else {
3251d522f475Smrg	Bool tty_got_hung;
3252d522f475Smrg
3253d522f475Smrg	/*
3254d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
3255d522f475Smrg	 * that has gone away).  Simply make up some reasonable
3256d522f475Smrg	 * defaults.
3257d522f475Smrg	 */
3258d522f475Smrg
3259d522f475Smrg	signal(SIGALRM, hungtty);
3260d522f475Smrg	alarm(2);		/* alarm(1) might return too soon */
3261d522f475Smrg	if (!sigsetjmp(env, 1)) {
3262d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
3263d522f475Smrg	    alarm(0);
3264d522f475Smrg	    tty_got_hung = False;
3265d522f475Smrg	} else {
3266d522f475Smrg	    tty_got_hung = True;
3267d522f475Smrg	    ttyfd = -1;
3268d522f475Smrg	    errno = ENXIO;
3269d522f475Smrg	}
32700bd37d32Smrg	memset(&pw, 0, sizeof(pw));
3271d522f475Smrg#if OPT_PTY_HANDSHAKE
3272d522f475Smrg	got_handshake_size = False;
3273d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
3274d522f475Smrg#if OPT_INITIAL_ERASE
3275d522f475Smrg	initial_erase = VAL_INITIAL_ERASE;
3276d522f475Smrg#endif
3277d522f475Smrg	signal(SIGALRM, SIG_DFL);
3278d522f475Smrg
3279d522f475Smrg	/*
3280d522f475Smrg	 * Check results and ignore current control terminal if
3281d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
3282d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
3283d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
32840bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
32850bd37d32Smrg	 * if xterm is run within a jail.
3286d522f475Smrg	 */
328720d2c4d2Smrg#if USE_NO_DEV_TTY
3288d522f475Smrg	no_dev_tty = False;
328920d2c4d2Smrg#endif
3290d522f475Smrg	if (ttyfd < 0) {
3291d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
32920bd37d32Smrg		errno == ENOENT ||
3293d522f475Smrg#ifdef ENODEV
3294d522f475Smrg		errno == ENODEV ||
3295d522f475Smrg#endif
3296d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
329720d2c4d2Smrg#if USE_NO_DEV_TTY
3298d522f475Smrg		no_dev_tty = True;
329920d2c4d2Smrg#endif
3300d522f475Smrg#ifdef HAS_LTCHARS
3301d522f475Smrg		ltc = d_ltc;
3302d522f475Smrg#endif /* HAS_LTCHARS */
3303d522f475Smrg#ifdef TIOCLSET
3304d522f475Smrg		lmode = d_lmode;
3305d522f475Smrg#endif /* TIOCLSET */
3306d522f475Smrg#ifdef TERMIO_STRUCT
3307d522f475Smrg		tio = d_tio;
3308d522f475Smrg#else /* !TERMIO_STRUCT */
3309d522f475Smrg		sg = d_sg;
3310d522f475Smrg		tc = d_tc;
3311d522f475Smrg		discipline = d_disipline;
3312d522f475Smrg#ifdef sony
3313d522f475Smrg		jmode = d_jmode;
3314d522f475Smrg		jtc = d_jtc;
3315d522f475Smrg#endif /* sony */
3316d522f475Smrg#endif /* TERMIO_STRUCT */
3317d522f475Smrg	    } else {
3318d522f475Smrg		SysError(ERROR_OPDEVTTY);
3319d522f475Smrg	    }
3320d522f475Smrg	} else {
3321d522f475Smrg
3322d522f475Smrg	    /* Get a copy of the current terminal's state,
3323d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
3324d522f475Smrg	     * may not have a controlling terminal at this point
3325d522f475Smrg	     * if started directly from xdm or xinit,
3326d522f475Smrg	     * in which case we just use the defaults as above.
3327d522f475Smrg	     */
3328d522f475Smrg#ifdef HAS_LTCHARS
3329d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
3330d522f475Smrg		ltc = d_ltc;
3331d522f475Smrg#endif /* HAS_LTCHARS */
3332d522f475Smrg#ifdef TIOCLSET
3333d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
3334d522f475Smrg		lmode = d_lmode;
3335d522f475Smrg#endif /* TIOCLSET */
3336d522f475Smrg#ifdef TERMIO_STRUCT
333720d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
333820d2c4d2Smrg	    if (rc == -1)
3339d522f475Smrg		tio = d_tio;
3340d522f475Smrg#else /* !TERMIO_STRUCT */
334120d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
334220d2c4d2Smrg	    if (rc == -1)
3343d522f475Smrg		sg = d_sg;
3344d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
3345d522f475Smrg		tc = d_tc;
3346d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
3347d522f475Smrg		discipline = d_disipline;
3348d522f475Smrg#ifdef sony
3349d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
3350d522f475Smrg		jmode = d_jmode;
3351d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
3352d522f475Smrg		jtc = d_jtc;
3353d522f475Smrg#endif /* sony */
3354d522f475Smrg#endif /* TERMIO_STRUCT */
3355d522f475Smrg
3356d522f475Smrg	    /*
3357d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
3358d522f475Smrg	     * erase value.  Just in case that will fail, first get
3359d522f475Smrg	     * the value from /dev/tty, so we will have something
3360d522f475Smrg	     * at least.
3361d522f475Smrg	     */
3362d522f475Smrg#if OPT_INITIAL_ERASE
3363d522f475Smrg	    if (resource.ptyInitialErase) {
3364d522f475Smrg#ifdef TERMIO_STRUCT
3365d522f475Smrg		initial_erase = tio.c_cc[VERASE];
3366d522f475Smrg#else /* !TERMIO_STRUCT */
3367d522f475Smrg		initial_erase = sg.sg_erase;
3368d522f475Smrg#endif /* TERMIO_STRUCT */
3369d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
3370d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
3371d522f475Smrg		       initial_erase));
3372d522f475Smrg	    }
3373d522f475Smrg#endif
3374d522f475Smrg#ifdef __MVS__
3375d522f475Smrg	    if (ttyGetAttr(ttyfd, &gio) == 0) {
3376d522f475Smrg		gio.c_cflag &= ~(HUPCL | PARENB);
3377d522f475Smrg		ttySetAttr(ttyfd, &gio);
3378d522f475Smrg	    }
3379d522f475Smrg#endif /* __MVS__ */
3380d522f475Smrg
3381d522f475Smrg	    close_fd(ttyfd);
3382d522f475Smrg	}
3383d522f475Smrg
3384d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
3385d522f475Smrg	    SysError(ERROR_PTYS);
3386d522f475Smrg	}
33870bd37d32Smrg	TRACE_TTYSIZE(screen->respond, "after get_pty");
3388d522f475Smrg#if OPT_INITIAL_ERASE
3389d522f475Smrg	if (resource.ptyInitialErase) {
3390d522f475Smrg#ifdef TERMIO_STRUCT
3391d522f475Smrg	    TERMIO_STRUCT my_tio;
339220d2c4d2Smrg	    rc = ttyGetAttr(screen->respond, &my_tio);
339320d2c4d2Smrg	    if (rc == 0)
3394d522f475Smrg		initial_erase = my_tio.c_cc[VERASE];
3395d522f475Smrg#else /* !TERMIO_STRUCT */
3396d522f475Smrg	    struct sgttyb my_sg;
339720d2c4d2Smrg	    rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg);
339820d2c4d2Smrg	    if (rc == 0)
3399d522f475Smrg		initial_erase = my_sg.sg_erase;
3400d522f475Smrg#endif /* TERMIO_STRUCT */
3401d522f475Smrg	    TRACE(("%s initial_erase:%d (from pty)\n",
3402d522f475Smrg		   (rc == 0) ? "OK" : "FAIL",
3403d522f475Smrg		   initial_erase));
3404d522f475Smrg	}
3405d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3406d522f475Smrg    }
3407d522f475Smrg
3408d522f475Smrg    /* avoid double MapWindow requests */
3409d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
3410d522f475Smrg
3411d522f475Smrg    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
3412d522f475Smrg				   False);
3413d522f475Smrg
3414d522f475Smrg    if (!TEK4014_ACTIVE(xw))
3415956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
3416d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
3417d522f475Smrg    if (Console) {
3418d522f475Smrg	/*
3419d522f475Smrg	 * Inform any running xconsole program
3420d522f475Smrg	 * that we are going to steal the console.
3421d522f475Smrg	 */
3422d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
3423d522f475Smrg	mit_console = XInternAtom(screen->display, mit_console_name, False);
3424d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
3425d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
3426d522f475Smrg		       mit_console, CurrentTime,
3427d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
3428d522f475Smrg    }
3429d522f475Smrg#endif
3430d522f475Smrg#if OPT_TEK4014
3431d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3432d522f475Smrg	envnew = tekterm;
3433d522f475Smrg    } else
3434d522f475Smrg#endif
3435d522f475Smrg    {
3436d522f475Smrg	envnew = vtterm;
3437d522f475Smrg    }
3438d522f475Smrg
3439d522f475Smrg    /*
3440d522f475Smrg     * This used to exit if no termcap entry was found for the specified
3441d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
3442d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
3443d522f475Smrg     * entry is not found.
3444d522f475Smrg     */
3445d522f475Smrg    ok_termcap = True;
344620d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
344720d2c4d2Smrg	const char *last = NULL;
344820d2c4d2Smrg	char *next;
344920d2c4d2Smrg
345020d2c4d2Smrg	TermName = x_strdup(*envnew);
3451d522f475Smrg	ok_termcap = False;
3452d522f475Smrg	while (*envnew != NULL) {
345320d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
345420d2c4d2Smrg		next = x_strdup(*envnew);
345520d2c4d2Smrg		if (get_termcap(xw, next)) {
345620d2c4d2Smrg		    free(TermName);
345720d2c4d2Smrg		    TermName = next;
34580bd37d32Smrg		    ok_termcap = True + 1;
345920d2c4d2Smrg		    break;
346020d2c4d2Smrg		} else {
346120d2c4d2Smrg		    free(next);
346220d2c4d2Smrg		}
3463d522f475Smrg	    }
3464d522f475Smrg	    last = *envnew;
3465d522f475Smrg	    envnew++;
3466d522f475Smrg	}
3467d522f475Smrg    }
3468d522f475Smrg    if (ok_termcap) {
3469a1f3da82Smrg	resource.term_name = TermName;
347020d2c4d2Smrg	resize_termcap(xw);
3471d522f475Smrg    }
3472d522f475Smrg
3473d522f475Smrg    /*
3474d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
3475d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
3476d522f475Smrg     */
3477d522f475Smrg#if OPT_INITIAL_ERASE
3478d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
3479d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
3480d522f475Smrg    setInitialErase = False;
3481d522f475Smrg    if (override_tty_modes && ttymodelist[XTTYMODE_erase].set) {
3482d522f475Smrg	initial_erase = ttymodelist[XTTYMODE_erase].value;
3483d522f475Smrg	setInitialErase = True;
3484d522f475Smrg    } else if (resource.ptyInitialErase) {
3485a1f3da82Smrg	/* EMPTY */ ;
3486d522f475Smrg    } else if (ok_termcap) {
348720d2c4d2Smrg	char *s = get_tcap_erase(xw);
3488d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
3489d522f475Smrg	if (s != 0) {
349020d2c4d2Smrg	    char *save = s;
3491d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
3492d522f475Smrg	    setInitialErase = True;
349320d2c4d2Smrg	    free(save);
3494d522f475Smrg	}
3495d522f475Smrg    }
3496d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
3497d522f475Smrg
3498d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
3499d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
3500d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
3501d522f475Smrg	if (initial_erase == ANSI_DEL) {
350220d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
3503d522f475Smrg	} else {
3504d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
3505d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
3506d522f475Smrg	}
3507d522f475Smrg	TRACE(("...sets DECBKM %s\n",
3508d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
3509d522f475Smrg    } else {
3510d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
3511d522f475Smrg    }
3512d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3513d522f475Smrg
3514d522f475Smrg#ifdef TTYSIZE_STRUCT
3515d522f475Smrg    /* tell tty how big window is */
3516d522f475Smrg#if OPT_TEK4014
3517d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3518d522f475Smrg	TTYSIZE_ROWS(ts) = 38;
3519d522f475Smrg	TTYSIZE_COLS(ts) = 81;
3520d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
352120d2c4d2Smrg	ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
352220d2c4d2Smrg	ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3523d522f475Smrg#endif
3524d522f475Smrg    } else
3525d522f475Smrg#endif
3526d522f475Smrg    {
352720d2c4d2Smrg	TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
352820d2c4d2Smrg	TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3529d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
353020d2c4d2Smrg	ts.ws_xpixel = (ttySize_t) FullWidth(screen);
353120d2c4d2Smrg	ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3532d522f475Smrg#endif
3533d522f475Smrg    }
353420d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
3535d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
3536d522f475Smrg	   TTYSIZE_ROWS(ts),
3537d522f475Smrg	   TTYSIZE_COLS(ts), i));
3538d522f475Smrg#endif /* TTYSIZE_STRUCT */
3539d522f475Smrg
35400bd37d32Smrg#if !defined(USE_OPENPTY)
35410bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
35420bd37d32Smrg    /*
35430bd37d32Smrg     * utempter checks the ownership of the device; some implementations
35440bd37d32Smrg     * set ownership in grantpt - do this first.
35450bd37d32Smrg     */
35460bd37d32Smrg    grantpt(screen->respond);
35470bd37d32Smrg#endif
35480bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
35490bd37d32Smrg    unlockpt(screen->respond);
35500bd37d32Smrg    TRACE_TTYSIZE(screen->respond, "after unlockpt");
35510bd37d32Smrg#endif
35520bd37d32Smrg#endif /* !USE_OPENPTY */
35530bd37d32Smrg
3554d522f475Smrg    added_utmp_entry = False;
3555d522f475Smrg#if defined(USE_UTEMPTER)
3556d522f475Smrg#undef UTMP
3557d522f475Smrg    if (!resource.utmpInhibit) {
3558d522f475Smrg	struct UTMP_STR dummy;
3559d522f475Smrg
3560d522f475Smrg	/* Note: utempter may trim it anyway */
3561d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
35620bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
35630bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
3564d522f475Smrg	addToUtmp(ttydev, dummy.ut_host, screen->respond);
3565d522f475Smrg	added_utmp_entry = True;
3566d522f475Smrg    }
3567d522f475Smrg#endif
3568d522f475Smrg
3569d522f475Smrg    if (am_slave < 0) {
3570d522f475Smrg#if OPT_PTY_HANDSHAKE
3571d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
3572d522f475Smrg	    SysError(ERROR_FORK);
3573d522f475Smrg#endif
3574d522f475Smrg	TRACE(("Forking...\n"));
3575d522f475Smrg	if ((screen->pid = fork()) == -1)
3576d522f475Smrg	    SysError(ERROR_FORK);
3577d522f475Smrg
3578d522f475Smrg	if (screen->pid == 0) {
3579d522f475Smrg#ifdef USE_USG_PTYS
358020d2c4d2Smrg	    int ptyfd = -1;
3581d522f475Smrg	    char *pty_name;
3582d522f475Smrg#endif
3583d522f475Smrg	    /*
3584d522f475Smrg	     * now in child process
3585d522f475Smrg	     */
3586d522f475Smrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
3587d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
3588d522f475Smrg#else
3589d522f475Smrg	    int pgrp = getpid();
3590d522f475Smrg#endif
3591d522f475Smrg	    TRACE_CHILD
3592d522f475Smrg
3593d522f475Smrg#ifdef USE_USG_PTYS
35940bd37d32Smrg#ifdef HAVE_SETPGID
35950bd37d32Smrg		setpgid(0, 0);
35960bd37d32Smrg#else
3597d522f475Smrg		setpgrp();
35980bd37d32Smrg#endif
35990bd37d32Smrg	    unlockpt(screen->respond);
36000bd37d32Smrg	    TRACE_TTYSIZE(screen->respond, "after unlockpt");
36010bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
36020bd37d32Smrg		SysError(ERROR_PTSNAME);
36030bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
36040bd37d32Smrg		SysError(ERROR_OPPTSNAME);
36050bd37d32Smrg	    }
3606d522f475Smrg#ifdef I_PUSH
36070bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ptem") < 0) {
36080bd37d32Smrg		SysError(ERROR_PTEM);
36090bd37d32Smrg	    }
3610d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
36110bd37d32Smrg	    else if (!x_getenv("CONSEM")
36120bd37d32Smrg		     && ioctl(ptyfd, I_PUSH, "consem") < 0) {
36130bd37d32Smrg		SysError(ERROR_CONSEM);
36140bd37d32Smrg	    }
3615d522f475Smrg#endif /* !SVR4 */
36160bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ldterm") < 0) {
36170bd37d32Smrg		SysError(ERROR_LDTERM);
36180bd37d32Smrg	    }
3619d522f475Smrg#ifdef SVR4			/* from Sony */
36200bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ttcompat") < 0) {
36210bd37d32Smrg		SysError(ERROR_TTCOMPAT);
36220bd37d32Smrg	    }
3623d522f475Smrg#endif /* SVR4 */
3624d522f475Smrg#endif /* I_PUSH */
36250bd37d32Smrg	    ttyfd = ptyfd;
3626d522f475Smrg#ifndef __MVS__
36270bd37d32Smrg	    close_fd(screen->respond);
3628d522f475Smrg#endif /* __MVS__ */
3629d522f475Smrg
3630d522f475Smrg#ifdef TTYSIZE_STRUCT
36310bd37d32Smrg	    /* tell tty how big window is */
3632d522f475Smrg#if OPT_TEK4014
36330bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
36340bd37d32Smrg		TTYSIZE_ROWS(ts) = 24;
36350bd37d32Smrg		TTYSIZE_COLS(ts) = 80;
3636d522f475Smrg#ifdef USE_STRUCT_WINSIZE
36370bd37d32Smrg		ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
36380bd37d32Smrg		ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3639d522f475Smrg#endif
36400bd37d32Smrg	    } else
3641d522f475Smrg#endif /* OPT_TEK4014 */
36420bd37d32Smrg	    {
36430bd37d32Smrg		TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
36440bd37d32Smrg		TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3645d522f475Smrg#ifdef USE_STRUCT_WINSIZE
36460bd37d32Smrg		ts.ws_xpixel = (ttySize_t) FullWidth(screen);
36470bd37d32Smrg		ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3648d522f475Smrg#endif
36490bd37d32Smrg	    }
3650d522f475Smrg#endif /* TTYSIZE_STRUCT */
3651d522f475Smrg
3652d522f475Smrg#endif /* USE_USG_PTYS */
3653d522f475Smrg
36540bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
3655d522f475Smrg
3656d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
36570bd37d32Smrg	    if (resource.ptyHandshake) {
36580bd37d32Smrg		char *ptr;
3659d522f475Smrg
36600bd37d32Smrg		/* close parent's sides of the pipes */
36610bd37d32Smrg		close(cp_pipe[0]);
36620bd37d32Smrg		close(pc_pipe[1]);
36630bd37d32Smrg
36640bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
36650bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
36660bd37d32Smrg		 * or err.
36670bd37d32Smrg		 */
36680bd37d32Smrg		if (cp_pipe[1] <= 2) {
36690bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
36700bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
36710bd37d32Smrg			cp_pipe[1] = i;
3672d522f475Smrg		    }
36730bd37d32Smrg		}
36740bd37d32Smrg		if (pc_pipe[0] <= 2) {
36750bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
36760bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
36770bd37d32Smrg			pc_pipe[0] = i;
3678d522f475Smrg		    }
36790bd37d32Smrg		}
3680d522f475Smrg
36810bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
36820bd37d32Smrg		close(ConnectionNumber(screen->display));
3683d522f475Smrg#ifndef __MVS__
36840bd37d32Smrg		if (screen->respond >= 0)
36850bd37d32Smrg		    close(screen->respond);
3686d522f475Smrg#endif /* __MVS__ */
3687d522f475Smrg
36880bd37d32Smrg		/* Now is the time to set up our process group and
36890bd37d32Smrg		 * open up the pty slave.
36900bd37d32Smrg		 */
3691d522f475Smrg#ifdef USE_SYSV_PGRP
3692d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
36930bd37d32Smrg		IGNORE_RC(setsid());
3694d522f475Smrg#else
36950bd37d32Smrg		IGNORE_RC(setpgrp());
3696d522f475Smrg#endif
3697d522f475Smrg#endif /* USE_SYSV_PGRP */
3698d522f475Smrg
3699d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
37000bd37d32Smrg		qsetlogin(getlogin(), ttydev);
3701d522f475Smrg#endif
37020bd37d32Smrg		if (ttyfd >= 0) {
3703d522f475Smrg#ifdef __MVS__
37040bd37d32Smrg		    if (ttyGetAttr(ttyfd, &gio) == 0) {
37050bd37d32Smrg			gio.c_cflag &= ~(HUPCL | PARENB);
37060bd37d32Smrg			ttySetAttr(ttyfd, &gio);
37070bd37d32Smrg		    }
3708d522f475Smrg#else /* !__MVS__ */
37090bd37d32Smrg		    close_fd(ttyfd);
3710d522f475Smrg#endif /* __MVS__ */
37110bd37d32Smrg		}
3712d522f475Smrg
37130bd37d32Smrg		for (;;) {
371420d2c4d2Smrg#if USE_NO_DEV_TTY
37150bd37d32Smrg		    if (!no_dev_tty
37160bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
37170bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
37180bd37d32Smrg			close_fd(ttyfd);
37190bd37d32Smrg		    }
372020d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
3721d522f475Smrg#ifdef CSRG_BASED
37220bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
3723d522f475Smrg#endif
37240bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
37250bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after open");
37260bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
37270bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after fixup");
3728d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
37290bd37d32Smrg			/* make /dev/tty work */
37300bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
3731d522f475Smrg#endif
3732d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
37330bd37d32Smrg			/* make /dev/tty work */
37340bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
3735d522f475Smrg#endif
3736d522f475Smrg#ifdef USE_SYSV_PGRP
37370bd37d32Smrg			/* We need to make sure that we are actually
37380bd37d32Smrg			 * the process group leader for the pty.  If
37390bd37d32Smrg			 * we are, then we should now be able to open
37400bd37d32Smrg			 * /dev/tty.
37410bd37d32Smrg			 */
37420bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
37430bd37d32Smrg			    /* success! */
37440bd37d32Smrg			    close(i);
3745d522f475Smrg			    break;
3746d522f475Smrg			}
37470bd37d32Smrg#else /* USE_SYSV_PGRP */
37480bd37d32Smrg			break;
37490bd37d32Smrg#endif /* USE_SYSV_PGRP */
37500bd37d32Smrg		    }
37510bd37d32Smrg		    perror("open ttydev");
3752d522f475Smrg#ifdef TIOCSCTTY
37530bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
3754d522f475Smrg#endif
37550bd37d32Smrg		    /* let our master know that the open failed */
37560bd37d32Smrg		    handshake.status = PTY_BAD;
37570bd37d32Smrg		    handshake.error = errno;
37580bd37d32Smrg		    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
37590bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
37600bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
37610bd37d32Smrg				    (const char *) &handshake,
37620bd37d32Smrg				    sizeof(handshake)));
3763d522f475Smrg
37640bd37d32Smrg		    /* get reply from parent */
37650bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
37660bd37d32Smrg				   sizeof(handshake));
37670bd37d32Smrg		    if (i <= 0) {
37680bd37d32Smrg			/* parent terminated */
37690bd37d32Smrg			exit(1);
3770d522f475Smrg		    }
3771d522f475Smrg
37720bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
37730bd37d32Smrg			/* No more ptys, let's shutdown. */
37740bd37d32Smrg			exit(1);
3775d522f475Smrg		    }
37760bd37d32Smrg
37770bd37d32Smrg		    /* We have a new pty to try */
37780bd37d32Smrg		    if (ttyfd >= 0)
37790bd37d32Smrg			close(ttyfd);
37800bd37d32Smrg		    free(ttydev);
37810bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
3782d522f475Smrg		}
3783d522f475Smrg
37840bd37d32Smrg		/* use the same tty name that everyone else will use
37850bd37d32Smrg		 * (from ttyname)
37860bd37d32Smrg		 */
37870bd37d32Smrg		if ((ptr = ttyname(ttyfd)) != 0) {
37880bd37d32Smrg		    free(ttydev);
37890bd37d32Smrg		    ttydev = x_strdup(ptr);
37900bd37d32Smrg		}
37910bd37d32Smrg	    }
37920bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
3793d522f475Smrg
3794d522f475Smrg	    set_pty_permissions(screen->uid,
3795d522f475Smrg				screen->gid,
3796d522f475Smrg				(resource.messages
3797d522f475Smrg				 ? 0622U
3798d522f475Smrg				 : 0600U));
3799d522f475Smrg
3800d522f475Smrg	    /*
3801d522f475Smrg	     * set up the tty modes
3802d522f475Smrg	     */
3803d522f475Smrg	    {
3804d522f475Smrg#ifdef TERMIO_STRUCT
3805d522f475Smrg#if defined(umips) || defined(CRAY) || defined(linux)
3806d522f475Smrg		/* If the control tty had its modes screwed around with,
3807d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
3808d522f475Smrg		   will have bad values.  Let's just get termio from the
3809d522f475Smrg		   new tty and tailor it.  */
3810d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
3811d522f475Smrg		    SysError(ERROR_TIOCGETP);
3812d522f475Smrg		tio.c_lflag |= ECHOE;
3813d522f475Smrg#endif /* umips */
3814d522f475Smrg		/* Now is also the time to change the modes of the
3815d522f475Smrg		 * child pty.
3816d522f475Smrg		 */
3817d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
381820d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
3819d522f475Smrg		tio.c_iflag |= ICRNL;
38200bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
3821d522f475Smrg#if OPT_LUIT_PROG
3822d522f475Smrg		if (command_to_exec_with_luit == 0)
3823d522f475Smrg#endif
3824d522f475Smrg		    if (screen->utf8_mode)
3825d522f475Smrg			tio.c_iflag |= IUTF8;
3826d522f475Smrg#endif
3827d522f475Smrg		/* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */
3828d522f475Smrg#ifndef USE_POSIX_TERMIOS
382920d2c4d2Smrg		UIntClr(tio.c_oflag,
383020d2c4d2Smrg			(OCRNL
383120d2c4d2Smrg			 | ONLRET
383220d2c4d2Smrg			 | NLDLY
383320d2c4d2Smrg			 | CRDLY
383420d2c4d2Smrg			 | TABDLY
383520d2c4d2Smrg			 | BSDLY
383620d2c4d2Smrg			 | VTDLY
383720d2c4d2Smrg			 | FFDLY));
3838d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3839d522f475Smrg#ifdef ONLCR
3840d522f475Smrg		tio.c_oflag |= ONLCR;
3841d522f475Smrg#endif /* ONLCR */
3842d522f475Smrg#ifdef OPOST
3843d522f475Smrg		tio.c_oflag |= OPOST;
3844d522f475Smrg#endif /* OPOST */
3845d522f475Smrg#ifndef USE_POSIX_TERMIOS
3846d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
3847d522f475Smrg#  define CBAUD V_CBAUD
3848d522f475Smrg# endif
384920d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
3850d522f475Smrg#ifdef BAUD_0
3851d522f475Smrg		/* baud rate is 0 (don't care) */
3852d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
3853d522f475Smrg		tio.c_ispeed = tio.c_ospeed = VAL_LINE_SPEED;
3854d522f475Smrg#else /* !BAUD_0 */
3855d522f475Smrg		tio.c_cflag |= VAL_LINE_SPEED;
3856d522f475Smrg#endif /* !BAUD_0 */
3857d522f475Smrg#else /* USE_POSIX_TERMIOS */
3858d522f475Smrg		cfsetispeed(&tio, VAL_LINE_SPEED);
3859d522f475Smrg		cfsetospeed(&tio, VAL_LINE_SPEED);
3860d522f475Smrg#ifdef __MVS__
3861d522f475Smrg		/* turn off bits that can't be set from the slave side */
3862d522f475Smrg		tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
3863d522f475Smrg#endif /* __MVS__ */
3864d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
3865d522f475Smrg		   when the xterm ends */
3866d522f475Smrg		tio.c_cflag &= ~CLOCAL;
3867d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3868d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
3869d522f475Smrg		 * echo
3870d522f475Smrg		 */
3871d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
3872d522f475Smrg#ifdef ECHOKE
3873d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
3874d522f475Smrg#endif
3875d522f475Smrg#ifdef ECHOCTL
3876d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
3877d522f475Smrg#endif
3878d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
3879d522f475Smrg		    if (validTtyChar(tio, nn)) {
3880d522f475Smrg			int sysMode = known_ttyChars[nn].sysMode;
3881d522f475Smrg#ifdef __MVS__
3882d522f475Smrg			if (tio.c_cc[sysMode] != 0) {
3883d522f475Smrg			    switch (sysMode) {
3884d522f475Smrg			    case VEOL:
3885d522f475Smrg			    case VEOF:
3886d522f475Smrg				continue;
3887d522f475Smrg			    }
3888d522f475Smrg			}
3889d522f475Smrg#endif
38900bd37d32Smrg			tio.c_cc[sysMode] = (cc_t) known_ttyChars[nn].myDefault;
3891d522f475Smrg		    }
3892d522f475Smrg		}
3893d522f475Smrg
3894d522f475Smrg		if (override_tty_modes) {
3895d522f475Smrg		    for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
3896d522f475Smrg			if (validTtyChar(tio, nn)) {
3897d522f475Smrg			    TMODE(known_ttyChars[nn].myMode,
3898d522f475Smrg				  tio.c_cc[known_ttyChars[nn].sysMode]);
3899d522f475Smrg			}
3900d522f475Smrg		    }
3901d522f475Smrg#ifdef HAS_LTCHARS
3902d522f475Smrg		    /* both SYSV and BSD have ltchars */
3903d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
3904d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
3905d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
3906d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
3907d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
3908d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
3909d522f475Smrg#endif
3910d522f475Smrg		}
3911d522f475Smrg#ifdef HAS_LTCHARS
3912d522f475Smrg#ifdef __hpux
3913d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
3914d522f475Smrg		 * are not set to _POSIX_VDISABLE */
3915d522f475Smrg		ltc.t_rprntc = ltc.t_rprntc = ltc.t_flushc =
3916d522f475Smrg		    ltc.t_werasc = ltc.t_lnextc = _POSIX_VDISABLE;
3917d522f475Smrg#endif /* __hpux */
3918d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
3919d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
3920d522f475Smrg#endif /* HAS_LTCHARS */
3921d522f475Smrg#ifdef TIOCLSET
3922d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
3923d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
3924d522f475Smrg#endif /* TIOCLSET */
3925d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
3926d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
3927d522f475Smrg
3928d522f475Smrg		/* ignore errors here - some platforms don't work */
392920d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
3930d522f475Smrg		if (screen->input_eight_bits)
3931d522f475Smrg		    tio.c_cflag |= CS8;
3932d522f475Smrg		else
3933d522f475Smrg		    tio.c_cflag |= CS7;
3934d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
3935d522f475Smrg
3936d522f475Smrg#else /* !TERMIO_STRUCT */
3937d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
3938d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
3939d522f475Smrg		/* make sure speed is set on pty so that editors work right */
3940d522f475Smrg		sg.sg_ispeed = VAL_LINE_SPEED;
3941d522f475Smrg		sg.sg_ospeed = VAL_LINE_SPEED;
3942d522f475Smrg		/* reset t_brkc to default value */
3943d522f475Smrg		tc.t_brkc = -1;
3944d522f475Smrg#ifdef LPASS8
3945d522f475Smrg		if (screen->input_eight_bits)
3946d522f475Smrg		    lmode |= LPASS8;
3947d522f475Smrg		else
3948d522f475Smrg		    lmode &= ~(LPASS8);
3949d522f475Smrg#endif
3950d522f475Smrg#ifdef sony
3951d522f475Smrg		jmode &= ~KM_KANJI;
3952d522f475Smrg#endif /* sony */
3953d522f475Smrg
3954d522f475Smrg		ltc = d_ltc;
3955d522f475Smrg
3956d522f475Smrg		if (override_tty_modes) {
3957d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
3958d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
3959d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
3960d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
3961d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
3962d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
3963d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
3964d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
3965d522f475Smrg		    /* both SYSV and BSD have ltchars */
3966d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
3967d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
3968d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
3969d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
3970d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
3971d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
3972d522f475Smrg		}
3973d522f475Smrg
3974d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
3975d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
3976d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
3977d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
3978d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
3979d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
3980d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
3981d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
3982d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
3983d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
3984d522f475Smrg#ifdef sony
3985d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
3986d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
3987d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
3988d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
3989d522f475Smrg#endif /* sony */
3990d522f475Smrg#endif /* TERMIO_STRUCT */
3991d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
3992d522f475Smrg		if (Console) {
3993d522f475Smrg#ifdef TIOCCONS
3994d522f475Smrg		    int on = 1;
3995d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
39960bd37d32Smrg			xtermPerror("cannot open console");
3997d522f475Smrg#endif
3998d522f475Smrg#ifdef SRIOCSREDIR
3999d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4000d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
40010bd37d32Smrg			xtermPerror("cannot open console");
400220d2c4d2Smrg		    IGNORE_RC(close(fd));
4003d522f475Smrg#endif
4004d522f475Smrg		}
4005d522f475Smrg#endif /* TIOCCONS */
4006d522f475Smrg	    }
4007d522f475Smrg
4008d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4009d522f475Smrg#ifdef USE_SYSV_SIGHUP
4010d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4011d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4012d522f475Smrg#else
4013d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4014d522f475Smrg#endif
4015d522f475Smrg	    /* restore various signals to their defaults */
4016d522f475Smrg	    signal(SIGINT, SIG_DFL);
4017d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4018d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4019d522f475Smrg
4020d522f475Smrg	    /*
4021d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4022d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4023d522f475Smrg	     * the terminal's erase mode from our best guess.
4024d522f475Smrg	     */
4025d522f475Smrg#if OPT_INITIAL_ERASE
4026d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4027d522f475Smrg		   initial_erase,
4028d522f475Smrg		   setInitialErase ? "YES" : "NO",
4029d522f475Smrg		   resource.ptyInitialErase,
4030d522f475Smrg		   override_tty_modes,
4031d522f475Smrg		   ttymodelist[XTTYMODE_erase].set));
4032d522f475Smrg	    if (setInitialErase) {
4033d522f475Smrg#if OPT_TRACE
4034d522f475Smrg		int old_erase;
4035d522f475Smrg#endif
4036d522f475Smrg#ifdef TERMIO_STRUCT
4037d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4038d522f475Smrg		    tio = d_tio;
4039d522f475Smrg#if OPT_TRACE
4040d522f475Smrg		old_erase = tio.c_cc[VERASE];
4041d522f475Smrg#endif
40420bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
404320d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4044d522f475Smrg#else /* !TERMIO_STRUCT */
4045d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4046d522f475Smrg		    sg = d_sg;
4047d522f475Smrg#if OPT_TRACE
4048d522f475Smrg		old_erase = sg.sg_erase;
4049d522f475Smrg#endif
4050d522f475Smrg		sg.sg_erase = initial_erase;
4051d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4052d522f475Smrg#endif /* TERMIO_STRUCT */
4053d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4054d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4055d522f475Smrg	    }
4056d522f475Smrg#endif
4057d522f475Smrg
4058d522f475Smrg	    xtermCopyEnv(environ);
4059d522f475Smrg
40600bd37d32Smrg	    /*
40610bd37d32Smrg	     * standards.freedesktop.org/startup-notification-spec/
40620bd37d32Smrg	     * notes that this variable is used when a "reliable" mechanism is
40630bd37d32Smrg	     * not available; in practice it must be unset to avoid confusing
40640bd37d32Smrg	     * GTK applications.
40650bd37d32Smrg	     */
40660bd37d32Smrg	    xtermUnsetenv("DESKTOP_STARTUP_ID");
40670bd37d32Smrg
4068a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4069a1f3da82Smrg	    if (!resource.term_name)
407020d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4071d522f475Smrg
4072d522f475Smrg	    sprintf(buf, "%lu",
4073d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4074d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4075d522f475Smrg
4076d522f475Smrg	    /* put the display into the environment of the shell */
4077d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4078d522f475Smrg
4079d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4080d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4081d522f475Smrg
4082e39b573cSmrg	    /*
4083e39b573cSmrg	     * For debugging only, add environment variables that can be used
4084e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4085e39b573cSmrg	     * processes.
4086e39b573cSmrg	     */
4087e39b573cSmrg#if OPT_TRACE
4088e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4089e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4090e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4091e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4092e39b573cSmrg#endif
4093e39b573cSmrg
4094d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4095d522f475Smrg
4096d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4097d522f475Smrg	     */
4098d522f475Smrg	    {
4099d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4100d522f475Smrg		close_fd(ttyfd);
4101d522f475Smrg
410220d2c4d2Smrg		IGNORE_RC(close(0));
4103d522f475Smrg
4104d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4105d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4106d522f475Smrg		}
410720d2c4d2Smrg		IGNORE_RC(close(1));
410820d2c4d2Smrg		IGNORE_RC(close(2));
4109d522f475Smrg		dup(0);
4110d522f475Smrg		dup(0);
4111d522f475Smrg#else
4112d522f475Smrg		/* dup the tty */
4113d522f475Smrg		for (i = 0; i <= 2; i++)
4114d522f475Smrg		    if (i != ttyfd) {
411520d2c4d2Smrg			IGNORE_RC(close(i));
411620d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4117d522f475Smrg		    }
4118d522f475Smrg#ifndef ATT
4119d522f475Smrg		/* and close the tty */
4120d522f475Smrg		if (ttyfd > 2)
4121d522f475Smrg		    close_fd(ttyfd);
4122d522f475Smrg#endif
4123d522f475Smrg#endif /* CRAY */
4124d522f475Smrg	    }
4125d522f475Smrg
4126d522f475Smrg#if !defined(USE_SYSV_PGRP)
4127d522f475Smrg#ifdef TIOCSCTTY
4128d522f475Smrg	    setsid();
4129d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4130d522f475Smrg#endif
4131d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4132d522f475Smrg	    setpgrp(0, 0);
4133d522f475Smrg	    close(open(ttydev, O_WRONLY));
4134d522f475Smrg	    setpgrp(0, pgrp);
4135d522f475Smrg#if defined(__QNX__)
4136d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4137d522f475Smrg#endif
4138d522f475Smrg#endif /* !USE_SYSV_PGRP */
4139d522f475Smrg
4140d522f475Smrg#ifdef Lynx
4141d522f475Smrg	    {
4142d522f475Smrg		TERMIO_STRUCT t;
4143d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4144d522f475Smrg		    /* this gets lost somewhere on our way... */
4145d522f475Smrg		    t.c_oflag |= OPOST;
4146d522f475Smrg		    ttySetAttr(0, &t);
4147d522f475Smrg		}
4148d522f475Smrg	    }
4149d522f475Smrg#endif
4150d522f475Smrg
4151d522f475Smrg#ifdef HAVE_UTMP
4152d522f475Smrg	    login_name = NULL;
41530bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
41540bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4155d522f475Smrg	    }
4156d522f475Smrg	    if (login_name != NULL) {
4157d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4158d522f475Smrg	    }
4159d522f475Smrg#ifndef USE_UTEMPTER
4160d522f475Smrg#ifdef USE_UTMP_SETGID
4161d522f475Smrg	    setEffectiveGroup(save_egid);
4162d522f475Smrg	    TRACE_IDS;
4163d522f475Smrg#endif
4164d522f475Smrg#ifdef USE_SYSV_UTMP
4165d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4166d522f475Smrg	     * for the following reasons:
4167d522f475Smrg	     *   - It needs to have our correct process id (for
4168d522f475Smrg	     *     login).
4169d522f475Smrg	     *   - If our parent was to set it after the fork(),
4170d522f475Smrg	     *     it might make it out before we need it.
4171d522f475Smrg	     *   - We need to do it before we go and change our
4172d522f475Smrg	     *     user and group id's.
4173d522f475Smrg	     */
4174d522f475Smrg	    (void) call_setutent();
4175d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4176d522f475Smrg
4177d522f475Smrg	    /* position to entry in utmp file */
4178d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
417920d2c4d2Smrg	    utret = find_utmp(&utmp);
418020d2c4d2Smrg	    if (utret == 0) {
4181d522f475Smrg		(void) call_setutent();
4182d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
418320d2c4d2Smrg		utret = find_utmp(&utmp);
418420d2c4d2Smrg		if (utret == 0) {
4185d522f475Smrg		    (void) call_setutent();
4186d522f475Smrg		}
4187d522f475Smrg	    }
4188d522f475Smrg#if OPT_TRACE
4189d522f475Smrg	    if (!utret)
4190d522f475Smrg		TRACE(("getutid: NULL\n"));
4191d522f475Smrg	    else
41920bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
419320d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
41940bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
41950bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4196d522f475Smrg#endif
4197d522f475Smrg
4198d522f475Smrg	    /* set up the new entry */
4199d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4200d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4201d522f475Smrg	    utmp.ut_xstatus = 2;
4202d522f475Smrg#endif
4203d522f475Smrg	    (void) strncpy(utmp.ut_user,
4204d522f475Smrg			   (login_name != NULL) ? login_name : "????",
4205d522f475Smrg			   sizeof(utmp.ut_user));
4206d522f475Smrg	    /* why are we copying this string again?  (see above) */
4207d522f475Smrg	    (void) strncpy(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4208d522f475Smrg	    (void) strncpy(utmp.ut_line,
4209d522f475Smrg			   my_pty_name(ttydev), sizeof(utmp.ut_line));
4210d522f475Smrg
4211d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4212d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4213d522f475Smrg#endif
4214d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4215d522f475Smrg	    SetUtmpSysLen(utmp);
4216d522f475Smrg#endif
4217d522f475Smrg
4218d522f475Smrg	    (void) strncpy(utmp.ut_name,
4219d522f475Smrg			   (login_name) ? login_name : "????",
4220d522f475Smrg			   sizeof(utmp.ut_name));
4221d522f475Smrg
4222d522f475Smrg	    utmp.ut_pid = getpid();
4223d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4224d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4225d522f475Smrg	    utmp.ut_session = getsid(0);
4226d522f475Smrg#endif
4227d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
4228d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
4229d522f475Smrg#else
4230d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
4231d522f475Smrg#endif
4232d522f475Smrg
4233d522f475Smrg	    /* write out the entry */
4234d522f475Smrg	    if (!resource.utmpInhibit) {
4235d522f475Smrg		errno = 0;
4236d522f475Smrg		call_pututline(&utmp);
42370bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
42380bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
42390bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
4240d522f475Smrg		       (long) utmp.ut_pid,
4241d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
4242d522f475Smrg	    }
4243d522f475Smrg#ifdef WTMP
4244d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
4245d522f475Smrg	    if (xw->misc.login_shell)
4246d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
4247d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4248d522f475Smrg	    if (xw->misc.login_shell)
4249d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
4250d522f475Smrg#else
4251d522f475Smrg	    if (xw->misc.login_shell &&
4252d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
42530bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4254d522f475Smrg		close(i);
4255d522f475Smrg	    }
4256d522f475Smrg#endif
4257d522f475Smrg#endif
4258d522f475Smrg	    /* close the file */
4259d522f475Smrg	    (void) call_endutent();
4260d522f475Smrg
4261d522f475Smrg#else /* USE_SYSV_UTMP */
4262d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
4263d522f475Smrg	     * utmp entry.
4264d522f475Smrg	     */
4265d522f475Smrg	    tslot = ttyslot();
4266d522f475Smrg	    added_utmp_entry = False;
4267d522f475Smrg	    {
42680bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
4269d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
4270956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
4271d522f475Smrg		    (void) strncpy(utmp.ut_line,
4272d522f475Smrg				   my_pty_name(ttydev),
4273d522f475Smrg				   sizeof(utmp.ut_line));
4274d522f475Smrg		    (void) strncpy(utmp.ut_name, login_name,
4275d522f475Smrg				   sizeof(utmp.ut_name));
4276d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4277d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
4278d522f475Smrg#endif
4279d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4280d522f475Smrg		    SetUtmpSysLen(utmp);
4281d522f475Smrg#endif
4282d522f475Smrg
4283d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
4284d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
42850bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4286d522f475Smrg		    close(i);
4287d522f475Smrg		    added_utmp_entry = True;
4288d522f475Smrg#if defined(WTMP)
4289d522f475Smrg		    if (xw->misc.login_shell &&
4290d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4291d522f475Smrg			int status;
4292d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
4293d522f475Smrg			status = close(i);
4294d522f475Smrg		    }
4295d522f475Smrg#elif defined(MNX_LASTLOG)
4296d522f475Smrg		    if (xw->misc.login_shell &&
4297d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
4298d522f475Smrg			lseek(i, (long) (screen->uid *
4299d522f475Smrg					 sizeof(utmp)), 0);
43000bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4301d522f475Smrg			close(i);
4302d522f475Smrg		    }
4303d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
4304d522f475Smrg		} else
4305d522f475Smrg		    tslot = -tslot;
4306d522f475Smrg	    }
4307d522f475Smrg
4308d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
4309d522f475Smrg	     * clean up after us.
4310d522f475Smrg	     */
4311d522f475Smrg#if OPT_PTY_HANDSHAKE
4312d522f475Smrg	    if (resource.ptyHandshake) {
4313d522f475Smrg		handshake.tty_slot = tslot;
4314d522f475Smrg	    }
4315d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4316d522f475Smrg#endif /* USE_SYSV_UTMP */
4317d522f475Smrg
4318d522f475Smrg#ifdef USE_LASTLOGX
4319d522f475Smrg	    if (xw->misc.login_shell) {
4320956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
4321d522f475Smrg		(void) strncpy(lastlogx.ll_line,
4322d522f475Smrg			       my_pty_name(ttydev),
4323d522f475Smrg			       sizeof(lastlogx.ll_line));
4324d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
4325d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
4326d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
4327d522f475Smrg	    }
4328d522f475Smrg#endif
4329d522f475Smrg
4330d522f475Smrg#ifdef USE_LASTLOG
4331d522f475Smrg	    if (xw->misc.login_shell &&
4332d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
4333d522f475Smrg		size_t size = sizeof(struct lastlog);
43340bd37d32Smrg		off_t offset = (off_t) (screen->uid * size);
4335d522f475Smrg
4336956cc18dSsnj		memset(&lastlog, 0, size);
4337d522f475Smrg		(void) strncpy(lastlog.ll_line,
4338d522f475Smrg			       my_pty_name(ttydev),
4339d522f475Smrg			       sizeof(lastlog.ll_line));
4340d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
4341d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
4342d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
43430bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
4344d522f475Smrg		}
4345d522f475Smrg		close(i);
4346d522f475Smrg	    }
4347d522f475Smrg#endif /* USE_LASTLOG */
4348d522f475Smrg
4349d522f475Smrg#if defined(USE_UTMP_SETGID)
4350d522f475Smrg	    disableSetGid();
4351d522f475Smrg	    TRACE_IDS;
4352d522f475Smrg#endif
4353d522f475Smrg
4354d522f475Smrg#if OPT_PTY_HANDSHAKE
4355d522f475Smrg	    /* Let our parent know that we set up our utmp entry
4356d522f475Smrg	     * so that it can clean up after us.
4357d522f475Smrg	     */
4358d522f475Smrg	    if (resource.ptyHandshake) {
4359d522f475Smrg		handshake.status = UTMP_ADDED;
4360d522f475Smrg		handshake.error = 0;
43610bd37d32Smrg		strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4362d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
436320d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
4364d522f475Smrg	    }
4365d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4366d522f475Smrg#endif /* USE_UTEMPTER */
4367d522f475Smrg#endif /* HAVE_UTMP */
4368d522f475Smrg
436920d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
4370d522f475Smrg	    TRACE_IDS;
4371d522f475Smrg#ifdef HAS_BSD_GROUPS
43720bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
43730bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
4374d522f475Smrg		    perror("initgroups failed");
4375d522f475Smrg		    SysError(ERROR_INIGROUPS);
4376d522f475Smrg		}
4377d522f475Smrg	    }
4378d522f475Smrg#endif
4379d522f475Smrg	    if (setuid(screen->uid)) {
4380d522f475Smrg		SysError(ERROR_SETUID);
4381d522f475Smrg	    }
4382d522f475Smrg	    TRACE_IDS;
4383d522f475Smrg#if OPT_PTY_HANDSHAKE
4384d522f475Smrg	    if (resource.ptyHandshake) {
4385d522f475Smrg		/* mark the pipes as close on exec */
43860bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
43870bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
4388d522f475Smrg
4389d522f475Smrg		/* We are at the point where we are going to
4390d522f475Smrg		 * exec our shell (or whatever).  Let our parent
4391d522f475Smrg		 * know we arrived safely.
4392d522f475Smrg		 */
4393d522f475Smrg		handshake.status = PTY_GOOD;
4394d522f475Smrg		handshake.error = 0;
43950bd37d32Smrg		(void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4396d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
439720d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
439820d2c4d2Smrg				(const char *) &handshake,
439920d2c4d2Smrg				sizeof(handshake)));
4400d522f475Smrg
4401d522f475Smrg		if (resource.wait_for_map) {
440220d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
440320d2c4d2Smrg				   sizeof(handshake));
4404d522f475Smrg		    if (i != sizeof(handshake) ||
4405d522f475Smrg			handshake.status != PTY_EXEC) {
4406d522f475Smrg			/* some very bad problem occurred */
4407d522f475Smrg			exit(ERROR_PTY_EXEC);
4408d522f475Smrg		    }
4409d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
4410d522f475Smrg			TRACE(("handshake ttysize: %dx%d\n",
4411d522f475Smrg			       handshake.rows, handshake.cols));
4412d522f475Smrg			set_max_row(screen, handshake.rows);
4413d522f475Smrg			set_max_col(screen, handshake.cols);
4414d522f475Smrg#ifdef TTYSIZE_STRUCT
4415d522f475Smrg			got_handshake_size = True;
441620d2c4d2Smrg			TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
441720d2c4d2Smrg			TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
4418d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
441920d2c4d2Smrg			ts.ws_xpixel = (ttySize_t) FullWidth(screen);
442020d2c4d2Smrg			ts.ws_ypixel = (ttySize_t) FullHeight(screen);
4421d522f475Smrg#endif
4422d522f475Smrg#endif /* TTYSIZE_STRUCT */
4423d522f475Smrg		    }
4424d522f475Smrg		}
4425d522f475Smrg	    }
4426d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4427d522f475Smrg
4428d522f475Smrg#ifdef USE_SYSV_ENVVARS
4429d522f475Smrg	    {
4430d522f475Smrg		char numbuf[12];
4431d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
4432d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
4433d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
4434d522f475Smrg		xtermSetenv("LINES", numbuf);
4435d522f475Smrg	    }
4436d522f475Smrg#ifdef HAVE_UTMP
44370bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
4438d522f475Smrg		if (!x_getenv("HOME"))
44390bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
4440d522f475Smrg		if (!x_getenv("SHELL"))
44410bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
4442d522f475Smrg	    }
4443d522f475Smrg#endif /* HAVE_UTMP */
4444d522f475Smrg#ifdef OWN_TERMINFO_DIR
4445d522f475Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
4446d522f475Smrg#endif
4447d522f475Smrg#else /* USE_SYSV_ENVVARS */
444820d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
444920d2c4d2Smrg		resize_termcap(xw);
445020d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
445120d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
445220d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
445320d2c4d2Smrg		}
445420d2c4d2Smrg		/*
445520d2c4d2Smrg		 * work around broken termcap entries */
445620d2c4d2Smrg		if (resource.useInsertMode) {
445720d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
445820d2c4d2Smrg		    /* don't get duplicates */
445920d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
446020d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
446120d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
446220d2c4d2Smrg		    if (*newtc)
446320d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
446420d2c4d2Smrg		}
446520d2c4d2Smrg		if (*newtc) {
4466d522f475Smrg#if OPT_INITIAL_ERASE
446720d2c4d2Smrg		    unsigned len;
446820d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
446920d2c4d2Smrg		    len = (unsigned) strlen(newtc);
447020d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
447120d2c4d2Smrg			len--;
447220d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
447320d2c4d2Smrg			    TERMCAP_ERASE,
447420d2c4d2Smrg			    CharOf(initial_erase));
447520d2c4d2Smrg#endif
447620d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
447720d2c4d2Smrg		}
4478d522f475Smrg	    }
4479d522f475Smrg#endif /* USE_SYSV_ENVVARS */
4480d522f475Smrg
4481d522f475Smrg#if OPT_PTY_HANDSHAKE
4482d522f475Smrg	    /*
4483d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
4484d522f475Smrg	     *
4485d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
4486d522f475Smrg	     * use that to prevent races.
4487d522f475Smrg	     */
4488d522f475Smrg	    if (resource.ptyHandshake
4489d522f475Smrg		&& resource.ptySttySize
4490d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
4491d522f475Smrg#ifdef TTYSIZE_STRUCT
449220d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
4493d522f475Smrg		TRACE(("ptyHandshake SET_TTYSIZE %dx%d return %d\n",
4494d522f475Smrg		       TTYSIZE_ROWS(ts),
4495d522f475Smrg		       TTYSIZE_COLS(ts), i));
4496d522f475Smrg#endif /* TTYSIZE_STRUCT */
4497d522f475Smrg	    }
4498d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4499d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4500d522f475Smrg
45010bd37d32Smrg	    /*
45020bd37d32Smrg	     * If we have an explicit program to run, make that set $SHELL.
45030bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
45040bd37d32Smrg	     * password information, if possible.
45050bd37d32Smrg	     *
45060bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
45070bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
45080bd37d32Smrg	     */
45090bd37d32Smrg	    if ((shell_path = explicit_shname) == NULL) {
45100bd37d32Smrg		if ((shell_path = x_getenv("SHELL")) == NULL) {
45110bd37d32Smrg		    if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
45120bd37d32Smrg			|| *(shell_path = x_strdup(pw.pw_shell)) == 0) {
45130bd37d32Smrg			if (shell_path)
45140bd37d32Smrg			    free(shell_path);
45150bd37d32Smrg			shell_path = x_strdup("/bin/sh");
45160bd37d32Smrg		    } else if (shell_path != 0) {
45170bd37d32Smrg			xtermSetenv("SHELL", shell_path);
45180bd37d32Smrg		    }
4519d522f475Smrg		}
4520d522f475Smrg	    } else {
4521d522f475Smrg		xtermSetenv("SHELL", explicit_shname);
4522d522f475Smrg	    }
45230bd37d32Smrg	    if (access(shell_path, X_OK) != 0) {
45240bd37d32Smrg		xtermPerror("Cannot use '%s' as shell", shell_path);
45250bd37d32Smrg		free(shell_path);
45260bd37d32Smrg		shell_path = x_strdup("/bin/sh");
45270bd37d32Smrg	    }
45280bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
4529d522f475Smrg
45300bd37d32Smrg	    shname = x_basename(shell_path);
45310bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
4532d522f475Smrg
4533d522f475Smrg#if OPT_LUIT_PROG
4534d522f475Smrg	    /*
4535d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
4536d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
4537d522f475Smrg	     * to command that the user gave anyway.
4538d522f475Smrg	     */
45392eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
45400bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
45410bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
45420bd37d32Smrg		free(myShell);
45430bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
4544d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
45450bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
45460bd37d32Smrg		xtermWarning("cannot support your locale.\n");
4547d522f475Smrg	    }
4548d522f475Smrg#endif
4549d522f475Smrg	    if (command_to_exec) {
45500bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
45510bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
45520bd37d32Smrg		free(myShell);
45530bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
4554d522f475Smrg		execvp(*command_to_exec, command_to_exec);
4555d522f475Smrg		if (command_to_exec[1] == 0)
45560bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
45570bd37d32Smrg			   (void *) 0);
45580bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
4559d522f475Smrg	    }
4560d522f475Smrg#ifdef USE_SYSV_SIGHUP
4561d522f475Smrg	    /* fix pts sh hanging around */
4562d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4563d522f475Smrg#endif
4564d522f475Smrg
4565d522f475Smrg	    shname_minus = CastMallocN(char, strlen(shname) + 2);
4566d522f475Smrg	    (void) strcpy(shname_minus, "-");
4567d522f475Smrg	    (void) strcat(shname_minus, shname);
4568d522f475Smrg#ifndef TERMIO_STRUCT
45690bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
45700bd37d32Smrg		     ? NTTYDISC
45710bd37d32Smrg		     : 0);
4572d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
4573d522f475Smrg#endif /* !TERMIO_STRUCT */
4574d522f475Smrg
4575d522f475Smrg#ifdef USE_LOGIN_DASH_P
45760bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
4577d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
4578d522f475Smrg#endif
45792eaa94a1Schristos
45802eaa94a1Schristos#if OPT_LUIT_PROG
45812eaa94a1Schristos	    if (command_to_exec_with_luit) {
45822eaa94a1Schristos		if (xw->misc.login_shell) {
45830bd37d32Smrg		    char *params[4];
45840bd37d32Smrg		    params[0] = x_strdup("-argv0");
45850bd37d32Smrg		    params[1] = shname_minus;
45860bd37d32Smrg		    params[2] = NULL;
45870bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
45880bd37d32Smrg				 + command_length_with_luit,
45890bd37d32Smrg				 params);
45902eaa94a1Schristos		}
45910bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
45922eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
45932eaa94a1Schristos		/* Exec failed. */
45940bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
45952eaa94a1Schristos	    }
45962eaa94a1Schristos#endif
45970bd37d32Smrg	    execlp(shell_path,
4598d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
4599d522f475Smrg		   (void *) 0);
4600d522f475Smrg
4601d522f475Smrg	    /* Exec failed. */
46020bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
460320d2c4d2Smrg	    IGNORE_RC(sleep(5));
46040bd37d32Smrg	    free(shell_path);
4605d522f475Smrg	    exit(ERROR_EXEC);
4606d522f475Smrg	}
4607d522f475Smrg	/* end if in child after fork */
4608d522f475Smrg#if OPT_PTY_HANDSHAKE
4609d522f475Smrg	if (resource.ptyHandshake) {
4610d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
4611d522f475Smrg	     * child process.
4612d522f475Smrg	     */
4613d522f475Smrg
4614d522f475Smrg	    /* close childs's sides of the pipes */
4615d522f475Smrg	    close(cp_pipe[1]);
4616d522f475Smrg	    close(pc_pipe[0]);
4617d522f475Smrg
4618d522f475Smrg	    for (done = 0; !done;) {
4619d522f475Smrg		if (read(cp_pipe[0],
4620d522f475Smrg			 (char *) &handshake,
4621d522f475Smrg			 sizeof(handshake)) <= 0) {
4622d522f475Smrg		    /* Our child is done talking to us.  If it terminated
4623d522f475Smrg		     * due to an error, we will catch the death of child
4624d522f475Smrg		     * and clean up.
4625d522f475Smrg		     */
4626d522f475Smrg		    break;
4627d522f475Smrg		}
4628d522f475Smrg
4629d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
4630d522f475Smrg		switch (handshake.status) {
4631d522f475Smrg		case PTY_GOOD:
4632d522f475Smrg		    /* Success!  Let's free up resources and
4633d522f475Smrg		     * continue.
4634d522f475Smrg		     */
4635d522f475Smrg		    done = 1;
4636d522f475Smrg		    break;
4637d522f475Smrg
4638d522f475Smrg		case PTY_BAD:
4639d522f475Smrg		    /* The open of the pty failed!  Let's get
4640d522f475Smrg		     * another one.
4641d522f475Smrg		     */
464220d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
4643d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
4644d522f475Smrg			/* no more ptys! */
46450bd37d32Smrg			xtermPerror("child process can find no available ptys");
4646d522f475Smrg			handshake.status = PTY_NOMORE;
4647d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
464820d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
464920d2c4d2Smrg					(const char *) &handshake,
465020d2c4d2Smrg					sizeof(handshake)));
4651d522f475Smrg			exit(ERROR_PTYS);
4652d522f475Smrg		    }
4653d522f475Smrg		    handshake.status = PTY_NEW;
46540bd37d32Smrg		    (void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4655d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
465620d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
465720d2c4d2Smrg				    (const char *) &handshake,
465820d2c4d2Smrg				    sizeof(handshake)));
4659d522f475Smrg		    break;
4660d522f475Smrg
4661d522f475Smrg		case PTY_FATALERROR:
4662d522f475Smrg		    errno = handshake.error;
4663d522f475Smrg		    close(cp_pipe[0]);
4664d522f475Smrg		    close(pc_pipe[1]);
4665d522f475Smrg		    SysError(handshake.fatal_error);
4666d522f475Smrg		    /*NOTREACHED */
4667d522f475Smrg
4668d522f475Smrg		case UTMP_ADDED:
4669d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
4670d522f475Smrg		     * this so that we can reset it later.
4671d522f475Smrg		     */
4672d522f475Smrg		    added_utmp_entry = True;
4673d522f475Smrg#ifndef	USE_SYSV_UTMP
4674d522f475Smrg		    tslot = handshake.tty_slot;
4675d522f475Smrg#endif /* USE_SYSV_UTMP */
4676d522f475Smrg		    free(ttydev);
4677d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
4678d522f475Smrg		    break;
4679d522f475Smrg		case PTY_NEW:
4680d522f475Smrg		case PTY_NOMORE:
4681d522f475Smrg		case UTMP_TTYSLOT:
4682d522f475Smrg		case PTY_EXEC:
4683d522f475Smrg		default:
46840bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
46850bd37d32Smrg				 (int) handshake.status);
4686d522f475Smrg		}
4687d522f475Smrg	    }
4688d522f475Smrg	    /* close our sides of the pipes */
4689d522f475Smrg	    if (!resource.wait_for_map) {
4690d522f475Smrg		close(cp_pipe[0]);
4691d522f475Smrg		close(pc_pipe[1]);
4692d522f475Smrg	    }
4693d522f475Smrg	}
4694d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4695d522f475Smrg    }
4696d522f475Smrg
4697d522f475Smrg    /* end if no slave */
4698d522f475Smrg    /*
4699d522f475Smrg     * still in parent (xterm process)
4700d522f475Smrg     */
4701d522f475Smrg#ifdef USE_SYSV_SIGHUP
4702d522f475Smrg    /* hung sh problem? */
4703d522f475Smrg    signal(SIGHUP, SIG_DFL);
4704d522f475Smrg#else
4705d522f475Smrg    signal(SIGHUP, SIG_IGN);
4706d522f475Smrg#endif
4707d522f475Smrg
4708d522f475Smrg/*
4709d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
4710d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
4711d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
4712d522f475Smrg * don't ignore the signals.  This is annoying.
4713d522f475Smrg */
4714d522f475Smrg
4715d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
4716d522f475Smrg    signal(SIGINT, SIG_IGN);
4717d522f475Smrg
4718d522f475Smrg#ifndef SYSV
4719d522f475Smrg    /* hung shell problem */
4720d522f475Smrg    signal(SIGQUIT, SIG_IGN);
4721d522f475Smrg#endif
4722d522f475Smrg    signal(SIGTERM, SIG_IGN);
4723d522f475Smrg#elif defined(SYSV) || defined(__osf__)
4724d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
4725d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
4726d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
4727d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
4728d522f475Smrg     * tank on everything.
4729d522f475Smrg     */
4730d522f475Smrg    if (getpid() == getpgrp()) {
4731d522f475Smrg	(void) signal(SIGINT, Exit);
4732d522f475Smrg	(void) signal(SIGQUIT, Exit);
4733d522f475Smrg	(void) signal(SIGTERM, Exit);
4734d522f475Smrg    } else {
4735d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
4736d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
4737d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
4738d522f475Smrg    }
4739d522f475Smrg    (void) signal(SIGPIPE, Exit);
4740d522f475Smrg#else /* SYSV */
4741d522f475Smrg    signal(SIGINT, Exit);
4742d522f475Smrg    signal(SIGQUIT, Exit);
4743d522f475Smrg    signal(SIGTERM, Exit);
4744d522f475Smrg    signal(SIGPIPE, Exit);
4745d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
47460bd37d32Smrg#ifdef NO_LEAKS
47470bd37d32Smrg    if (ok_termcap != True)
47480bd37d32Smrg	free(TermName);
47490bd37d32Smrg#endif
4750d522f475Smrg
4751d522f475Smrg    return 0;
4752d522f475Smrg}				/* end spawnXTerm */
4753d522f475Smrg
47540bd37d32Smrgvoid
4755d522f475SmrgExit(int n)
4756d522f475Smrg{
475720d2c4d2Smrg    XtermWidget xw = term;
475820d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
4759d522f475Smrg
4760d522f475Smrg#ifdef USE_UTEMPTER
47610bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
47620bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
47630bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
4764d522f475Smrg	removeFromUtmp();
47650bd37d32Smrg    }
4766d522f475Smrg#elif defined(HAVE_UTMP)
4767d522f475Smrg#ifdef USE_SYSV_UTMP
4768d522f475Smrg    struct UTMP_STR utmp;
4769d522f475Smrg    struct UTMP_STR *utptr;
4770d522f475Smrg
47710bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
4772d522f475Smrg    /* don't do this more than once */
47730bd37d32Smrg    if (xterm_exiting) {
47740bd37d32Smrg	exit(n);
47750bd37d32Smrg    }
4776d522f475Smrg    xterm_exiting = True;
4777d522f475Smrg
4778d522f475Smrg#ifdef PUCC_PTYD
4779d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
4780d522f475Smrg#endif /* PUCC_PTYD */
4781d522f475Smrg
4782d522f475Smrg    /* cleanup the utmp entry we forged earlier */
4783d522f475Smrg    if (!resource.utmpInhibit
4784d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
4785d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
4786d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4787d522f475Smrg	) {
4788d522f475Smrg#if defined(USE_UTMP_SETGID)
4789d522f475Smrg	setEffectiveGroup(save_egid);
4790d522f475Smrg	TRACE_IDS;
4791d522f475Smrg#endif
4792d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
4793d522f475Smrg	(void) call_setutent();
4794d522f475Smrg
4795d522f475Smrg	/*
4796d522f475Smrg	 * We could use getutline() if we didn't support old systems.
4797d522f475Smrg	 */
4798d522f475Smrg	while ((utptr = find_utmp(&utmp)) != 0) {
4799d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
4800d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
4801d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4802d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4803d522f475Smrg		utptr->ut_session = getsid(0);
4804d522f475Smrg#endif
4805d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
4806d522f475Smrg		utptr->ut_tv.tv_usec = 0;
4807d522f475Smrg#else
4808d522f475Smrg		*utptr->ut_user = 0;
4809d522f475Smrg		utptr->ut_time = time((time_t *) 0);
4810d522f475Smrg#endif
4811d522f475Smrg		(void) call_pututline(utptr);
4812d522f475Smrg#ifdef WTMP
4813d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
481420d2c4d2Smrg		if (xw->misc.login_shell)
4815d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
4816d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4817d522f475Smrg		strncpy(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
481820d2c4d2Smrg		if (xw->misc.login_shell)
4819d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
4820d522f475Smrg#else
4821d522f475Smrg		/* set wtmp entry if wtmp file exists */
482220d2c4d2Smrg		if (xw->misc.login_shell) {
4823d522f475Smrg		    int fd;
4824d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
48250bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
4826d522f475Smrg			close(fd);
4827d522f475Smrg		    }
4828d522f475Smrg		}
4829d522f475Smrg#endif
4830d522f475Smrg#endif
4831d522f475Smrg		break;
4832d522f475Smrg	    }
4833d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
4834d522f475Smrg	}
4835d522f475Smrg	(void) call_endutent();
4836d522f475Smrg#ifdef USE_UTMP_SETGID
4837d522f475Smrg	disableSetGid();
4838d522f475Smrg	TRACE_IDS;
4839d522f475Smrg#endif
4840d522f475Smrg    }
4841d522f475Smrg#else /* not USE_SYSV_UTMP */
4842d522f475Smrg    int wfd;
4843d522f475Smrg    struct utmp utmp;
4844d522f475Smrg
48450bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
4846d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
4847d522f475Smrg	(am_slave < 0 && tslot > 0)) {
4848d522f475Smrg#if defined(USE_UTMP_SETGID)
4849d522f475Smrg	setEffectiveGroup(save_egid);
4850d522f475Smrg	TRACE_IDS;
4851d522f475Smrg#endif
4852d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
4853956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
4854d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
48550bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
4856d522f475Smrg	    close(wfd);
4857d522f475Smrg	}
4858d522f475Smrg#ifdef WTMP
485920d2c4d2Smrg	if (xw->misc.login_shell &&
4860d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4861d522f475Smrg	    (void) strncpy(utmp.ut_line,
4862d522f475Smrg			   my_pty_name(ttydev),
4863d522f475Smrg			   sizeof(utmp.ut_line));
4864d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
48650bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
4866d522f475Smrg	    close(wfd);
4867d522f475Smrg	}
4868d522f475Smrg#endif /* WTMP */
4869d522f475Smrg#ifdef USE_UTMP_SETGID
4870d522f475Smrg	disableSetGid();
4871d522f475Smrg	TRACE_IDS;
4872d522f475Smrg#endif
4873d522f475Smrg    }
4874d522f475Smrg#endif /* USE_SYSV_UTMP */
4875d522f475Smrg#endif /* HAVE_UTMP */
4876d522f475Smrg
4877d522f475Smrg    /*
4878d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
4879d522f475Smrg     * in the middle of the data.
4880d522f475Smrg     */
4881d522f475Smrg    ttyFlush(screen->respond);
4882d522f475Smrg
4883e39b573cSmrg#ifdef USE_PTY_SEARCH
4884d522f475Smrg    if (am_slave < 0) {
4885d522f475Smrg	TRACE_IDS;
4886d522f475Smrg	/* restore ownership of tty and pty */
4887d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
4888d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
4889d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
4890d522f475Smrg#endif
4891d522f475Smrg    }
4892e39b573cSmrg#endif
4893d522f475Smrg
4894d522f475Smrg    /*
48950bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
4896d522f475Smrg     * grabbing it, and *then* having us release ownership....
4897d522f475Smrg     */
4898d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
4899d522f475Smrg#ifdef ALLOWLOGGING
4900d522f475Smrg    if (screen->logging)
490120d2c4d2Smrg	CloseLog(xw);
4902d522f475Smrg#endif
4903d522f475Smrg
4904e39b573cSmrg    xtermPrintOnXError(xw, n);
4905e39b573cSmrg
4906d522f475Smrg#ifdef NO_LEAKS
4907d522f475Smrg    if (n == 0) {
49080bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
49090bd37d32Smrg
4910d522f475Smrg	TRACE(("Freeing memory leaks\n"));
4911d522f475Smrg
49120bd37d32Smrg	if (toplevel) {
49130bd37d32Smrg	    XtDestroyWidget(toplevel);
49140bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
49150bd37d32Smrg	}
49160bd37d32Smrg	sortedOpts(0, 0, 0);
49170bd37d32Smrg	noleaks_charproc();
49180bd37d32Smrg	noleaks_ptydata();
4919d522f475Smrg#if OPT_WIDE_CHARS
49200bd37d32Smrg	noleaks_CharacterClass();
4921d522f475Smrg#endif
49220bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
49230bd37d32Smrg	XtCloseDisplay(dpy);
49240bd37d32Smrg	XtDestroyApplicationContext(app_con);
49250bd37d32Smrg	xtermCloseSession();
49260bd37d32Smrg	TRACE(("closed display\n"));
49270bd37d32Smrg
492820d2c4d2Smrg	TRACE_CLOSE();
4929d522f475Smrg    }
4930d522f475Smrg#endif
4931d522f475Smrg
4932d522f475Smrg    exit(n);
4933d522f475Smrg}
4934d522f475Smrg
4935d522f475Smrg/* ARGSUSED */
4936d522f475Smrgstatic void
493720d2c4d2Smrgresize_termcap(XtermWidget xw)
4938d522f475Smrg{
493920d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
494020d2c4d2Smrg
4941d522f475Smrg#ifndef USE_SYSV_ENVVARS
4942d522f475Smrg    if (!TEK4014_ACTIVE(xw) && *newtc) {
4943d522f475Smrg	TScreen *screen = TScreenOf(xw);
4944d522f475Smrg	char *ptr1, *ptr2;
4945d522f475Smrg	size_t i;
4946d522f475Smrg	int li_first = 0;
4947d522f475Smrg	char *temp;
4948d522f475Smrg	char oldtc[TERMCAP_SIZE];
4949d522f475Smrg
4950d522f475Smrg	strcpy(oldtc, newtc);
4951d522f475Smrg	TRACE(("resize %s\n", oldtc));
4952d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
4953d522f475Smrg	    strcat(oldtc, "co#80:");
4954d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
4955d522f475Smrg	}
4956d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
4957d522f475Smrg	    strcat(oldtc, "li#24:");
4958d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
4959d522f475Smrg	}
4960d522f475Smrg	if (ptr1 > ptr2) {
4961d522f475Smrg	    li_first++;
4962d522f475Smrg	    temp = ptr1;
4963d522f475Smrg	    ptr1 = ptr2;
4964d522f475Smrg	    ptr2 = temp;
4965d522f475Smrg	}
4966d522f475Smrg	ptr1 += 3;
4967d522f475Smrg	ptr2 += 3;
4968956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
4969d522f475Smrg	temp = newtc + i;
4970d522f475Smrg	sprintf(temp, "%d", (li_first
4971d522f475Smrg			     ? MaxRows(screen)
4972d522f475Smrg			     : MaxCols(screen)));
4973d522f475Smrg	temp += strlen(temp);
49740bd37d32Smrg	if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) {
49750bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
49760bd37d32Smrg	    temp += i;
49770bd37d32Smrg	    sprintf(temp, "%d", (li_first
49780bd37d32Smrg				 ? MaxCols(screen)
49790bd37d32Smrg				 : MaxRows(screen)));
49800bd37d32Smrg	    if ((ptr2 = strchr(ptr2, ':')) != 0) {
49810bd37d32Smrg		strcat(temp, ptr2);
49820bd37d32Smrg	    }
49830bd37d32Smrg	}
4984d522f475Smrg	TRACE(("   ==> %s\n", newtc));
4985d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
4986d522f475Smrg    }
4987d522f475Smrg#endif /* USE_SYSV_ENVVARS */
4988d522f475Smrg}
4989d522f475Smrg
4990d522f475Smrg#endif /* ! VMS */
4991d522f475Smrg
4992d522f475Smrg/*
4993d522f475Smrg * Does a non-blocking wait for a child process.  If the system
4994d522f475Smrg * doesn't support non-blocking wait, do nothing.
4995d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
4996d522f475Smrg */
4997d522f475Smrgint
4998d522f475Smrgnonblocking_wait(void)
4999d522f475Smrg{
5000d522f475Smrg#ifdef USE_POSIX_WAIT
5001d522f475Smrg    pid_t pid;
5002d522f475Smrg
5003d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5004d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5005d522f475Smrg    /* cannot do non-blocking wait */
5006d522f475Smrg    int pid = 0;
5007d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5008d522f475Smrg#if defined(Lynx)
5009d522f475Smrg    int status;
5010d522f475Smrg#else
5011d522f475Smrg    union wait status;
5012d522f475Smrg#endif
5013d522f475Smrg    int pid;
5014d522f475Smrg
5015d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5016d522f475Smrg#endif /* USE_POSIX_WAIT else */
5017d522f475Smrg    return pid;
5018d522f475Smrg}
5019d522f475Smrg
5020d522f475Smrg#ifndef VMS
5021d522f475Smrg
5022d522f475Smrg/* ARGSUSED */
50230bd37d32Smrgstatic void
5024d522f475Smrgreapchild(int n GCC_UNUSED)
5025d522f475Smrg{
5026d522f475Smrg    int olderrno = errno;
5027d522f475Smrg    int pid;
5028d522f475Smrg
50290bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
50300bd37d32Smrg
5031d522f475Smrg    pid = wait(NULL);
5032d522f475Smrg
5033d522f475Smrg#ifdef USE_SYSV_SIGNALS
5034d522f475Smrg    /* cannot re-enable signal before waiting for child
5035d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5036d522f475Smrg     */
5037d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5038d522f475Smrg#endif
5039d522f475Smrg
5040d522f475Smrg    do {
504120d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
50420bd37d32Smrg	    DEBUG_MSG("Exiting\n");
5043d522f475Smrg	    if (!hold_screen)
5044d522f475Smrg		need_cleanup = True;
5045d522f475Smrg	}
5046d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5047d522f475Smrg
5048d522f475Smrg    errno = olderrno;
5049d522f475Smrg}
5050d522f475Smrg#endif /* !VMS */
5051d522f475Smrg
5052d522f475Smrgstatic void
505320d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5054d522f475Smrg{
5055d522f475Smrg    char *base = buf;
5056d522f475Smrg    char *first = base;
5057d522f475Smrg    int count = 0;
5058d522f475Smrg    size_t len = strlen(str);
5059d522f475Smrg
5060d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5061d522f475Smrg
5062d522f475Smrg    while (*buf != 0) {
5063d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5064d522f475Smrg	    while (*buf != 0) {
5065d522f475Smrg		if (*buf == '\\')
5066d522f475Smrg		    buf++;
5067d522f475Smrg		else if (*buf == ':')
5068d522f475Smrg		    break;
5069d522f475Smrg		if (*buf != 0)
5070d522f475Smrg		    buf++;
5071d522f475Smrg	    }
50720bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
50730bd37d32Smrg		;
50740bd37d32Smrg	    }
5075d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5076d522f475Smrg	    return;
5077d522f475Smrg	} else if (*buf == '\\') {
5078d522f475Smrg	    buf++;
5079d522f475Smrg	} else if (*buf == ':') {
5080d522f475Smrg	    first = buf;
5081d522f475Smrg	    count = 0;
5082d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5083d522f475Smrg	    count++;
5084d522f475Smrg	}
5085d522f475Smrg	if (*buf != 0)
5086d522f475Smrg	    buf++;
5087d522f475Smrg    }
5088d522f475Smrg    TRACE(("...cannot remove\n"));
5089d522f475Smrg}
5090d522f475Smrg
5091d522f475Smrg/*
5092d522f475Smrg * parse_tty_modes accepts lines of the following form:
5093d522f475Smrg *
5094d522f475Smrg *         [SETTING] ...
5095d522f475Smrg *
5096d522f475Smrg * where setting consists of the words in the modelist followed by a character
5097d522f475Smrg * or ^char.
5098d522f475Smrg */
5099d522f475Smrgstatic int
5100d522f475Smrgparse_tty_modes(char *s, struct _xttymodes *modelist)
5101d522f475Smrg{
5102d522f475Smrg    struct _xttymodes *mp;
5103d522f475Smrg    int c;
5104d522f475Smrg    int count = 0;
5105d522f475Smrg
5106d522f475Smrg    TRACE(("parse_tty_modes\n"));
5107a1f3da82Smrg    for (;;) {
5108d522f475Smrg	size_t len;
5109d522f475Smrg
5110d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5111d522f475Smrg	    s++;
5112d522f475Smrg	if (!*s)
5113d522f475Smrg	    return count;
5114d522f475Smrg
5115d522f475Smrg	for (len = 0; isalnum(CharOf(s[len])); ++len) ;
5116d522f475Smrg	for (mp = modelist; mp->name; mp++) {
5117d522f475Smrg	    if (len == mp->len
5118d522f475Smrg		&& strncmp(s, mp->name, mp->len) == 0)
5119d522f475Smrg		break;
5120d522f475Smrg	}
5121d522f475Smrg	if (!mp->name)
5122d522f475Smrg	    return -1;
5123d522f475Smrg
5124d522f475Smrg	s += mp->len;
5125d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5126d522f475Smrg	    s++;
5127d522f475Smrg	if (!*s)
5128d522f475Smrg	    return -1;
5129d522f475Smrg
5130d522f475Smrg	if ((c = decode_keyvalue(&s, False)) != -1) {
5131d522f475Smrg	    mp->value = c;
5132d522f475Smrg	    mp->set = 1;
5133d522f475Smrg	    count++;
5134d522f475Smrg	    TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
5135d522f475Smrg	}
5136d522f475Smrg    }
5137d522f475Smrg}
5138d522f475Smrg
5139d522f475Smrg#ifndef VMS			/* don't use pipes on OpenVMS */
5140d522f475Smrgint
5141d522f475SmrgGetBytesAvailable(int fd)
5142d522f475Smrg{
5143d522f475Smrg#if defined(FIONREAD)
5144d522f475Smrg    int arg;
5145d522f475Smrg    ioctl(fd, FIONREAD, (char *) &arg);
5146d522f475Smrg    return (int) arg;
5147d522f475Smrg#elif defined(__CYGWIN__)
5148d522f475Smrg    fd_set set;
514920d2c4d2Smrg    struct timeval select_timeout =
5150d522f475Smrg    {0, 0};
5151d522f475Smrg
5152d522f475Smrg    FD_ZERO(&set);
5153d522f475Smrg    FD_SET(fd, &set);
515420d2c4d2Smrg    if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0)
5155d522f475Smrg	return 1;
5156d522f475Smrg    else
5157d522f475Smrg	return 0;
5158d522f475Smrg#elif defined(FIORDCK)
5159d522f475Smrg    return (ioctl(fd, FIORDCHK, NULL));
5160d522f475Smrg#else /* !FIORDCK */
5161d522f475Smrg    struct pollfd pollfds[1];
5162d522f475Smrg
5163d522f475Smrg    pollfds[0].fd = fd;
5164d522f475Smrg    pollfds[0].events = POLLIN;
5165d522f475Smrg    return poll(pollfds, 1, 0);
5166d522f475Smrg#endif
5167d522f475Smrg}
5168d522f475Smrg#endif /* !VMS */
5169d522f475Smrg
5170d522f475Smrg/* Utility function to try to hide system differences from
5171d522f475Smrg   everybody who used to call killpg() */
5172d522f475Smrg
5173d522f475Smrgint
5174d522f475Smrgkill_process_group(int pid, int sig)
5175d522f475Smrg{
5176d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5177d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5178d522f475Smrg    return kill(-pid, sig);
5179d522f475Smrg#else
5180d522f475Smrg    return killpg(pid, sig);
5181d522f475Smrg#endif
5182d522f475Smrg}
5183d522f475Smrg
5184d522f475Smrg#if OPT_EBCDIC
5185d522f475Smrgint
5186d522f475SmrgA2E(int x)
5187d522f475Smrg{
5188d522f475Smrg    char c;
5189d522f475Smrg    c = x;
5190d522f475Smrg    __atoe_l(&c, 1);
5191d522f475Smrg    return c;
5192d522f475Smrg}
5193d522f475Smrg
5194d522f475Smrgint
5195d522f475SmrgE2A(int x)
5196d522f475Smrg{
5197d522f475Smrg    char c;
5198d522f475Smrg    c = x;
5199d522f475Smrg    __etoa_l(&c, 1);
5200d522f475Smrg    return c;
5201d522f475Smrg}
5202d522f475Smrg#endif
5203d522f475Smrg
5204d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
5205d522f475Smrg#include <sys/types.h>
5206d522f475Smrg#include <sys/proc_msg.h>
5207d522f475Smrg#include <sys/kernel.h>
5208d522f475Smrg#include <string.h>
5209d522f475Smrg#include <errno.h>
5210d522f475Smrg
5211d522f475Smrgstruct _proc_session ps;
5212d522f475Smrgstruct _proc_session_reply rps;
5213d522f475Smrg
5214d522f475Smrgint
5215d522f475Smrgqsetlogin(char *login, char *ttyname)
5216d522f475Smrg{
5217d522f475Smrg    int v = getsid(getpid());
5218d522f475Smrg
5219d522f475Smrg    memset(&ps, 0, sizeof(ps));
5220d522f475Smrg    memset(&rps, 0, sizeof(rps));
5221d522f475Smrg
5222d522f475Smrg    ps.type = _PROC_SESSION;
5223d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
5224d522f475Smrg    ps.sid = v;
5225d522f475Smrg    strcpy(ps.name, login);
5226d522f475Smrg
5227d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5228d522f475Smrg
5229d522f475Smrg    if (rps.status < 0)
5230d522f475Smrg	return (rps.status);
5231d522f475Smrg
5232d522f475Smrg    ps.type = _PROC_SESSION;
5233d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
5234d522f475Smrg    ps.sid = v;
5235d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
5236d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5237d522f475Smrg
5238d522f475Smrg    return (rps.status);
5239d522f475Smrg}
5240d522f475Smrg#endif
5241