main.c revision 2e4f8982
12e4f8982Smrg/* $XTermId: main.c,v 1.784 2016/10/07 00:40:34 tom Exp $ */
20bd37d32Smrg
30bd37d32Smrg/*
42e4f8982Smrg * Copyright 2002-2015,2016 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>
94894e0ac8Smrg#include <graphics.h>
95d522f475Smrg
96d522f475Smrg#include <X11/cursorfont.h>
97d522f475Smrg#include <X11/Xlocale.h>
98d522f475Smrg
99d522f475Smrg#if OPT_TOOLBAR
100d522f475Smrg
101d522f475Smrg#if defined(HAVE_LIB_XAW)
102d522f475Smrg#include <X11/Xaw/Form.h>
103d522f475Smrg#elif defined(HAVE_LIB_XAW3D)
104d522f475Smrg#include <X11/Xaw3d/Form.h>
10501037d57Smrg#elif defined(HAVE_LIB_XAW3DXFT)
10601037d57Smrg#include <X11/Xaw3dxft/Form.h>
107d522f475Smrg#elif defined(HAVE_LIB_NEXTAW)
108d522f475Smrg#include <X11/neXtaw/Form.h>
109d522f475Smrg#elif defined(HAVE_LIB_XAWPLUS)
110d522f475Smrg#include <X11/XawPlus/Form.h>
111d522f475Smrg#endif
112d522f475Smrg
113d522f475Smrg#endif /* OPT_TOOLBAR */
114d522f475Smrg
115d522f475Smrg#include <pwd.h>
116d522f475Smrg#include <ctype.h>
117d522f475Smrg
118d522f475Smrg#include <data.h>
119d522f475Smrg#include <error.h>
120d522f475Smrg#include <menu.h>
121d522f475Smrg#include <main.h>
122d522f475Smrg#include <xstrings.h>
123d522f475Smrg#include <xtermcap.h>
124d522f475Smrg#include <xterm_io.h>
125d522f475Smrg
126d522f475Smrg#if OPT_WIDE_CHARS
127d522f475Smrg#include <charclass.h>
128d522f475Smrg#endif
129d522f475Smrg
130d522f475Smrg#ifdef __osf__
131d522f475Smrg#define USE_SYSV_SIGNALS
132d522f475Smrg#define WTMP
133d522f475Smrg#include <pty.h>		/* openpty() */
134d522f475Smrg#endif
135d522f475Smrg
136d522f475Smrg#ifdef __sgi
137d522f475Smrg#include <grp.h>		/* initgroups() */
138d522f475Smrg#endif
139d522f475Smrg
1400bd37d32Smrgstatic void Syntax(char *) GCC_NORETURN;
1410bd37d32Smrgstatic void HsSysError(int) GCC_NORETURN;
142d522f475Smrg
1432e4f8982Smrg#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE) || ( defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 1) )
144d522f475Smrg#define USE_POSIX_SIGNALS
145d522f475Smrg#endif
146d522f475Smrg
147d522f475Smrg#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
148d522f475Smrg/* older SYSV systems cannot ignore SIGHUP.
149d522f475Smrg   Shell hangs, or you get extra shells, or something like that */
150d522f475Smrg#define USE_SYSV_SIGHUP
151d522f475Smrg#endif
152d522f475Smrg
153d522f475Smrg#if defined(sony) && defined(bsd43) && !defined(KANJI)
154d522f475Smrg#define KANJI
155d522f475Smrg#endif
156d522f475Smrg
157d522f475Smrg#ifdef linux
158d522f475Smrg#define USE_SYSV_PGRP
159d522f475Smrg#define USE_SYSV_SIGNALS
160d522f475Smrg#define WTMP
161d522f475Smrg#ifdef __GLIBC__
162d522f475Smrg#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
163d522f475Smrg#include <pty.h>
164d522f475Smrg#endif
165d522f475Smrg#endif
166d522f475Smrg#endif
167d522f475Smrg
168d522f475Smrg#ifdef __MVS__
169d522f475Smrg#define USE_SYSV_PGRP
170d522f475Smrg#define USE_SYSV_SIGNALS
171d522f475Smrg#endif
172d522f475Smrg
173d522f475Smrg#ifdef __CYGWIN__
174d522f475Smrg#define WTMP
175d522f475Smrg#endif
176d522f475Smrg
177d522f475Smrg#ifdef __SCO__
178d522f475Smrg#ifndef _SVID3
179d522f475Smrg#define _SVID3
180d522f475Smrg#endif
181d522f475Smrg#endif
182d522f475Smrg
183d522f475Smrg#if defined(__GLIBC__) && !defined(linux)
184d522f475Smrg#define USE_SYSV_PGRP
185d522f475Smrg#define WTMP
186d522f475Smrg#endif
187d522f475Smrg
188d522f475Smrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID)
189d522f475Smrg#include <grp.h>
190d522f475Smrg#endif
191d522f475Smrg
192d522f475Smrg#ifndef TTY_GROUP_NAME
193d522f475Smrg#define TTY_GROUP_NAME "tty"
194d522f475Smrg#endif
195d522f475Smrg
196d522f475Smrg#include <sys/stat.h>
197d522f475Smrg
198d522f475Smrg#ifdef Lynx
199d522f475Smrg#ifndef BSDLY
200d522f475Smrg#define BSDLY	0
201d522f475Smrg#endif
202d522f475Smrg#ifndef VTDLY
203d522f475Smrg#define VTDLY	0
204d522f475Smrg#endif
205d522f475Smrg#ifndef FFDLY
206d522f475Smrg#define FFDLY	0
207d522f475Smrg#endif
208d522f475Smrg#endif
209d522f475Smrg
210d522f475Smrg#ifdef SYSV			/* { */
211d522f475Smrg
212d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
213d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
214d522f475Smrg#include <poll.h>		/* for POLLIN */
215d522f475Smrg#endif /* USE_USG_PTYS */
216d522f475Smrg
217d522f475Smrg#define USE_SYSV_SIGNALS
218d522f475Smrg#define	USE_SYSV_PGRP
219d522f475Smrg
220d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
221d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
222d522f475Smrg#endif
223d522f475Smrg
224d522f475Smrg/*
225d522f475Smrg * now get system-specific includes
226d522f475Smrg */
227d522f475Smrg#ifdef macII
228d522f475Smrg#include <sys/ttychars.h>
229d522f475Smrg#undef USE_SYSV_ENVVARS
230d522f475Smrg#undef FIOCLEX
231d522f475Smrg#undef FIONCLEX
232d522f475Smrg#define setpgrp2 setpgrp
233d522f475Smrg#include <sgtty.h>
234d522f475Smrg#include <sys/resource.h>
235d522f475Smrg#endif
236d522f475Smrg
237d522f475Smrg#ifdef __hpux
238d522f475Smrg#include <sys/ptyio.h>
239d522f475Smrg#endif /* __hpux */
240d522f475Smrg
241d522f475Smrg#ifdef __osf__
242d522f475Smrg#undef  USE_SYSV_PGRP
243d522f475Smrg#define setpgrp setpgid
244d522f475Smrg#endif
245d522f475Smrg
246d522f475Smrg#ifdef __sgi
247d522f475Smrg#include <sys/sysmacros.h>
248d522f475Smrg#endif /* __sgi */
249d522f475Smrg
250d522f475Smrg#ifdef sun
251d522f475Smrg#include <sys/strredir.h>
252d522f475Smrg#endif
253d522f475Smrg
254e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
255d522f475Smrg
256d522f475Smrg#ifdef __QNX__
257d522f475Smrg
258d522f475Smrg#ifndef __QNXNTO__
259d522f475Smrg#define ttyslot() 1
260d522f475Smrg#else
261d522f475Smrg#define USE_SYSV_PGRP
262d522f475Smrgextern __inline__
263d522f475Smrgint
264d522f475Smrgttyslot(void)
265d522f475Smrg{
266d522f475Smrg    return 1;			/* yuk */
267d522f475Smrg}
268d522f475Smrg#endif
269d522f475Smrg
270d522f475Smrg#else
271d522f475Smrg
272d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
273d522f475Smrg#define setpgrp setpgid
274d522f475Smrg#endif
275d522f475Smrg
276d522f475Smrg#ifndef linux
277d522f475Smrg#ifndef VMS
278d522f475Smrg#ifndef USE_POSIX_TERMIOS
279d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
280d522f475Smrg#include <sgtty.h>
281d522f475Smrg#endif
282d522f475Smrg#endif /* USE_POSIX_TERMIOS */
283d522f475Smrg#ifdef Lynx
284d522f475Smrg#include <resource.h>
285d522f475Smrg#else
286d522f475Smrg#include <sys/resource.h>
287d522f475Smrg#endif
288d522f475Smrg#endif /* !VMS */
289d522f475Smrg#endif /* !linux */
290d522f475Smrg
291d522f475Smrg#endif /* __QNX__ */
292d522f475Smrg
293d522f475Smrg#endif /* } !SYSV */
294d522f475Smrg
295d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
296d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
297d522f475Smrg#ifndef NOFILE
298d522f475Smrg#define NOFILE OPEN_MAX
299d522f475Smrg#endif
300d522f475Smrg#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
301d522f475Smrg#include <sys/param.h>		/* for NOFILE */
302d522f475Smrg#endif
303d522f475Smrg
304d522f475Smrg#if defined(BSD) && (BSD >= 199103)
305d522f475Smrg#define WTMP
306d522f475Smrg#endif
307d522f475Smrg
308d522f475Smrg#include <stdio.h>
309d522f475Smrg
310d522f475Smrg#ifdef __hpux
311d522f475Smrg#include <sys/utsname.h>
312d522f475Smrg#endif /* __hpux */
313d522f475Smrg
314d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
315d522f475Smrg#define ttyslot() 1
316d522f475Smrg#endif /* apollo */
317d522f475Smrg
318d522f475Smrg#if defined(UTMPX_FOR_UTMP)
319d522f475Smrg#define UTMP_STR utmpx
320d522f475Smrg#else
321d522f475Smrg#define UTMP_STR utmp
322d522f475Smrg#endif
323d522f475Smrg
324d522f475Smrg#if defined(USE_UTEMPTER)
325d522f475Smrg#include <utempter.h>
326d522f475Smrg#endif
327d522f475Smrg
3282e4f8982Smrg#if defined(I_FIND) && defined(I_PUSH)
3292e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_FIND, name) == 0 \
3302e4f8982Smrg			 && ioctl(fd, I_PUSH, name) < 0
3312e4f8982Smrg#else
3322e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_PUSH, name) < 0
3332e4f8982Smrg#endif
3342e4f8982Smrg
335d522f475Smrg#if defined(UTMPX_FOR_UTMP)
336d522f475Smrg
337d522f475Smrg#include <utmpx.h>
338d522f475Smrg
339d522f475Smrg#define call_endutent  endutxent
340d522f475Smrg#define call_getutid   getutxid
341d522f475Smrg#define call_pututline pututxline
342d522f475Smrg#define call_setutent  setutxent
343d522f475Smrg#define call_updwtmp   updwtmpx
344d522f475Smrg
345d522f475Smrg#elif defined(HAVE_UTMP)
346d522f475Smrg
347d522f475Smrg#include <utmp.h>
348d522f475Smrg
349d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
350d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
351d522f475Smrg#endif
352d522f475Smrg
353d522f475Smrg#define call_endutent  endutent
354d522f475Smrg#define call_getutid   getutid
355d522f475Smrg#define call_pututline pututline
356d522f475Smrg#define call_setutent  setutent
357d522f475Smrg#define call_updwtmp   updwtmp
358d522f475Smrg
359d522f475Smrg#endif
360d522f475Smrg
361d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
362d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
363d522f475Smrg#endif
364d522f475Smrg
365d522f475Smrg#ifndef USE_LASTLOGX
366d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
367d522f475Smrg#define USE_LASTLOGX 1
368d522f475Smrg#endif
369d522f475Smrg#endif
370d522f475Smrg
371d522f475Smrg#ifdef  PUCC_PTYD
372d522f475Smrg#include <local/openpty.h>
373d522f475Smrg#endif /* PUCC_PTYD */
374d522f475Smrg
375d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
376d522f475Smrg#include <util.h>		/* openpty() */
377d522f475Smrg#endif
378d522f475Smrg
379956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
380d522f475Smrg#include <libutil.h>		/* openpty() */
381d522f475Smrg#endif
382d522f475Smrg
383d522f475Smrg#if !defined(UTMP_FILENAME)
384d522f475Smrg#if defined(UTMP_FILE)
385d522f475Smrg#define UTMP_FILENAME UTMP_FILE
386d522f475Smrg#elif defined(_PATH_UTMP)
387d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
388d522f475Smrg#else
389d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
390d522f475Smrg#endif
391d522f475Smrg#endif
392d522f475Smrg
393d522f475Smrg#ifndef LASTLOG_FILENAME
394d522f475Smrg#ifdef _PATH_LASTLOG
395d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
396d522f475Smrg#else
397d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
398d522f475Smrg#endif
399d522f475Smrg#endif
400d522f475Smrg
401d522f475Smrg#if !defined(WTMP_FILENAME)
402d522f475Smrg#if defined(WTMP_FILE)
403d522f475Smrg#define WTMP_FILENAME WTMP_FILE
404d522f475Smrg#elif defined(_PATH_WTMP)
405d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
406d522f475Smrg#elif defined(SYSV)
407d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
408d522f475Smrg#else
409d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
410d522f475Smrg#endif
411d522f475Smrg#endif
412d522f475Smrg
413d522f475Smrg#include <signal.h>
414d522f475Smrg
415d522f475Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
416d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
417d522f475Smrg#endif
418d522f475Smrg
419d522f475Smrg#ifdef SIGTSTP
420d522f475Smrg#include <sys/wait.h>
421d522f475Smrg#endif
422d522f475Smrg
423d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
424d522f475Smrg#undef ECHOKE
425d522f475Smrg#undef ECHOCTL
426d522f475Smrg#endif
427d522f475Smrg
428d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
429d522f475Smrg#include <sys/ttydefaults.h>
430d522f475Smrg#endif
431d522f475Smrg
432d522f475Smrg#ifdef X_NOT_POSIX
433d522f475Smrgextern long lseek();
434d522f475Smrg#if defined(USG) || defined(SVR4)
435d522f475Smrgextern unsigned sleep();
436d522f475Smrg#else
437d522f475Smrgextern void sleep();
438d522f475Smrg#endif
439d522f475Smrgextern char *ttyname();
440d522f475Smrg#endif
441d522f475Smrg
442d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
443d522f475Smrgextern char *ptsname(int);
444d522f475Smrg#endif
445d522f475Smrg
446d522f475Smrg#ifndef VMS
4470bd37d32Smrgstatic void reapchild(int /* n */ );
4482e4f8982Smrgstatic int spawnXTerm(XtermWidget	/* xw */
4492e4f8982Smrg		      ,unsigned /* line_speed */ );
45020d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
451d522f475Smrg#ifdef USE_PTY_SEARCH
45220d2c4d2Smrgstatic int pty_search(int * /* pty */ );
453d522f475Smrg#endif
454d522f475Smrg#endif /* ! VMS */
455d522f475Smrg
456d522f475Smrgstatic int get_pty(int *pty, char *from);
45720d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
458e0a2b6dfSmrgstatic void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
459d522f475Smrg
460d522f475Smrgstatic Bool added_utmp_entry = False;
461d522f475Smrg
462d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
463d522f475Smrgstatic uid_t save_euid;
464d522f475Smrgstatic gid_t save_egid;
465d522f475Smrg#endif
466d522f475Smrg
467d522f475Smrgstatic uid_t save_ruid;
468d522f475Smrgstatic gid_t save_rgid;
469d522f475Smrg
470d522f475Smrg#if defined(USE_UTMP_SETGID)
471d522f475Smrgstatic int really_get_pty(int *pty, char *from);
472d522f475Smrg#endif
473d522f475Smrg
474d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
475d522f475Smrgstatic Bool xterm_exiting = False;
476d522f475Smrg#endif
477d522f475Smrg
478d522f475Smrgstatic char *explicit_shname = NULL;
479d522f475Smrg
480d522f475Smrg/*
481d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
482d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
483d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
484d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
485d522f475Smrg** SEGV.
486d522f475Smrg*/
487d522f475Smrgstatic char **command_to_exec = NULL;
488d522f475Smrg
489d522f475Smrg#if OPT_LUIT_PROG
490d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
4910bd37d32Smrgstatic unsigned command_length_with_luit = 0;
492d522f475Smrg#endif
493d522f475Smrg
494d522f475Smrg#define TERMCAP_ERASE "kb"
495d522f475Smrg#define VAL_INITIAL_ERASE A2E(8)
496d522f475Smrg
497d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
498d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
499d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
500d522f475Smrg * about padding generally store the code in a short, which does not have
501d522f475Smrg * enough bits for the extended values.
502d522f475Smrg */
503d522f475Smrg#ifdef B38400			/* everyone should define this */
504d522f475Smrg#define VAL_LINE_SPEED B38400
505d522f475Smrg#else /* ...but xterm's used this for a long time */
506d522f475Smrg#define VAL_LINE_SPEED B9600
507d522f475Smrg#endif
508d522f475Smrg
509d522f475Smrg/*
510d522f475Smrg * Allow use of system default characters if defined and reasonable.
511d522f475Smrg * These are based on the BSD ttydefaults.h
512d522f475Smrg */
513d522f475Smrg#ifndef CBRK
514d522f475Smrg#define CBRK     0xff		/* was 0 */
515d522f475Smrg#endif
516d522f475Smrg#ifndef CDISCARD
517d522f475Smrg#define CDISCARD CONTROL('O')
518d522f475Smrg#endif
519d522f475Smrg#ifndef CDSUSP
520d522f475Smrg#define CDSUSP   CONTROL('Y')
521d522f475Smrg#endif
522d522f475Smrg#ifndef CEOF
523d522f475Smrg#define CEOF     CONTROL('D')
524d522f475Smrg#endif
525d522f475Smrg#ifndef CEOL
526d522f475Smrg#define CEOL	 0xff		/* was 0 */
527d522f475Smrg#endif
528d522f475Smrg#ifndef CERASE
529d522f475Smrg#define CERASE   0177
530d522f475Smrg#endif
531d522f475Smrg#ifndef CERASE2
532d522f475Smrg#define	CERASE2  CONTROL('H')
533d522f475Smrg#endif
534d522f475Smrg#ifndef CFLUSH
535d522f475Smrg#define CFLUSH   CONTROL('O')
536d522f475Smrg#endif
537d522f475Smrg#ifndef CINTR
538d522f475Smrg#define CINTR    CONTROL('C')
539d522f475Smrg#endif
540d522f475Smrg#ifndef CKILL
541d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
542d522f475Smrg#endif
543d522f475Smrg#ifndef CLNEXT
544d522f475Smrg#define CLNEXT   CONTROL('V')
545d522f475Smrg#endif
546d522f475Smrg#ifndef CNUL
547d522f475Smrg#define CNUL     0
548d522f475Smrg#endif
549d522f475Smrg#ifndef CQUIT
550d522f475Smrg#define CQUIT    CONTROL('\\')
551d522f475Smrg#endif
552d522f475Smrg#ifndef CRPRNT
553d522f475Smrg#define CRPRNT   CONTROL('R')
554d522f475Smrg#endif
555d522f475Smrg#ifndef CREPRINT
556d522f475Smrg#define CREPRINT CRPRNT
557d522f475Smrg#endif
558d522f475Smrg#ifndef CSTART
559d522f475Smrg#define CSTART   CONTROL('Q')
560d522f475Smrg#endif
561d522f475Smrg#ifndef CSTATUS
562d522f475Smrg#define	CSTATUS  CONTROL('T')
563d522f475Smrg#endif
564d522f475Smrg#ifndef CSTOP
565d522f475Smrg#define CSTOP    CONTROL('S')
566d522f475Smrg#endif
567d522f475Smrg#ifndef CSUSP
568d522f475Smrg#define CSUSP    CONTROL('Z')
569d522f475Smrg#endif
570d522f475Smrg#ifndef CSWTCH
571d522f475Smrg#define CSWTCH   0
572d522f475Smrg#endif
573d522f475Smrg#ifndef CWERASE
574d522f475Smrg#define CWERASE  CONTROL('W')
575d522f475Smrg#endif
576d522f475Smrg
577d522f475Smrg#ifdef USE_ANY_SYSV_TERMIO
578d522f475Smrg#define TERMIO_STRUCT struct termio
579d522f475Smrg#define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
580d522f475Smrg#define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
581d522f475Smrg#define ttyFlush(fd)          ioctl(fd, TCFLSH, 1)
582d522f475Smrg#elif defined(USE_POSIX_TERMIOS)
583d522f475Smrg#define TERMIO_STRUCT struct termios
584d522f475Smrg#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
585d522f475Smrg#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
586d522f475Smrg#define ttyFlush(fd)          tcflush(fd, TCOFLUSH)
587d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO */
588d522f475Smrg
589d522f475Smrg#ifndef VMS
590d522f475Smrg#ifdef TERMIO_STRUCT
591d522f475Smrg/* The following structures are initialized in main() in order
592d522f475Smrg** to eliminate any assumptions about the internal order of their
593d522f475Smrg** contents.
594d522f475Smrg*/
595d522f475Smrgstatic TERMIO_STRUCT d_tio;
596d522f475Smrg
597d522f475Smrg#ifdef HAS_LTCHARS
598d522f475Smrgstatic struct ltchars d_ltc;
599d522f475Smrg#endif /* HAS_LTCHARS */
600d522f475Smrg
601d522f475Smrg#ifdef TIOCLSET
602d522f475Smrgstatic unsigned int d_lmode;
603d522f475Smrg#endif /* TIOCLSET */
604d522f475Smrg
605d522f475Smrg#else /* !TERMIO_STRUCT */
606d522f475Smrgstatic struct sgttyb d_sg =
607d522f475Smrg{
608d522f475Smrg    0, 0, 0177, CKILL, (EVENP | ODDP | ECHO | XTABS | CRMOD)
609d522f475Smrg};
610d522f475Smrgstatic struct tchars d_tc =
611d522f475Smrg{
612d522f475Smrg    CINTR, CQUIT, CSTART,
613d522f475Smrg    CSTOP, CEOF, CBRK
614d522f475Smrg};
615d522f475Smrgstatic struct ltchars d_ltc =
616d522f475Smrg{
617d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
618d522f475Smrg    CFLUSH, CWERASE, CLNEXT
619d522f475Smrg};
620d522f475Smrgstatic int d_disipline = NTTYDISC;
621d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
622d522f475Smrg#ifdef sony
623d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
624d522f475Smrgstatic struct jtchars d_jtc =
625d522f475Smrg{
626d522f475Smrg    'J', 'B'
627d522f475Smrg};
628d522f475Smrg#endif /* sony */
629d522f475Smrg#endif /* TERMIO_STRUCT */
630d522f475Smrg#endif /* ! VMS */
631d522f475Smrg
632d522f475Smrg/*
633d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
634d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
635d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
636d522f475Smrg */
637d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
638d522f475Smrgstatic Boolean override_tty_modes = False;
639d522f475Smrg/* *INDENT-OFF* */
640d522f475Smrgstatic struct _xttymodes {
64120d2c4d2Smrg    const char *name;
642d522f475Smrg    size_t len;
643d522f475Smrg    int set;
644d522f475Smrg    int value;
645d522f475Smrg} ttymodelist[] = {
646d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
647d522f475Smrg#define XTTYMODE_intr	0
648d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
649d522f475Smrg#define XTTYMODE_quit	1
650d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
651d522f475Smrg#define XTTYMODE_erase	2
652d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
653d522f475Smrg#define XTTYMODE_kill	3
654d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
655d522f475Smrg#define XTTYMODE_eof	4
656d522f475Smrg    TTYMODE("eol"),		/* VEOL */
657d522f475Smrg#define XTTYMODE_eol	5
658d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
659d522f475Smrg#define XTTYMODE_swtch	6
660d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
661d522f475Smrg#define XTTYMODE_start	7
662d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
663d522f475Smrg#define XTTYMODE_stop	8
664d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
665d522f475Smrg#define XTTYMODE_brk	9
666d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
667d522f475Smrg#define XTTYMODE_susp	10
668d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
669d522f475Smrg#define XTTYMODE_dsusp	11
670d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
671d522f475Smrg#define XTTYMODE_rprnt	12
672d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
673d522f475Smrg#define XTTYMODE_flush	13
674d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
675d522f475Smrg#define XTTYMODE_weras	14
676d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
677d522f475Smrg#define XTTYMODE_lnext	15
678d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
679d522f475Smrg#define XTTYMODE_status	16
680d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
681d522f475Smrg#define XTTYMODE_erase2	17
682d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
683d522f475Smrg#define XTTYMODE_eol2	18
684d522f475Smrg    { NULL,	0, 0, '\0' },	/* end of data */
685d522f475Smrg};
686d522f475Smrg
687d522f475Smrg#define validTtyChar(data, n) \
688d522f475Smrg	    (known_ttyChars[n].sysMode >= 0 && \
689d522f475Smrg	     known_ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
690d522f475Smrg
691d522f475Smrgstatic const struct {
692d522f475Smrg    int sysMode;
693d522f475Smrg    int myMode;
694d522f475Smrg    int myDefault;
695d522f475Smrg} known_ttyChars[] = {
696d522f475Smrg#ifdef VINTR
697d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
698d522f475Smrg#endif
699d522f475Smrg#ifdef VQUIT
700d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
701d522f475Smrg#endif
702d522f475Smrg#ifdef VERASE
703d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
704d522f475Smrg#endif
705d522f475Smrg#ifdef VKILL
706d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
707d522f475Smrg#endif
708d522f475Smrg#ifdef VEOF
709d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
710d522f475Smrg#endif
711d522f475Smrg#ifdef VEOL
712d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
713d522f475Smrg#endif
714d522f475Smrg#ifdef VSWTCH
715d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
716d522f475Smrg#endif
717d522f475Smrg#ifdef VSTART
718d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
719d522f475Smrg#endif
720d522f475Smrg#ifdef VSTOP
721d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
722d522f475Smrg#endif
723d522f475Smrg#ifdef VSUSP
724d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
725d522f475Smrg#endif
726d522f475Smrg#ifdef VDSUSP
727d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
728d522f475Smrg#endif
729d522f475Smrg#ifdef VREPRINT
730d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
731d522f475Smrg#endif
732d522f475Smrg#ifdef VDISCARD
733d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
734d522f475Smrg#endif
735d522f475Smrg#ifdef VWERASE
736d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
737d522f475Smrg#endif
738d522f475Smrg#ifdef VLNEXT
739d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
740d522f475Smrg#endif
741d522f475Smrg#ifdef VSTATUS
742d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
743d522f475Smrg#endif
744d522f475Smrg#ifdef VERASE2
745d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
746d522f475Smrg#endif
747d522f475Smrg#ifdef VEOL2
748d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
749d522f475Smrg#endif
750d522f475Smrg};
751d522f475Smrg/* *INDENT-ON* */
752d522f475Smrg
7530bd37d32Smrg#define TMODE(ind,var) if (ttymodelist[ind].set) var = (cc_t) ttymodelist[ind].value
754d522f475Smrg
755d522f475Smrgstatic int parse_tty_modes(char *s, struct _xttymodes *modelist);
756d522f475Smrg
757d522f475Smrg#ifndef USE_UTEMPTER
758d522f475Smrg#ifdef USE_SYSV_UTMP
759d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
760d522f475Smrgextern struct utmp *getutid();
761d522f475Smrg#endif /* AIXV3 */
762d522f475Smrg
763d522f475Smrg#else /* not USE_SYSV_UTMP */
764d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
765d522f475Smrg#endif /* USE_SYSV_UTMP */
766d522f475Smrg
767d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
768d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
769d522f475Smrg#else
770d522f475Smrg#undef USE_LASTLOG
771d522f475Smrg#endif
772d522f475Smrg
773d522f475Smrg#ifdef WTMP
774d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
775d522f475Smrg#endif
776d522f475Smrg#endif /* !USE_UTEMPTER */
777d522f475Smrg
778d522f475Smrg/*
779d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
780d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
781d522f475Smrg * WTMP and USE_LASTLOG.
782d522f475Smrg */
783d522f475Smrg#ifdef USE_LOGIN_DASH_P
784d522f475Smrg#ifndef LOGIN_FILENAME
785d522f475Smrg#define LOGIN_FILENAME "/bin/login"
786d522f475Smrg#endif
787d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
788d522f475Smrg#endif
789d522f475Smrg
79001037d57Smrgstatic char noPassedPty[2];
79101037d57Smrgstatic char *passedPty = noPassedPty;	/* 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	    } \
819894e0ac8Smrg	    copy_filled(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
886e0a2b6dfSmrg#if OPT_REPORT_COLORS
887e0a2b6dfSmrg    Bres("reportColors", "ReportColors", reportColors, False),
888e0a2b6dfSmrg#endif
889e0a2b6dfSmrg#if OPT_REPORT_FONTS
890e0a2b6dfSmrg    Bres("reportFonts", "ReportFonts", reportFonts, False),
891e0a2b6dfSmrg#endif
892d522f475Smrg#if OPT_SAME_NAME
893d522f475Smrg    Bres("sameName", "SameName", sameName, True),
894d522f475Smrg#endif
895d522f475Smrg#if OPT_SESSION_MGT
896d522f475Smrg    Bres("sessionMgt", "SessionMgt", sessionMgt, True),
897d522f475Smrg#endif
898d522f475Smrg#if OPT_TOOLBAR
899d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
900d522f475Smrg#endif
901956cc18dSsnj#if OPT_MAXIMIZE
902956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
903a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
904956cc18dSsnj#endif
905d522f475Smrg};
906d522f475Smrg
90720d2c4d2Smrgstatic String fallback_resources[] =
908d522f475Smrg{
909e39b573cSmrg#if OPT_TOOLBAR
910e39b573cSmrg    "*toolBar: false",
911e39b573cSmrg#endif
912d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
913d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
914d522f475Smrg    "*SimpleMenu*Sme.height: 16",
915d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
916d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
917d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
918d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
919d522f475Smrg#if OPT_TEK4014
920d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
921d522f475Smrg#endif
922d522f475Smrg    NULL
923d522f475Smrg};
924d522f475Smrg
925d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
926d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
927d522f475Smrg/* *INDENT-OFF* */
928d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
92920d2c4d2Smrg{"-geometry",	"*vt100.geometry",XrmoptionSepArg,	(XPointer) NULL},
93020d2c4d2Smrg{"-132",	"*c132",	XrmoptionNoArg,		(XPointer) "on"},
93120d2c4d2Smrg{"+132",	"*c132",	XrmoptionNoArg,		(XPointer) "off"},
93220d2c4d2Smrg{"-ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "on"},
93320d2c4d2Smrg{"+ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "off"},
93420d2c4d2Smrg{"-aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "on"},
93520d2c4d2Smrg{"+aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "off"},
936d522f475Smrg#ifndef NO_ACTIVE_ICON
93720d2c4d2Smrg{"-ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "off"},
93820d2c4d2Smrg{"+ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "on"},
939d522f475Smrg#endif /* NO_ACTIVE_ICON */
94020d2c4d2Smrg{"-b",		"*internalBorder",XrmoptionSepArg,	(XPointer) NULL},
94120d2c4d2Smrg{"-bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "on"},
94220d2c4d2Smrg{"+bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "off"},
94320d2c4d2Smrg{"-bcf",	"*cursorOffTime",XrmoptionSepArg,	(XPointer) NULL},
94420d2c4d2Smrg{"-bcn",	"*cursorOnTime",XrmoptionSepArg,	(XPointer) NULL},
94520d2c4d2Smrg{"-bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "off"},
94620d2c4d2Smrg{"+bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "on"},
94720d2c4d2Smrg{"-cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "off"},
94820d2c4d2Smrg{"+cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "on"},
94920d2c4d2Smrg{"-cc",		"*charClass",	XrmoptionSepArg,	(XPointer) NULL},
95020d2c4d2Smrg{"-cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "off"},
95120d2c4d2Smrg{"+cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "on"},
95220d2c4d2Smrg{"-cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "off"},
95320d2c4d2Smrg{"+cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "on"},
95420d2c4d2Smrg{"-cr",		"*cursorColor",	XrmoptionSepArg,	(XPointer) NULL},
95520d2c4d2Smrg{"-cu",		"*curses",	XrmoptionNoArg,		(XPointer) "on"},
95620d2c4d2Smrg{"+cu",		"*curses",	XrmoptionNoArg,		(XPointer) "off"},
95720d2c4d2Smrg{"-dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "off"},
95820d2c4d2Smrg{"+dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "on"},
95920d2c4d2Smrg{"-fb",		"*boldFont",	XrmoptionSepArg,	(XPointer) NULL},
96020d2c4d2Smrg{"-fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"off"},
96120d2c4d2Smrg{"+fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"on"},
96220d2c4d2Smrg{"-fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"off"},
96320d2c4d2Smrg{"+fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"on"},
964d522f475Smrg#ifndef NO_ACTIVE_ICON
96520d2c4d2Smrg{"-fi",		"*iconFont",	XrmoptionSepArg,	(XPointer) NULL},
966d522f475Smrg#endif /* NO_ACTIVE_ICON */
967d522f475Smrg#if OPT_RENDERFONT
96820d2c4d2Smrg{"-fa",		"*faceName",	XrmoptionSepArg,	(XPointer) NULL},
96920d2c4d2Smrg{"-fd",		"*faceNameDoublesize", XrmoptionSepArg,	(XPointer) NULL},
97020d2c4d2Smrg{"-fs",		"*faceSize",	XrmoptionSepArg,	(XPointer) NULL},
971d522f475Smrg#endif
97201037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
97301037d57Smrg{"-itc",	"*colorITMode",	XrmoptionNoArg,		(XPointer) "off"},
97401037d57Smrg{"+itc",	"*colorITMode",	XrmoptionNoArg,		(XPointer) "on"},
97501037d57Smrg#endif
976d522f475Smrg#if OPT_WIDE_CHARS
97720d2c4d2Smrg{"-fw",		"*wideFont",	XrmoptionSepArg,	(XPointer) NULL},
97820d2c4d2Smrg{"-fwb",	"*wideBoldFont", XrmoptionSepArg,	(XPointer) NULL},
979d522f475Smrg#endif
980d522f475Smrg#if OPT_INPUT_METHOD
98120d2c4d2Smrg{"-fx",		"*ximFont",	XrmoptionSepArg,	(XPointer) NULL},
982d522f475Smrg#endif
983d522f475Smrg#if OPT_HIGHLIGHT_COLOR
98420d2c4d2Smrg{"-hc",		"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
98520d2c4d2Smrg{"-hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "on"},
98620d2c4d2Smrg{"+hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "off"},
98720d2c4d2Smrg{"-selfg",	"*highlightTextColor", XrmoptionSepArg,	(XPointer) NULL},
98820d2c4d2Smrg{"-selbg",	"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
989d522f475Smrg#endif
990d522f475Smrg#if OPT_HP_FUNC_KEYS
99120d2c4d2Smrg{"-hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "on"},
99220d2c4d2Smrg{"+hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "off"},
993d522f475Smrg#endif
99420d2c4d2Smrg{"-hold",	"*hold",	XrmoptionNoArg,		(XPointer) "on"},
99520d2c4d2Smrg{"+hold",	"*hold",	XrmoptionNoArg,		(XPointer) "off"},
996d522f475Smrg#if OPT_INITIAL_ERASE
99720d2c4d2Smrg{"-ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "on"},
99820d2c4d2Smrg{"+ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "off"},
999d522f475Smrg#endif
100020d2c4d2Smrg{"-j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "on"},
100120d2c4d2Smrg{"+j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "off"},
1002d522f475Smrg#if OPT_C1_PRINT
100320d2c4d2Smrg{"-k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "on"},
100420d2c4d2Smrg{"+k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "off"},
1005d522f475Smrg#endif
100620d2c4d2Smrg{"-kt",		"*keyboardType", XrmoptionSepArg,	(XPointer) NULL},
1007d522f475Smrg/* parse logging options anyway for compatibility */
100820d2c4d2Smrg{"-l",		"*logging",	XrmoptionNoArg,		(XPointer) "on"},
100920d2c4d2Smrg{"+l",		"*logging",	XrmoptionNoArg,		(XPointer) "off"},
101020d2c4d2Smrg{"-lf",		"*logFile",	XrmoptionSepArg,	(XPointer) NULL},
101120d2c4d2Smrg{"-ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "on"},
101220d2c4d2Smrg{"+ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "off"},
101320d2c4d2Smrg{"-mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "on"},
101420d2c4d2Smrg{"+mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "off"},
101520d2c4d2Smrg{"-mc",		"*multiClickTime", XrmoptionSepArg,	(XPointer) NULL},
101620d2c4d2Smrg{"-mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "off"},
101720d2c4d2Smrg{"+mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "on"},
101820d2c4d2Smrg{"-ms",		"*pointerColor",XrmoptionSepArg,	(XPointer) NULL},
101920d2c4d2Smrg{"-nb",		"*nMarginBell",	XrmoptionSepArg,	(XPointer) NULL},
102020d2c4d2Smrg{"-nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "off"},
102120d2c4d2Smrg{"+nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "on"},
102220d2c4d2Smrg{"-pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "on"},
102320d2c4d2Smrg{"+pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "off"},
102420d2c4d2Smrg{"-rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "on"},
102520d2c4d2Smrg{"+rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "off"},
102620d2c4d2Smrg{"-s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "on"},
102720d2c4d2Smrg{"+s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "off"},
102820d2c4d2Smrg{"-sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "on"},
102920d2c4d2Smrg{"+sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "off"},
1030e0a2b6dfSmrg#if OPT_REPORT_COLORS
1031e0a2b6dfSmrg{"-report-colors","*reportColors", XrmoptionNoArg,	(XPointer) "on"},
1032e0a2b6dfSmrg#endif
1033e0a2b6dfSmrg#if OPT_REPORT_FONTS
1034e0a2b6dfSmrg{"-report-fonts","*reportFonts", XrmoptionNoArg,	(XPointer) "on"},
1035e0a2b6dfSmrg#endif
1036d522f475Smrg#ifdef SCROLLBAR_RIGHT
103720d2c4d2Smrg{"-leftbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "off"},
103820d2c4d2Smrg{"-rightbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "on"},
103920d2c4d2Smrg#endif
104020d2c4d2Smrg{"-rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "off"},
104120d2c4d2Smrg{"+rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "on"},
104220d2c4d2Smrg{"-sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "on"},
104320d2c4d2Smrg{"+sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "off"},
10440bd37d32Smrg{"-sh",		"*scaleHeight", XrmoptionSepArg,	(XPointer) NULL},
104520d2c4d2Smrg{"-si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "off"},
104620d2c4d2Smrg{"+si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "on"},
104720d2c4d2Smrg{"-sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "on"},
104820d2c4d2Smrg{"+sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "off"},
104920d2c4d2Smrg{"-sl",		"*saveLines",	XrmoptionSepArg,	(XPointer) NULL},
1050d522f475Smrg#if OPT_SUNPC_KBD
105120d2c4d2Smrg{"-sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "on"},
105220d2c4d2Smrg{"+sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "off"},
1053d522f475Smrg#endif
1054d522f475Smrg#if OPT_TEK4014
105520d2c4d2Smrg{"-t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "on"},
105620d2c4d2Smrg{"+t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "off"},
1057d522f475Smrg#endif
105820d2c4d2Smrg{"-ti",		"*decTerminalID",XrmoptionSepArg,	(XPointer) NULL},
105920d2c4d2Smrg{"-tm",		"*ttyModes",	XrmoptionSepArg,	(XPointer) NULL},
106020d2c4d2Smrg{"-tn",		"*termName",	XrmoptionSepArg,	(XPointer) NULL},
1061d522f475Smrg#if OPT_WIDE_CHARS
106220d2c4d2Smrg{"-u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "2"},
106320d2c4d2Smrg{"+u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "0"},
1064d522f475Smrg#endif
1065d522f475Smrg#if OPT_LUIT_PROG
106620d2c4d2Smrg{"-lc",		"*locale",	XrmoptionNoArg,		(XPointer) "on"},
106720d2c4d2Smrg{"+lc",		"*locale",	XrmoptionNoArg,		(XPointer) "off"},
106820d2c4d2Smrg{"-lcc",	"*localeFilter",XrmoptionSepArg,	(XPointer) NULL},
106920d2c4d2Smrg{"-en",		"*locale",	XrmoptionSepArg,	(XPointer) NULL},
107020d2c4d2Smrg#endif
107120d2c4d2Smrg{"-uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "on"},
107220d2c4d2Smrg{"+uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "off"},
107320d2c4d2Smrg{"-ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "off"},
107420d2c4d2Smrg{"+ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "on"},
107520d2c4d2Smrg{"-ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "off"},
107620d2c4d2Smrg{"+ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "on"},
107720d2c4d2Smrg{"-ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "on"},
107820d2c4d2Smrg{"+ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "off"},
107920d2c4d2Smrg{"-im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "on"},
108020d2c4d2Smrg{"+im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "off"},
108120d2c4d2Smrg{"-vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "on"},
108220d2c4d2Smrg{"+vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "off"},
108320d2c4d2Smrg{"-pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "on"},
108420d2c4d2Smrg{"+pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "off"},
1085d522f475Smrg#if OPT_WIDE_CHARS
108620d2c4d2Smrg{"-wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "on"},
108720d2c4d2Smrg{"+wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "off"},
108820d2c4d2Smrg{"-mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "on"},
108920d2c4d2Smrg{"+mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "off"},
109020d2c4d2Smrg{"-cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "on"},
109120d2c4d2Smrg{"+cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "off"},
109220d2c4d2Smrg#endif
109320d2c4d2Smrg{"-wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "on"},
109420d2c4d2Smrg{"+wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "off"},
1095d522f475Smrg#if OPT_ZICONBEEP
109620d2c4d2Smrg{"-ziconbeep",	"*zIconBeep",	XrmoptionSepArg,	(XPointer) NULL},
1097d522f475Smrg#endif
1098d522f475Smrg#if OPT_SAME_NAME
109920d2c4d2Smrg{"-samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "on"},
110020d2c4d2Smrg{"+samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "off"},
1101d522f475Smrg#endif
1102d522f475Smrg#if OPT_SESSION_MGT
110320d2c4d2Smrg{"-sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "on"},
110420d2c4d2Smrg{"+sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "off"},
1105d522f475Smrg#endif
1106d522f475Smrg#if OPT_TOOLBAR
110720d2c4d2Smrg{"-tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "on"},
110820d2c4d2Smrg{"+tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "off"},
1109d522f475Smrg#endif
1110956cc18dSsnj#if OPT_MAXIMIZE
111120d2c4d2Smrg{"-maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "on"},
111220d2c4d2Smrg{"+maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "off"},
1113a1f3da82Smrg{"-fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "on"},
1114a1f3da82Smrg{"+fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "off"},
1115956cc18dSsnj#endif
1116d522f475Smrg/* options that we process ourselves */
111720d2c4d2Smrg{"-help",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
111820d2c4d2Smrg{"-version",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
11192e4f8982Smrg{"-baudrate",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
112020d2c4d2Smrg{"-class",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
112120d2c4d2Smrg{"-e",		NULL,		XrmoptionSkipLine,	(XPointer) NULL},
112220d2c4d2Smrg{"-into",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
1123d522f475Smrg/* bogus old compatibility stuff for which there are
1124d522f475Smrg   standard XtOpenApplication options now */
112520d2c4d2Smrg{"%",		"*tekGeometry",	XrmoptionStickyArg,	(XPointer) NULL},
112620d2c4d2Smrg{"#",		".iconGeometry",XrmoptionStickyArg,	(XPointer) NULL},
112720d2c4d2Smrg{"-T",		".title",	XrmoptionSepArg,	(XPointer) NULL},
112820d2c4d2Smrg{"-n",		"*iconName",	XrmoptionSepArg,	(XPointer) NULL},
112920d2c4d2Smrg{"-r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
113020d2c4d2Smrg{"+r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
113120d2c4d2Smrg{"-rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
113220d2c4d2Smrg{"+rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
113320d2c4d2Smrg{"-w",		".borderWidth", XrmoptionSepArg,	(XPointer) NULL},
1134d522f475Smrg};
1135d522f475Smrg
1136d522f475Smrgstatic OptionHelp xtermOptions[] = {
1137d522f475Smrg{ "-version",              "print the version number" },
1138d522f475Smrg{ "-help",                 "print out this message" },
1139d522f475Smrg{ "-display displayname",  "X server to contact" },
1140d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1141d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1142d522f475Smrg{ "-bg color",             "background color" },
1143d522f475Smrg{ "-fg color",             "foreground color" },
1144d522f475Smrg{ "-bd color",             "border color" },
1145d522f475Smrg{ "-bw number",            "border width in pixels" },
1146d522f475Smrg{ "-fn fontname",          "normal text font" },
1147d522f475Smrg{ "-fb fontname",          "bold text font" },
1148d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1149d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1150d522f475Smrg#if OPT_RENDERFONT
1151d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1152d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1153d522f475Smrg{ "-fs size",              "FreeType font-size" },
1154d522f475Smrg#endif
1155d522f475Smrg#if OPT_WIDE_CHARS
1156d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1157d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1158d522f475Smrg#endif
1159d522f475Smrg#if OPT_INPUT_METHOD
1160d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1161d522f475Smrg#endif
1162d522f475Smrg{ "-iconic",               "start iconic" },
1163d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
11642e4f8982Smrg{ "-baudrate rate",        "set line-speed (default 38400)" },
1165d522f475Smrg{ "-class string",         "class string (XTerm)" },
1166d522f475Smrg{ "-title string",         "title string" },
1167d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1168d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1169d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1170d522f475Smrg#ifndef NO_ACTIVE_ICON
1171d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1172d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1173d522f475Smrg#endif /* NO_ACTIVE_ICON */
1174d522f475Smrg{ "-b number",             "internal border in pixels" },
1175d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1176d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1177d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1178d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1179d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1180d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1181d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1182d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1183d522f475Smrg{ "-cr color",             "text cursor color" },
1184d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1185d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1186d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1187d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1188d522f475Smrg{ "-selbg color",          "selection background color" },
1189d522f475Smrg{ "-selfg color",          "selection foreground color" },
11900bd37d32Smrg/* -hc is deprecated, not shown in help message */
1191d522f475Smrg#endif
1192d522f475Smrg#if OPT_HP_FUNC_KEYS
1193d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1194d522f475Smrg#endif
1195d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1196d522f475Smrg#if OPT_INITIAL_ERASE
1197d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1198d522f475Smrg#endif
1199d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1200d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1201d522f475Smrg#if OPT_C1_PRINT
1202d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1203d522f475Smrg#endif
1204d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1205d522f475Smrg#ifdef ALLOWLOGGING
1206d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1207d522f475Smrg{ "-lf filename",          "logging filename" },
1208d522f475Smrg#else
1209d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1210d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1211d522f475Smrg#endif
1212d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1213d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1214d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1215d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1216d522f475Smrg{ "-ms color",             "pointer color" },
1217d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
1218d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1219d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1220d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1221d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1222d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1223d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1224e0a2b6dfSmrg#if OPT_REPORT_COLORS
1225e0a2b6dfSmrg{ "-report-colors",        "report colors as they are allocated" },
1226e0a2b6dfSmrg#endif
1227e0a2b6dfSmrg#if OPT_REPORT_FONTS
1228e0a2b6dfSmrg{ "-report-fonts",         "report fonts as loaded to stdout" },
1229e0a2b6dfSmrg#endif
1230d522f475Smrg#ifdef SCROLLBAR_RIGHT
1231d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1232d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1233d522f475Smrg#endif
1234d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1235d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1236894e0ac8Smrg{ "-sh number",            "scale line-height values by the given number" },
1237d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1238d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1239d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1240d522f475Smrg#if OPT_SUNPC_KBD
1241d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1242d522f475Smrg#endif
1243d522f475Smrg#if OPT_TEK4014
1244d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1245d522f475Smrg#endif
1246d522f475Smrg#if OPT_TOOLBAR
1247d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1248d522f475Smrg#endif
1249d522f475Smrg{ "-ti termid",            "terminal identifier" },
1250d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1251d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1252d522f475Smrg#if OPT_WIDE_CHARS
1253d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1254d522f475Smrg#endif
1255d522f475Smrg#if OPT_LUIT_PROG
1256d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1257d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
12580bd37d32Smrg/* -en is deprecated, not shown in help message */
1259d522f475Smrg#endif
12602eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1261d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1262d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1263d522f475Smrg#ifdef HAVE_UTMP
1264d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1265d522f475Smrg#else
1266d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1267d522f475Smrg#endif
1268d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1269d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
127001037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
127101037d57Smrg{ "-/+itc",                "turn off/on display of italic as color"},
127201037d57Smrg#endif
1273d522f475Smrg#if OPT_WIDE_CHARS
1274d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1275d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1276d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1277d522f475Smrg#endif
1278d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1279d522f475Smrg{ "-e command args ...",   "command to execute" },
1280d522f475Smrg#if OPT_TEK4014
1281d522f475Smrg{ "%geom",                 "Tek window geometry" },
1282d522f475Smrg#endif
1283d522f475Smrg{ "#geom",                 "icon window geometry" },
1284d522f475Smrg{ "-T string",             "title name for window" },
1285d522f475Smrg{ "-n string",             "icon name for window" },
1286d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1287d522f475Smrg{ "-C",                    "intercept console messages" },
1288d522f475Smrg#else
1289d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1290d522f475Smrg#endif
1291d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1292d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1293d522f475Smrg#if OPT_ZICONBEEP
1294d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1295d522f475Smrg#endif
1296d522f475Smrg#if OPT_SAME_NAME
1297d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1298d522f475Smrg#endif
1299d522f475Smrg#if OPT_SESSION_MGT
1300d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1301d522f475Smrg#endif
1302956cc18dSsnj#if OPT_MAXIMIZE
1303956cc18dSsnj{"-/+maximized",           "turn on/off maxmize on startup" },
1304a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1305956cc18dSsnj#endif
1306d522f475Smrg{ NULL, NULL }};
1307d522f475Smrg/* *INDENT-ON* */
1308d522f475Smrg
130901037d57Smrgstatic const char *const message[] =
1310d522f475Smrg{
1311d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1312d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1313d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1314d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1315d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
1316d522f475Smrg    NULL};
1317d522f475Smrg
1318d522f475Smrg/*
1319d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1320d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1321d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1322d522f475Smrg */
1323d522f475Smrgstatic int
1324d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1325d522f475Smrg{
1326d522f475Smrg    char *string = *ptr;
1327d522f475Smrg    int value = -1;
1328d522f475Smrg
132920d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1330d522f475Smrg    if (*string == '^') {
1331d522f475Smrg	switch (*++string) {
1332d522f475Smrg	case '?':
1333d522f475Smrg	    value = A2E(ANSI_DEL);
1334d522f475Smrg	    break;
1335d522f475Smrg	case '-':
1336d522f475Smrg	    if (!termcap) {
1337d522f475Smrg		errno = 0;
1338d522f475Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
1339d522f475Smrg		value = _POSIX_VDISABLE;
1340d522f475Smrg#endif
1341d522f475Smrg#if defined(_PC_VDISABLE)
1342d522f475Smrg		if (value == -1) {
134320d2c4d2Smrg		    value = (int) fpathconf(0, _PC_VDISABLE);
1344d522f475Smrg		    if (value == -1) {
1345d522f475Smrg			if (errno != 0)
1346d522f475Smrg			    break;	/* skip this (error) */
1347d522f475Smrg			value = 0377;
1348d522f475Smrg		    }
1349d522f475Smrg		}
1350d522f475Smrg#elif defined(VDISABLE)
1351d522f475Smrg		if (value == -1)
1352d522f475Smrg		    value = VDISABLE;
1353d522f475Smrg#endif
1354d522f475Smrg		break;
1355d522f475Smrg	    }
1356d522f475Smrg	    /* FALLTHRU */
1357d522f475Smrg	default:
1358d522f475Smrg	    value = CONTROL(*string);
1359d522f475Smrg	    break;
1360d522f475Smrg	}
1361d522f475Smrg	++string;
1362d522f475Smrg    } else if (termcap && (*string == '\\')) {
13632e4f8982Smrg	char *s = (string + 1);
1364d522f475Smrg	char *d;
13652e4f8982Smrg	int temp = (int) strtol(s, &d, 8);
13662e4f8982Smrg	if (PartS2L(s, d) && temp > 0) {
1367d522f475Smrg	    value = temp;
1368d522f475Smrg	    string = d;
1369d522f475Smrg	}
1370d522f475Smrg    } else {
1371d522f475Smrg	value = CharOf(*string);
1372d522f475Smrg	++string;
1373d522f475Smrg    }
1374d522f475Smrg    *ptr = string;
137520d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1376d522f475Smrg    return value;
1377d522f475Smrg}
1378d522f475Smrg
1379d522f475Smrgstatic int
13800bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
13810bd37d32Smrg{
13820bd37d32Smrg    int result = -1;
13830bd37d32Smrg    int n;
13840bd37d32Smrg    int ch;
13850bd37d32Smrg
13860bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
13870bd37d32Smrg	if (param[n] == ch) {
13880bd37d32Smrg	    result = n;
13890bd37d32Smrg	} else {
13900bd37d32Smrg	    if (param[n] != '\0')
13910bd37d32Smrg		result = -1;
13920bd37d32Smrg	    break;
13930bd37d32Smrg	}
13940bd37d32Smrg    }
13950bd37d32Smrg
13960bd37d32Smrg    return result;
13970bd37d32Smrg}
13980bd37d32Smrg
13990bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
14000bd37d32Smrgstatic int
14010bd37d32SmrgcountArg(XrmOptionDescRec * item)
1402d522f475Smrg{
14030bd37d32Smrg    int result = 0;
14040bd37d32Smrg
14050bd37d32Smrg    switch (item->argKind) {
14060bd37d32Smrg    case XrmoptionNoArg:
14070bd37d32Smrg	/* FALLTHRU */
14080bd37d32Smrg    case XrmoptionIsArg:
14090bd37d32Smrg	/* FALLTHRU */
14100bd37d32Smrg    case XrmoptionStickyArg:
14110bd37d32Smrg	break;
14120bd37d32Smrg    case XrmoptionSepArg:
14130bd37d32Smrg	/* FALLTHRU */
14140bd37d32Smrg    case XrmoptionResArg:
14150bd37d32Smrg	/* FALLTHRU */
14160bd37d32Smrg    case XrmoptionSkipArg:
14170bd37d32Smrg	result = 1;
14180bd37d32Smrg	break;
14190bd37d32Smrg    case XrmoptionSkipLine:
14200bd37d32Smrg	break;
14210bd37d32Smrg    case XrmoptionSkipNArgs:
14220bd37d32Smrg	result = (int) (long) (item->value);
14230bd37d32Smrg	break;
14240bd37d32Smrg    }
14250bd37d32Smrg    return result;
14260bd37d32Smrg}
14270bd37d32Smrg
14280bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
14290bd37d32Smrg
14300bd37d32Smrg/*
14310bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
14320bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
14330bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
14340bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
14350bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
14360bd37d32Smrg * standard table (something that the X libraries should do).
14370bd37d32Smrg */
14380bd37d32Smrgstatic XrmOptionDescRec *
14390bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
14400bd37d32Smrg{
14410bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
14420bd37d32Smrg    /* *INDENT-OFF* */
14430bd37d32Smrg#define DATA(option,kind) { option, NULL, kind, (XtPointer) NULL }
14440bd37d32Smrg    static XrmOptionDescRec opTable[] = {
14450bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
14460bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
14470bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
14480bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
14490bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
14500bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
14510bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
14520bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
14530bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
14540bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
14550bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
14560bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
14570bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
14580bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
14590bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
14600bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
14610bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
14620bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
14630bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
14640bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
14650bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
14660bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
14670bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
14680bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
14690bd37d32Smrg#endif /* TIOCCONS */
14700bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
14710bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
14720bd37d32Smrg    };
14730bd37d32Smrg#undef DATA
14740bd37d32Smrg    /* *INDENT-ON* */
14750bd37d32Smrg
14760bd37d32Smrg    XrmOptionDescRec *result = 0;
14770bd37d32Smrg    Cardinal inlist;
14780bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
14790bd37d32Smrg    int atbest = -1;
14800bd37d32Smrg    int best = -1;
14810bd37d32Smrg    int test;
14820bd37d32Smrg    Boolean exact = False;
14830bd37d32Smrg    int ambiguous1 = -1;
14840bd37d32Smrg    int ambiguous2 = -1;
14850bd37d32Smrg    char *option;
14860bd37d32Smrg    char *value;
14870bd37d32Smrg
14880bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
14890bd37d32Smrg		 ? &optionDescList[n] \
14900bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
14910bd37d32Smrg
14920bd37d32Smrg    if ((option = argv[*num]) != 0) {
14930bd37d32Smrg	Boolean need_value;
14940bd37d32Smrg	Boolean have_value = False;
14950bd37d32Smrg
14960bd37d32Smrg	TRACE(("parseArg %s\n", option));
14970bd37d32Smrg	if ((value = argv[(*num) + 1]) != 0) {
1498e0a2b6dfSmrg	    have_value = (Boolean) !isOption(value);
14990bd37d32Smrg	}
15000bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
15010bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
15020bd37d32Smrg
15030bd37d32Smrg	    test = matchArg(check, option);
15040bd37d32Smrg	    if (test < 0)
15050bd37d32Smrg		continue;
15060bd37d32Smrg
15070bd37d32Smrg	    /* check for exact match */
15080bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
15090bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
15100bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
15110bd37d32Smrg			exact = True;
15120bd37d32Smrg			atbest = (int) inlist;
15130bd37d32Smrg			break;
15140bd37d32Smrg		    }
15150bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
15160bd37d32Smrg		    exact = True;
15170bd37d32Smrg		    atbest = (int) inlist;
15180bd37d32Smrg		    break;
15190bd37d32Smrg		}
15200bd37d32Smrg	    }
15210bd37d32Smrg
15220bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
15230bd37d32Smrg
15240bd37d32Smrg	    if (need_value && value != 0) {
15250bd37d32Smrg		;
15260bd37d32Smrg	    } else if (need_value ^ have_value) {
15270bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
15280bd37d32Smrg		continue;
15290bd37d32Smrg	    }
15300bd37d32Smrg
15310bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
15320bd37d32Smrg	    if (test > 0
15330bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
15340bd37d32Smrg		atbest = (int) inlist;
1535e0a2b6dfSmrg		if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
1536e0a2b6dfSmrg		    /* in particular, silence a warning about ambiguity */
1537e0a2b6dfSmrg		    exact = 1;
1538e0a2b6dfSmrg		}
15390bd37d32Smrg		break;
15400bd37d32Smrg	    }
15410bd37d32Smrg	    if (test > best) {
15420bd37d32Smrg		best = test;
15430bd37d32Smrg		atbest = (int) inlist;
15440bd37d32Smrg	    } else if (test == best) {
15450bd37d32Smrg		if (atbest >= 0) {
15460bd37d32Smrg		    if (atbest > 0) {
15470bd37d32Smrg			ambiguous1 = (int) inlist;
15480bd37d32Smrg			ambiguous2 = (int) atbest;
15490bd37d32Smrg		    }
15500bd37d32Smrg		    atbest = -1;
15510bd37d32Smrg		}
15520bd37d32Smrg	    }
15530bd37d32Smrg	}
15540bd37d32Smrg    }
15550bd37d32Smrg
15560bd37d32Smrg    *valuep = 0;
15570bd37d32Smrg    if (atbest >= 0) {
15580bd37d32Smrg	result = ITEM(atbest);
15590bd37d32Smrg	if (!exact) {
15600bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
15610bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
15620bd37d32Smrg			     ITEM(ambiguous1)->option,
15630bd37d32Smrg			     ITEM(ambiguous2)->option);
15640bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
15650bd37d32Smrg		result = 0;
15660bd37d32Smrg	    }
15670bd37d32Smrg	}
15680bd37d32Smrg	if (result != 0) {
15690bd37d32Smrg	    TRACE(("...result %s\n", result->option));
15700bd37d32Smrg	    /* expand abbreviations */
15710bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
15720bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
15730bd37d32Smrg		    argv[*num] = x_strdup(result->option);
15740bd37d32Smrg		}
15750bd37d32Smrg	    }
15760bd37d32Smrg
15770bd37d32Smrg	    /* adjust (*num) to skip option value */
15780bd37d32Smrg	    (*num) += countArg(result);
15790bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
15800bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
15810bd37d32Smrg		*valuep = argv[*num];
15820bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
15830bd37d32Smrg	    }
15840bd37d32Smrg	}
15850bd37d32Smrg    }
15860bd37d32Smrg#undef ITEM
15870bd37d32Smrg    return result;
1588d522f475Smrg}
1589d522f475Smrg
1590d522f475Smrgstatic void
1591d522f475SmrgSyntax(char *badOption)
1592d522f475Smrg{
1593d522f475Smrg    OptionHelp *opt;
1594d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1595d522f475Smrg    int col;
1596d522f475Smrg
15970bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
15980bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1599d522f475Smrg
1600d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1601956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1602d522f475Smrg    for (opt = list; opt->opt; opt++) {
1603956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1604d522f475Smrg	if (col + len > 79) {
1605d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1606d522f475Smrg	    col = 3;
1607d522f475Smrg	}
1608d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1609d522f475Smrg	col += len;
1610d522f475Smrg    }
1611d522f475Smrg
1612d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1613d522f475Smrg	    ProgramName);
1614d522f475Smrg    exit(1);
1615d522f475Smrg}
1616d522f475Smrg
1617d522f475Smrgstatic void
1618d522f475SmrgVersion(void)
1619d522f475Smrg{
1620d522f475Smrg    printf("%s\n", xtermVersion());
1621d522f475Smrg    fflush(stdout);
1622d522f475Smrg}
1623d522f475Smrg
1624d522f475Smrgstatic void
1625d522f475SmrgHelp(void)
1626d522f475Smrg{
1627d522f475Smrg    OptionHelp *opt;
1628d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
162901037d57Smrg    const char *const *cpp;
1630d522f475Smrg
1631d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1632d522f475Smrg	   xtermVersion(), ProgramName);
1633d522f475Smrg    printf("where options include:\n");
1634d522f475Smrg    for (opt = list; opt->opt; opt++) {
1635d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1636d522f475Smrg    }
1637d522f475Smrg
1638d522f475Smrg    putchar('\n');
1639d522f475Smrg    for (cpp = message; *cpp; cpp++)
1640d522f475Smrg	puts(*cpp);
1641d522f475Smrg    putchar('\n');
1642d522f475Smrg    fflush(stdout);
1643d522f475Smrg}
1644d522f475Smrg
1645d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1646d522f475Smrg/* ARGSUSED */
1647d522f475Smrgstatic Boolean
1648d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1649894e0ac8Smrg			Atom *selection GCC_UNUSED,
1650894e0ac8Smrg			Atom *target GCC_UNUSED,
1651894e0ac8Smrg			Atom *type GCC_UNUSED,
1652d522f475Smrg			XtPointer *value GCC_UNUSED,
1653d522f475Smrg			unsigned long *length GCC_UNUSED,
1654d522f475Smrg			int *format GCC_UNUSED)
1655d522f475Smrg{
1656d522f475Smrg    /* we don't save console output, so can't offer it */
1657d522f475Smrg    return False;
1658d522f475Smrg}
1659d522f475Smrg#endif /* TIOCCONS */
1660d522f475Smrg
1661d522f475Smrg/*
1662d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1663d522f475Smrg */
1664d522f475Smrg/* ARGSUSED */
1665d522f475Smrgstatic void
1666d522f475SmrgDeleteWindow(Widget w,
1667894e0ac8Smrg	     XEvent *event GCC_UNUSED,
1668e0a2b6dfSmrg	     String *params GCC_UNUSED,
1669d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1670d522f475Smrg{
1671d522f475Smrg#if OPT_TEK4014
1672d522f475Smrg    if (w == toplevel) {
1673d522f475Smrg	if (TEK4014_SHOWN(term))
1674d522f475Smrg	    hide_vt_window();
1675d522f475Smrg	else
1676d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
167720d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1678d522f475Smrg	hide_tek_window();
1679d522f475Smrg    else
1680d522f475Smrg#endif
1681d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1682d522f475Smrg}
1683d522f475Smrg
1684d522f475Smrg/* ARGSUSED */
1685d522f475Smrgstatic void
1686d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1687894e0ac8Smrg		XEvent *event,
1688e0a2b6dfSmrg		String *params GCC_UNUSED,
1689d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1690d522f475Smrg{
1691d522f475Smrg    switch (event->type) {
1692d522f475Smrg    case MappingNotify:
1693d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1694d522f475Smrg	break;
1695d522f475Smrg    }
1696d522f475Smrg}
1697d522f475Smrg
1698d522f475Smrgstatic XtActionsRec actionProcs[] =
1699d522f475Smrg{
1700d522f475Smrg    {"DeleteWindow", DeleteWindow},
1701d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1702d522f475Smrg};
1703d522f475Smrg
1704d522f475Smrg/*
1705d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1706d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1707d522f475Smrg * utmp.
1708d522f475Smrg */
1709d522f475Smrgstatic char *
1710d522f475Smrgmy_pty_name(char *device)
1711d522f475Smrg{
1712d522f475Smrg    size_t len = strlen(device);
1713d522f475Smrg    Bool name = False;
1714d522f475Smrg
1715d522f475Smrg    while (len != 0) {
1716d522f475Smrg	int ch = device[len - 1];
1717d522f475Smrg	if (isdigit(ch)) {
1718d522f475Smrg	    len--;
1719d522f475Smrg	} else if (ch == '/') {
1720d522f475Smrg	    if (name)
1721d522f475Smrg		break;
1722d522f475Smrg	    len--;
1723d522f475Smrg	} else if (isalpha(ch)) {
1724d522f475Smrg	    name = True;
1725d522f475Smrg	    len--;
1726d522f475Smrg	} else {
1727d522f475Smrg	    break;
1728d522f475Smrg	}
1729d522f475Smrg    }
1730d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1731d522f475Smrg    return device + len;
1732d522f475Smrg}
1733d522f475Smrg
1734d522f475Smrg/*
1735d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1736d522f475Smrg * last few characters for a utmp identifier.
1737d522f475Smrg */
1738d522f475Smrgstatic char *
1739d522f475Smrgmy_pty_id(char *device)
1740d522f475Smrg{
1741d522f475Smrg    char *name = my_pty_name(device);
1742d522f475Smrg    char *leaf = x_basename(name);
1743d522f475Smrg
1744d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1745956cc18dSsnj	int len = (int) strlen(leaf);
1746d522f475Smrg	if (PTYCHARLEN < len)
1747d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1748d522f475Smrg    }
1749d522f475Smrg    TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
1750d522f475Smrg    return leaf;
1751d522f475Smrg}
1752d522f475Smrg
1753d522f475Smrg/*
1754d522f475Smrg * Set the tty/pty identifier
1755d522f475Smrg */
1756d522f475Smrgstatic void
1757d522f475Smrgset_pty_id(char *device, char *id)
1758d522f475Smrg{
1759d522f475Smrg    char *name = my_pty_name(device);
1760d522f475Smrg    char *leaf = x_basename(name);
1761d522f475Smrg
1762d522f475Smrg    if (name == leaf) {
1763d522f475Smrg	strcpy(my_pty_id(device), id);
1764d522f475Smrg    } else {
1765d522f475Smrg	strcpy(leaf, id);
1766d522f475Smrg    }
1767d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
1768d522f475Smrg}
1769d522f475Smrg
1770d522f475Smrg/*
1771d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
1772d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
1773d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
1774d522f475Smrg * not, fall-thru to the original logic.
1775d522f475Smrg */
1776d522f475Smrgstatic Bool
1777d522f475SmrgParseSccn(char *option)
1778d522f475Smrg{
1779d522f475Smrg    char *leaf = x_basename(option);
1780d522f475Smrg    Bool code = False;
1781d522f475Smrg
178201037d57Smrg    passedPty = x_strdup(option);
1783d522f475Smrg    if (leaf != option) {
1784d522f475Smrg	if (leaf - option > 0
1785d522f475Smrg	    && isdigit(CharOf(*leaf))
1786d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
1787956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
1788d522f475Smrg	    /*
1789d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
1790d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
1791d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
1792d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
1793d522f475Smrg	     */
1794d522f475Smrg	    passedPty[len] = 0;
1795d522f475Smrg	    code = True;
1796d522f475Smrg	}
1797d522f475Smrg    } else {
1798d522f475Smrg	code = (sscanf(option, "%c%c%d",
1799d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
180001037d57Smrg	passedPty[2] = '\0';
1801d522f475Smrg    }
1802d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
1803d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
1804d522f475Smrg    return code;
1805d522f475Smrg}
1806d522f475Smrg
1807d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
1808d522f475Smrg/*
1809d522f475Smrg * From "man utmp":
1810d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
1811d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
1812d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
1813d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
1814d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
1815d522f475Smrg * ut_time, ut_user and ut_host as well.
1816d522f475Smrg *
1817d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
1818d522f475Smrg * pty implementation allows more than 3 digits.
1819d522f475Smrg */
1820d522f475Smrgstatic char *
1821d522f475Smrgmy_utmp_id(char *device)
1822d522f475Smrg{
1823d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
1824d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
1825d522f475Smrg    static char result[UTIDSIZE + 1];
1826d522f475Smrg
1827d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
1828d522f475Smrg    /*
1829d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
1830d522f475Smrg     * issues, and can use the available space in ut_id differently from the
1831d522f475Smrg     * default convention.
1832d522f475Smrg     *
1833d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
1834d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
1835d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
1836d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
1837d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
1838d522f475Smrg     * last three digits of the device name, regardless of the format of the
1839d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
1840d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
1841d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
1842d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
1843d522f475Smrg     */
1844d522f475Smrg    int len, n;
1845d522f475Smrg
1846d522f475Smrg    len = strlen(device);
1847d522f475Smrg    n = UTIDSIZE;
1848d522f475Smrg    result[n] = '\0';
1849d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
1850d522f475Smrg	result[--n] = device[--len];
1851d522f475Smrg    while (n > 0)
1852d522f475Smrg	result[--n] = '0';
1853d522f475Smrg    result[0] = 'x';
1854d522f475Smrg#else
1855d522f475Smrg    char *name = my_pty_name(device);
1856d522f475Smrg    char *leaf = x_basename(name);
1857d522f475Smrg    size_t len = strlen(leaf);
1858d522f475Smrg
1859d522f475Smrg    if ((UTIDSIZE - 1) < len)
1860d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
1861d522f475Smrg    sprintf(result, "p%s", leaf);
1862d522f475Smrg#endif
1863d522f475Smrg
1864d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
1865d522f475Smrg    return result;
1866d522f475Smrg}
1867d522f475Smrg#endif /* USE_SYSV_UTMP */
1868d522f475Smrg
1869d522f475Smrg#ifdef USE_POSIX_SIGNALS
1870d522f475Smrg
1871d522f475Smrgtypedef void (*sigfunc) (int);
1872d522f475Smrg
1873d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
1874d522f475Smrg   has just been stopped and not actually killed */
1875d522f475Smrg
1876d522f475Smrgstatic sigfunc
1877d522f475Smrgposix_signal(int signo, sigfunc func)
1878d522f475Smrg{
1879d522f475Smrg    struct sigaction act, oact;
1880d522f475Smrg
1881d522f475Smrg    act.sa_handler = func;
1882d522f475Smrg    sigemptyset(&act.sa_mask);
1883d522f475Smrg#ifdef SA_RESTART
1884d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
1885d522f475Smrg#else
1886d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
1887d522f475Smrg#endif
1888d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
1889d522f475Smrg	return (SIG_ERR);
1890d522f475Smrg    return (oact.sa_handler);
1891d522f475Smrg}
1892d522f475Smrg
18930bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
1894d522f475Smrg
1895d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
1896d522f475Smrgstatic void
1897d522f475SmrgdisableSetUid(void)
1898d522f475Smrg{
1899d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
1900d522f475Smrg    if (setuid(save_ruid) == -1) {
19010bd37d32Smrg	xtermWarning("unable to reset uid\n");
1902d522f475Smrg	exit(1);
1903d522f475Smrg    }
1904d522f475Smrg    TRACE_IDS;
1905d522f475Smrg}
1906d522f475Smrg#else
1907d522f475Smrg#define disableSetUid()		/* nothing */
1908d522f475Smrg#endif /* DISABLE_SETUID */
1909d522f475Smrg
1910d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
1911d522f475Smrgstatic void
1912d522f475SmrgdisableSetGid(void)
1913d522f475Smrg{
1914d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
1915d522f475Smrg    if (setegid(save_rgid) == -1) {
19160bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
1917d522f475Smrg	exit(1);
1918d522f475Smrg    }
1919d522f475Smrg    TRACE_IDS;
1920d522f475Smrg}
1921d522f475Smrg#else
1922d522f475Smrg#define disableSetGid()		/* nothing */
1923d522f475Smrg#endif /* DISABLE_SETGID */
1924d522f475Smrg
1925d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
1926d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
1927d522f475Smrgstatic void
1928d522f475SmrgsetEffectiveGroup(gid_t group)
1929d522f475Smrg{
1930d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
1931d522f475Smrg    if (setegid(group) == -1) {
1932d522f475Smrg#ifdef __MVS__
1933d522f475Smrg	if (!(errno == EMVSERR))	/* could happen if _BPX_SHAREAS=REUSE */
1934d522f475Smrg#endif
1935d522f475Smrg	{
19360bd37d32Smrg	    xtermPerror("setegid(%d)", (int) group);
1937d522f475Smrg	}
1938d522f475Smrg    }
1939d522f475Smrg    TRACE_IDS;
1940d522f475Smrg}
1941d522f475Smrg#endif
1942d522f475Smrg
1943d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
1944d522f475Smrgstatic void
1945d522f475SmrgsetEffectiveUser(uid_t user)
1946d522f475Smrg{
1947d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
1948d522f475Smrg    if (seteuid(user) == -1) {
1949d522f475Smrg#ifdef __MVS__
1950d522f475Smrg	if (!(errno == EMVSERR))
1951d522f475Smrg#endif
1952d522f475Smrg	{
19530bd37d32Smrg	    xtermPerror("seteuid(%d)", (int) user);
1954d522f475Smrg	}
1955d522f475Smrg    }
1956d522f475Smrg    TRACE_IDS;
1957d522f475Smrg}
1958d522f475Smrg#endif
1959d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
1960d522f475Smrg
19612e4f8982Smrg#if OPT_LUIT_PROG
19622e4f8982Smrgstatic Boolean
19632e4f8982Smrgcomplex_command(char **args)
19642e4f8982Smrg{
19652e4f8982Smrg    Boolean result = False;
19662e4f8982Smrg    if (x_countargv(args) == 1) {
19672e4f8982Smrg	char *check = xtermFindShell(args[0], False);
19682e4f8982Smrg	if (check == 0) {
19692e4f8982Smrg	    result = True;
19702e4f8982Smrg	} else {
19712e4f8982Smrg	    free(check);
19722e4f8982Smrg	}
19732e4f8982Smrg    }
19742e4f8982Smrg    return result;
19752e4f8982Smrg}
19762e4f8982Smrg#endif
19772e4f8982Smrg
19782e4f8982Smrgstatic unsigned
19792e4f8982Smrglookup_baudrate(const char *value)
19802e4f8982Smrg{
19812e4f8982Smrg    struct speed {
19822e4f8982Smrg	unsigned given_speed;	/* values for 'ospeed' */
19832e4f8982Smrg	unsigned actual_speed;	/* the actual speed */
19842e4f8982Smrg    };
19852e4f8982Smrg
19862e4f8982Smrg#define DATA(number) { B##number, number }
19872e4f8982Smrg
19882e4f8982Smrg    static struct speed const speeds[] =
19892e4f8982Smrg    {
19902e4f8982Smrg	DATA(0),
19912e4f8982Smrg	DATA(50),
19922e4f8982Smrg	DATA(75),
19932e4f8982Smrg	DATA(110),
19942e4f8982Smrg	DATA(134),
19952e4f8982Smrg	DATA(150),
19962e4f8982Smrg	DATA(200),
19972e4f8982Smrg	DATA(300),
19982e4f8982Smrg	DATA(600),
19992e4f8982Smrg	DATA(1200),
20002e4f8982Smrg	DATA(1800),
20012e4f8982Smrg	DATA(2400),
20022e4f8982Smrg	DATA(4800),
20032e4f8982Smrg	DATA(9600),
20042e4f8982Smrg#ifdef B19200
20052e4f8982Smrg	DATA(19200),
20062e4f8982Smrg#elif defined(EXTA)
20072e4f8982Smrg	{EXTA, 19200},
20082e4f8982Smrg#endif
20092e4f8982Smrg#ifdef B28800
20102e4f8982Smrg	DATA(28800),
20112e4f8982Smrg#endif
20122e4f8982Smrg#ifdef B38400
20132e4f8982Smrg	DATA(38400),
20142e4f8982Smrg#elif defined(EXTB)
20152e4f8982Smrg	{EXTB, 38400},
20162e4f8982Smrg#endif
20172e4f8982Smrg#ifdef B57600
20182e4f8982Smrg	DATA(57600),
20192e4f8982Smrg#endif
20202e4f8982Smrg#ifdef B76800
20212e4f8982Smrg	DATA(76800),
20222e4f8982Smrg#endif
20232e4f8982Smrg#ifdef B115200
20242e4f8982Smrg	DATA(115200),
20252e4f8982Smrg#endif
20262e4f8982Smrg#ifdef B153600
20272e4f8982Smrg	DATA(153600),
20282e4f8982Smrg#endif
20292e4f8982Smrg#ifdef B230400
20302e4f8982Smrg	DATA(230400),
20312e4f8982Smrg#endif
20322e4f8982Smrg#ifdef B307200
20332e4f8982Smrg	DATA(307200),
20342e4f8982Smrg#endif
20352e4f8982Smrg#ifdef B460800
20362e4f8982Smrg	DATA(460800),
20372e4f8982Smrg#endif
20382e4f8982Smrg#ifdef B500000
20392e4f8982Smrg	DATA(500000),
20402e4f8982Smrg#endif
20412e4f8982Smrg#ifdef B576000
20422e4f8982Smrg	DATA(576000),
20432e4f8982Smrg#endif
20442e4f8982Smrg#ifdef B921600
20452e4f8982Smrg	DATA(921600),
20462e4f8982Smrg#endif
20472e4f8982Smrg#ifdef B1000000
20482e4f8982Smrg	DATA(1000000),
20492e4f8982Smrg#endif
20502e4f8982Smrg#ifdef B1152000
20512e4f8982Smrg	DATA(1152000),
20522e4f8982Smrg#endif
20532e4f8982Smrg#ifdef B1500000
20542e4f8982Smrg	DATA(1500000),
20552e4f8982Smrg#endif
20562e4f8982Smrg#ifdef B2000000
20572e4f8982Smrg	DATA(2000000),
20582e4f8982Smrg#endif
20592e4f8982Smrg#ifdef B2500000
20602e4f8982Smrg	DATA(2500000),
20612e4f8982Smrg#endif
20622e4f8982Smrg#ifdef B3000000
20632e4f8982Smrg	DATA(3000000),
20642e4f8982Smrg#endif
20652e4f8982Smrg#ifdef B3500000
20662e4f8982Smrg	DATA(3500000),
20672e4f8982Smrg#endif
20682e4f8982Smrg#ifdef B4000000
20692e4f8982Smrg	DATA(4000000),
20702e4f8982Smrg#endif
20712e4f8982Smrg    };
20722e4f8982Smrg#undef DATA
20732e4f8982Smrg    unsigned result = 0;
20742e4f8982Smrg    long check;
20752e4f8982Smrg    char *next;
20762e4f8982Smrg    if (x_toupper(*value) == 'B')
20772e4f8982Smrg	value++;
20782e4f8982Smrg    if (isdigit(CharOf(*value))) {
20792e4f8982Smrg	check = strtol(value, &next, 10);
20802e4f8982Smrg	if (FullS2L(value, next) && (check > 0)) {
20812e4f8982Smrg	    Cardinal n;
20822e4f8982Smrg	    for (n = 0; n < XtNumber(speeds); ++n) {
20832e4f8982Smrg		if (speeds[n].actual_speed == (unsigned) check) {
20842e4f8982Smrg		    result = speeds[n].given_speed;
20852e4f8982Smrg		    break;
20862e4f8982Smrg		}
20872e4f8982Smrg	    }
20882e4f8982Smrg	}
20892e4f8982Smrg    }
20902e4f8982Smrg    if (result == 0) {
20912e4f8982Smrg	fprintf(stderr, "unsupported value for baudrate: %s\n", value);
20922e4f8982Smrg    }
20932e4f8982Smrg    return result;
20942e4f8982Smrg}
20952e4f8982Smrg
2096d522f475Smrgint
2097d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
2098d522f475Smrg{
2099a1f3da82Smrg#if OPT_MAXIMIZE
2100a1f3da82Smrg#define DATA(name) { #name, es##name }
210101037d57Smrg    static const FlagList tblFullscreen[] =
2102a1f3da82Smrg    {
2103a1f3da82Smrg	DATA(Always),
2104a1f3da82Smrg	DATA(Never)
2105a1f3da82Smrg    };
2106a1f3da82Smrg#undef DATA
2107a1f3da82Smrg#endif
2108a1f3da82Smrg
2109d522f475Smrg    Widget form_top, menu_top;
2110d522f475Smrg    Dimension menu_high;
2111d522f475Smrg    TScreen *screen;
2112d522f475Smrg    int mode;
2113e0a2b6dfSmrg    char *my_class = x_strdup(DEFCLASS);
21142e4f8982Smrg    unsigned line_speed = VAL_LINE_SPEED;
2115d522f475Smrg    Window winToEmbedInto = None;
2116d522f475Smrg
2117d522f475Smrg    ProgramName = argv[0];
2118d522f475Smrg
2119d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
2120d522f475Smrg    save_euid = geteuid();
2121d522f475Smrg    save_egid = getegid();
2122d522f475Smrg#endif
2123d522f475Smrg
2124d522f475Smrg    save_ruid = getuid();
2125d522f475Smrg    save_rgid = getgid();
2126d522f475Smrg
2127d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
2128d522f475Smrg#if defined(DISABLE_SETUID)
2129d522f475Smrg    disableSetUid();
2130d522f475Smrg#endif
2131d522f475Smrg#if defined(DISABLE_SETGID)
2132d522f475Smrg    disableSetGid();
2133d522f475Smrg#endif
2134d522f475Smrg    TRACE_IDS;
2135d522f475Smrg#endif
2136d522f475Smrg
2137d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
2138d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
2139d522f475Smrg#ifdef USE_PTY_DEVICE
2140d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
2141d522f475Smrg    if (!ttydev || !ptydev)
2142d522f475Smrg#else
2143d522f475Smrg    if (!ttydev)
2144d522f475Smrg#endif
2145d522f475Smrg    {
21460bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
2147d522f475Smrg	exit(1);
2148d522f475Smrg    }
2149d522f475Smrg    strcpy(ttydev, TTYDEV);
2150d522f475Smrg#ifdef USE_PTY_DEVICE
2151d522f475Smrg    strcpy(ptydev, PTYDEV);
2152d522f475Smrg#endif
2153d522f475Smrg
2154d522f475Smrg#if defined(USE_UTMP_SETGID)
2155d522f475Smrg    get_pty(NULL, NULL);
2156d522f475Smrg    disableSetUid();
2157d522f475Smrg    disableSetGid();
2158d522f475Smrg    TRACE_IDS;
2159d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
2160d522f475Smrg#endif
2161d522f475Smrg
2162d522f475Smrg    /* Do these first, since we may not be able to open the display */
2163d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
2164d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
2165d522f475Smrg    if (argc > 1) {
21660bd37d32Smrg	XrmOptionDescRec *option_ptr;
21670bd37d32Smrg	char *option_value;
2168d522f475Smrg	int n;
2169e39b573cSmrg	Bool quit = False;
2170d522f475Smrg
2171d522f475Smrg	for (n = 1; n < argc; n++) {
21720bd37d32Smrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
21730bd37d32Smrg		if (argv[n] == 0) {
21740bd37d32Smrg		    break;
21750bd37d32Smrg		} else if (isOption(argv[n])) {
21760bd37d32Smrg		    Syntax(argv[n]);
21770bd37d32Smrg		} else if (explicit_shname != 0) {
21780bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
21790bd37d32Smrg		    Syntax(argv[n]);
21800bd37d32Smrg		}
21810bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
21820bd37d32Smrg		if (explicit_shname == 0)
21830bd37d32Smrg		    exit(0);
21840bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
21850bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
21860bd37d32Smrg		command_to_exec = (argv + n + 1);
21870bd37d32Smrg		if (!command_to_exec[0])
21880bd37d32Smrg		    Syntax(argv[n]);
21890bd37d32Smrg		break;
21900bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2191d522f475Smrg		Version();
2192e39b573cSmrg		quit = True;
21930bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2194d522f475Smrg		Help();
2195e39b573cSmrg		quit = True;
21962e4f8982Smrg	    } else if (!strcmp(option_ptr->option, "-baudrate")) {
21972e4f8982Smrg		if ((line_speed = lookup_baudrate(option_value)) == 0) {
21982e4f8982Smrg		    Help();
21992e4f8982Smrg		    quit = True;
22002e4f8982Smrg		}
22010bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
2202e0a2b6dfSmrg		free(my_class);
22030bd37d32Smrg		if ((my_class = x_strdup(option_value)) == 0) {
2204d522f475Smrg		    Help();
2205e39b573cSmrg		    quit = True;
2206d522f475Smrg		}
22070bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
22080bd37d32Smrg		char *endPtr;
22090bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
22102e4f8982Smrg		if (!FullS2L(option_value, endPtr)) {
22112e4f8982Smrg		    Help();
22122e4f8982Smrg		    quit = True;
22132e4f8982Smrg		}
2214d522f475Smrg	    }
2215d522f475Smrg	}
2216d522f475Smrg	if (quit)
2217d522f475Smrg	    exit(0);
22180bd37d32Smrg	/*
22190bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
22200bd37d32Smrg	 * then give up.
22210bd37d32Smrg	 */
22220bd37d32Smrg	if (n < argc && !command_to_exec) {
22230bd37d32Smrg	    Syntax(argv[n]);
22240bd37d32Smrg	}
2225d522f475Smrg    }
2226d522f475Smrg
22270bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2228d522f475Smrg#if OPT_I18N_SUPPORT
2229d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2230d522f475Smrg#endif
2231d522f475Smrg
2232d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2233d522f475Smrg    /* Initialization is done here rather than above in order
2234d522f475Smrg     * to prevent any assumptions about the order of the contents
2235d522f475Smrg     * of the various terminal structures (which may change from
2236d522f475Smrg     * implementation to implementation).
2237d522f475Smrg     */
2238d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2239d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2240d522f475Smrg#ifdef TAB3
2241d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR | TAB3;
2242d522f475Smrg#else
2243d522f475Smrg#ifdef ONLCR
2244d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR;
2245d522f475Smrg#else
2246d522f475Smrg    d_tio.c_oflag = OPOST;
2247d522f475Smrg#endif
2248d522f475Smrg#endif
2249d522f475Smrg    {
2250d522f475Smrg	Cardinal nn;
2251d522f475Smrg
2252d522f475Smrg	/* fill in default-values */
2253d522f475Smrg	for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2254d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2255d522f475Smrg		d_tio.c_cc[known_ttyChars[nn].sysMode] =
22560bd37d32Smrg		    (cc_t) known_ttyChars[nn].myDefault;
2257d522f475Smrg	    }
2258d522f475Smrg	}
2259d522f475Smrg    }
2260d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
22612e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2262d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2263d522f475Smrg#ifdef ECHOKE
2264d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2265d522f475Smrg#endif
2266d522f475Smrg#ifdef ECHOCTL
2267d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2268d522f475Smrg#endif
2269d522f475Smrg#ifndef USE_TERMIOS		/* { */
2270d522f475Smrg    d_tio.c_line = 0;
2271d522f475Smrg#endif /* } */
2272d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2273d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2274d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2275d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2276d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2277d522f475Smrg    d_ltc.t_werasc = CWERASE;
2278d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2279d522f475Smrg#endif /* } HAS_LTCHARS */
2280d522f475Smrg#ifdef TIOCLSET			/* { */
2281d522f475Smrg    d_lmode = 0;
2282d522f475Smrg#endif /* } TIOCLSET */
2283d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2284d522f475Smrg#ifndef USE_POSIX_TERMIOS
2285d522f475Smrg#ifdef BAUD_0			/* { */
2286d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2287d522f475Smrg#else /* }{ !BAUD_0 */
22882e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2289d522f475Smrg#endif /* } !BAUD_0 */
2290d522f475Smrg#else /* USE_POSIX_TERMIOS */
2291d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
22922e4f8982Smrg    cfsetispeed(&d_tio, line_speed);
22932e4f8982Smrg    cfsetospeed(&d_tio, line_speed);
2294d522f475Smrg#endif
2295d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2296d522f475Smrg#ifdef ECHOKE
2297d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2298d522f475Smrg#endif
2299d522f475Smrg#ifdef ECHOCTL
2300d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2301d522f475Smrg#endif
2302d522f475Smrg#ifndef USE_POSIX_TERMIOS
2303d522f475Smrg#ifdef NTTYDISC
2304d522f475Smrg    d_tio.c_line = NTTYDISC;
2305d522f475Smrg#else
2306d522f475Smrg    d_tio.c_line = 0;
2307d522f475Smrg#endif
2308d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2309d522f475Smrg#ifdef __sgi
2310d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2311d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2312d522f475Smrg#endif
2313d522f475Smrg#ifdef __MVS__
2314d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2315d522f475Smrg#endif
2316d522f475Smrg    {
2317d522f475Smrg	Cardinal nn;
2318d522f475Smrg	int i;
2319d522f475Smrg
2320d522f475Smrg	/* try to inherit tty settings */
2321d522f475Smrg	for (i = 0; i <= 2; i++) {
2322d522f475Smrg	    TERMIO_STRUCT deftio;
2323d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2324d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2325d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2326d522f475Smrg			d_tio.c_cc[known_ttyChars[nn].sysMode] =
2327d522f475Smrg			    deftio.c_cc[known_ttyChars[nn].sysMode];
2328d522f475Smrg		    }
2329d522f475Smrg		}
2330d522f475Smrg		break;
2331d522f475Smrg	    }
2332d522f475Smrg	}
2333d522f475Smrg    }
2334d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2335d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2336d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2337d522f475Smrg#endif /* } */
2338d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2339d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2340d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2341d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2342d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2343d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2344d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2345d522f475Smrg#endif /* } HAS_LTCHARS */
2346d522f475Smrg
2347d522f475Smrg#ifdef TIOCLSET			/* { */
2348d522f475Smrg    d_lmode = 0;
2349d522f475Smrg#endif /* } TIOCLSET */
2350d522f475Smrg#endif /* } macII, ATT, CRAY */
2351d522f475Smrg#endif /* } TERMIO_STRUCT */
2352d522f475Smrg
2353d522f475Smrg    /* Init the Toolkit. */
2354d522f475Smrg    {
2355d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2356d522f475Smrg	setEffectiveGroup(save_rgid);
2357d522f475Smrg	setEffectiveUser(save_ruid);
2358d522f475Smrg	TRACE_IDS;
2359d522f475Smrg#endif
23600bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
23610bd37d32Smrg					my_class,
23620bd37d32Smrg					optionDescList,
23630bd37d32Smrg					XtNumber(optionDescList),
23640bd37d32Smrg					&argc, (String *) argv,
23650bd37d32Smrg					fallback_resources,
23660bd37d32Smrg					sessionShellWidgetClass,
23670bd37d32Smrg					NULL, 0);
2368d522f475Smrg
2369d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2370d522f475Smrg				  application_resources,
2371d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2372d522f475Smrg	TRACE_XRES();
2373a1f3da82Smrg#if OPT_MAXIMIZE
2374a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2375a1f3da82Smrg					      tblFullscreen,
2376a1f3da82Smrg					      XtNumber(tblFullscreen));
2377a1f3da82Smrg#endif
2378e39b573cSmrg	VTInitTranslations();
2379d522f475Smrg#if OPT_PTY_HANDSHAKE
2380d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2381d522f475Smrg#endif
2382d522f475Smrg
2383d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2384d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2385d522f475Smrg#if !defined(DISABLE_SETUID)
2386d522f475Smrg	setEffectiveUser(save_euid);
2387d522f475Smrg#endif
2388d522f475Smrg#if !defined(DISABLE_SETGID)
2389d522f475Smrg	setEffectiveGroup(save_egid);
2390d522f475Smrg#endif
2391d522f475Smrg	TRACE_IDS;
2392d522f475Smrg#endif
2393d522f475Smrg#endif
2394d522f475Smrg    }
2395d522f475Smrg
2396d522f475Smrg    /*
2397d522f475Smrg     * ICCCM delete_window.
2398d522f475Smrg     */
2399d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2400d522f475Smrg
2401d522f475Smrg    /*
2402d522f475Smrg     * fill in terminal modes
2403d522f475Smrg     */
2404d522f475Smrg    if (resource.tty_modes) {
2405d522f475Smrg	int n = parse_tty_modes(resource.tty_modes, ttymodelist);
2406d522f475Smrg	if (n < 0) {
24070bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2408d522f475Smrg	} else if (n > 0) {
2409d522f475Smrg	    override_tty_modes = True;
2410d522f475Smrg	}
2411d522f475Smrg    }
24120bd37d32Smrg    initZIconBeep();
2413d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2414d522f475Smrg    if (resource.icon_geometry != NULL) {
2415d522f475Smrg	int scr, junk;
2416d522f475Smrg	int ix, iy;
2417d522f475Smrg	Arg args[2];
2418d522f475Smrg
2419d522f475Smrg	for (scr = 0;		/* yyuucchh */
2420d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2421d522f475Smrg	     scr++) ;
2422d522f475Smrg
2423d522f475Smrg	args[0].name = XtNiconX;
2424d522f475Smrg	args[1].name = XtNiconY;
2425d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2426d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2427d522f475Smrg	args[0].value = (XtArgVal) ix;
2428d522f475Smrg	args[1].value = (XtArgVal) iy;
2429d522f475Smrg	XtSetValues(toplevel, args, 2);
2430d522f475Smrg    }
2431d522f475Smrg
2432d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2433d522f475Smrg		number_ourTopLevelShellArgs);
2434d522f475Smrg
2435d522f475Smrg#if OPT_WIDE_CHARS
2436d522f475Smrg    /* seems as good a place as any */
2437d522f475Smrg    init_classtab();
2438d522f475Smrg#endif
2439d522f475Smrg
2440d522f475Smrg    /* Parse the rest of the command line */
2441d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2442d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
24430bd37d32Smrg	if (!isOption(*argv)) {
2444d522f475Smrg#ifdef VMS
2445d522f475Smrg	    Syntax(*argv);
2446d522f475Smrg#else
2447d522f475Smrg	    if (argc > 1)
2448d522f475Smrg		Syntax(*argv);
2449d522f475Smrg	    continue;
2450d522f475Smrg#endif
24510bd37d32Smrg	}
2452d522f475Smrg
2453d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2454d522f475Smrg	switch (argv[0][1]) {
2455d522f475Smrg	case 'C':
2456d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2457d522f475Smrg#ifndef __sgi
2458d522f475Smrg	    {
2459d522f475Smrg		struct stat sbuf;
2460d522f475Smrg
2461d522f475Smrg		/* Must be owner and have read/write permission.
2462d522f475Smrg		   xdm cooperates to give the console the right user. */
2463d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2464d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2465d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2466d522f475Smrg		    Console = True;
2467d522f475Smrg		} else
2468d522f475Smrg		    Console = False;
2469d522f475Smrg	    }
2470d522f475Smrg#else /* __sgi */
2471d522f475Smrg	    Console = True;
2472d522f475Smrg#endif /* __sgi */
2473d522f475Smrg#endif /* TIOCCONS */
2474d522f475Smrg	    continue;
2475d522f475Smrg	case 'S':
2476d522f475Smrg	    if (!ParseSccn(*argv + 2))
2477d522f475Smrg		Syntax(*argv);
2478d522f475Smrg	    continue;
2479d522f475Smrg#ifdef DEBUG
2480d522f475Smrg	case 'D':
2481d522f475Smrg	    debug = True;
2482d522f475Smrg	    continue;
2483d522f475Smrg#endif /* DEBUG */
24842e4f8982Smrg	case 'b':
24852e4f8982Smrg	    if (strcmp(argv[0], "-baudrate"))
24862e4f8982Smrg		Syntax(*argv);
24872e4f8982Smrg	    argc--, argv++;
24882e4f8982Smrg	    continue;
24890bd37d32Smrg	case 'c':
24900bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2491d522f475Smrg		Syntax(*argv);
24920bd37d32Smrg	    argc--, argv++;
2493d522f475Smrg	    continue;
2494d522f475Smrg	case 'e':
24950bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2496d522f475Smrg		Syntax(*argv);
24970bd37d32Smrg	    command_to_exec = (argv + 1);
2498d522f475Smrg	    break;
2499d522f475Smrg	case 'i':
25000bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2501d522f475Smrg		Syntax(*argv);
25020bd37d32Smrg	    argc--, argv++;
2503d522f475Smrg	    continue;
2504d522f475Smrg
2505d522f475Smrg	default:
2506d522f475Smrg	    Syntax(*argv);
2507d522f475Smrg	}
2508d522f475Smrg	break;
2509d522f475Smrg    }
2510d522f475Smrg
2511d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2512d522f475Smrg
2513d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2514d522f475Smrg						 form_top,
2515d522f475Smrg#if OPT_TOOLBAR
2516d522f475Smrg						 XtNmenuBar, menu_top,
2517d522f475Smrg						 XtNresizable, True,
2518d522f475Smrg						 XtNfromVert, menu_top,
2519d522f475Smrg						 XtNleft, XawChainLeft,
2520d522f475Smrg						 XtNright, XawChainRight,
2521d522f475Smrg						 XtNtop, XawChainTop,
2522d522f475Smrg						 XtNbottom, XawChainBottom,
2523d522f475Smrg						 XtNmenuHeight, menu_high,
2524d522f475Smrg#endif
2525d522f475Smrg						 (XtPointer) 0);
2526d522f475Smrg    decode_keyboard_type(term, &resource);
2527d522f475Smrg
2528d522f475Smrg    screen = TScreenOf(term);
2529d522f475Smrg    screen->inhibit = 0;
2530d522f475Smrg
2531d522f475Smrg#ifdef ALLOWLOGGING
2532d522f475Smrg    if (term->misc.logInhibit)
2533d522f475Smrg	screen->inhibit |= I_LOG;
2534d522f475Smrg#endif
2535d522f475Smrg    if (term->misc.signalInhibit)
2536d522f475Smrg	screen->inhibit |= I_SIGNAL;
2537d522f475Smrg#if OPT_TEK4014
2538d522f475Smrg    if (term->misc.tekInhibit)
2539d522f475Smrg	screen->inhibit |= I_TEK;
2540d522f475Smrg#endif
2541d522f475Smrg
2542d522f475Smrg    /*
2543d522f475Smrg     * We might start by showing the tek4014 window.
2544d522f475Smrg     */
2545d522f475Smrg#if OPT_TEK4014
2546d522f475Smrg    if (screen->inhibit & I_TEK)
2547d522f475Smrg	TEK4014_ACTIVE(term) = False;
2548d522f475Smrg
2549d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2550d522f475Smrg	SysError(ERROR_INIT);
2551d522f475Smrg#endif
2552d522f475Smrg
2553d522f475Smrg    /*
2554d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2555d522f475Smrg     */
2556d522f475Smrg#if OPT_TOOLBAR
2557d522f475Smrg    ShowToolbar(resource.toolBar);
2558d522f475Smrg#endif
2559d522f475Smrg
25600bd37d32Smrg    xtermOpenSession();
2561d522f475Smrg
2562d522f475Smrg    /*
2563d522f475Smrg     * Set title and icon name if not specified
2564d522f475Smrg     */
2565d522f475Smrg    if (command_to_exec) {
2566d522f475Smrg	Arg args[2];
2567d522f475Smrg
2568d522f475Smrg	if (!resource.title) {
2569d522f475Smrg	    if (command_to_exec) {
2570d522f475Smrg		resource.title = x_basename(command_to_exec[0]);
2571d522f475Smrg	    }			/* else not reached */
2572d522f475Smrg	}
2573d522f475Smrg
2574d522f475Smrg	if (!resource.icon_name)
2575d522f475Smrg	    resource.icon_name = resource.title;
2576d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2577d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2578d522f475Smrg
25790bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2580d522f475Smrg	       resource.title,
2581d522f475Smrg	       resource.icon_name,
25820bd37d32Smrg	       NonNull(resource.icon_hint),
2583d522f475Smrg	       *command_to_exec));
2584d522f475Smrg
2585d522f475Smrg	XtSetValues(toplevel, args, 2);
2586d522f475Smrg    }
2587d522f475Smrg#if OPT_LUIT_PROG
2588d522f475Smrg    if (term->misc.callfilter) {
25890bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
25900bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
25910bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
25920bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
25930bd37d32Smrg
25940bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
25950bd37d32Smrg						  (count_split
25960bd37d32Smrg						   + count_exec
25970bd37d32Smrg						   + count_using
25980bd37d32Smrg						   + 8));
25990bd37d32Smrg	if (command_to_exec_with_luit == NULL)
26000bd37d32Smrg	    SysError(ERROR_LUMALLOC);
26010bd37d32Smrg
26020bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
26030bd37d32Smrg	if (count_using) {
26040bd37d32Smrg	    char *encoding_opt[4];
26050bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
26060bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
26070bd37d32Smrg	    encoding_opt[2] = 0;
26080bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
26090bd37d32Smrg	}
26100bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
26110bd37d32Smrg	if (count_exec) {
26122e4f8982Smrg	    static char *fixup_shell[] =
26132e4f8982Smrg	    {"sh", "-c", 0};
26140bd37d32Smrg	    char *delimiter[2];
26150bd37d32Smrg	    delimiter[0] = x_strdup("--");
26160bd37d32Smrg	    delimiter[1] = 0;
26170bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
26182e4f8982Smrg	    if (complex_command(command_to_exec)) {
26192e4f8982Smrg		x_appendargv(command_to_exec_with_luit, fixup_shell);
26202e4f8982Smrg	    }
26210bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2622d522f475Smrg	}
26230bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
26240bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2625d522f475Smrg    }
2626d522f475Smrg#endif
2627d522f475Smrg
26280bd37d32Smrg    if_DEBUG({
2629d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2630d522f475Smrg	   done securely by a privileged xterm process (although we try),
2631d522f475Smrg	   so the debug feature is disabled by default. */
2632e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2633d522f475Smrg	int i = -1;
26340bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
26350bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
26360bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2637d522f475Smrg	}
2638d522f475Smrg	if (i >= 0) {
2639d522f475Smrg	    dup2(i, 2);
2640d522f475Smrg
2641d522f475Smrg	    /* mark this file as close on exec */
2642d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2643d522f475Smrg	}
26440bd37d32Smrg    });
2645d522f475Smrg
26462e4f8982Smrg    spawnXTerm(term, line_speed);
2647d522f475Smrg
2648d522f475Smrg#ifndef VMS
2649d522f475Smrg    /* Child process is out there, let's catch its termination */
2650d522f475Smrg
2651d522f475Smrg#ifdef USE_POSIX_SIGNALS
2652d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2653d522f475Smrg#else
2654d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2655d522f475Smrg#endif
2656d522f475Smrg    /* Realize procs have now been executed */
2657d522f475Smrg
2658d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2659d522f475Smrg	char buf[80];
2660d522f475Smrg
2661d522f475Smrg	buf[0] = '\0';
2662d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
266320d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2664d522f475Smrg    }
2665d522f475Smrg#ifdef AIXV3
2666d522f475Smrg#if (OSMAJORVERSION < 4)
2667d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2668d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2669d522f475Smrg     * to the slave-pty process when xterm exits.
2670d522f475Smrg     */
2671d522f475Smrg
2672d522f475Smrg    {
2673d522f475Smrg	TERMIO_STRUCT tio;
2674d522f475Smrg
2675d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
2676d522f475Smrg	    SysError(ERROR_TIOCGETP);
2677d522f475Smrg
2678d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
2679d522f475Smrg
2680d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
2681d522f475Smrg	    SysError(ERROR_TIOCSETP);
2682d522f475Smrg    }
2683d522f475Smrg#endif
2684d522f475Smrg#endif
268501037d57Smrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__) || defined(__minix)
2686d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
2687d522f475Smrg	SysError(ERROR_F_GETFL);
2688d522f475Smrg#ifdef O_NDELAY
2689d522f475Smrg    mode |= O_NDELAY;
2690d522f475Smrg#else
2691d522f475Smrg    mode |= O_NONBLOCK;
2692d522f475Smrg#endif /* O_NDELAY */
2693d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
2694d522f475Smrg	SysError(ERROR_F_SETFL);
2695d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
2696d522f475Smrg    mode = 1;
2697d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
2698d522f475Smrg	SysError(ERROR_FIONBIO);
2699d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
2700d522f475Smrg
2701d522f475Smrg    /* The erase character is used to delete the current completion */
2702d522f475Smrg#if OPT_DABBREV
2703d522f475Smrg#ifdef TERMIO_STRUCT
2704d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
2705d522f475Smrg#else
2706d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
2707d522f475Smrg#endif
2708d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
2709d522f475Smrg#endif
2710d522f475Smrg
2711d522f475Smrg    FD_ZERO(&pty_mask);
2712d522f475Smrg    FD_ZERO(&X_mask);
2713d522f475Smrg    FD_ZERO(&Select_mask);
2714d522f475Smrg    FD_SET(screen->respond, &pty_mask);
2715d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
2716d522f475Smrg    FD_SET(screen->respond, &Select_mask);
2717d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
2718d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
2719d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
2720d522f475Smrg		 : (1 + screen->respond));
2721d522f475Smrg
2722d522f475Smrg#endif /* !VMS */
27230bd37d32Smrg    if_DEBUG({
27240bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
27250bd37d32Smrg    });
2726d522f475Smrg    XSetErrorHandler(xerror);
2727d522f475Smrg    XSetIOErrorHandler(xioerror);
272801037d57Smrg#if OPT_SESSION_MGT
2729e39b573cSmrg    IceSetIOErrorHandler(ice_error);
273001037d57Smrg#endif
2731d522f475Smrg
2732d522f475Smrg    initPtyData(&VTbuffer);
2733d522f475Smrg#ifdef ALLOWLOGGING
2734d522f475Smrg    if (term->misc.log_on) {
273520d2c4d2Smrg	StartLog(term);
2736d522f475Smrg    }
2737d522f475Smrg#endif
2738d522f475Smrg
27390bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
2740d522f475Smrg#if OPT_COLOR_RES
2741a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
2742a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
274320d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
274420d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2745d522f475Smrg
2746a1f3da82Smrg    if (term->misc.re_verse0) {
2747a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
2748a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
2749a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
2750a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
2751a1f3da82Smrg	} else {
2752a1f3da82Smrg	    ReverseVideo(term);
2753a1f3da82Smrg	}
2754a1f3da82Smrg	term->misc.re_verse = True;
2755a1f3da82Smrg	update_reversevideo();
2756a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
2757a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
2758a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
2759a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2760a1f3da82Smrg    }
2761d522f475Smrg#endif /* OPT_COLOR_RES */
2762d522f475Smrg
2763956cc18dSsnj#if OPT_MAXIMIZE
2764956cc18dSsnj    if (resource.maximized)
2765956cc18dSsnj	RequestMaximize(term, True);
2766956cc18dSsnj#endif
2767d522f475Smrg    for (;;) {
2768d522f475Smrg#if OPT_TEK4014
2769d522f475Smrg	if (TEK4014_ACTIVE(term))
2770d522f475Smrg	    TekRun();
2771d522f475Smrg	else
2772d522f475Smrg#endif
2773956cc18dSsnj	    VTRun(term);
2774d522f475Smrg    }
2775d522f475Smrg}
2776d522f475Smrg
2777956cc18dSsnj#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2778d522f475Smrg#define USE_OPENPTY 1
2779d522f475Smrgstatic int opened_tty = -1;
2780d522f475Smrg#endif
2781d522f475Smrg
2782d522f475Smrg/*
2783d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
2784d522f475Smrg *
2785d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
2786d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
2787d522f475Smrg * so that if a pty master is found and later, we find that the slave
2788d522f475Smrg * has problems, we can re-enter this function and get another one.
2789d522f475Smrg */
2790d522f475Smrgstatic int
2791d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
2792d522f475Smrg{
2793d522f475Smrg    int result = 1;
2794d522f475Smrg
27950bd37d32Smrg#if defined(USE_OPENPTY)
27960bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
27972e4f8982Smrg    if (opened_tty >= 0) {
27982e4f8982Smrg	close(opened_tty);
27992e4f8982Smrg	opened_tty = -1;
28002e4f8982Smrg    }
28010bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
28020bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
28030bd37d32Smrg	char *name = ptsname(*pty);
28040bd37d32Smrg	if (name != 0) {
28050bd37d32Smrg	    strcpy(ttydev, name);
28060bd37d32Smrg	    result = 0;
28070bd37d32Smrg	}
28080bd37d32Smrg    }
28090bd37d32Smrg#ifdef USE_PTY_SEARCH
28100bd37d32Smrg    if (result) {
28110bd37d32Smrg	result = pty_search(pty);
28120bd37d32Smrg    }
28130bd37d32Smrg#endif
28140bd37d32Smrg#elif defined(PUCC_PTYD)
2815d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
2816d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
2817d522f475Smrg			       save_ruid, from)) < 0);
2818d522f475Smrg#elif defined(__QNXNTO__)
2819d522f475Smrg    result = pty_search(pty);
2820d522f475Smrg#else
2821d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
2822d522f475Smrg#ifdef __GLIBC__		/* if __GLIBC__ and USE_USG_PTYS, we know glibc >= 2.1 */
2823d522f475Smrg    /* GNU libc 2 allows us to abstract away from having to know the
2824d522f475Smrg       master pty device name. */
2825d522f475Smrg    if ((*pty = getpt()) >= 0) {
2826d522f475Smrg	char *name = ptsname(*pty);
2827d522f475Smrg	if (name != 0) {	/* if filesystem is trashed, this may be null */
2828d522f475Smrg	    strcpy(ttydev, name);
2829d522f475Smrg	    result = 0;
2830d522f475Smrg	}
2831d522f475Smrg    }
2832d522f475Smrg#elif defined(__MVS__)
2833d522f475Smrg    result = pty_search(pty);
2834d522f475Smrg#else
28350bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
2836d522f475Smrg#endif
28370bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
28380bd37d32Smrg    if (!result)
28390bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
2840d522f475Smrg#endif
2841d522f475Smrg
2842d522f475Smrg#elif defined(AIXV3)
2843d522f475Smrg
2844d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
2845d522f475Smrg	strcpy(ttydev, ttyname(*pty));
2846d522f475Smrg	result = 0;
2847d522f475Smrg    }
2848d522f475Smrg#elif defined(__convex__)
2849d522f475Smrg
2850d522f475Smrg    char *pty_name;
2851d522f475Smrg    extern char *getpty(void);
2852d522f475Smrg
2853d522f475Smrg    while ((pty_name = getpty()) != NULL) {
2854d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
2855d522f475Smrg	    strcpy(ptydev, pty_name);
2856d522f475Smrg	    strcpy(ttydev, pty_name);
2857d522f475Smrg	    *x_basename(ttydev) = 't';
2858d522f475Smrg	    result = 0;
2859d522f475Smrg	    break;
2860d522f475Smrg	}
2861d522f475Smrg    }
2862d522f475Smrg
2863d522f475Smrg#elif defined(sequent)
2864d522f475Smrg
2865d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
2866d522f475Smrg
2867d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
2868d522f475Smrg
2869d522f475Smrg    char *tty_name;
2870d522f475Smrg
2871d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
2872d522f475Smrg    if (tty_name != 0) {
2873d522f475Smrg	strcpy(ttydev, tty_name);
2874d522f475Smrg	result = 0;
2875d522f475Smrg    }
2876d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
2877d522f475Smrg
2878d522f475Smrg    struct stat fstat_buf;
2879d522f475Smrg
2880d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
2881d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
2882d522f475Smrg	result = 0;
2883d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
2884d522f475Smrg    }
2885d522f475Smrg#elif defined(__hpux)
2886d522f475Smrg
2887d522f475Smrg    /*
2888d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
2889d522f475Smrg     */
2890d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
2891d522f475Smrg	char *name = ptsname(*pty);
2892d522f475Smrg	if (name != 0) {
2893d522f475Smrg	    strcpy(ttydev, name);
2894d522f475Smrg	    result = 0;
2895d522f475Smrg	} else {		/* permissions, or other unexpected problem */
2896d522f475Smrg	    close(*pty);
2897d522f475Smrg	    *pty = -1;
2898d522f475Smrg	    result = pty_search(pty);
2899d522f475Smrg	}
2900d522f475Smrg    } else {
2901d522f475Smrg	result = pty_search(pty);
2902d522f475Smrg    }
2903d522f475Smrg
2904d522f475Smrg#else
2905d522f475Smrg
2906d522f475Smrg    result = pty_search(pty);
2907d522f475Smrg
2908d522f475Smrg#endif
2909d522f475Smrg#endif
2910d522f475Smrg
2911d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
2912d522f475Smrg	   ttydev != 0 ? ttydev : "?",
2913d522f475Smrg	   ptydev != 0 ? ptydev : "?",
2914d522f475Smrg	   result ? "FAIL" : "OK",
2915d522f475Smrg	   pty != 0 ? *pty : -1));
2916d522f475Smrg    return result;
2917d522f475Smrg}
2918d522f475Smrg
2919d522f475Smrgstatic void
2920e0a2b6dfSmrgset_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
2921d522f475Smrg{
2922d522f475Smrg#ifdef USE_TTY_GROUP
2923d522f475Smrg    struct group *ttygrp;
2924d522f475Smrg
2925d522f475Smrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
2926d522f475Smrg	gid = ttygrp->gr_gid;
2927d522f475Smrg	mode &= 0660U;
2928d522f475Smrg    }
2929d522f475Smrg    endgrent();
2930d522f475Smrg#endif /* USE_TTY_GROUP */
2931d522f475Smrg
2932d522f475Smrg    TRACE_IDS;
2933d522f475Smrg    set_owner(ttydev, uid, gid, mode);
2934d522f475Smrg}
2935d522f475Smrg
2936d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
2937d522f475Smrg#undef get_pty
2938d522f475Smrg/*
2939d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
2940d522f475Smrg * result.
2941d522f475Smrg */
2942d522f475Smrgstatic int
2943d522f475Smrgget_pty(int *pty, char *from)
2944d522f475Smrg{
2945d522f475Smrg    static int m_pty = -1;
2946d522f475Smrg    int result = -1;
2947d522f475Smrg
2948d522f475Smrg    if (pty == NULL) {
2949d522f475Smrg	result = really_get_pty(&m_pty, from);
2950d522f475Smrg
2951d522f475Smrg	seteuid(0);
2952d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
2953d522f475Smrg	seteuid(save_ruid);
2954d522f475Smrg	TRACE_IDS;
2955d522f475Smrg
2956d522f475Smrg    } else if (m_pty != -1) {
2957d522f475Smrg	*pty = m_pty;
2958d522f475Smrg	result = 0;
2959d522f475Smrg    } else {
2960d522f475Smrg	result = -1;
2961d522f475Smrg    }
29620bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
29630bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
29640bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
29650bd37d32Smrg	   result ? "FAIL" : "OK",
29660bd37d32Smrg	   pty != 0 ? *pty : -1));
29672e4f8982Smrg#ifdef USE_OPENPTY
29682e4f8982Smrg    if (opened_tty >= 0) {
29692e4f8982Smrg	close(opened_tty);
29702e4f8982Smrg	opened_tty = -1;
29712e4f8982Smrg    }
29722e4f8982Smrg#endif
2973d522f475Smrg    return result;
2974d522f475Smrg}
2975d522f475Smrg#endif
2976d522f475Smrg
2977d522f475Smrg/*
2978d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
2979d522f475Smrg * we might allocate.  Used on those systems that do not have
2980d522f475Smrg * a functional interface for allocating a pty.
2981d522f475Smrg * Returns 0 if found a pty, 1 if fails.
2982d522f475Smrg */
2983d522f475Smrg#ifdef USE_PTY_SEARCH
2984d522f475Smrgstatic int
2985d522f475Smrgpty_search(int *pty)
2986d522f475Smrg{
2987d522f475Smrg    static int devindex = 0, letter = 0;
2988d522f475Smrg
2989d522f475Smrg#if defined(CRAY) || defined(__MVS__)
2990d522f475Smrg    while (devindex < MAXPTTYS) {
2991d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
2992d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
2993d522f475Smrg	devindex++;
2994d522f475Smrg
2995d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2996d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2997d522f475Smrg	    return 0;
2998d522f475Smrg	}
2999d522f475Smrg    }
3000d522f475Smrg#else /* CRAY || __MVS__ */
3001d522f475Smrg    while (PTYCHAR1[letter]) {
3002d522f475Smrg	ttydev[strlen(ttydev) - 2] =
3003d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
3004d522f475Smrg
3005d522f475Smrg	while (PTYCHAR2[devindex]) {
3006d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
3007d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
3008d522f475Smrg	    devindex++;
3009d522f475Smrg
3010d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
3011d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
3012d522f475Smrg#ifdef sun
3013d522f475Smrg		/* Need to check the process group of the pty.
3014d522f475Smrg		 * If it exists, then the slave pty is in use,
3015d522f475Smrg		 * and we need to get another one.
3016d522f475Smrg		 */
3017d522f475Smrg		int pgrp_rtn;
3018d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
3019d522f475Smrg		    close(*pty);
3020d522f475Smrg		    continue;
3021d522f475Smrg		}
3022d522f475Smrg#endif /* sun */
3023d522f475Smrg		return 0;
3024d522f475Smrg	    }
3025d522f475Smrg	}
3026d522f475Smrg	devindex = 0;
3027d522f475Smrg	letter++;
3028d522f475Smrg    }
3029d522f475Smrg#endif /* CRAY else */
3030d522f475Smrg    /*
3031d522f475Smrg     * We were unable to allocate a pty master!  Return an error
3032d522f475Smrg     * condition and let our caller terminate cleanly.
3033d522f475Smrg     */
3034d522f475Smrg    return 1;
3035d522f475Smrg}
3036d522f475Smrg#endif /* USE_PTY_SEARCH */
3037d522f475Smrg
3038d522f475Smrg/*
3039d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
3040d522f475Smrg * the latter has support for switching character sets.  We support the
3041d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
3042d522f475Smrg * choose 4014 over 4015.
3043d522f475Smrg *
3044d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
3045d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
3046d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
3047d522f475Smrg * later Tektronix terminals), and 4 character sizes.
3048d522f475Smrg * All of these are supported by xterm.
3049d522f475Smrg */
3050d522f475Smrg
3051d522f475Smrg#if OPT_TEK4014
305201037d57Smrgstatic const char *const tekterm[] =
3053d522f475Smrg{
3054d522f475Smrg    "tek4014",
3055d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
3056d522f475Smrg    "tek4012",			/* 4010 with lower case */
3057d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
3058d522f475Smrg    "tek4010",			/* small screen, upper-case only */
3059d522f475Smrg    "dumb",
3060d522f475Smrg    0
3061d522f475Smrg};
3062d522f475Smrg#endif
3063d522f475Smrg
3064d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
3065d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
3066d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
3067d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
3068d522f475Smrg * The VT420 has up to 48 lines on the screen.
3069d522f475Smrg */
3070d522f475Smrg
307101037d57Smrgstatic const char *const vtterm[] =
3072d522f475Smrg{
3073d522f475Smrg#ifdef USE_X11TERM
3074d522f475Smrg    "x11term",			/* for people who want special term name */
3075d522f475Smrg#endif
3076d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
3077d522f475Smrg    "xterm",			/* the prefered name, should be fastest */
3078d522f475Smrg    "vt102",
3079d522f475Smrg    "vt100",
3080d522f475Smrg    "ansi",
3081d522f475Smrg    "dumb",
3082d522f475Smrg    0
3083d522f475Smrg};
3084d522f475Smrg
3085d522f475Smrg/* ARGSUSED */
30860bd37d32Smrgstatic void
3087d522f475Smrghungtty(int i GCC_UNUSED)
3088d522f475Smrg{
30890bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
3090d522f475Smrg    siglongjmp(env, 1);
3091d522f475Smrg}
3092d522f475Smrg
3093d522f475Smrg#if OPT_PTY_HANDSHAKE
3094d522f475Smrg#define NO_FDS {-1, -1}
3095d522f475Smrg
3096d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
3097d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
3098d522f475Smrg
3099d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
3100d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
3101d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
3102d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
3103d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
3104d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
3105d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
3106d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
3107d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
3108d522f475Smrg} status_t;
3109d522f475Smrg
3110d522f475Smrgtypedef struct {
3111d522f475Smrg    status_t status;
3112d522f475Smrg    int error;
3113d522f475Smrg    int fatal_error;
3114d522f475Smrg    int tty_slot;
3115d522f475Smrg    int rows;
3116d522f475Smrg    int cols;
3117d522f475Smrg    char buffer[1024];
3118d522f475Smrg} handshake_t;
3119d522f475Smrg
3120d522f475Smrg#if OPT_TRACE
3121d522f475Smrgstatic void
3122d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
3123d522f475Smrg{
3124d522f475Smrg    const char *status = "?";
3125d522f475Smrg    switch (data->status) {
3126d522f475Smrg    case PTY_BAD:
3127d522f475Smrg	status = "PTY_BAD";
3128d522f475Smrg	break;
3129d522f475Smrg    case PTY_FATALERROR:
3130d522f475Smrg	status = "PTY_FATALERROR";
3131d522f475Smrg	break;
3132d522f475Smrg    case PTY_GOOD:
3133d522f475Smrg	status = "PTY_GOOD";
3134d522f475Smrg	break;
3135d522f475Smrg    case PTY_NEW:
3136d522f475Smrg	status = "PTY_NEW";
3137d522f475Smrg	break;
3138d522f475Smrg    case PTY_NOMORE:
3139d522f475Smrg	status = "PTY_NOMORE";
3140d522f475Smrg	break;
3141d522f475Smrg    case UTMP_ADDED:
3142d522f475Smrg	status = "UTMP_ADDED";
3143d522f475Smrg	break;
3144d522f475Smrg    case UTMP_TTYSLOT:
3145d522f475Smrg	status = "UTMP_TTYSLOT";
3146d522f475Smrg	break;
3147d522f475Smrg    case PTY_EXEC:
3148d522f475Smrg	status = "PTY_EXEC";
3149d522f475Smrg	break;
3150d522f475Smrg    }
3151d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
3152d522f475Smrg	   tag,
3153d522f475Smrg	   status,
3154d522f475Smrg	   data->error,
3155d522f475Smrg	   data->fatal_error,
3156d522f475Smrg	   data->buffer));
3157d522f475Smrg}
3158d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
3159d522f475Smrg#else
3160d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
3161d522f475Smrg#endif
3162d522f475Smrg
3163d522f475Smrg/* HsSysError()
3164d522f475Smrg *
3165d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
3166d522f475Smrg * over the errno and error exit to the master process so that it can
3167d522f475Smrg * display our error message and exit with our exit code so that the
3168d522f475Smrg * user can see it.
3169d522f475Smrg */
3170d522f475Smrg
3171d522f475Smrgstatic void
3172d522f475SmrgHsSysError(int error)
3173d522f475Smrg{
3174d522f475Smrg    handshake_t handshake;
3175d522f475Smrg
3176d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3177d522f475Smrg    handshake.status = PTY_FATALERROR;
3178d522f475Smrg    handshake.error = errno;
3179d522f475Smrg    handshake.fatal_error = error;
31800bd37d32Smrg    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
3181d522f475Smrg
3182d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
3183d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
3184d522f475Smrg	       handshake.error,
3185d522f475Smrg	       handshake.fatal_error,
3186d522f475Smrg	       handshake.buffer));
3187d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
318820d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
318920d2c4d2Smrg			(const char *) &handshake,
319020d2c4d2Smrg			sizeof(handshake)));
3191d522f475Smrg    } else {
31920bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
31930bd37d32Smrg		     handshake.error,
31940bd37d32Smrg		     handshake.fatal_error,
31950bd37d32Smrg		     handshake.buffer);
3196d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3197d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3198d522f475Smrg    }
3199d522f475Smrg    exit(error);
3200d522f475Smrg}
3201d522f475Smrg
3202d522f475Smrgvoid
3203d522f475Smrgfirst_map_occurred(void)
3204d522f475Smrg{
3205d522f475Smrg    if (resource.wait_for_map) {
3206d522f475Smrg	handshake_t handshake;
3207d522f475Smrg	TScreen *screen = TScreenOf(term);
3208d522f475Smrg
3209d522f475Smrg	memset(&handshake, 0, sizeof(handshake));
3210d522f475Smrg	handshake.status = PTY_EXEC;
3211d522f475Smrg	handshake.rows = screen->max_row;
3212d522f475Smrg	handshake.cols = screen->max_col;
3213d522f475Smrg
3214d522f475Smrg	if (pc_pipe[1] >= 0) {
3215d522f475Smrg	    TRACE(("first_map_occurred: %dx%d\n", handshake.rows, handshake.cols));
3216d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
321720d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
321820d2c4d2Smrg			    (const char *) &handshake,
321920d2c4d2Smrg			    sizeof(handshake)));
3220d522f475Smrg	    close(cp_pipe[0]);
3221d522f475Smrg	    close(pc_pipe[1]);
3222d522f475Smrg	}
3223d522f475Smrg	resource.wait_for_map = False;
3224d522f475Smrg    }
3225d522f475Smrg}
3226d522f475Smrg#else
3227d522f475Smrg/*
3228d522f475Smrg * temporary hack to get xterm working on att ptys
3229d522f475Smrg */
3230d522f475Smrgstatic void
3231d522f475SmrgHsSysError(int error)
3232d522f475Smrg{
32330bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
32340bd37d32Smrg		 error, errno, ttydev);
3235d522f475Smrg    exit(error);
3236d522f475Smrg}
3237d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3238d522f475Smrg
3239d522f475Smrg#ifndef VMS
3240d522f475Smrgstatic void
3241e0a2b6dfSmrgset_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
3242d522f475Smrg{
3243d522f475Smrg    int why;
3244d522f475Smrg
3245d522f475Smrg    TRACE_IDS;
324620d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
32470bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3248d522f475Smrg
3249d522f475Smrg    if (chown(device, uid, gid) < 0) {
3250d522f475Smrg	why = errno;
3251d522f475Smrg	if (why != ENOENT
3252d522f475Smrg	    && save_ruid == 0) {
32530bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
32540bd37d32Smrg			device, (long) uid, (long) gid);
3255d522f475Smrg	}
3256d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3257e39b573cSmrg    } else if (chmod(device, mode) < 0) {
3258d522f475Smrg	why = errno;
3259d522f475Smrg	if (why != ENOENT) {
3260d522f475Smrg	    struct stat sb;
3261d522f475Smrg	    if (stat(device, &sb) < 0) {
32620bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
32630bd37d32Smrg			    device, (unsigned) mode);
3264d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
32650bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
32660bd37d32Smrg			    device,
32670bd37d32Smrg			    (unsigned long) mode,
32680bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3269d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
32700bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3271d522f475Smrg	    }
3272d522f475Smrg	}
3273d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3274d522f475Smrg    }
3275d522f475Smrg}
3276d522f475Smrg
3277894e0ac8Smrg/*
3278894e0ac8Smrg * utmp data may not be null-terminated; even if it is, there may be garbage
3279894e0ac8Smrg * after the null.  This fills the unused part of the result with nulls.
3280894e0ac8Smrg */
3281894e0ac8Smrgstatic void
3282894e0ac8Smrgcopy_filled(char *target, const char *source, size_t len)
3283894e0ac8Smrg{
3284894e0ac8Smrg    size_t used = 0;
3285894e0ac8Smrg    while (used < len) {
3286894e0ac8Smrg	if ((target[used] = source[used]) == 0)
3287894e0ac8Smrg	    break;
3288894e0ac8Smrg	++used;
3289894e0ac8Smrg    }
3290894e0ac8Smrg    while (used < len) {
3291894e0ac8Smrg	target[used++] = '\0';
3292894e0ac8Smrg    }
3293894e0ac8Smrg}
3294894e0ac8Smrg
3295d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3296d522f475Smrg/*
3297d522f475Smrg * getutid() only looks at ut_type and ut_id.
3298d522f475Smrg * But we'll also check ut_line in find_utmp().
3299d522f475Smrg */
3300d522f475Smrgstatic void
3301d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3302d522f475Smrg{
3303d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3304d522f475Smrg    tofind->ut_type = type;
3305894e0ac8Smrg    copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3306894e0ac8Smrg    copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3307d522f475Smrg}
3308d522f475Smrg
3309d522f475Smrg/*
3310d522f475Smrg * We could use getutline() if we didn't support old systems.
3311d522f475Smrg */
3312d522f475Smrgstatic struct UTMP_STR *
3313d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3314d522f475Smrg{
3315d522f475Smrg    struct UTMP_STR *result;
33160bd37d32Smrg    struct UTMP_STR limited;
3317d522f475Smrg    struct UTMP_STR working;
3318d522f475Smrg
3319d522f475Smrg    for (;;) {
3320d522f475Smrg	memset(&working, 0, sizeof(working));
3321d522f475Smrg	working.ut_type = tofind->ut_type;
3322894e0ac8Smrg	copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3323d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3324d522f475Smrg	working.ut_type = 0;
3325d522f475Smrg#endif
3326d522f475Smrg	if ((result = call_getutid(&working)) == 0)
3327d522f475Smrg	    break;
3328894e0ac8Smrg	copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line));
33290bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3330d522f475Smrg	    break;
3331d522f475Smrg	/*
3332d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3333d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3334d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3335d522f475Smrg	 */
3336d522f475Smrg	memset(result, 0, sizeof(*result));
3337d522f475Smrg    }
3338d522f475Smrg    return result;
3339d522f475Smrg}
3340d522f475Smrg#endif /* HAVE_UTMP... */
3341d522f475Smrg
3342d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3343d522f475Smrg
334420d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
334520d2c4d2Smrg#define USE_NO_DEV_TTY 1
334620d2c4d2Smrg#else
334720d2c4d2Smrg#define USE_NO_DEV_TTY 0
334820d2c4d2Smrg#endif
334920d2c4d2Smrg
3350e0a2b6dfSmrgstatic int
3351e0a2b6dfSmrgsame_leaf(char *a, char *b)
3352e0a2b6dfSmrg{
3353e0a2b6dfSmrg    char *p = x_basename(a);
3354e0a2b6dfSmrg    char *q = x_basename(b);
3355e0a2b6dfSmrg    return !strcmp(p, q);
3356e0a2b6dfSmrg}
3357e0a2b6dfSmrg
3358e0a2b6dfSmrg/*
3359e0a2b6dfSmrg * "good enough" (inode wouldn't port to Cygwin)
3360e0a2b6dfSmrg */
3361e0a2b6dfSmrgstatic int
3362e0a2b6dfSmrgsame_file(const char *a, const char *b)
3363e0a2b6dfSmrg{
3364e0a2b6dfSmrg    struct stat asb;
3365e0a2b6dfSmrg    struct stat bsb;
3366e0a2b6dfSmrg    int result = 0;
3367e0a2b6dfSmrg
3368e0a2b6dfSmrg    if ((stat(a, &asb) == 0)
3369e0a2b6dfSmrg	&& (stat(b, &bsb) == 0)
3370e0a2b6dfSmrg	&& ((asb.st_mode & S_IFMT) == S_IFREG)
3371e0a2b6dfSmrg	&& ((bsb.st_mode & S_IFMT) == S_IFREG)
3372e0a2b6dfSmrg	&& (asb.st_mtime == bsb.st_mtime)
3373e0a2b6dfSmrg	&& (asb.st_size == bsb.st_size)) {
3374e0a2b6dfSmrg	result = 1;
3375e0a2b6dfSmrg    }
3376e0a2b6dfSmrg    return result;
3377e0a2b6dfSmrg}
3378e0a2b6dfSmrg
3379e0a2b6dfSmrg/*
3380e0a2b6dfSmrg * Only set $SHELL for paths found in the standard location.
3381e0a2b6dfSmrg */
3382e0a2b6dfSmrgstatic Boolean
3383e0a2b6dfSmrgvalidShell(const char *pathname)
3384e0a2b6dfSmrg{
3385e0a2b6dfSmrg    Boolean result = False;
3386e0a2b6dfSmrg    const char *ok_shells = "/etc/shells";
3387e0a2b6dfSmrg    char *blob;
3388e0a2b6dfSmrg    struct stat sb;
3389e0a2b6dfSmrg    size_t rc;
3390e0a2b6dfSmrg    FILE *fp;
3391e0a2b6dfSmrg
3392e0a2b6dfSmrg    if (validProgram(pathname)
3393e0a2b6dfSmrg	&& stat(ok_shells, &sb) == 0
3394e0a2b6dfSmrg	&& (sb.st_mode & S_IFMT) == S_IFREG
33952e4f8982Smrg	&& ((size_t) sb.st_size > 0)
33962e4f8982Smrg	&& ((size_t) sb.st_size < (((size_t) ~0) - 2))
3397e0a2b6dfSmrg	&& (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
3398e0a2b6dfSmrg	if ((fp = fopen(ok_shells, "r")) != 0) {
3399e0a2b6dfSmrg	    rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
3400e0a2b6dfSmrg	    if (rc == (size_t) sb.st_size) {
3401e0a2b6dfSmrg		char *p = blob;
3402e0a2b6dfSmrg		char *q, *r;
3403e0a2b6dfSmrg		blob[rc] = '\0';
3404e0a2b6dfSmrg		while (!result && (q = strtok(p, "\n")) != 0) {
3405e0a2b6dfSmrg		    if ((r = x_strtrim(q)) != 0) {
3406e0a2b6dfSmrg			TRACE(("...test \"%s\"\n", q));
3407e0a2b6dfSmrg			if (!strcmp(q, pathname)) {
3408e0a2b6dfSmrg			    result = True;
3409e0a2b6dfSmrg			} else if (same_leaf(q, (char *) pathname) &&
3410e0a2b6dfSmrg				   same_file(q, pathname)) {
3411e0a2b6dfSmrg			    result = True;
3412e0a2b6dfSmrg			}
3413e0a2b6dfSmrg			free(r);
3414e0a2b6dfSmrg		    }
3415e0a2b6dfSmrg		    p = 0;
3416e0a2b6dfSmrg		}
3417e0a2b6dfSmrg	    }
3418e0a2b6dfSmrg	    fclose(fp);
3419e0a2b6dfSmrg	}
3420e0a2b6dfSmrg	free(blob);
3421e0a2b6dfSmrg    }
3422e0a2b6dfSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3423e0a2b6dfSmrg    return result;
3424e0a2b6dfSmrg}
3425e0a2b6dfSmrg
3426e0a2b6dfSmrgstatic char *
3427e0a2b6dfSmrgresetShell(char *oldPath)
3428e0a2b6dfSmrg{
3429e0a2b6dfSmrg    char *newPath = x_strdup("/bin/sh");
3430e0a2b6dfSmrg    char *envPath = getenv("SHELL");
3431e0a2b6dfSmrg    if (oldPath != 0)
3432e0a2b6dfSmrg	free(oldPath);
3433e0a2b6dfSmrg    if (!IsEmpty(envPath))
3434e0a2b6dfSmrg	xtermSetenv("SHELL", newPath);
3435e0a2b6dfSmrg    return newPath;
3436e0a2b6dfSmrg}
3437e0a2b6dfSmrg
3438d522f475Smrg/*
3439d522f475Smrg *  Inits pty and tty and forks a login process.
3440d522f475Smrg *  Does not close fd Xsocket.
3441d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3442d522f475Smrg */
3443d522f475Smrgstatic int
34442e4f8982SmrgspawnXTerm(XtermWidget xw, unsigned line_speed)
3445d522f475Smrg{
3446d522f475Smrg    TScreen *screen = TScreenOf(xw);
3447d522f475Smrg    Cardinal nn;
3448d522f475Smrg#if OPT_PTY_HANDSHAKE
3449d522f475Smrg    Bool got_handshake_size = False;
3450d522f475Smrg    handshake_t handshake;
3451d522f475Smrg    int done;
3452d522f475Smrg#endif
3453d522f475Smrg#if OPT_INITIAL_ERASE
3454d522f475Smrg    int initial_erase = VAL_INITIAL_ERASE;
3455d522f475Smrg    Bool setInitialErase;
3456d522f475Smrg#endif
3457d522f475Smrg    int rc = 0;
3458d522f475Smrg    int ttyfd = -1;
3459d522f475Smrg    Bool ok_termcap;
3460d522f475Smrg    char *newtc;
3461d522f475Smrg
3462d522f475Smrg#ifdef TERMIO_STRUCT
3463d522f475Smrg    TERMIO_STRUCT tio;
3464d522f475Smrg#ifdef __MVS__
3465d522f475Smrg    TERMIO_STRUCT gio;
3466d522f475Smrg#endif /* __MVS__ */
3467d522f475Smrg#ifdef TIOCLSET
3468d522f475Smrg    unsigned lmode;
3469d522f475Smrg#endif /* TIOCLSET */
3470d522f475Smrg#ifdef HAS_LTCHARS
3471d522f475Smrg    struct ltchars ltc;
3472d522f475Smrg#endif /* HAS_LTCHARS */
3473d522f475Smrg#else /* !TERMIO_STRUCT */
3474d522f475Smrg    int ldisc = 0;
3475d522f475Smrg    int discipline;
3476d522f475Smrg    unsigned lmode;
3477d522f475Smrg    struct tchars tc;
3478d522f475Smrg    struct ltchars ltc;
3479d522f475Smrg    struct sgttyb sg;
3480d522f475Smrg#ifdef sony
3481d522f475Smrg    int jmode;
3482d522f475Smrg    struct jtchars jtc;
3483d522f475Smrg#endif /* sony */
3484d522f475Smrg#endif /* TERMIO_STRUCT */
3485d522f475Smrg
34860bd37d32Smrg    char *shell_path = 0;
34870bd37d32Smrg    char *shname, *shname_minus;
348820d2c4d2Smrg    int i;
348920d2c4d2Smrg#if USE_NO_DEV_TTY
349020d2c4d2Smrg    int no_dev_tty = False;
349120d2c4d2Smrg#endif
349201037d57Smrg    const char *const *envnew;	/* new environment */
3493d522f475Smrg    char buf[64];
3494d522f475Smrg    char *TermName = NULL;
3495d522f475Smrg#ifdef TTYSIZE_STRUCT
3496d522f475Smrg    TTYSIZE_STRUCT ts;
3497d522f475Smrg#endif
34980bd37d32Smrg    struct passwd pw;
3499d522f475Smrg    char *login_name = NULL;
3500d522f475Smrg#ifndef USE_UTEMPTER
3501d522f475Smrg#ifdef HAVE_UTMP
3502d522f475Smrg    struct UTMP_STR utmp;
3503d522f475Smrg#ifdef USE_SYSV_UTMP
3504d522f475Smrg    struct UTMP_STR *utret = NULL;
3505d522f475Smrg#endif
3506d522f475Smrg#ifdef USE_LASTLOG
3507d522f475Smrg    struct lastlog lastlog;
3508d522f475Smrg#endif
3509d522f475Smrg#ifdef USE_LASTLOGX
3510d522f475Smrg    struct lastlogx lastlogx;
3511d522f475Smrg#endif /* USE_LASTLOG */
3512d522f475Smrg#endif /* HAVE_UTMP */
3513d522f475Smrg#endif /* !USE_UTEMPTER */
3514d522f475Smrg
3515e39b573cSmrg#if OPT_TRACE
3516e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
3517e39b573cSmrg#endif
3518e39b573cSmrg
3519d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
3520d522f475Smrg    (void) rc;
3521d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3522d522f475Smrg    (void) utret;
3523d522f475Smrg#endif
3524d522f475Smrg
3525d522f475Smrg    screen->uid = save_ruid;
3526d522f475Smrg    screen->gid = save_rgid;
3527d522f475Smrg
3528d522f475Smrg#ifdef SIGTTOU
3529d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
3530d522f475Smrg    signal(SIGTTOU, SIG_IGN);
3531d522f475Smrg#endif
3532d522f475Smrg
3533d522f475Smrg#if OPT_PTY_HANDSHAKE
3534d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3535d522f475Smrg#endif
3536d522f475Smrg
3537d522f475Smrg    if (am_slave >= 0) {
3538d522f475Smrg	screen->respond = am_slave;
3539d522f475Smrg	set_pty_id(ttydev, passedPty);
3540d522f475Smrg#ifdef USE_PTY_DEVICE
3541d522f475Smrg	set_pty_id(ptydev, passedPty);
3542d522f475Smrg#endif
3543d522f475Smrg	if (xtermResetIds(screen) < 0)
3544d522f475Smrg	    exit(1);
3545d522f475Smrg    } else {
3546d522f475Smrg	Bool tty_got_hung;
3547d522f475Smrg
3548d522f475Smrg	/*
3549d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
3550d522f475Smrg	 * that has gone away).  Simply make up some reasonable
3551d522f475Smrg	 * defaults.
3552d522f475Smrg	 */
3553d522f475Smrg
3554d522f475Smrg	signal(SIGALRM, hungtty);
3555d522f475Smrg	alarm(2);		/* alarm(1) might return too soon */
3556d522f475Smrg	if (!sigsetjmp(env, 1)) {
3557d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
3558d522f475Smrg	    alarm(0);
3559d522f475Smrg	    tty_got_hung = False;
3560d522f475Smrg	} else {
3561d522f475Smrg	    tty_got_hung = True;
3562d522f475Smrg	    ttyfd = -1;
3563d522f475Smrg	    errno = ENXIO;
3564d522f475Smrg	}
35652e4f8982Smrg	shell_path = 0;
35660bd37d32Smrg	memset(&pw, 0, sizeof(pw));
3567d522f475Smrg#if OPT_PTY_HANDSHAKE
3568d522f475Smrg	got_handshake_size = False;
3569d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
3570d522f475Smrg#if OPT_INITIAL_ERASE
3571d522f475Smrg	initial_erase = VAL_INITIAL_ERASE;
3572d522f475Smrg#endif
3573d522f475Smrg	signal(SIGALRM, SIG_DFL);
3574d522f475Smrg
3575d522f475Smrg	/*
3576d522f475Smrg	 * Check results and ignore current control terminal if
3577d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
3578d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
3579d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
35800bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
35810bd37d32Smrg	 * if xterm is run within a jail.
3582d522f475Smrg	 */
358320d2c4d2Smrg#if USE_NO_DEV_TTY
3584d522f475Smrg	no_dev_tty = False;
358520d2c4d2Smrg#endif
3586d522f475Smrg	if (ttyfd < 0) {
3587d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
35880bd37d32Smrg		errno == ENOENT ||
3589d522f475Smrg#ifdef ENODEV
3590d522f475Smrg		errno == ENODEV ||
3591d522f475Smrg#endif
3592d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
359320d2c4d2Smrg#if USE_NO_DEV_TTY
3594d522f475Smrg		no_dev_tty = True;
359520d2c4d2Smrg#endif
3596d522f475Smrg#ifdef HAS_LTCHARS
3597d522f475Smrg		ltc = d_ltc;
3598d522f475Smrg#endif /* HAS_LTCHARS */
3599d522f475Smrg#ifdef TIOCLSET
3600d522f475Smrg		lmode = d_lmode;
3601d522f475Smrg#endif /* TIOCLSET */
3602d522f475Smrg#ifdef TERMIO_STRUCT
3603d522f475Smrg		tio = d_tio;
3604d522f475Smrg#else /* !TERMIO_STRUCT */
3605d522f475Smrg		sg = d_sg;
3606d522f475Smrg		tc = d_tc;
3607d522f475Smrg		discipline = d_disipline;
3608d522f475Smrg#ifdef sony
3609d522f475Smrg		jmode = d_jmode;
3610d522f475Smrg		jtc = d_jtc;
3611d522f475Smrg#endif /* sony */
3612d522f475Smrg#endif /* TERMIO_STRUCT */
3613d522f475Smrg	    } else {
3614d522f475Smrg		SysError(ERROR_OPDEVTTY);
3615d522f475Smrg	    }
3616d522f475Smrg	} else {
3617d522f475Smrg
3618d522f475Smrg	    /* Get a copy of the current terminal's state,
3619d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
3620d522f475Smrg	     * may not have a controlling terminal at this point
3621d522f475Smrg	     * if started directly from xdm or xinit,
3622d522f475Smrg	     * in which case we just use the defaults as above.
3623d522f475Smrg	     */
3624d522f475Smrg#ifdef HAS_LTCHARS
3625d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
3626d522f475Smrg		ltc = d_ltc;
3627d522f475Smrg#endif /* HAS_LTCHARS */
3628d522f475Smrg#ifdef TIOCLSET
3629d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
3630d522f475Smrg		lmode = d_lmode;
3631d522f475Smrg#endif /* TIOCLSET */
3632d522f475Smrg#ifdef TERMIO_STRUCT
363320d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
363420d2c4d2Smrg	    if (rc == -1)
3635d522f475Smrg		tio = d_tio;
3636d522f475Smrg#else /* !TERMIO_STRUCT */
363720d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
363820d2c4d2Smrg	    if (rc == -1)
3639d522f475Smrg		sg = d_sg;
3640d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
3641d522f475Smrg		tc = d_tc;
3642d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
3643d522f475Smrg		discipline = d_disipline;
3644d522f475Smrg#ifdef sony
3645d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
3646d522f475Smrg		jmode = d_jmode;
3647d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
3648d522f475Smrg		jtc = d_jtc;
3649d522f475Smrg#endif /* sony */
3650d522f475Smrg#endif /* TERMIO_STRUCT */
3651d522f475Smrg
3652d522f475Smrg	    /*
3653d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
3654d522f475Smrg	     * erase value.  Just in case that will fail, first get
3655d522f475Smrg	     * the value from /dev/tty, so we will have something
3656d522f475Smrg	     * at least.
3657d522f475Smrg	     */
3658d522f475Smrg#if OPT_INITIAL_ERASE
3659d522f475Smrg	    if (resource.ptyInitialErase) {
3660d522f475Smrg#ifdef TERMIO_STRUCT
3661d522f475Smrg		initial_erase = tio.c_cc[VERASE];
3662d522f475Smrg#else /* !TERMIO_STRUCT */
3663d522f475Smrg		initial_erase = sg.sg_erase;
3664d522f475Smrg#endif /* TERMIO_STRUCT */
3665d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
3666d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
3667d522f475Smrg		       initial_erase));
3668d522f475Smrg	    }
3669d522f475Smrg#endif
3670d522f475Smrg#ifdef __MVS__
3671d522f475Smrg	    if (ttyGetAttr(ttyfd, &gio) == 0) {
3672d522f475Smrg		gio.c_cflag &= ~(HUPCL | PARENB);
3673d522f475Smrg		ttySetAttr(ttyfd, &gio);
3674d522f475Smrg	    }
3675d522f475Smrg#endif /* __MVS__ */
3676d522f475Smrg
3677d522f475Smrg	    close_fd(ttyfd);
3678d522f475Smrg	}
3679d522f475Smrg
3680d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
3681d522f475Smrg	    SysError(ERROR_PTYS);
3682d522f475Smrg	}
36830bd37d32Smrg	TRACE_TTYSIZE(screen->respond, "after get_pty");
3684d522f475Smrg#if OPT_INITIAL_ERASE
3685d522f475Smrg	if (resource.ptyInitialErase) {
3686d522f475Smrg#ifdef TERMIO_STRUCT
3687d522f475Smrg	    TERMIO_STRUCT my_tio;
368820d2c4d2Smrg	    rc = ttyGetAttr(screen->respond, &my_tio);
368920d2c4d2Smrg	    if (rc == 0)
3690d522f475Smrg		initial_erase = my_tio.c_cc[VERASE];
3691d522f475Smrg#else /* !TERMIO_STRUCT */
3692d522f475Smrg	    struct sgttyb my_sg;
369320d2c4d2Smrg	    rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg);
369420d2c4d2Smrg	    if (rc == 0)
3695d522f475Smrg		initial_erase = my_sg.sg_erase;
3696d522f475Smrg#endif /* TERMIO_STRUCT */
3697d522f475Smrg	    TRACE(("%s initial_erase:%d (from pty)\n",
3698d522f475Smrg		   (rc == 0) ? "OK" : "FAIL",
3699d522f475Smrg		   initial_erase));
3700d522f475Smrg	}
3701d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3702d522f475Smrg    }
3703d522f475Smrg
3704d522f475Smrg    /* avoid double MapWindow requests */
3705d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
3706d522f475Smrg
3707d522f475Smrg    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
3708d522f475Smrg				   False);
3709d522f475Smrg
3710d522f475Smrg    if (!TEK4014_ACTIVE(xw))
3711956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
3712d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
3713d522f475Smrg    if (Console) {
3714d522f475Smrg	/*
3715d522f475Smrg	 * Inform any running xconsole program
3716d522f475Smrg	 * that we are going to steal the console.
3717d522f475Smrg	 */
3718d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
3719d522f475Smrg	mit_console = XInternAtom(screen->display, mit_console_name, False);
3720d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
3721d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
3722d522f475Smrg		       mit_console, CurrentTime,
3723d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
3724d522f475Smrg    }
3725d522f475Smrg#endif
3726d522f475Smrg#if OPT_TEK4014
3727d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3728d522f475Smrg	envnew = tekterm;
3729d522f475Smrg    } else
3730d522f475Smrg#endif
3731d522f475Smrg    {
3732d522f475Smrg	envnew = vtterm;
3733d522f475Smrg    }
3734d522f475Smrg
3735d522f475Smrg    /*
3736d522f475Smrg     * This used to exit if no termcap entry was found for the specified
3737d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
3738d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
3739d522f475Smrg     * entry is not found.
3740d522f475Smrg     */
3741d522f475Smrg    ok_termcap = True;
374220d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
374320d2c4d2Smrg	const char *last = NULL;
374420d2c4d2Smrg	char *next;
374520d2c4d2Smrg
374620d2c4d2Smrg	TermName = x_strdup(*envnew);
3747d522f475Smrg	ok_termcap = False;
3748d522f475Smrg	while (*envnew != NULL) {
374920d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
375020d2c4d2Smrg		next = x_strdup(*envnew);
375120d2c4d2Smrg		if (get_termcap(xw, next)) {
375220d2c4d2Smrg		    free(TermName);
375320d2c4d2Smrg		    TermName = next;
37540bd37d32Smrg		    ok_termcap = True + 1;
375520d2c4d2Smrg		    break;
375620d2c4d2Smrg		} else {
375720d2c4d2Smrg		    free(next);
375820d2c4d2Smrg		}
3759d522f475Smrg	    }
3760d522f475Smrg	    last = *envnew;
3761d522f475Smrg	    envnew++;
3762d522f475Smrg	}
3763d522f475Smrg    }
3764d522f475Smrg    if (ok_termcap) {
3765a1f3da82Smrg	resource.term_name = TermName;
376620d2c4d2Smrg	resize_termcap(xw);
3767d522f475Smrg    }
3768d522f475Smrg
3769d522f475Smrg    /*
3770d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
3771d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
3772d522f475Smrg     */
3773d522f475Smrg#if OPT_INITIAL_ERASE
3774d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
3775d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
3776d522f475Smrg    setInitialErase = False;
3777d522f475Smrg    if (override_tty_modes && ttymodelist[XTTYMODE_erase].set) {
3778d522f475Smrg	initial_erase = ttymodelist[XTTYMODE_erase].value;
3779d522f475Smrg	setInitialErase = True;
3780d522f475Smrg    } else if (resource.ptyInitialErase) {
3781a1f3da82Smrg	/* EMPTY */ ;
3782d522f475Smrg    } else if (ok_termcap) {
378320d2c4d2Smrg	char *s = get_tcap_erase(xw);
3784d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
3785d522f475Smrg	if (s != 0) {
378620d2c4d2Smrg	    char *save = s;
3787d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
3788d522f475Smrg	    setInitialErase = True;
378920d2c4d2Smrg	    free(save);
3790d522f475Smrg	}
3791d522f475Smrg    }
3792d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
3793d522f475Smrg
3794d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
3795d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
3796d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
3797d522f475Smrg	if (initial_erase == ANSI_DEL) {
379820d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
3799d522f475Smrg	} else {
3800d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
3801d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
3802d522f475Smrg	}
3803d522f475Smrg	TRACE(("...sets DECBKM %s\n",
3804d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
3805d522f475Smrg    } else {
3806d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
3807d522f475Smrg    }
3808d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3809d522f475Smrg
3810d522f475Smrg#ifdef TTYSIZE_STRUCT
3811d522f475Smrg    /* tell tty how big window is */
3812d522f475Smrg#if OPT_TEK4014
3813d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3814d522f475Smrg	TTYSIZE_ROWS(ts) = 38;
3815d522f475Smrg	TTYSIZE_COLS(ts) = 81;
3816d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
381720d2c4d2Smrg	ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
381820d2c4d2Smrg	ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3819d522f475Smrg#endif
3820d522f475Smrg    } else
3821d522f475Smrg#endif
3822d522f475Smrg    {
382320d2c4d2Smrg	TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
382420d2c4d2Smrg	TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3825d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
382620d2c4d2Smrg	ts.ws_xpixel = (ttySize_t) FullWidth(screen);
382720d2c4d2Smrg	ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3828d522f475Smrg#endif
3829d522f475Smrg    }
383020d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
3831d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
3832d522f475Smrg	   TTYSIZE_ROWS(ts),
3833d522f475Smrg	   TTYSIZE_COLS(ts), i));
3834d522f475Smrg#endif /* TTYSIZE_STRUCT */
3835d522f475Smrg
38360bd37d32Smrg#if !defined(USE_OPENPTY)
38370bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
38380bd37d32Smrg    /*
38390bd37d32Smrg     * utempter checks the ownership of the device; some implementations
38400bd37d32Smrg     * set ownership in grantpt - do this first.
38410bd37d32Smrg     */
38420bd37d32Smrg    grantpt(screen->respond);
38430bd37d32Smrg#endif
38440bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
38450bd37d32Smrg    unlockpt(screen->respond);
38460bd37d32Smrg    TRACE_TTYSIZE(screen->respond, "after unlockpt");
38470bd37d32Smrg#endif
38480bd37d32Smrg#endif /* !USE_OPENPTY */
38490bd37d32Smrg
3850d522f475Smrg    added_utmp_entry = False;
3851d522f475Smrg#if defined(USE_UTEMPTER)
3852d522f475Smrg#undef UTMP
38532e4f8982Smrg    if ((xw->misc.login_shell || !command_to_exec) && !resource.utmpInhibit) {
3854d522f475Smrg	struct UTMP_STR dummy;
3855d522f475Smrg
3856d522f475Smrg	/* Note: utempter may trim it anyway */
3857d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
38580bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
38590bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
3860d522f475Smrg	addToUtmp(ttydev, dummy.ut_host, screen->respond);
3861d522f475Smrg	added_utmp_entry = True;
3862d522f475Smrg    }
3863d522f475Smrg#endif
3864d522f475Smrg
3865d522f475Smrg    if (am_slave < 0) {
3866d522f475Smrg#if OPT_PTY_HANDSHAKE
3867d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
3868d522f475Smrg	    SysError(ERROR_FORK);
3869d522f475Smrg#endif
3870d522f475Smrg	TRACE(("Forking...\n"));
3871d522f475Smrg	if ((screen->pid = fork()) == -1)
3872d522f475Smrg	    SysError(ERROR_FORK);
3873d522f475Smrg
3874d522f475Smrg	if (screen->pid == 0) {
3875d522f475Smrg#ifdef USE_USG_PTYS
387620d2c4d2Smrg	    int ptyfd = -1;
3877d522f475Smrg	    char *pty_name;
3878d522f475Smrg#endif
3879d522f475Smrg	    /*
3880d522f475Smrg	     * now in child process
3881d522f475Smrg	     */
3882d522f475Smrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
3883d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
3884d522f475Smrg#else
3885d522f475Smrg	    int pgrp = getpid();
3886d522f475Smrg#endif
3887d522f475Smrg	    TRACE_CHILD
3888d522f475Smrg
3889d522f475Smrg#ifdef USE_USG_PTYS
38900bd37d32Smrg#ifdef HAVE_SETPGID
38910bd37d32Smrg		setpgid(0, 0);
38920bd37d32Smrg#else
3893d522f475Smrg		setpgrp();
38940bd37d32Smrg#endif
38950bd37d32Smrg	    unlockpt(screen->respond);
38960bd37d32Smrg	    TRACE_TTYSIZE(screen->respond, "after unlockpt");
38970bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
38980bd37d32Smrg		SysError(ERROR_PTSNAME);
38990bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
39000bd37d32Smrg		SysError(ERROR_OPPTSNAME);
39010bd37d32Smrg	    }
3902d522f475Smrg#ifdef I_PUSH
39032e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ptem")) {
39040bd37d32Smrg		SysError(ERROR_PTEM);
39050bd37d32Smrg	    }
3906d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
39070bd37d32Smrg	    else if (!x_getenv("CONSEM")
39082e4f8982Smrg		     && PUSH_FAILS(ptyfd, "consem")) {
39090bd37d32Smrg		SysError(ERROR_CONSEM);
39100bd37d32Smrg	    }
3911d522f475Smrg#endif /* !SVR4 */
39122e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ldterm")) {
39130bd37d32Smrg		SysError(ERROR_LDTERM);
39140bd37d32Smrg	    }
3915d522f475Smrg#ifdef SVR4			/* from Sony */
39162e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ttcompat")) {
39170bd37d32Smrg		SysError(ERROR_TTCOMPAT);
39180bd37d32Smrg	    }
3919d522f475Smrg#endif /* SVR4 */
3920d522f475Smrg#endif /* I_PUSH */
39210bd37d32Smrg	    ttyfd = ptyfd;
3922d522f475Smrg#ifndef __MVS__
39230bd37d32Smrg	    close_fd(screen->respond);
3924d522f475Smrg#endif /* __MVS__ */
3925d522f475Smrg
3926d522f475Smrg#ifdef TTYSIZE_STRUCT
39270bd37d32Smrg	    /* tell tty how big window is */
3928d522f475Smrg#if OPT_TEK4014
39290bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
39300bd37d32Smrg		TTYSIZE_ROWS(ts) = 24;
39310bd37d32Smrg		TTYSIZE_COLS(ts) = 80;
3932d522f475Smrg#ifdef USE_STRUCT_WINSIZE
39330bd37d32Smrg		ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
39340bd37d32Smrg		ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3935d522f475Smrg#endif
39360bd37d32Smrg	    } else
3937d522f475Smrg#endif /* OPT_TEK4014 */
39380bd37d32Smrg	    {
39390bd37d32Smrg		TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
39400bd37d32Smrg		TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3941d522f475Smrg#ifdef USE_STRUCT_WINSIZE
39420bd37d32Smrg		ts.ws_xpixel = (ttySize_t) FullWidth(screen);
39430bd37d32Smrg		ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3944d522f475Smrg#endif
39450bd37d32Smrg	    }
3946d522f475Smrg#endif /* TTYSIZE_STRUCT */
3947d522f475Smrg
3948d522f475Smrg#endif /* USE_USG_PTYS */
3949d522f475Smrg
39500bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
3951d522f475Smrg
3952d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
39530bd37d32Smrg	    if (resource.ptyHandshake) {
39540bd37d32Smrg		char *ptr;
3955d522f475Smrg
39560bd37d32Smrg		/* close parent's sides of the pipes */
39570bd37d32Smrg		close(cp_pipe[0]);
39580bd37d32Smrg		close(pc_pipe[1]);
39590bd37d32Smrg
39600bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
39610bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
39620bd37d32Smrg		 * or err.
39630bd37d32Smrg		 */
39640bd37d32Smrg		if (cp_pipe[1] <= 2) {
39650bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
39660bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
39670bd37d32Smrg			cp_pipe[1] = i;
3968d522f475Smrg		    }
39690bd37d32Smrg		}
39700bd37d32Smrg		if (pc_pipe[0] <= 2) {
39710bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
39720bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
39730bd37d32Smrg			pc_pipe[0] = i;
3974d522f475Smrg		    }
39750bd37d32Smrg		}
3976d522f475Smrg
39770bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
39780bd37d32Smrg		close(ConnectionNumber(screen->display));
3979d522f475Smrg#ifndef __MVS__
3980894e0ac8Smrg		if (screen->respond >= 0)
3981894e0ac8Smrg		    close(screen->respond);
3982d522f475Smrg#endif /* __MVS__ */
3983d522f475Smrg
39840bd37d32Smrg		/* Now is the time to set up our process group and
39850bd37d32Smrg		 * open up the pty slave.
39860bd37d32Smrg		 */
3987d522f475Smrg#ifdef USE_SYSV_PGRP
3988d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
39890bd37d32Smrg		IGNORE_RC(setsid());
3990d522f475Smrg#else
39910bd37d32Smrg		IGNORE_RC(setpgrp());
3992d522f475Smrg#endif
3993d522f475Smrg#endif /* USE_SYSV_PGRP */
3994d522f475Smrg
3995d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
39960bd37d32Smrg		qsetlogin(getlogin(), ttydev);
3997d522f475Smrg#endif
39980bd37d32Smrg		if (ttyfd >= 0) {
3999d522f475Smrg#ifdef __MVS__
40000bd37d32Smrg		    if (ttyGetAttr(ttyfd, &gio) == 0) {
40010bd37d32Smrg			gio.c_cflag &= ~(HUPCL | PARENB);
40020bd37d32Smrg			ttySetAttr(ttyfd, &gio);
40030bd37d32Smrg		    }
4004d522f475Smrg#else /* !__MVS__ */
40050bd37d32Smrg		    close_fd(ttyfd);
4006d522f475Smrg#endif /* __MVS__ */
40070bd37d32Smrg		}
4008d522f475Smrg
40090bd37d32Smrg		for (;;) {
401020d2c4d2Smrg#if USE_NO_DEV_TTY
40110bd37d32Smrg		    if (!no_dev_tty
40120bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
40130bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
40140bd37d32Smrg			close_fd(ttyfd);
40150bd37d32Smrg		    }
401620d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
4017d522f475Smrg#ifdef CSRG_BASED
40180bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
4019d522f475Smrg#endif
40200bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
40210bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after open");
40220bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
40230bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after fixup");
4024d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
40250bd37d32Smrg			/* make /dev/tty work */
40260bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
4027d522f475Smrg#endif
4028d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
40290bd37d32Smrg			/* make /dev/tty work */
40300bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
4031d522f475Smrg#endif
4032d522f475Smrg#ifdef USE_SYSV_PGRP
40330bd37d32Smrg			/* We need to make sure that we are actually
40340bd37d32Smrg			 * the process group leader for the pty.  If
40350bd37d32Smrg			 * we are, then we should now be able to open
40360bd37d32Smrg			 * /dev/tty.
40370bd37d32Smrg			 */
40380bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
40390bd37d32Smrg			    /* success! */
40400bd37d32Smrg			    close(i);
4041d522f475Smrg			    break;
4042d522f475Smrg			}
40430bd37d32Smrg#else /* USE_SYSV_PGRP */
40440bd37d32Smrg			break;
40450bd37d32Smrg#endif /* USE_SYSV_PGRP */
40460bd37d32Smrg		    }
40470bd37d32Smrg		    perror("open ttydev");
4048d522f475Smrg#ifdef TIOCSCTTY
40490bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
4050d522f475Smrg#endif
40510bd37d32Smrg		    /* let our master know that the open failed */
40520bd37d32Smrg		    handshake.status = PTY_BAD;
40530bd37d32Smrg		    handshake.error = errno;
40540bd37d32Smrg		    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
40550bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
40560bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
40570bd37d32Smrg				    (const char *) &handshake,
40580bd37d32Smrg				    sizeof(handshake)));
4059d522f475Smrg
40600bd37d32Smrg		    /* get reply from parent */
40610bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
40620bd37d32Smrg				   sizeof(handshake));
40630bd37d32Smrg		    if (i <= 0) {
40640bd37d32Smrg			/* parent terminated */
40650bd37d32Smrg			exit(1);
4066d522f475Smrg		    }
4067d522f475Smrg
40680bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
40690bd37d32Smrg			/* No more ptys, let's shutdown. */
40700bd37d32Smrg			exit(1);
4071d522f475Smrg		    }
40720bd37d32Smrg
40730bd37d32Smrg		    /* We have a new pty to try */
40740bd37d32Smrg		    if (ttyfd >= 0)
40750bd37d32Smrg			close(ttyfd);
40760bd37d32Smrg		    free(ttydev);
40770bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
4078d522f475Smrg		}
4079d522f475Smrg
40800bd37d32Smrg		/* use the same tty name that everyone else will use
40810bd37d32Smrg		 * (from ttyname)
40820bd37d32Smrg		 */
40830bd37d32Smrg		if ((ptr = ttyname(ttyfd)) != 0) {
40840bd37d32Smrg		    free(ttydev);
40850bd37d32Smrg		    ttydev = x_strdup(ptr);
40860bd37d32Smrg		}
40870bd37d32Smrg	    }
40880bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
4089d522f475Smrg
4090d522f475Smrg	    set_pty_permissions(screen->uid,
4091d522f475Smrg				screen->gid,
4092d522f475Smrg				(resource.messages
4093d522f475Smrg				 ? 0622U
4094d522f475Smrg				 : 0600U));
4095d522f475Smrg
4096d522f475Smrg	    /*
4097d522f475Smrg	     * set up the tty modes
4098d522f475Smrg	     */
4099d522f475Smrg	    {
4100d522f475Smrg#ifdef TERMIO_STRUCT
4101d522f475Smrg#if defined(umips) || defined(CRAY) || defined(linux)
4102d522f475Smrg		/* If the control tty had its modes screwed around with,
4103d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
4104d522f475Smrg		   will have bad values.  Let's just get termio from the
4105d522f475Smrg		   new tty and tailor it.  */
4106d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4107d522f475Smrg		    SysError(ERROR_TIOCGETP);
4108d522f475Smrg		tio.c_lflag |= ECHOE;
4109d522f475Smrg#endif /* umips */
4110d522f475Smrg		/* Now is also the time to change the modes of the
4111d522f475Smrg		 * child pty.
4112d522f475Smrg		 */
4113d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
411420d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
4115d522f475Smrg		tio.c_iflag |= ICRNL;
41160bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
4117d522f475Smrg#if OPT_LUIT_PROG
4118d522f475Smrg		if (command_to_exec_with_luit == 0)
4119d522f475Smrg#endif
4120d522f475Smrg		    if (screen->utf8_mode)
4121d522f475Smrg			tio.c_iflag |= IUTF8;
4122d522f475Smrg#endif
4123d522f475Smrg		/* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */
4124d522f475Smrg#ifndef USE_POSIX_TERMIOS
412520d2c4d2Smrg		UIntClr(tio.c_oflag,
412620d2c4d2Smrg			(OCRNL
412720d2c4d2Smrg			 | ONLRET
412820d2c4d2Smrg			 | NLDLY
412920d2c4d2Smrg			 | CRDLY
413020d2c4d2Smrg			 | TABDLY
413120d2c4d2Smrg			 | BSDLY
413220d2c4d2Smrg			 | VTDLY
413320d2c4d2Smrg			 | FFDLY));
4134d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4135d522f475Smrg#ifdef ONLCR
4136d522f475Smrg		tio.c_oflag |= ONLCR;
4137d522f475Smrg#endif /* ONLCR */
4138d522f475Smrg#ifdef OPOST
4139d522f475Smrg		tio.c_oflag |= OPOST;
4140d522f475Smrg#endif /* OPOST */
4141d522f475Smrg#ifndef USE_POSIX_TERMIOS
4142d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
4143d522f475Smrg#  define CBAUD V_CBAUD
4144d522f475Smrg# endif
414520d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
4146d522f475Smrg#ifdef BAUD_0
4147d522f475Smrg		/* baud rate is 0 (don't care) */
4148d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
41492e4f8982Smrg		tio.c_ispeed = tio.c_ospeed = line_speed;
4150d522f475Smrg#else /* !BAUD_0 */
41512e4f8982Smrg		tio.c_cflag |= line_speed;
4152d522f475Smrg#endif /* !BAUD_0 */
4153d522f475Smrg#else /* USE_POSIX_TERMIOS */
41542e4f8982Smrg		cfsetispeed(&tio, line_speed);
41552e4f8982Smrg		cfsetospeed(&tio, line_speed);
4156d522f475Smrg#ifdef __MVS__
4157d522f475Smrg		/* turn off bits that can't be set from the slave side */
4158d522f475Smrg		tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
4159d522f475Smrg#endif /* __MVS__ */
4160d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
4161d522f475Smrg		   when the xterm ends */
41622e4f8982Smrg		tio.c_cflag &= (unsigned) ~CLOCAL;
4163d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4164d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
4165d522f475Smrg		 * echo
4166d522f475Smrg		 */
4167d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
4168d522f475Smrg#ifdef ECHOKE
4169d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
4170d522f475Smrg#endif
4171d522f475Smrg#ifdef ECHOCTL
4172d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
4173d522f475Smrg#endif
4174d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
4175d522f475Smrg		    if (validTtyChar(tio, nn)) {
4176d522f475Smrg			int sysMode = known_ttyChars[nn].sysMode;
4177d522f475Smrg#ifdef __MVS__
4178d522f475Smrg			if (tio.c_cc[sysMode] != 0) {
4179d522f475Smrg			    switch (sysMode) {
4180d522f475Smrg			    case VEOL:
4181d522f475Smrg			    case VEOF:
4182d522f475Smrg				continue;
4183d522f475Smrg			    }
4184d522f475Smrg			}
4185d522f475Smrg#endif
41860bd37d32Smrg			tio.c_cc[sysMode] = (cc_t) known_ttyChars[nn].myDefault;
4187d522f475Smrg		    }
4188d522f475Smrg		}
4189d522f475Smrg
4190d522f475Smrg		if (override_tty_modes) {
4191d522f475Smrg		    for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
4192d522f475Smrg			if (validTtyChar(tio, nn)) {
4193d522f475Smrg			    TMODE(known_ttyChars[nn].myMode,
4194d522f475Smrg				  tio.c_cc[known_ttyChars[nn].sysMode]);
4195d522f475Smrg			}
4196d522f475Smrg		    }
4197d522f475Smrg#ifdef HAS_LTCHARS
4198d522f475Smrg		    /* both SYSV and BSD have ltchars */
4199d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4200d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4201d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4202d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4203d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4204d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4205d522f475Smrg#endif
4206d522f475Smrg		}
4207d522f475Smrg#ifdef HAS_LTCHARS
4208d522f475Smrg#ifdef __hpux
4209d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
4210d522f475Smrg		 * are not set to _POSIX_VDISABLE */
4211d522f475Smrg		ltc.t_rprntc = ltc.t_rprntc = ltc.t_flushc =
4212d522f475Smrg		    ltc.t_werasc = ltc.t_lnextc = _POSIX_VDISABLE;
4213d522f475Smrg#endif /* __hpux */
4214d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
4215d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4216d522f475Smrg#endif /* HAS_LTCHARS */
4217d522f475Smrg#ifdef TIOCLSET
4218d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4219d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4220d522f475Smrg#endif /* TIOCLSET */
4221d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
4222d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4223d522f475Smrg
4224d522f475Smrg		/* ignore errors here - some platforms don't work */
422520d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
4226d522f475Smrg		if (screen->input_eight_bits)
4227d522f475Smrg		    tio.c_cflag |= CS8;
4228d522f475Smrg		else
4229d522f475Smrg		    tio.c_cflag |= CS7;
4230d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
4231d522f475Smrg
4232d522f475Smrg#else /* !TERMIO_STRUCT */
4233d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
4234d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
4235d522f475Smrg		/* make sure speed is set on pty so that editors work right */
42362e4f8982Smrg		sg.sg_ispeed = line_speed;
42372e4f8982Smrg		sg.sg_ospeed = line_speed;
4238d522f475Smrg		/* reset t_brkc to default value */
4239d522f475Smrg		tc.t_brkc = -1;
4240d522f475Smrg#ifdef LPASS8
4241d522f475Smrg		if (screen->input_eight_bits)
4242d522f475Smrg		    lmode |= LPASS8;
4243d522f475Smrg		else
4244d522f475Smrg		    lmode &= ~(LPASS8);
4245d522f475Smrg#endif
4246d522f475Smrg#ifdef sony
4247d522f475Smrg		jmode &= ~KM_KANJI;
4248d522f475Smrg#endif /* sony */
4249d522f475Smrg
4250d522f475Smrg		ltc = d_ltc;
4251d522f475Smrg
4252d522f475Smrg		if (override_tty_modes) {
4253d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
4254d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
4255d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
4256d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
4257d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
4258d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
4259d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
4260d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
4261d522f475Smrg		    /* both SYSV and BSD have ltchars */
4262d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4263d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4264d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4265d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4266d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4267d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4268d522f475Smrg		}
4269d522f475Smrg
4270d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
4271d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4272d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
4273d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4274d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
4275d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
4276d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
4277d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
4278d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4279d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4280d522f475Smrg#ifdef sony
4281d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
4282d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
4283d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
4284d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
4285d522f475Smrg#endif /* sony */
4286d522f475Smrg#endif /* TERMIO_STRUCT */
4287d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4288d522f475Smrg		if (Console) {
4289d522f475Smrg#ifdef TIOCCONS
4290d522f475Smrg		    int on = 1;
4291d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
42920bd37d32Smrg			xtermPerror("cannot open console");
4293d522f475Smrg#endif
4294d522f475Smrg#ifdef SRIOCSREDIR
4295d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4296d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
42970bd37d32Smrg			xtermPerror("cannot open console");
429820d2c4d2Smrg		    IGNORE_RC(close(fd));
4299d522f475Smrg#endif
4300d522f475Smrg		}
4301d522f475Smrg#endif /* TIOCCONS */
4302d522f475Smrg	    }
4303d522f475Smrg
4304d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4305d522f475Smrg#ifdef USE_SYSV_SIGHUP
4306d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4307d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4308d522f475Smrg#else
4309d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4310d522f475Smrg#endif
4311d522f475Smrg	    /* restore various signals to their defaults */
4312d522f475Smrg	    signal(SIGINT, SIG_DFL);
4313d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4314d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4315d522f475Smrg
4316d522f475Smrg	    /*
4317d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4318d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4319d522f475Smrg	     * the terminal's erase mode from our best guess.
4320d522f475Smrg	     */
4321d522f475Smrg#if OPT_INITIAL_ERASE
4322d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4323d522f475Smrg		   initial_erase,
4324d522f475Smrg		   setInitialErase ? "YES" : "NO",
4325d522f475Smrg		   resource.ptyInitialErase,
4326d522f475Smrg		   override_tty_modes,
4327d522f475Smrg		   ttymodelist[XTTYMODE_erase].set));
4328d522f475Smrg	    if (setInitialErase) {
4329d522f475Smrg#if OPT_TRACE
4330d522f475Smrg		int old_erase;
4331d522f475Smrg#endif
4332d522f475Smrg#ifdef TERMIO_STRUCT
4333d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4334d522f475Smrg		    tio = d_tio;
4335d522f475Smrg#if OPT_TRACE
4336d522f475Smrg		old_erase = tio.c_cc[VERASE];
4337d522f475Smrg#endif
43380bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
433920d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4340d522f475Smrg#else /* !TERMIO_STRUCT */
4341d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4342d522f475Smrg		    sg = d_sg;
4343d522f475Smrg#if OPT_TRACE
4344d522f475Smrg		old_erase = sg.sg_erase;
4345d522f475Smrg#endif
4346d522f475Smrg		sg.sg_erase = initial_erase;
4347d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4348d522f475Smrg#endif /* TERMIO_STRUCT */
4349d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4350d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4351d522f475Smrg	    }
4352d522f475Smrg#endif
4353d522f475Smrg
4354d522f475Smrg	    xtermCopyEnv(environ);
4355d522f475Smrg
43560bd37d32Smrg	    /*
43570bd37d32Smrg	     * standards.freedesktop.org/startup-notification-spec/
43580bd37d32Smrg	     * notes that this variable is used when a "reliable" mechanism is
43590bd37d32Smrg	     * not available; in practice it must be unset to avoid confusing
43600bd37d32Smrg	     * GTK applications.
43610bd37d32Smrg	     */
43620bd37d32Smrg	    xtermUnsetenv("DESKTOP_STARTUP_ID");
4363e0a2b6dfSmrg	    /*
4364e0a2b6dfSmrg	     * We set this temporarily to work around poor design of Xcursor.
4365e0a2b6dfSmrg	     * Unset it here to avoid confusion.
4366e0a2b6dfSmrg	     */
4367e0a2b6dfSmrg	    xtermUnsetenv("XCURSOR_PATH");
43680bd37d32Smrg
4369a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4370a1f3da82Smrg	    if (!resource.term_name)
437120d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4372d522f475Smrg
4373d522f475Smrg	    sprintf(buf, "%lu",
4374d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4375d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4376d522f475Smrg
4377d522f475Smrg	    /* put the display into the environment of the shell */
4378d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4379d522f475Smrg
4380d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4381d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4382d522f475Smrg
4383e39b573cSmrg	    /*
4384e39b573cSmrg	     * For debugging only, add environment variables that can be used
4385e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4386e39b573cSmrg	     * processes.
4387e39b573cSmrg	     */
4388e39b573cSmrg#if OPT_TRACE
4389e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4390e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4391e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4392e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4393e39b573cSmrg#endif
4394e39b573cSmrg
4395d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4396d522f475Smrg
4397d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4398d522f475Smrg	     */
4399d522f475Smrg	    {
4400d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4401d522f475Smrg		close_fd(ttyfd);
4402d522f475Smrg
440320d2c4d2Smrg		IGNORE_RC(close(0));
4404d522f475Smrg
4405d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4406d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4407d522f475Smrg		}
440820d2c4d2Smrg		IGNORE_RC(close(1));
440920d2c4d2Smrg		IGNORE_RC(close(2));
4410d522f475Smrg		dup(0);
4411d522f475Smrg		dup(0);
4412d522f475Smrg#else
4413d522f475Smrg		/* dup the tty */
4414d522f475Smrg		for (i = 0; i <= 2; i++)
4415d522f475Smrg		    if (i != ttyfd) {
441620d2c4d2Smrg			IGNORE_RC(close(i));
441720d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4418d522f475Smrg		    }
4419d522f475Smrg#ifndef ATT
4420d522f475Smrg		/* and close the tty */
4421d522f475Smrg		if (ttyfd > 2)
4422d522f475Smrg		    close_fd(ttyfd);
4423d522f475Smrg#endif
4424d522f475Smrg#endif /* CRAY */
4425d522f475Smrg	    }
4426d522f475Smrg
4427d522f475Smrg#if !defined(USE_SYSV_PGRP)
4428d522f475Smrg#ifdef TIOCSCTTY
4429d522f475Smrg	    setsid();
4430d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4431d522f475Smrg#endif
4432d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4433d522f475Smrg	    setpgrp(0, 0);
4434d522f475Smrg	    close(open(ttydev, O_WRONLY));
4435d522f475Smrg	    setpgrp(0, pgrp);
4436d522f475Smrg#if defined(__QNX__)
4437d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4438d522f475Smrg#endif
4439d522f475Smrg#endif /* !USE_SYSV_PGRP */
4440d522f475Smrg
4441d522f475Smrg#ifdef Lynx
4442d522f475Smrg	    {
4443d522f475Smrg		TERMIO_STRUCT t;
4444d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4445d522f475Smrg		    /* this gets lost somewhere on our way... */
4446d522f475Smrg		    t.c_oflag |= OPOST;
4447d522f475Smrg		    ttySetAttr(0, &t);
4448d522f475Smrg		}
4449d522f475Smrg	    }
4450d522f475Smrg#endif
4451d522f475Smrg
4452d522f475Smrg#ifdef HAVE_UTMP
4453d522f475Smrg	    login_name = NULL;
44540bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
44550bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4456d522f475Smrg	    }
4457d522f475Smrg	    if (login_name != NULL) {
4458d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4459d522f475Smrg	    }
4460d522f475Smrg#ifndef USE_UTEMPTER
4461d522f475Smrg#ifdef USE_UTMP_SETGID
4462d522f475Smrg	    setEffectiveGroup(save_egid);
4463d522f475Smrg	    TRACE_IDS;
4464d522f475Smrg#endif
4465d522f475Smrg#ifdef USE_SYSV_UTMP
4466d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4467d522f475Smrg	     * for the following reasons:
4468d522f475Smrg	     *   - It needs to have our correct process id (for
4469d522f475Smrg	     *     login).
4470d522f475Smrg	     *   - If our parent was to set it after the fork(),
4471d522f475Smrg	     *     it might make it out before we need it.
4472d522f475Smrg	     *   - We need to do it before we go and change our
4473d522f475Smrg	     *     user and group id's.
4474d522f475Smrg	     */
4475d522f475Smrg	    (void) call_setutent();
4476d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4477d522f475Smrg
4478d522f475Smrg	    /* position to entry in utmp file */
4479d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
448020d2c4d2Smrg	    utret = find_utmp(&utmp);
448120d2c4d2Smrg	    if (utret == 0) {
4482d522f475Smrg		(void) call_setutent();
4483d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
448420d2c4d2Smrg		utret = find_utmp(&utmp);
448520d2c4d2Smrg		if (utret == 0) {
4486d522f475Smrg		    (void) call_setutent();
4487d522f475Smrg		}
4488d522f475Smrg	    }
4489d522f475Smrg#if OPT_TRACE
4490d522f475Smrg	    if (!utret)
4491d522f475Smrg		TRACE(("getutid: NULL\n"));
4492d522f475Smrg	    else
44930bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
449420d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
44950bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
44960bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4497d522f475Smrg#endif
4498d522f475Smrg
4499d522f475Smrg	    /* set up the new entry */
4500d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4501d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4502d522f475Smrg	    utmp.ut_xstatus = 2;
4503d522f475Smrg#endif
4504894e0ac8Smrg	    copy_filled(utmp.ut_user,
4505894e0ac8Smrg			(login_name != NULL) ? login_name : "????",
4506894e0ac8Smrg			sizeof(utmp.ut_user));
4507d522f475Smrg	    /* why are we copying this string again?  (see above) */
4508894e0ac8Smrg	    copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4509894e0ac8Smrg	    copy_filled(utmp.ut_line,
4510894e0ac8Smrg			my_pty_name(ttydev), sizeof(utmp.ut_line));
4511d522f475Smrg
4512d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4513d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4514d522f475Smrg#endif
4515d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4516d522f475Smrg	    SetUtmpSysLen(utmp);
4517d522f475Smrg#endif
4518d522f475Smrg
4519894e0ac8Smrg	    copy_filled(utmp.ut_name,
4520894e0ac8Smrg			(login_name) ? login_name : "????",
4521894e0ac8Smrg			sizeof(utmp.ut_name));
4522d522f475Smrg
4523d522f475Smrg	    utmp.ut_pid = getpid();
4524d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4525d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4526d522f475Smrg	    utmp.ut_session = getsid(0);
4527d522f475Smrg#endif
4528d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
4529d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
4530d522f475Smrg#else
4531d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
4532d522f475Smrg#endif
4533d522f475Smrg
4534d522f475Smrg	    /* write out the entry */
4535d522f475Smrg	    if (!resource.utmpInhibit) {
4536d522f475Smrg		errno = 0;
4537d522f475Smrg		call_pututline(&utmp);
45380bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
45390bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
45400bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
4541d522f475Smrg		       (long) utmp.ut_pid,
4542d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
4543d522f475Smrg	    }
4544d522f475Smrg#ifdef WTMP
4545d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
4546d522f475Smrg	    if (xw->misc.login_shell)
4547d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
4548d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4549d522f475Smrg	    if (xw->misc.login_shell)
4550d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
4551d522f475Smrg#else
4552d522f475Smrg	    if (xw->misc.login_shell &&
4553d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
45540bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4555d522f475Smrg		close(i);
4556d522f475Smrg	    }
4557d522f475Smrg#endif
4558d522f475Smrg#endif
4559d522f475Smrg	    /* close the file */
4560d522f475Smrg	    (void) call_endutent();
4561d522f475Smrg
4562d522f475Smrg#else /* USE_SYSV_UTMP */
4563d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
4564d522f475Smrg	     * utmp entry.
4565d522f475Smrg	     */
4566d522f475Smrg	    tslot = ttyslot();
4567d522f475Smrg	    added_utmp_entry = False;
4568d522f475Smrg	    {
45690bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
4570d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
4571956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
4572894e0ac8Smrg		    copy_filled(utmp.ut_line,
4573894e0ac8Smrg				my_pty_name(ttydev),
4574894e0ac8Smrg				sizeof(utmp.ut_line));
4575894e0ac8Smrg		    copy_filled(utmp.ut_name, login_name,
4576894e0ac8Smrg				sizeof(utmp.ut_name));
4577d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4578d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
4579d522f475Smrg#endif
4580d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4581d522f475Smrg		    SetUtmpSysLen(utmp);
4582d522f475Smrg#endif
4583d522f475Smrg
4584d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
4585d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
45860bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4587d522f475Smrg		    close(i);
4588d522f475Smrg		    added_utmp_entry = True;
4589d522f475Smrg#if defined(WTMP)
4590d522f475Smrg		    if (xw->misc.login_shell &&
4591d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4592d522f475Smrg			int status;
4593d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
4594d522f475Smrg			status = close(i);
4595d522f475Smrg		    }
4596d522f475Smrg#elif defined(MNX_LASTLOG)
4597d522f475Smrg		    if (xw->misc.login_shell &&
4598d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
4599d522f475Smrg			lseek(i, (long) (screen->uid *
4600d522f475Smrg					 sizeof(utmp)), 0);
46010bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4602d522f475Smrg			close(i);
4603d522f475Smrg		    }
4604d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
4605d522f475Smrg		} else
4606d522f475Smrg		    tslot = -tslot;
4607d522f475Smrg	    }
4608d522f475Smrg
4609d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
4610d522f475Smrg	     * clean up after us.
4611d522f475Smrg	     */
4612d522f475Smrg#if OPT_PTY_HANDSHAKE
4613d522f475Smrg	    if (resource.ptyHandshake) {
4614d522f475Smrg		handshake.tty_slot = tslot;
4615d522f475Smrg	    }
4616d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4617d522f475Smrg#endif /* USE_SYSV_UTMP */
4618d522f475Smrg
4619d522f475Smrg#ifdef USE_LASTLOGX
4620d522f475Smrg	    if (xw->misc.login_shell) {
4621956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
4622d522f475Smrg		(void) strncpy(lastlogx.ll_line,
4623d522f475Smrg			       my_pty_name(ttydev),
4624d522f475Smrg			       sizeof(lastlogx.ll_line));
4625d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
4626d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
4627d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
4628d522f475Smrg	    }
4629d522f475Smrg#endif
4630d522f475Smrg
4631d522f475Smrg#ifdef USE_LASTLOG
4632d522f475Smrg	    if (xw->misc.login_shell &&
4633d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
4634d522f475Smrg		size_t size = sizeof(struct lastlog);
46350bd37d32Smrg		off_t offset = (off_t) (screen->uid * size);
4636d522f475Smrg
4637956cc18dSsnj		memset(&lastlog, 0, size);
4638d522f475Smrg		(void) strncpy(lastlog.ll_line,
4639d522f475Smrg			       my_pty_name(ttydev),
4640d522f475Smrg			       sizeof(lastlog.ll_line));
4641d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
4642d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
4643d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
46440bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
4645d522f475Smrg		}
4646d522f475Smrg		close(i);
4647d522f475Smrg	    }
4648d522f475Smrg#endif /* USE_LASTLOG */
4649d522f475Smrg
4650d522f475Smrg#if defined(USE_UTMP_SETGID)
4651d522f475Smrg	    disableSetGid();
4652d522f475Smrg	    TRACE_IDS;
4653d522f475Smrg#endif
4654d522f475Smrg
4655d522f475Smrg#if OPT_PTY_HANDSHAKE
4656d522f475Smrg	    /* Let our parent know that we set up our utmp entry
4657d522f475Smrg	     * so that it can clean up after us.
4658d522f475Smrg	     */
4659d522f475Smrg	    if (resource.ptyHandshake) {
4660d522f475Smrg		handshake.status = UTMP_ADDED;
4661d522f475Smrg		handshake.error = 0;
46620bd37d32Smrg		strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4663d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
466420d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
4665d522f475Smrg	    }
4666d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4667d522f475Smrg#endif /* USE_UTEMPTER */
4668d522f475Smrg#endif /* HAVE_UTMP */
4669d522f475Smrg
467020d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
4671d522f475Smrg	    TRACE_IDS;
4672e0a2b6dfSmrg#ifdef HAVE_INITGROUPS
46730bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
46740bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
4675d522f475Smrg		    perror("initgroups failed");
4676d522f475Smrg		    SysError(ERROR_INIGROUPS);
4677d522f475Smrg		}
4678d522f475Smrg	    }
4679d522f475Smrg#endif
4680d522f475Smrg	    if (setuid(screen->uid)) {
4681d522f475Smrg		SysError(ERROR_SETUID);
4682d522f475Smrg	    }
4683d522f475Smrg	    TRACE_IDS;
4684d522f475Smrg#if OPT_PTY_HANDSHAKE
4685d522f475Smrg	    if (resource.ptyHandshake) {
4686d522f475Smrg		/* mark the pipes as close on exec */
46870bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
46880bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
4689d522f475Smrg
4690d522f475Smrg		/* We are at the point where we are going to
4691d522f475Smrg		 * exec our shell (or whatever).  Let our parent
4692d522f475Smrg		 * know we arrived safely.
4693d522f475Smrg		 */
4694d522f475Smrg		handshake.status = PTY_GOOD;
4695d522f475Smrg		handshake.error = 0;
46960bd37d32Smrg		(void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4697d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
469820d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
469920d2c4d2Smrg				(const char *) &handshake,
470020d2c4d2Smrg				sizeof(handshake)));
4701d522f475Smrg
4702d522f475Smrg		if (resource.wait_for_map) {
470320d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
470420d2c4d2Smrg				   sizeof(handshake));
4705d522f475Smrg		    if (i != sizeof(handshake) ||
4706d522f475Smrg			handshake.status != PTY_EXEC) {
4707d522f475Smrg			/* some very bad problem occurred */
4708d522f475Smrg			exit(ERROR_PTY_EXEC);
4709d522f475Smrg		    }
4710d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
4711d522f475Smrg			TRACE(("handshake ttysize: %dx%d\n",
4712d522f475Smrg			       handshake.rows, handshake.cols));
4713d522f475Smrg			set_max_row(screen, handshake.rows);
4714d522f475Smrg			set_max_col(screen, handshake.cols);
4715d522f475Smrg#ifdef TTYSIZE_STRUCT
4716d522f475Smrg			got_handshake_size = True;
471720d2c4d2Smrg			TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
471820d2c4d2Smrg			TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
4719d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
472020d2c4d2Smrg			ts.ws_xpixel = (ttySize_t) FullWidth(screen);
472120d2c4d2Smrg			ts.ws_ypixel = (ttySize_t) FullHeight(screen);
4722d522f475Smrg#endif
4723d522f475Smrg#endif /* TTYSIZE_STRUCT */
4724d522f475Smrg		    }
4725d522f475Smrg		}
4726d522f475Smrg	    }
4727d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4728d522f475Smrg
4729d522f475Smrg#ifdef USE_SYSV_ENVVARS
4730d522f475Smrg	    {
4731d522f475Smrg		char numbuf[12];
4732d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
4733d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
4734d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
4735d522f475Smrg		xtermSetenv("LINES", numbuf);
4736d522f475Smrg	    }
4737d522f475Smrg#ifdef HAVE_UTMP
47380bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
4739d522f475Smrg		if (!x_getenv("HOME"))
47400bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
4741d522f475Smrg		if (!x_getenv("SHELL"))
47420bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
4743d522f475Smrg	    }
4744d522f475Smrg#endif /* HAVE_UTMP */
4745d522f475Smrg#ifdef OWN_TERMINFO_DIR
4746d522f475Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
4747d522f475Smrg#endif
4748d522f475Smrg#else /* USE_SYSV_ENVVARS */
474920d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
475020d2c4d2Smrg		resize_termcap(xw);
475120d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
475220d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
475320d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
475420d2c4d2Smrg		}
475520d2c4d2Smrg		/*
475620d2c4d2Smrg		 * work around broken termcap entries */
475720d2c4d2Smrg		if (resource.useInsertMode) {
475820d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
475920d2c4d2Smrg		    /* don't get duplicates */
476020d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
476120d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
476220d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
476320d2c4d2Smrg		    if (*newtc)
476420d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
476520d2c4d2Smrg		}
476620d2c4d2Smrg		if (*newtc) {
4767d522f475Smrg#if OPT_INITIAL_ERASE
476820d2c4d2Smrg		    unsigned len;
476920d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
477020d2c4d2Smrg		    len = (unsigned) strlen(newtc);
477120d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
477220d2c4d2Smrg			len--;
477320d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
477420d2c4d2Smrg			    TERMCAP_ERASE,
477520d2c4d2Smrg			    CharOf(initial_erase));
477620d2c4d2Smrg#endif
477720d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
477820d2c4d2Smrg		}
4779d522f475Smrg	    }
4780d522f475Smrg#endif /* USE_SYSV_ENVVARS */
4781d522f475Smrg
4782d522f475Smrg#if OPT_PTY_HANDSHAKE
4783d522f475Smrg	    /*
4784d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
4785d522f475Smrg	     *
4786d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
4787d522f475Smrg	     * use that to prevent races.
4788d522f475Smrg	     */
4789d522f475Smrg	    if (resource.ptyHandshake
4790d522f475Smrg		&& resource.ptySttySize
4791d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
4792d522f475Smrg#ifdef TTYSIZE_STRUCT
479320d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
4794d522f475Smrg		TRACE(("ptyHandshake SET_TTYSIZE %dx%d return %d\n",
4795d522f475Smrg		       TTYSIZE_ROWS(ts),
4796d522f475Smrg		       TTYSIZE_COLS(ts), i));
4797d522f475Smrg#endif /* TTYSIZE_STRUCT */
4798d522f475Smrg	    }
4799d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4800d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4801d522f475Smrg
48020bd37d32Smrg	    /*
4803e0a2b6dfSmrg	     * If we have an explicit shell to run, make that set $SHELL.
4804e0a2b6dfSmrg	     * Next, allow an existing setting of $SHELL, for absolute paths.
48050bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
48060bd37d32Smrg	     * password information, if possible.
48070bd37d32Smrg	     *
48080bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
48090bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
48100bd37d32Smrg	     */
4811e0a2b6dfSmrg	    if (validShell(explicit_shname)) {
4812e0a2b6dfSmrg		xtermSetenv("SHELL", explicit_shname);
4813e0a2b6dfSmrg	    } else if (validProgram(shell_path = x_getenv("SHELL"))) {
4814e0a2b6dfSmrg		if (!validShell(shell_path)) {
4815e0a2b6dfSmrg		    xtermUnsetenv("SHELL");
4816d522f475Smrg		}
4817e0a2b6dfSmrg	    } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
4818e0a2b6dfSmrg		       || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
4819e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4820e0a2b6dfSmrg	    } else if (validShell(shell_path)) {
4821e0a2b6dfSmrg		xtermSetenv("SHELL", shell_path);
4822d522f475Smrg	    } else {
4823e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4824d522f475Smrg	    }
4825e0a2b6dfSmrg
4826e0a2b6dfSmrg	    /*
4827e0a2b6dfSmrg	     * Set $XTERM_SHELL, which is not necessarily a valid shell, but
4828e0a2b6dfSmrg	     * is executable.
4829e0a2b6dfSmrg	     */
4830e0a2b6dfSmrg	    if (validProgram(explicit_shname)) {
4831e0a2b6dfSmrg		shell_path = explicit_shname;
4832e0a2b6dfSmrg	    } else if (shell_path == 0) {
4833e0a2b6dfSmrg		/* this could happen if the explicit shname lost a race */
4834e0a2b6dfSmrg		shell_path = resetShell(shell_path);
48350bd37d32Smrg	    }
48360bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
4837d522f475Smrg
48380bd37d32Smrg	    shname = x_basename(shell_path);
48390bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
4840d522f475Smrg
4841d522f475Smrg#if OPT_LUIT_PROG
4842d522f475Smrg	    /*
4843d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
4844d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
4845d522f475Smrg	     * to command that the user gave anyway.
4846d522f475Smrg	     */
48472eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
48480bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
48490bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
48500bd37d32Smrg		free(myShell);
48510bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
4852d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
48530bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
48540bd37d32Smrg		xtermWarning("cannot support your locale.\n");
4855d522f475Smrg	    }
4856d522f475Smrg#endif
4857d522f475Smrg	    if (command_to_exec) {
48580bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
48590bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
48600bd37d32Smrg		free(myShell);
48610bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
4862d522f475Smrg		execvp(*command_to_exec, command_to_exec);
4863d522f475Smrg		if (command_to_exec[1] == 0)
48640bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
48650bd37d32Smrg			   (void *) 0);
48660bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
4867d522f475Smrg	    }
4868d522f475Smrg#ifdef USE_SYSV_SIGHUP
4869d522f475Smrg	    /* fix pts sh hanging around */
4870d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4871d522f475Smrg#endif
4872d522f475Smrg
487301037d57Smrg	    if ((shname_minus = CastMallocN(char, strlen(shname) + 2)) != 0) {
487401037d57Smrg		(void) strcpy(shname_minus, "-");
487501037d57Smrg		(void) strcat(shname_minus, shname);
487601037d57Smrg	    } else {
487701037d57Smrg		static char default_minus[] = "-sh";
487801037d57Smrg		shname_minus = default_minus;
487901037d57Smrg	    }
4880d522f475Smrg#ifndef TERMIO_STRUCT
48810bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
48820bd37d32Smrg		     ? NTTYDISC
48830bd37d32Smrg		     : 0);
4884d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
4885d522f475Smrg#endif /* !TERMIO_STRUCT */
4886d522f475Smrg
4887d522f475Smrg#ifdef USE_LOGIN_DASH_P
48880bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
4889d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
4890d522f475Smrg#endif
48912eaa94a1Schristos
48922eaa94a1Schristos#if OPT_LUIT_PROG
48932eaa94a1Schristos	    if (command_to_exec_with_luit) {
48942eaa94a1Schristos		if (xw->misc.login_shell) {
48950bd37d32Smrg		    char *params[4];
48960bd37d32Smrg		    params[0] = x_strdup("-argv0");
48970bd37d32Smrg		    params[1] = shname_minus;
48980bd37d32Smrg		    params[2] = NULL;
48990bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
49000bd37d32Smrg				 + command_length_with_luit,
49010bd37d32Smrg				 params);
49022eaa94a1Schristos		}
49030bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
49042eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
49052eaa94a1Schristos		/* Exec failed. */
49060bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
49072eaa94a1Schristos	    }
49082eaa94a1Schristos#endif
49090bd37d32Smrg	    execlp(shell_path,
4910d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
4911d522f475Smrg		   (void *) 0);
4912d522f475Smrg
4913d522f475Smrg	    /* Exec failed. */
49140bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
491520d2c4d2Smrg	    IGNORE_RC(sleep(5));
49160bd37d32Smrg	    free(shell_path);
4917d522f475Smrg	    exit(ERROR_EXEC);
4918d522f475Smrg	}
4919d522f475Smrg	/* end if in child after fork */
4920d522f475Smrg#if OPT_PTY_HANDSHAKE
4921d522f475Smrg	if (resource.ptyHandshake) {
4922d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
4923d522f475Smrg	     * child process.
4924d522f475Smrg	     */
4925d522f475Smrg
4926d522f475Smrg	    /* close childs's sides of the pipes */
4927d522f475Smrg	    close(cp_pipe[1]);
4928d522f475Smrg	    close(pc_pipe[0]);
4929d522f475Smrg
4930d522f475Smrg	    for (done = 0; !done;) {
4931d522f475Smrg		if (read(cp_pipe[0],
4932d522f475Smrg			 (char *) &handshake,
4933d522f475Smrg			 sizeof(handshake)) <= 0) {
4934d522f475Smrg		    /* Our child is done talking to us.  If it terminated
4935d522f475Smrg		     * due to an error, we will catch the death of child
4936d522f475Smrg		     * and clean up.
4937d522f475Smrg		     */
4938d522f475Smrg		    break;
4939d522f475Smrg		}
4940d522f475Smrg
4941d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
4942d522f475Smrg		switch (handshake.status) {
4943d522f475Smrg		case PTY_GOOD:
4944d522f475Smrg		    /* Success!  Let's free up resources and
4945d522f475Smrg		     * continue.
4946d522f475Smrg		     */
4947d522f475Smrg		    done = 1;
4948d522f475Smrg		    break;
4949d522f475Smrg
4950d522f475Smrg		case PTY_BAD:
4951d522f475Smrg		    /* The open of the pty failed!  Let's get
4952d522f475Smrg		     * another one.
4953d522f475Smrg		     */
495420d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
4955d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
4956d522f475Smrg			/* no more ptys! */
49570bd37d32Smrg			xtermPerror("child process can find no available ptys");
4958d522f475Smrg			handshake.status = PTY_NOMORE;
4959d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
496020d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
496120d2c4d2Smrg					(const char *) &handshake,
496220d2c4d2Smrg					sizeof(handshake)));
4963d522f475Smrg			exit(ERROR_PTYS);
4964d522f475Smrg		    }
4965d522f475Smrg		    handshake.status = PTY_NEW;
49660bd37d32Smrg		    (void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4967d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
496820d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
496920d2c4d2Smrg				    (const char *) &handshake,
497020d2c4d2Smrg				    sizeof(handshake)));
4971d522f475Smrg		    break;
4972d522f475Smrg
4973d522f475Smrg		case PTY_FATALERROR:
4974d522f475Smrg		    errno = handshake.error;
4975d522f475Smrg		    close(cp_pipe[0]);
4976d522f475Smrg		    close(pc_pipe[1]);
4977d522f475Smrg		    SysError(handshake.fatal_error);
4978d522f475Smrg		    /*NOTREACHED */
4979d522f475Smrg
4980d522f475Smrg		case UTMP_ADDED:
4981d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
4982d522f475Smrg		     * this so that we can reset it later.
4983d522f475Smrg		     */
4984d522f475Smrg		    added_utmp_entry = True;
4985d522f475Smrg#ifndef	USE_SYSV_UTMP
4986d522f475Smrg		    tslot = handshake.tty_slot;
4987d522f475Smrg#endif /* USE_SYSV_UTMP */
4988d522f475Smrg		    free(ttydev);
4989d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
4990d522f475Smrg		    break;
4991d522f475Smrg		case PTY_NEW:
4992d522f475Smrg		case PTY_NOMORE:
4993d522f475Smrg		case UTMP_TTYSLOT:
4994d522f475Smrg		case PTY_EXEC:
4995d522f475Smrg		default:
49960bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
49970bd37d32Smrg				 (int) handshake.status);
4998d522f475Smrg		}
4999d522f475Smrg	    }
5000d522f475Smrg	    /* close our sides of the pipes */
5001d522f475Smrg	    if (!resource.wait_for_map) {
5002d522f475Smrg		close(cp_pipe[0]);
5003d522f475Smrg		close(pc_pipe[1]);
5004d522f475Smrg	    }
5005d522f475Smrg	}
5006d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5007d522f475Smrg    }
5008d522f475Smrg
5009d522f475Smrg    /* end if no slave */
5010d522f475Smrg    /*
5011d522f475Smrg     * still in parent (xterm process)
5012d522f475Smrg     */
5013d522f475Smrg#ifdef USE_SYSV_SIGHUP
5014d522f475Smrg    /* hung sh problem? */
5015d522f475Smrg    signal(SIGHUP, SIG_DFL);
5016d522f475Smrg#else
5017d522f475Smrg    signal(SIGHUP, SIG_IGN);
5018d522f475Smrg#endif
5019d522f475Smrg
5020d522f475Smrg/*
5021d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
5022d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
5023d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
5024d522f475Smrg * don't ignore the signals.  This is annoying.
5025d522f475Smrg */
5026d522f475Smrg
5027d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
5028d522f475Smrg    signal(SIGINT, SIG_IGN);
5029d522f475Smrg
5030d522f475Smrg#ifndef SYSV
5031d522f475Smrg    /* hung shell problem */
5032d522f475Smrg    signal(SIGQUIT, SIG_IGN);
5033d522f475Smrg#endif
5034d522f475Smrg    signal(SIGTERM, SIG_IGN);
5035d522f475Smrg#elif defined(SYSV) || defined(__osf__)
5036d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
5037d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
5038d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
5039d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
5040d522f475Smrg     * tank on everything.
5041d522f475Smrg     */
5042d522f475Smrg    if (getpid() == getpgrp()) {
5043d522f475Smrg	(void) signal(SIGINT, Exit);
5044d522f475Smrg	(void) signal(SIGQUIT, Exit);
5045d522f475Smrg	(void) signal(SIGTERM, Exit);
5046d522f475Smrg    } else {
5047d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
5048d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
5049d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
5050d522f475Smrg    }
5051d522f475Smrg    (void) signal(SIGPIPE, Exit);
5052d522f475Smrg#else /* SYSV */
5053d522f475Smrg    signal(SIGINT, Exit);
5054d522f475Smrg    signal(SIGQUIT, Exit);
5055d522f475Smrg    signal(SIGTERM, Exit);
5056d522f475Smrg    signal(SIGPIPE, Exit);
5057d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
50580bd37d32Smrg#ifdef NO_LEAKS
50590bd37d32Smrg    if (ok_termcap != True)
50600bd37d32Smrg	free(TermName);
50610bd37d32Smrg#endif
5062d522f475Smrg
5063d522f475Smrg    return 0;
5064d522f475Smrg}				/* end spawnXTerm */
5065d522f475Smrg
50660bd37d32Smrgvoid
5067d522f475SmrgExit(int n)
5068d522f475Smrg{
506920d2c4d2Smrg    XtermWidget xw = term;
507020d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
5071d522f475Smrg
5072d522f475Smrg#ifdef USE_UTEMPTER
50730bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
50740bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
50750bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
5076d522f475Smrg	removeFromUtmp();
50770bd37d32Smrg    }
5078d522f475Smrg#elif defined(HAVE_UTMP)
5079d522f475Smrg#ifdef USE_SYSV_UTMP
5080d522f475Smrg    struct UTMP_STR utmp;
5081d522f475Smrg    struct UTMP_STR *utptr;
5082d522f475Smrg
50830bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
5084d522f475Smrg    /* don't do this more than once */
50850bd37d32Smrg    if (xterm_exiting) {
50860bd37d32Smrg	exit(n);
50870bd37d32Smrg    }
5088d522f475Smrg    xterm_exiting = True;
5089d522f475Smrg
5090d522f475Smrg#ifdef PUCC_PTYD
5091d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
5092d522f475Smrg#endif /* PUCC_PTYD */
5093d522f475Smrg
5094d522f475Smrg    /* cleanup the utmp entry we forged earlier */
5095d522f475Smrg    if (!resource.utmpInhibit
5096d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
5097d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
5098d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5099d522f475Smrg	) {
5100d522f475Smrg#if defined(USE_UTMP_SETGID)
5101d522f475Smrg	setEffectiveGroup(save_egid);
5102d522f475Smrg	TRACE_IDS;
5103d522f475Smrg#endif
5104d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
5105d522f475Smrg	(void) call_setutent();
5106d522f475Smrg
5107d522f475Smrg	/*
5108d522f475Smrg	 * We could use getutline() if we didn't support old systems.
5109d522f475Smrg	 */
5110d522f475Smrg	while ((utptr = find_utmp(&utmp)) != 0) {
5111d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
5112d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
5113d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
5114d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
5115d522f475Smrg		utptr->ut_session = getsid(0);
5116d522f475Smrg#endif
5117d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
5118d522f475Smrg		utptr->ut_tv.tv_usec = 0;
5119d522f475Smrg#else
5120d522f475Smrg		*utptr->ut_user = 0;
5121d522f475Smrg		utptr->ut_time = time((time_t *) 0);
5122d522f475Smrg#endif
5123d522f475Smrg		(void) call_pututline(utptr);
5124d522f475Smrg#ifdef WTMP
5125d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
512620d2c4d2Smrg		if (xw->misc.login_shell)
5127d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
5128d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
5129894e0ac8Smrg		copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
513020d2c4d2Smrg		if (xw->misc.login_shell)
5131d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
5132d522f475Smrg#else
5133d522f475Smrg		/* set wtmp entry if wtmp file exists */
513420d2c4d2Smrg		if (xw->misc.login_shell) {
5135d522f475Smrg		    int fd;
5136d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
51370bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
5138d522f475Smrg			close(fd);
5139d522f475Smrg		    }
5140d522f475Smrg		}
5141d522f475Smrg#endif
5142d522f475Smrg#endif
5143d522f475Smrg		break;
5144d522f475Smrg	    }
5145d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
5146d522f475Smrg	}
5147d522f475Smrg	(void) call_endutent();
5148d522f475Smrg#ifdef USE_UTMP_SETGID
5149d522f475Smrg	disableSetGid();
5150d522f475Smrg	TRACE_IDS;
5151d522f475Smrg#endif
5152d522f475Smrg    }
5153d522f475Smrg#else /* not USE_SYSV_UTMP */
5154d522f475Smrg    int wfd;
5155d522f475Smrg    struct utmp utmp;
5156d522f475Smrg
51570bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
5158d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
5159d522f475Smrg	(am_slave < 0 && tslot > 0)) {
5160d522f475Smrg#if defined(USE_UTMP_SETGID)
5161d522f475Smrg	setEffectiveGroup(save_egid);
5162d522f475Smrg	TRACE_IDS;
5163d522f475Smrg#endif
5164d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
5165956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
5166d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
51670bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5168d522f475Smrg	    close(wfd);
5169d522f475Smrg	}
5170d522f475Smrg#ifdef WTMP
517120d2c4d2Smrg	if (xw->misc.login_shell &&
5172d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
5173894e0ac8Smrg	    copy_filled(utmp.ut_line,
5174894e0ac8Smrg			my_pty_name(ttydev),
5175894e0ac8Smrg			sizeof(utmp.ut_line));
5176d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
51770bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5178d522f475Smrg	    close(wfd);
5179d522f475Smrg	}
5180d522f475Smrg#endif /* WTMP */
5181d522f475Smrg#ifdef USE_UTMP_SETGID
5182d522f475Smrg	disableSetGid();
5183d522f475Smrg	TRACE_IDS;
5184d522f475Smrg#endif
5185d522f475Smrg    }
5186d522f475Smrg#endif /* USE_SYSV_UTMP */
5187d522f475Smrg#endif /* HAVE_UTMP */
5188d522f475Smrg
5189e0a2b6dfSmrg    cleanup_colored_cursor();
5190e0a2b6dfSmrg
5191d522f475Smrg    /*
5192d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
5193d522f475Smrg     * in the middle of the data.
5194d522f475Smrg     */
5195d522f475Smrg    ttyFlush(screen->respond);
5196d522f475Smrg
5197e39b573cSmrg#ifdef USE_PTY_SEARCH
5198d522f475Smrg    if (am_slave < 0) {
5199d522f475Smrg	TRACE_IDS;
5200d522f475Smrg	/* restore ownership of tty and pty */
5201d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
5202d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
5203d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
5204d522f475Smrg#endif
5205d522f475Smrg    }
5206e39b573cSmrg#endif
5207d522f475Smrg
5208d522f475Smrg    /*
52090bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
5210d522f475Smrg     * grabbing it, and *then* having us release ownership....
5211d522f475Smrg     */
5212d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
5213d522f475Smrg#ifdef ALLOWLOGGING
5214d522f475Smrg    if (screen->logging)
521520d2c4d2Smrg	CloseLog(xw);
5216d522f475Smrg#endif
5217d522f475Smrg
5218e39b573cSmrg    xtermPrintOnXError(xw, n);
5219e39b573cSmrg
5220d522f475Smrg#ifdef NO_LEAKS
5221d522f475Smrg    if (n == 0) {
52220bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
52230bd37d32Smrg
5224d522f475Smrg	TRACE(("Freeing memory leaks\n"));
5225d522f475Smrg
52260bd37d32Smrg	if (toplevel) {
52270bd37d32Smrg	    XtDestroyWidget(toplevel);
52280bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
52290bd37d32Smrg	}
52300bd37d32Smrg	sortedOpts(0, 0, 0);
52310bd37d32Smrg	noleaks_charproc();
52320bd37d32Smrg	noleaks_ptydata();
5233894e0ac8Smrg#if OPT_GRAPHICS
5234894e0ac8Smrg	noleaks_graphics();
5235894e0ac8Smrg#endif
5236d522f475Smrg#if OPT_WIDE_CHARS
52370bd37d32Smrg	noleaks_CharacterClass();
5238d522f475Smrg#endif
52390bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
52400bd37d32Smrg	XtCloseDisplay(dpy);
52410bd37d32Smrg	XtDestroyApplicationContext(app_con);
52420bd37d32Smrg	xtermCloseSession();
52430bd37d32Smrg	TRACE(("closed display\n"));
52440bd37d32Smrg
524520d2c4d2Smrg	TRACE_CLOSE();
5246d522f475Smrg    }
5247d522f475Smrg#endif
5248d522f475Smrg
5249d522f475Smrg    exit(n);
5250d522f475Smrg}
5251d522f475Smrg
5252d522f475Smrg/* ARGSUSED */
5253d522f475Smrgstatic void
525420d2c4d2Smrgresize_termcap(XtermWidget xw)
5255d522f475Smrg{
525620d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
525720d2c4d2Smrg
5258d522f475Smrg#ifndef USE_SYSV_ENVVARS
5259d522f475Smrg    if (!TEK4014_ACTIVE(xw) && *newtc) {
5260d522f475Smrg	TScreen *screen = TScreenOf(xw);
5261d522f475Smrg	char *ptr1, *ptr2;
5262d522f475Smrg	size_t i;
5263d522f475Smrg	int li_first = 0;
5264d522f475Smrg	char *temp;
5265d522f475Smrg	char oldtc[TERMCAP_SIZE];
5266d522f475Smrg
5267d522f475Smrg	strcpy(oldtc, newtc);
5268d522f475Smrg	TRACE(("resize %s\n", oldtc));
5269d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
5270d522f475Smrg	    strcat(oldtc, "co#80:");
5271d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
5272d522f475Smrg	}
5273d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
5274d522f475Smrg	    strcat(oldtc, "li#24:");
5275d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
5276d522f475Smrg	}
5277d522f475Smrg	if (ptr1 > ptr2) {
5278d522f475Smrg	    li_first++;
5279d522f475Smrg	    temp = ptr1;
5280d522f475Smrg	    ptr1 = ptr2;
5281d522f475Smrg	    ptr2 = temp;
5282d522f475Smrg	}
5283d522f475Smrg	ptr1 += 3;
5284d522f475Smrg	ptr2 += 3;
5285956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
5286d522f475Smrg	temp = newtc + i;
5287d522f475Smrg	sprintf(temp, "%d", (li_first
5288d522f475Smrg			     ? MaxRows(screen)
5289d522f475Smrg			     : MaxCols(screen)));
5290d522f475Smrg	temp += strlen(temp);
52910bd37d32Smrg	if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) {
52920bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
52930bd37d32Smrg	    temp += i;
52940bd37d32Smrg	    sprintf(temp, "%d", (li_first
52950bd37d32Smrg				 ? MaxCols(screen)
52960bd37d32Smrg				 : MaxRows(screen)));
52970bd37d32Smrg	    if ((ptr2 = strchr(ptr2, ':')) != 0) {
52980bd37d32Smrg		strcat(temp, ptr2);
52990bd37d32Smrg	    }
53000bd37d32Smrg	}
5301d522f475Smrg	TRACE(("   ==> %s\n", newtc));
5302d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
5303d522f475Smrg    }
5304d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5305d522f475Smrg}
5306d522f475Smrg
5307d522f475Smrg#endif /* ! VMS */
5308d522f475Smrg
5309d522f475Smrg/*
5310d522f475Smrg * Does a non-blocking wait for a child process.  If the system
5311d522f475Smrg * doesn't support non-blocking wait, do nothing.
5312d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
5313d522f475Smrg */
5314d522f475Smrgint
5315d522f475Smrgnonblocking_wait(void)
5316d522f475Smrg{
5317d522f475Smrg#ifdef USE_POSIX_WAIT
5318d522f475Smrg    pid_t pid;
5319d522f475Smrg
5320d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5321d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5322d522f475Smrg    /* cannot do non-blocking wait */
5323d522f475Smrg    int pid = 0;
5324d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5325d522f475Smrg#if defined(Lynx)
5326d522f475Smrg    int status;
5327d522f475Smrg#else
5328d522f475Smrg    union wait status;
5329d522f475Smrg#endif
5330d522f475Smrg    int pid;
5331d522f475Smrg
5332d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5333d522f475Smrg#endif /* USE_POSIX_WAIT else */
5334d522f475Smrg    return pid;
5335d522f475Smrg}
5336d522f475Smrg
5337d522f475Smrg#ifndef VMS
5338d522f475Smrg
5339d522f475Smrg/* ARGSUSED */
53400bd37d32Smrgstatic void
5341d522f475Smrgreapchild(int n GCC_UNUSED)
5342d522f475Smrg{
5343d522f475Smrg    int olderrno = errno;
5344d522f475Smrg    int pid;
5345d522f475Smrg
53460bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
53470bd37d32Smrg
5348d522f475Smrg    pid = wait(NULL);
5349d522f475Smrg
5350d522f475Smrg#ifdef USE_SYSV_SIGNALS
5351d522f475Smrg    /* cannot re-enable signal before waiting for child
5352d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5353d522f475Smrg     */
5354d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5355d522f475Smrg#endif
5356d522f475Smrg
5357d522f475Smrg    do {
535820d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
53590bd37d32Smrg	    DEBUG_MSG("Exiting\n");
53602e4f8982Smrg	    if (hold_screen)
53612e4f8982Smrg		caught_intr = True;
53622e4f8982Smrg	    else
5363d522f475Smrg		need_cleanup = True;
5364d522f475Smrg	}
5365d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5366d522f475Smrg
5367d522f475Smrg    errno = olderrno;
5368d522f475Smrg}
5369d522f475Smrg#endif /* !VMS */
5370d522f475Smrg
5371d522f475Smrgstatic void
537220d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5373d522f475Smrg{
5374d522f475Smrg    char *base = buf;
5375d522f475Smrg    char *first = base;
5376d522f475Smrg    int count = 0;
5377d522f475Smrg    size_t len = strlen(str);
5378d522f475Smrg
5379d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5380d522f475Smrg
5381d522f475Smrg    while (*buf != 0) {
5382d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5383d522f475Smrg	    while (*buf != 0) {
5384d522f475Smrg		if (*buf == '\\')
5385d522f475Smrg		    buf++;
5386d522f475Smrg		else if (*buf == ':')
5387d522f475Smrg		    break;
5388d522f475Smrg		if (*buf != 0)
5389d522f475Smrg		    buf++;
5390d522f475Smrg	    }
53910bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
53920bd37d32Smrg		;
53930bd37d32Smrg	    }
5394d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5395d522f475Smrg	    return;
5396d522f475Smrg	} else if (*buf == '\\') {
5397d522f475Smrg	    buf++;
5398d522f475Smrg	} else if (*buf == ':') {
5399d522f475Smrg	    first = buf;
5400d522f475Smrg	    count = 0;
5401d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5402d522f475Smrg	    count++;
5403d522f475Smrg	}
5404d522f475Smrg	if (*buf != 0)
5405d522f475Smrg	    buf++;
5406d522f475Smrg    }
5407d522f475Smrg    TRACE(("...cannot remove\n"));
5408d522f475Smrg}
5409d522f475Smrg
5410d522f475Smrg/*
5411d522f475Smrg * parse_tty_modes accepts lines of the following form:
5412d522f475Smrg *
5413d522f475Smrg *         [SETTING] ...
5414d522f475Smrg *
5415d522f475Smrg * where setting consists of the words in the modelist followed by a character
5416d522f475Smrg * or ^char.
5417d522f475Smrg */
5418d522f475Smrgstatic int
5419d522f475Smrgparse_tty_modes(char *s, struct _xttymodes *modelist)
5420d522f475Smrg{
5421d522f475Smrg    struct _xttymodes *mp;
5422d522f475Smrg    int c;
5423d522f475Smrg    int count = 0;
5424d522f475Smrg
5425d522f475Smrg    TRACE(("parse_tty_modes\n"));
5426a1f3da82Smrg    for (;;) {
5427d522f475Smrg	size_t len;
5428d522f475Smrg
5429d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5430d522f475Smrg	    s++;
5431d522f475Smrg	if (!*s)
5432d522f475Smrg	    return count;
5433d522f475Smrg
5434d522f475Smrg	for (len = 0; isalnum(CharOf(s[len])); ++len) ;
5435d522f475Smrg	for (mp = modelist; mp->name; mp++) {
5436d522f475Smrg	    if (len == mp->len
5437d522f475Smrg		&& strncmp(s, mp->name, mp->len) == 0)
5438d522f475Smrg		break;
5439d522f475Smrg	}
5440d522f475Smrg	if (!mp->name)
5441d522f475Smrg	    return -1;
5442d522f475Smrg
5443d522f475Smrg	s += mp->len;
5444d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5445d522f475Smrg	    s++;
5446d522f475Smrg	if (!*s)
5447d522f475Smrg	    return -1;
5448d522f475Smrg
5449d522f475Smrg	if ((c = decode_keyvalue(&s, False)) != -1) {
5450d522f475Smrg	    mp->value = c;
5451d522f475Smrg	    mp->set = 1;
5452d522f475Smrg	    count++;
5453d522f475Smrg	    TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
5454d522f475Smrg	}
5455d522f475Smrg    }
5456d522f475Smrg}
5457d522f475Smrg
5458d522f475Smrg#ifndef VMS			/* don't use pipes on OpenVMS */
5459d522f475Smrgint
5460d522f475SmrgGetBytesAvailable(int fd)
5461d522f475Smrg{
5462d522f475Smrg#if defined(FIONREAD)
5463d522f475Smrg    int arg;
5464d522f475Smrg    ioctl(fd, FIONREAD, (char *) &arg);
5465d522f475Smrg    return (int) arg;
5466d522f475Smrg#elif defined(__CYGWIN__)
5467d522f475Smrg    fd_set set;
546820d2c4d2Smrg    struct timeval select_timeout =
5469d522f475Smrg    {0, 0};
5470d522f475Smrg
5471d522f475Smrg    FD_ZERO(&set);
5472d522f475Smrg    FD_SET(fd, &set);
547320d2c4d2Smrg    if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0)
5474d522f475Smrg	return 1;
5475d522f475Smrg    else
5476d522f475Smrg	return 0;
5477d522f475Smrg#elif defined(FIORDCK)
5478d522f475Smrg    return (ioctl(fd, FIORDCHK, NULL));
5479d522f475Smrg#else /* !FIORDCK */
5480d522f475Smrg    struct pollfd pollfds[1];
5481d522f475Smrg
5482d522f475Smrg    pollfds[0].fd = fd;
5483d522f475Smrg    pollfds[0].events = POLLIN;
5484d522f475Smrg    return poll(pollfds, 1, 0);
5485d522f475Smrg#endif
5486d522f475Smrg}
5487d522f475Smrg#endif /* !VMS */
5488d522f475Smrg
5489d522f475Smrg/* Utility function to try to hide system differences from
5490d522f475Smrg   everybody who used to call killpg() */
5491d522f475Smrg
5492d522f475Smrgint
5493d522f475Smrgkill_process_group(int pid, int sig)
5494d522f475Smrg{
5495d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5496d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5497d522f475Smrg    return kill(-pid, sig);
5498d522f475Smrg#else
5499d522f475Smrg    return killpg(pid, sig);
5500d522f475Smrg#endif
5501d522f475Smrg}
5502d522f475Smrg
5503d522f475Smrg#if OPT_EBCDIC
5504d522f475Smrgint
5505d522f475SmrgA2E(int x)
5506d522f475Smrg{
5507d522f475Smrg    char c;
5508d522f475Smrg    c = x;
5509d522f475Smrg    __atoe_l(&c, 1);
5510d522f475Smrg    return c;
5511d522f475Smrg}
5512d522f475Smrg
5513d522f475Smrgint
5514d522f475SmrgE2A(int x)
5515d522f475Smrg{
5516d522f475Smrg    char c;
5517d522f475Smrg    c = x;
5518d522f475Smrg    __etoa_l(&c, 1);
5519d522f475Smrg    return c;
5520d522f475Smrg}
5521d522f475Smrg#endif
5522d522f475Smrg
5523d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
5524d522f475Smrg#include <sys/types.h>
5525d522f475Smrg#include <sys/proc_msg.h>
5526d522f475Smrg#include <sys/kernel.h>
5527d522f475Smrg#include <string.h>
5528d522f475Smrg#include <errno.h>
5529d522f475Smrg
5530d522f475Smrgstruct _proc_session ps;
5531d522f475Smrgstruct _proc_session_reply rps;
5532d522f475Smrg
5533d522f475Smrgint
5534d522f475Smrgqsetlogin(char *login, char *ttyname)
5535d522f475Smrg{
5536d522f475Smrg    int v = getsid(getpid());
5537d522f475Smrg
5538d522f475Smrg    memset(&ps, 0, sizeof(ps));
5539d522f475Smrg    memset(&rps, 0, sizeof(rps));
5540d522f475Smrg
5541d522f475Smrg    ps.type = _PROC_SESSION;
5542d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
5543d522f475Smrg    ps.sid = v;
5544d522f475Smrg    strcpy(ps.name, login);
5545d522f475Smrg
5546d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5547d522f475Smrg
5548d522f475Smrg    if (rps.status < 0)
5549d522f475Smrg	return (rps.status);
5550d522f475Smrg
5551d522f475Smrg    ps.type = _PROC_SESSION;
5552d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
5553d522f475Smrg    ps.sid = v;
5554d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
5555d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5556d522f475Smrg
5557d522f475Smrg    return (rps.status);
5558d522f475Smrg}
5559d522f475Smrg#endif
556001037d57Smrg
556101037d57Smrg#ifdef __minix
556201037d57Smrgint
556301037d57Smrgsetpgrp(void)
556401037d57Smrg{
556501037d57Smrg    return 0;
556601037d57Smrg}
556701037d57Smrg
556801037d57Smrgvoid
556901037d57Smrg_longjmp(jmp_buf _env, int _val)
557001037d57Smrg{
557101037d57Smrg    longjmp(_env, _val);
557201037d57Smrg}
557301037d57Smrg#endif
5574