main.c revision 04b94745
104b94745Smrg/* $XTermId: main.c,v 1.921 2024/05/22 20:11:43 tom Exp $ */
20bd37d32Smrg
30bd37d32Smrg/*
404b94745Smrg * Copyright 2002-2023,2024 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 *
32f2e35a3aSmrg * Copyright 1987, 1988  X Consortium
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 *
50f2e35a3aSmrg * Except as contained in this notice, the name of the X Consortium shall not be
510bd37d32Smrg * used in advertising or otherwise to promote the sale, use or other dealings
52f2e35a3aSmrg * in this Software without prior written authorization from the X Consortium.
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
9604b94745Smrg/* xterm uses these X Toolkit resource names, which are exported in array */
9704b94745Smrg#undef XtNborderWidth
9804b94745Smrg#undef XtNiconName
9904b94745Smrg#undef XtNgeometry
10004b94745Smrg#undef XtNreverseVideo
10104b94745Smrg#undef XtNtitle
10204b94745Smrg
10304b94745Smrg#define XtNborderWidth		"borderWidth"
10404b94745Smrg#define XtNgeometry		"geometry"
10504b94745Smrg#define XtNiconName		"iconName"
10604b94745Smrg#define XtNreverseVideo		"reverseVideo"
10704b94745Smrg#define XtNtitle		"title"
10804b94745Smrg
109d522f475Smrg#if OPT_TOOLBAR
110d522f475Smrg
111d522f475Smrg#if defined(HAVE_LIB_XAW)
112d522f475Smrg#include <X11/Xaw/Form.h>
113d522f475Smrg#elif defined(HAVE_LIB_XAW3D)
114d522f475Smrg#include <X11/Xaw3d/Form.h>
11501037d57Smrg#elif defined(HAVE_LIB_XAW3DXFT)
11601037d57Smrg#include <X11/Xaw3dxft/Form.h>
117f2e35a3aSmrg#include <X11/Xaw3dxft/Xaw3dXft.h>
118d522f475Smrg#elif defined(HAVE_LIB_NEXTAW)
119d522f475Smrg#include <X11/neXtaw/Form.h>
120d522f475Smrg#elif defined(HAVE_LIB_XAWPLUS)
121d522f475Smrg#include <X11/XawPlus/Form.h>
122d522f475Smrg#endif
123d522f475Smrg
124f2e35a3aSmrg#else
125f2e35a3aSmrg
126f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
127f2e35a3aSmrg#include <X11/Xaw3dxft/Xaw3dXft.h>
128f2e35a3aSmrg#endif
129f2e35a3aSmrg
130d522f475Smrg#endif /* OPT_TOOLBAR */
131d522f475Smrg
132d522f475Smrg#include <pwd.h>
133d522f475Smrg#include <ctype.h>
134d522f475Smrg
135d522f475Smrg#include <data.h>
136d522f475Smrg#include <error.h>
137d522f475Smrg#include <menu.h>
138d522f475Smrg#include <main.h>
139d522f475Smrg#include <xstrings.h>
140d522f475Smrg#include <xtermcap.h>
141d522f475Smrg#include <xterm_io.h>
142d522f475Smrg
143d522f475Smrg#if OPT_WIDE_CHARS
144d522f475Smrg#include <charclass.h>
145d522f475Smrg#endif
146d522f475Smrg
147d522f475Smrg#ifdef __osf__
148d522f475Smrg#define USE_SYSV_SIGNALS
149d522f475Smrg#define WTMP
150d522f475Smrg#include <pty.h>		/* openpty() */
151d522f475Smrg#endif
152d522f475Smrg
153d522f475Smrg#ifdef __sgi
154d522f475Smrg#include <grp.h>		/* initgroups() */
155d522f475Smrg#endif
156d522f475Smrg
157ad37e533Smrgstatic GCC_NORETURN void hungtty(int);
158ad37e533Smrgstatic GCC_NORETURN void Syntax(char *);
159ad37e533Smrgstatic GCC_NORETURN void HsSysError(int);
160d522f475Smrg
16104b94745Smrg#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_VERSION) || ( defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 1) )
162d522f475Smrg#define USE_POSIX_SIGNALS
163d522f475Smrg#endif
164d522f475Smrg
165d522f475Smrg#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
166d522f475Smrg/* older SYSV systems cannot ignore SIGHUP.
167d522f475Smrg   Shell hangs, or you get extra shells, or something like that */
168d522f475Smrg#define USE_SYSV_SIGHUP
169d522f475Smrg#endif
170d522f475Smrg
171d522f475Smrg#if defined(sony) && defined(bsd43) && !defined(KANJI)
172d522f475Smrg#define KANJI
173d522f475Smrg#endif
174d522f475Smrg
17504b94745Smrg#ifdef __linux__
176d522f475Smrg#define USE_SYSV_PGRP
177d522f475Smrg#define USE_SYSV_SIGNALS
178d522f475Smrg#define WTMP
17904b94745Smrg#ifdef HAVE_PTY_H
180d522f475Smrg#include <pty.h>
181d522f475Smrg#endif
182d522f475Smrg#endif
183d522f475Smrg
184d522f475Smrg#ifdef __MVS__
185d522f475Smrg#define USE_SYSV_PGRP
186d522f475Smrg#define USE_SYSV_SIGNALS
187d522f475Smrg#endif
188d522f475Smrg
189d522f475Smrg#ifdef __CYGWIN__
190d522f475Smrg#define WTMP
191d522f475Smrg#endif
192d522f475Smrg
193d522f475Smrg#ifdef __SCO__
194d522f475Smrg#ifndef _SVID3
195d522f475Smrg#define _SVID3
196d522f475Smrg#endif
197d522f475Smrg#endif
198d522f475Smrg
19904b94745Smrg#if defined(__GLIBC__) && !defined(__linux__)
200d522f475Smrg#define USE_SYSV_PGRP
201d522f475Smrg#define WTMP
202d522f475Smrg#endif
203d522f475Smrg
204f2e35a3aSmrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID) || defined(HAVE_INITGROUPS)
205d522f475Smrg#include <grp.h>
206d522f475Smrg#endif
207d522f475Smrg
208d522f475Smrg#ifndef TTY_GROUP_NAME
209d522f475Smrg#define TTY_GROUP_NAME "tty"
210d522f475Smrg#endif
211d522f475Smrg
212d522f475Smrg#include <sys/stat.h>
213d522f475Smrg
214d522f475Smrg#ifdef Lynx
215d522f475Smrg#ifndef BSDLY
216d522f475Smrg#define BSDLY	0
217d522f475Smrg#endif
218d522f475Smrg#ifndef VTDLY
219d522f475Smrg#define VTDLY	0
220d522f475Smrg#endif
221d522f475Smrg#ifndef FFDLY
222d522f475Smrg#define FFDLY	0
223d522f475Smrg#endif
224d522f475Smrg#endif
225d522f475Smrg
226d522f475Smrg#ifdef SYSV			/* { */
227d522f475Smrg
228d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
229d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
230d522f475Smrg#include <poll.h>		/* for POLLIN */
231d522f475Smrg#endif /* USE_USG_PTYS */
232d522f475Smrg
233d522f475Smrg#define USE_SYSV_SIGNALS
234d522f475Smrg#define	USE_SYSV_PGRP
235d522f475Smrg
236d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
237d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
238d522f475Smrg#endif
239d522f475Smrg
240d522f475Smrg/*
241d522f475Smrg * now get system-specific includes
242d522f475Smrg */
243d522f475Smrg#ifdef macII
244d522f475Smrg#include <sys/ttychars.h>
245d522f475Smrg#undef USE_SYSV_ENVVARS
246d522f475Smrg#undef FIOCLEX
247d522f475Smrg#undef FIONCLEX
248d522f475Smrg#define setpgrp2 setpgrp
249d522f475Smrg#include <sgtty.h>
250d522f475Smrg#include <sys/resource.h>
251d522f475Smrg#endif
252d522f475Smrg
253d522f475Smrg#ifdef __hpux
254d522f475Smrg#include <sys/ptyio.h>
255d522f475Smrg#endif /* __hpux */
256d522f475Smrg
257d522f475Smrg#ifdef __osf__
258d522f475Smrg#undef  USE_SYSV_PGRP
259d522f475Smrg#define setpgrp setpgid
260d522f475Smrg#endif
261d522f475Smrg
262d522f475Smrg#ifdef __sgi
263d522f475Smrg#include <sys/sysmacros.h>
264d522f475Smrg#endif /* __sgi */
265d522f475Smrg
266d522f475Smrg#ifdef sun
267d522f475Smrg#include <sys/strredir.h>
268d522f475Smrg#endif
269d522f475Smrg
270e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
271d522f475Smrg
272d522f475Smrg#ifdef __QNX__
273d522f475Smrg
274d522f475Smrg#ifndef __QNXNTO__
275d522f475Smrg#define ttyslot() 1
276d522f475Smrg#else
277d522f475Smrg#define USE_SYSV_PGRP
278d522f475Smrgextern __inline__
279d522f475Smrgint
280d522f475Smrgttyslot(void)
281d522f475Smrg{
282d522f475Smrg    return 1;			/* yuk */
283d522f475Smrg}
284d522f475Smrg#endif
285d522f475Smrg
286d522f475Smrg#else
287d522f475Smrg
288d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
289d522f475Smrg#define setpgrp setpgid
290d522f475Smrg#endif
291d522f475Smrg
29204b94745Smrg#ifndef __linux__
293d522f475Smrg#ifndef VMS
294d522f475Smrg#ifndef USE_POSIX_TERMIOS
295d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
296d522f475Smrg#include <sgtty.h>
297d522f475Smrg#endif
298d522f475Smrg#endif /* USE_POSIX_TERMIOS */
299d522f475Smrg#ifdef Lynx
300d522f475Smrg#include <resource.h>
301d522f475Smrg#else
302d522f475Smrg#include <sys/resource.h>
303d522f475Smrg#endif
304d522f475Smrg#endif /* !VMS */
30504b94745Smrg#endif /* !__linux__ */
306d522f475Smrg
307d522f475Smrg#endif /* __QNX__ */
308d522f475Smrg
309d522f475Smrg#endif /* } !SYSV */
310d522f475Smrg
311d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
312d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
313d522f475Smrg#ifndef NOFILE
314d522f475Smrg#define NOFILE OPEN_MAX
315d522f475Smrg#endif
316d522f475Smrg#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
317d522f475Smrg#include <sys/param.h>		/* for NOFILE */
318d522f475Smrg#endif
319d522f475Smrg
320d522f475Smrg#if defined(BSD) && (BSD >= 199103)
321d522f475Smrg#define WTMP
322d522f475Smrg#endif
323d522f475Smrg
324d522f475Smrg#include <stdio.h>
32504b94745Smrg#include <math.h>
326d522f475Smrg
327d522f475Smrg#ifdef __hpux
328d522f475Smrg#include <sys/utsname.h>
329d522f475Smrg#endif /* __hpux */
330d522f475Smrg
331d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
332d522f475Smrg#define ttyslot() 1
333d522f475Smrg#endif /* apollo */
334d522f475Smrg
335d522f475Smrg#if defined(UTMPX_FOR_UTMP)
336d522f475Smrg#define UTMP_STR utmpx
337d522f475Smrg#else
338d522f475Smrg#define UTMP_STR utmp
339d522f475Smrg#endif
340d522f475Smrg
341d522f475Smrg#if defined(USE_UTEMPTER)
342d522f475Smrg#include <utempter.h>
343f2e35a3aSmrg#if 1
344f2e35a3aSmrg#define UTEMPTER_ADD(pty,hostname,master_fd) utempter_add_record(master_fd, hostname)
345f2e35a3aSmrg#define UTEMPTER_DEL()                       utempter_remove_added_record ()
346f2e35a3aSmrg#else
347f2e35a3aSmrg#define UTEMPTER_ADD(pty,hostname,master_fd) addToUtmp(pty, hostname, master_fd)
348f2e35a3aSmrg#define UTEMPTER_DEL()                       removeFromUtmp()
349f2e35a3aSmrg#endif
350d522f475Smrg#endif
351d522f475Smrg
3522e4f8982Smrg#if defined(I_FIND) && defined(I_PUSH)
3532e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_FIND, name) == 0 \
3542e4f8982Smrg			 && ioctl(fd, I_PUSH, name) < 0
3552e4f8982Smrg#else
3562e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_PUSH, name) < 0
3572e4f8982Smrg#endif
3582e4f8982Smrg
359d522f475Smrg#if defined(UTMPX_FOR_UTMP)
360d522f475Smrg
361d522f475Smrg#include <utmpx.h>
362d522f475Smrg
363d522f475Smrg#define call_endutent  endutxent
364d522f475Smrg#define call_getutid   getutxid
365d522f475Smrg#define call_pututline pututxline
366d522f475Smrg#define call_setutent  setutxent
367d522f475Smrg#define call_updwtmp   updwtmpx
368d522f475Smrg
369d522f475Smrg#elif defined(HAVE_UTMP)
370d522f475Smrg
371d522f475Smrg#include <utmp.h>
372d522f475Smrg
373d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
374d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
375d522f475Smrg#endif
376d522f475Smrg
377d522f475Smrg#define call_endutent  endutent
378d522f475Smrg#define call_getutid   getutid
379d522f475Smrg#define call_pututline pututline
380d522f475Smrg#define call_setutent  setutent
381d522f475Smrg#define call_updwtmp   updwtmp
382d522f475Smrg
383d522f475Smrg#endif
384d522f475Smrg
385d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
386d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
387d522f475Smrg#endif
388d522f475Smrg
389d522f475Smrg#ifndef USE_LASTLOGX
390d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
391d522f475Smrg#define USE_LASTLOGX 1
392d522f475Smrg#endif
393d522f475Smrg#endif
394d522f475Smrg
395d522f475Smrg#ifdef  PUCC_PTYD
396d522f475Smrg#include <local/openpty.h>
397d522f475Smrg#endif /* PUCC_PTYD */
398d522f475Smrg
399d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
400d522f475Smrg#include <util.h>		/* openpty() */
401d522f475Smrg#endif
402d522f475Smrg
403956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
404d522f475Smrg#include <libutil.h>		/* openpty() */
405d522f475Smrg#endif
406d522f475Smrg
407d522f475Smrg#if !defined(UTMP_FILENAME)
408d522f475Smrg#if defined(UTMP_FILE)
409d522f475Smrg#define UTMP_FILENAME UTMP_FILE
410d522f475Smrg#elif defined(_PATH_UTMP)
411d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
412d522f475Smrg#else
413d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
414d522f475Smrg#endif
415d522f475Smrg#endif
416d522f475Smrg
417d522f475Smrg#ifndef LASTLOG_FILENAME
418d522f475Smrg#ifdef _PATH_LASTLOG
419d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
420d522f475Smrg#else
421d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
422d522f475Smrg#endif
423d522f475Smrg#endif
424d522f475Smrg
425d522f475Smrg#if !defined(WTMP_FILENAME)
426d522f475Smrg#if defined(WTMP_FILE)
427d522f475Smrg#define WTMP_FILENAME WTMP_FILE
428d522f475Smrg#elif defined(_PATH_WTMP)
429d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
430d522f475Smrg#elif defined(SYSV)
431d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
432d522f475Smrg#else
433d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
434d522f475Smrg#endif
435d522f475Smrg#endif
436d522f475Smrg
437d522f475Smrg#include <signal.h>
438d522f475Smrg
43904b94745Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_VERSION))
440d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
441d522f475Smrg#endif
442d522f475Smrg
443d522f475Smrg#ifdef SIGTSTP
444d522f475Smrg#include <sys/wait.h>
445d522f475Smrg#endif
446d522f475Smrg
447d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
448d522f475Smrg#undef ECHOKE
449d522f475Smrg#undef ECHOCTL
450d522f475Smrg#endif
451d522f475Smrg
452d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
453d522f475Smrg#include <sys/ttydefaults.h>
454d522f475Smrg#endif
455d522f475Smrg
456d522f475Smrg#ifdef X_NOT_POSIX
457d522f475Smrgextern long lseek();
458d522f475Smrg#if defined(USG) || defined(SVR4)
459d522f475Smrgextern unsigned sleep();
460d522f475Smrg#else
461d522f475Smrgextern void sleep();
462d522f475Smrg#endif
463d522f475Smrgextern char *ttyname();
464d522f475Smrg#endif
465d522f475Smrg
466d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
467d522f475Smrgextern char *ptsname(int);
468d522f475Smrg#endif
469d522f475Smrg
470d522f475Smrg#ifndef VMS
4710bd37d32Smrgstatic void reapchild(int /* n */ );
4722e4f8982Smrgstatic int spawnXTerm(XtermWidget	/* xw */
4732e4f8982Smrg		      ,unsigned /* line_speed */ );
47420d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
475d522f475Smrg#ifdef USE_PTY_SEARCH
47620d2c4d2Smrgstatic int pty_search(int * /* pty */ );
477d522f475Smrg#endif
478d522f475Smrg#endif /* ! VMS */
479d522f475Smrg
480d522f475Smrgstatic int get_pty(int *pty, char *from);
48120d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
482e0a2b6dfSmrgstatic void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
483d522f475Smrg
484d522f475Smrgstatic Bool added_utmp_entry = False;
485d522f475Smrg
486d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
487d522f475Smrgstatic uid_t save_euid;
488d522f475Smrgstatic gid_t save_egid;
489d522f475Smrg#endif
490d522f475Smrg
491d522f475Smrgstatic uid_t save_ruid;
492d522f475Smrgstatic gid_t save_rgid;
493d522f475Smrg
494d522f475Smrg#if defined(USE_UTMP_SETGID)
495d522f475Smrgstatic int really_get_pty(int *pty, char *from);
496d522f475Smrg#endif
497d522f475Smrg
498d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
499d522f475Smrgstatic Bool xterm_exiting = False;
500d522f475Smrg#endif
501d522f475Smrg
502d522f475Smrgstatic char *explicit_shname = NULL;
503d522f475Smrg
504d522f475Smrg/*
505d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
506d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
507d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
508d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
509d522f475Smrg** SEGV.
510d522f475Smrg*/
511d522f475Smrgstatic char **command_to_exec = NULL;
512d522f475Smrg
513d522f475Smrg#if OPT_LUIT_PROG
514d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
5150bd37d32Smrgstatic unsigned command_length_with_luit = 0;
516d522f475Smrg#endif
517d522f475Smrg
518d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
519d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
520d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
521d522f475Smrg * about padding generally store the code in a short, which does not have
522d522f475Smrg * enough bits for the extended values.
523d522f475Smrg */
524d522f475Smrg#ifdef B38400			/* everyone should define this */
525d522f475Smrg#define VAL_LINE_SPEED B38400
526d522f475Smrg#else /* ...but xterm's used this for a long time */
527d522f475Smrg#define VAL_LINE_SPEED B9600
528d522f475Smrg#endif
529d522f475Smrg
530d522f475Smrg/*
531d522f475Smrg * Allow use of system default characters if defined and reasonable.
532d522f475Smrg * These are based on the BSD ttydefaults.h
533d522f475Smrg */
534d522f475Smrg#ifndef CBRK
535d522f475Smrg#define CBRK     0xff		/* was 0 */
536d522f475Smrg#endif
537d522f475Smrg#ifndef CDISCARD
538d522f475Smrg#define CDISCARD CONTROL('O')
539d522f475Smrg#endif
540d522f475Smrg#ifndef CDSUSP
541d522f475Smrg#define CDSUSP   CONTROL('Y')
542d522f475Smrg#endif
543d522f475Smrg#ifndef CEOF
544d522f475Smrg#define CEOF     CONTROL('D')
545d522f475Smrg#endif
546d522f475Smrg#ifndef CEOL
547d522f475Smrg#define CEOL	 0xff		/* was 0 */
548d522f475Smrg#endif
549d522f475Smrg#ifndef CERASE
550d522f475Smrg#define CERASE   0177
551d522f475Smrg#endif
552d522f475Smrg#ifndef CERASE2
553d522f475Smrg#define	CERASE2  CONTROL('H')
554d522f475Smrg#endif
555d522f475Smrg#ifndef CFLUSH
556d522f475Smrg#define CFLUSH   CONTROL('O')
557d522f475Smrg#endif
558d522f475Smrg#ifndef CINTR
559d522f475Smrg#define CINTR    CONTROL('C')
560d522f475Smrg#endif
561d522f475Smrg#ifndef CKILL
562d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
563d522f475Smrg#endif
564d522f475Smrg#ifndef CLNEXT
565d522f475Smrg#define CLNEXT   CONTROL('V')
566d522f475Smrg#endif
567d522f475Smrg#ifndef CNUL
568d522f475Smrg#define CNUL     0
569d522f475Smrg#endif
570d522f475Smrg#ifndef CQUIT
571d522f475Smrg#define CQUIT    CONTROL('\\')
572d522f475Smrg#endif
573d522f475Smrg#ifndef CRPRNT
574d522f475Smrg#define CRPRNT   CONTROL('R')
575d522f475Smrg#endif
576d522f475Smrg#ifndef CREPRINT
577d522f475Smrg#define CREPRINT CRPRNT
578d522f475Smrg#endif
579d522f475Smrg#ifndef CSTART
580d522f475Smrg#define CSTART   CONTROL('Q')
581d522f475Smrg#endif
582d522f475Smrg#ifndef CSTATUS
583d522f475Smrg#define	CSTATUS  CONTROL('T')
584d522f475Smrg#endif
585d522f475Smrg#ifndef CSTOP
586d522f475Smrg#define CSTOP    CONTROL('S')
587d522f475Smrg#endif
588d522f475Smrg#ifndef CSUSP
589d522f475Smrg#define CSUSP    CONTROL('Z')
590d522f475Smrg#endif
591d522f475Smrg#ifndef CSWTCH
592d522f475Smrg#define CSWTCH   0
593d522f475Smrg#endif
594d522f475Smrg#ifndef CWERASE
595d522f475Smrg#define CWERASE  CONTROL('W')
596d522f475Smrg#endif
597d522f475Smrg
598d522f475Smrg#ifndef VMS
599d522f475Smrg#ifdef TERMIO_STRUCT
600d522f475Smrg/* The following structures are initialized in main() in order
601d522f475Smrg** to eliminate any assumptions about the internal order of their
602d522f475Smrg** contents.
603d522f475Smrg*/
604d522f475Smrgstatic TERMIO_STRUCT d_tio;
605d522f475Smrg
606f2e35a3aSmrg#ifndef ONLCR
607f2e35a3aSmrg#define ONLCR 0
608f2e35a3aSmrg#endif
609f2e35a3aSmrg
610f2e35a3aSmrg#ifndef OPOST
611f2e35a3aSmrg#define OPOST 0
612f2e35a3aSmrg#endif
613f2e35a3aSmrg
614f2e35a3aSmrg#define D_TIO_FLAGS (OPOST | ONLCR)
615f2e35a3aSmrg
616d522f475Smrg#ifdef HAS_LTCHARS
617d522f475Smrgstatic struct ltchars d_ltc;
618d522f475Smrg#endif /* HAS_LTCHARS */
619d522f475Smrg
620d522f475Smrg#ifdef TIOCLSET
621d522f475Smrgstatic unsigned int d_lmode;
622d522f475Smrg#endif /* TIOCLSET */
623d522f475Smrg
624d522f475Smrg#else /* !TERMIO_STRUCT */
625f2e35a3aSmrg
626f2e35a3aSmrg#define D_SG_FLAGS (EVENP | ODDP | ECHO | CRMOD)
627f2e35a3aSmrg
628d522f475Smrgstatic struct sgttyb d_sg =
629d522f475Smrg{
630f2e35a3aSmrg    0, 0, 0177, CKILL, (D_SG_FLAGS | XTABS)
631d522f475Smrg};
632d522f475Smrgstatic struct tchars d_tc =
633d522f475Smrg{
634d522f475Smrg    CINTR, CQUIT, CSTART,
635d522f475Smrg    CSTOP, CEOF, CBRK
636d522f475Smrg};
637d522f475Smrgstatic struct ltchars d_ltc =
638d522f475Smrg{
639d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
640d522f475Smrg    CFLUSH, CWERASE, CLNEXT
641d522f475Smrg};
642d522f475Smrgstatic int d_disipline = NTTYDISC;
643d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
644d522f475Smrg#ifdef sony
645d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
646d522f475Smrgstatic struct jtchars d_jtc =
647d522f475Smrg{
648d522f475Smrg    'J', 'B'
649d522f475Smrg};
650d522f475Smrg#endif /* sony */
651d522f475Smrg#endif /* TERMIO_STRUCT */
652d522f475Smrg#endif /* ! VMS */
653d522f475Smrg
654d522f475Smrg/*
655d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
656d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
657d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
658d522f475Smrg */
659d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
660d522f475Smrgstatic Boolean override_tty_modes = False;
661d522f475Smrg/* *INDENT-OFF* */
662f2e35a3aSmrgstatic struct {
66320d2c4d2Smrg    const char *name;
664d522f475Smrg    size_t len;
665d522f475Smrg    int set;
666d522f475Smrg    int value;
667f2e35a3aSmrg} ttyModes[] = {
668d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
669d522f475Smrg#define XTTYMODE_intr	0
670d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
671d522f475Smrg#define XTTYMODE_quit	1
672d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
673d522f475Smrg#define XTTYMODE_erase	2
674d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
675d522f475Smrg#define XTTYMODE_kill	3
676d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
677d522f475Smrg#define XTTYMODE_eof	4
678d522f475Smrg    TTYMODE("eol"),		/* VEOL */
679d522f475Smrg#define XTTYMODE_eol	5
680d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
681d522f475Smrg#define XTTYMODE_swtch	6
682d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
683d522f475Smrg#define XTTYMODE_start	7
684d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
685d522f475Smrg#define XTTYMODE_stop	8
686d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
687d522f475Smrg#define XTTYMODE_brk	9
688d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
689d522f475Smrg#define XTTYMODE_susp	10
690d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
691d522f475Smrg#define XTTYMODE_dsusp	11
692d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
693d522f475Smrg#define XTTYMODE_rprnt	12
694d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
695d522f475Smrg#define XTTYMODE_flush	13
696d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
697d522f475Smrg#define XTTYMODE_weras	14
698d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
699d522f475Smrg#define XTTYMODE_lnext	15
700d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
701d522f475Smrg#define XTTYMODE_status	16
702d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
703d522f475Smrg#define XTTYMODE_erase2	17
704d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
705d522f475Smrg#define XTTYMODE_eol2	18
706f2e35a3aSmrg    TTYMODE("tabs"),		/* TAB0 */
707f2e35a3aSmrg#define XTTYMODE_tabs	19
708f2e35a3aSmrg    TTYMODE("-tabs"),		/* TAB3 */
709f2e35a3aSmrg#define XTTYMODE__tabs	20
710d522f475Smrg};
711d522f475Smrg
712f2e35a3aSmrg#ifndef TAB0
713f2e35a3aSmrg#define TAB0 0
714f2e35a3aSmrg#endif
715f2e35a3aSmrg
716f2e35a3aSmrg#ifndef TAB3
717f2e35a3aSmrg#if defined(OXTABS)
718f2e35a3aSmrg#define TAB3 OXTABS
719f2e35a3aSmrg#elif defined(XTABS)
720f2e35a3aSmrg#define TAB3 XTABS
721f2e35a3aSmrg#endif
722f2e35a3aSmrg#endif
723f2e35a3aSmrg
724f2e35a3aSmrg#ifndef TABDLY
725f2e35a3aSmrg#define TABDLY (TAB0|TAB3)
726f2e35a3aSmrg#endif
727f2e35a3aSmrg
728f2e35a3aSmrg#define isTtyMode(p,q) (ttyChars[p].myMode == q && ttyModes[q].set)
729f2e35a3aSmrg
730f2e35a3aSmrg#define isTabMode(n) \
731f2e35a3aSmrg	(isTtyMode(n, XTTYMODE_tabs) || \
732f2e35a3aSmrg	 isTtyMode(n, XTTYMODE__tabs))
733f2e35a3aSmrg
734f2e35a3aSmrg#define TMODE(ind,var) \
735f2e35a3aSmrg	if (ttyModes[ind].set) \
736f2e35a3aSmrg	    var = (cc_t) ttyModes[ind].value
737f2e35a3aSmrg
738d522f475Smrg#define validTtyChar(data, n) \
739f2e35a3aSmrg	    (ttyChars[n].sysMode >= 0 && \
740f2e35a3aSmrg	     ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
741d522f475Smrg
742d522f475Smrgstatic const struct {
743d522f475Smrg    int sysMode;
744d522f475Smrg    int myMode;
745d522f475Smrg    int myDefault;
746f2e35a3aSmrg} ttyChars[] = {
747d522f475Smrg#ifdef VINTR
748d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
749d522f475Smrg#endif
750d522f475Smrg#ifdef VQUIT
751d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
752d522f475Smrg#endif
753d522f475Smrg#ifdef VERASE
754d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
755d522f475Smrg#endif
756d522f475Smrg#ifdef VKILL
757d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
758d522f475Smrg#endif
759d522f475Smrg#ifdef VEOF
760d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
761d522f475Smrg#endif
762d522f475Smrg#ifdef VEOL
763d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
764d522f475Smrg#endif
765d522f475Smrg#ifdef VSWTCH
766d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
767d522f475Smrg#endif
768d522f475Smrg#ifdef VSTART
769d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
770d522f475Smrg#endif
771d522f475Smrg#ifdef VSTOP
772d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
773d522f475Smrg#endif
774d522f475Smrg#ifdef VSUSP
775d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
776d522f475Smrg#endif
777d522f475Smrg#ifdef VDSUSP
778d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
779d522f475Smrg#endif
780d522f475Smrg#ifdef VREPRINT
781d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
782d522f475Smrg#endif
783d522f475Smrg#ifdef VDISCARD
784d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
785d522f475Smrg#endif
786d522f475Smrg#ifdef VWERASE
787d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
788d522f475Smrg#endif
789d522f475Smrg#ifdef VLNEXT
790d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
791d522f475Smrg#endif
792d522f475Smrg#ifdef VSTATUS
793d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
794d522f475Smrg#endif
795d522f475Smrg#ifdef VERASE2
796d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
797d522f475Smrg#endif
798d522f475Smrg#ifdef VEOL2
799d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
800d522f475Smrg#endif
801f2e35a3aSmrg    { -1,       XTTYMODE_tabs,   TAB0 },
802f2e35a3aSmrg    { -1,       XTTYMODE__tabs,  TAB3 },
803d522f475Smrg};
804d522f475Smrg/* *INDENT-ON* */
805d522f475Smrg
806f2e35a3aSmrgstatic int parse_tty_modes(char *s);
807d522f475Smrg
808d522f475Smrg#ifndef USE_UTEMPTER
809d522f475Smrg#ifdef USE_SYSV_UTMP
810d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
811d522f475Smrgextern struct utmp *getutid();
812d522f475Smrg#endif /* AIXV3 */
813d522f475Smrg
814d522f475Smrg#else /* not USE_SYSV_UTMP */
815d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
816d522f475Smrg#endif /* USE_SYSV_UTMP */
817d522f475Smrg
818d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
819d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
820d522f475Smrg#else
821d522f475Smrg#undef USE_LASTLOG
822d522f475Smrg#endif
823d522f475Smrg
824d522f475Smrg#ifdef WTMP
825d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
826d522f475Smrg#endif
827d522f475Smrg#endif /* !USE_UTEMPTER */
828d522f475Smrg
829d522f475Smrg/*
830d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
831d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
832d522f475Smrg * WTMP and USE_LASTLOG.
833d522f475Smrg */
834d522f475Smrg#ifdef USE_LOGIN_DASH_P
835d522f475Smrg#ifndef LOGIN_FILENAME
836d522f475Smrg#define LOGIN_FILENAME "/bin/login"
837d522f475Smrg#endif
838d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
839d522f475Smrg#endif
840d522f475Smrg
84101037d57Smrgstatic char noPassedPty[2];
84201037d57Smrgstatic char *passedPty = noPassedPty;	/* name if pty if slave */
843d522f475Smrg
844d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
845d522f475Smrgstatic int Console;
846d522f475Smrg#include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
847d522f475Smrg#define MIT_CONSOLE_LEN	12
848d522f475Smrg#define MIT_CONSOLE "MIT_CONSOLE_"
849d522f475Smrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
850d522f475Smrgstatic Atom mit_console;
851d522f475Smrg#endif /* TIOCCONS */
852d522f475Smrg
853d522f475Smrg#ifndef USE_SYSV_UTMP
854d522f475Smrgstatic int tslot;
855d522f475Smrg#endif /* USE_SYSV_UTMP */
856d522f475Smrgstatic sigjmp_buf env;
857d522f475Smrg
858d522f475Smrg#define SetUtmpHost(dst, screen) \
859d522f475Smrg	{ \
860d522f475Smrg	    char host[sizeof(dst) + 1]; \
861f2e35a3aSmrg	    strncpy(host, DisplayString(screen->display), sizeof(host) - 1); \
862f2e35a3aSmrg	    host[sizeof(dst)] = '\0'; \
863d522f475Smrg	    TRACE(("DisplayString(%s)\n", host)); \
864d522f475Smrg	    if (!resource.utmpDisplayId) { \
865d522f475Smrg		char *endptr = strrchr(host, ':'); \
866d522f475Smrg		if (endptr) { \
867d522f475Smrg		    TRACE(("trimming display-id '%s'\n", host)); \
868d522f475Smrg		    *endptr = '\0'; \
869d522f475Smrg		} \
870d522f475Smrg	    } \
871894e0ac8Smrg	    copy_filled(dst, host, sizeof(dst)); \
872d522f475Smrg	}
873d522f475Smrg
874d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
875d522f475Smrg#  define SetUtmpSysLen(utmp) 			   \
876d522f475Smrg	{ \
877d522f475Smrg	    utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
878f2e35a3aSmrg	    utmp.ut_syslen = (short) ((int) strlen(utmp.ut_host) + 1); \
879d522f475Smrg	}
880d522f475Smrg#endif
881d522f475Smrg
882d522f475Smrg/* used by VT (charproc.c) */
883d522f475Smrg
884d522f475Smrgstatic XtResource application_resources[] =
885d522f475Smrg{
88604b94745Smrg    Sres(XtNiconGeometry, XtCIconGeometry, icon_geometry, NULL),
887d522f475Smrg    Sres(XtNtitle, XtCTitle, title, NULL),
8880bd37d32Smrg    Sres(XtNiconHint, XtCIconHint, icon_hint, NULL),
889d522f475Smrg    Sres(XtNiconName, XtCIconName, icon_name, NULL),
89004b94745Smrg    Sres(XtNtermName, XtCTermName, term_name, NULL),
89104b94745Smrg    Sres(XtNttyModes, XtCTtyModes, tty_modes, NULL),
89204b94745Smrg    Sres(XtNvalidShells, XtCValidShells, valid_shells, NULL),
89304b94745Smrg    Bres(XtNhold, XtCHold, hold_screen, False),
89404b94745Smrg    Bres(XtNutmpInhibit, XtCUtmpInhibit, utmpInhibit, False),
89504b94745Smrg    Bres(XtNutmpDisplayId, XtCUtmpDisplayId, utmpDisplayId, True),
89604b94745Smrg    Bres(XtNmessages, XtCMessages, messages, True),
89704b94745Smrg    Ires(XtNminBufSize, XtCMinBufSize, minBufSize, 4096),
89804b94745Smrg    Ires(XtNmaxBufSize, XtCMaxBufSize, maxBufSize, 32768),
89904b94745Smrg    Sres(XtNmenuLocale, XtCMenuLocale, menuLocale, DEF_MENU_LOCALE),
90004b94745Smrg    Sres(XtNomitTranslation, XtCOmitTranslation, omitTranslation, NULL),
90104b94745Smrg    Sres(XtNkeyboardType, XtCKeyboardType, keyboardType, "unknown"),
902ad37e533Smrg#ifdef HAVE_LIB_XCURSOR
90304b94745Smrg    Sres(XtNcursorTheme, XtCCursorTheme, cursorTheme, "none"),
904ad37e533Smrg#endif
905e39b573cSmrg#if OPT_PRINT_ON_EXIT
90604b94745Smrg    Ires(XtNprintModeImmediate, XtCPrintModeImmediate, printModeNow, 0),
90704b94745Smrg    Ires(XtNprintOptsImmediate, XtCPrintOptsImmediate, printOptsNow, 9),
90804b94745Smrg    Sres(XtNprintFileImmediate, XtCPrintFileImmediate, printFileNow, NULL),
90904b94745Smrg    Ires(XtNprintModeOnXError, XtCPrintModeOnXError, printModeOnXError, 0),
91004b94745Smrg    Ires(XtNprintOptsOnXError, XtCPrintOptsOnXError, printOptsOnXError, 9),
91104b94745Smrg    Sres(XtNprintFileOnXError, XtCPrintFileOnXError, printFileOnXError, NULL),
912e39b573cSmrg#endif
913d522f475Smrg#if OPT_SUNPC_KBD
91404b94745Smrg    Bres(XtNsunKeyboard, XtCSunKeyboard, sunKeyboard, False),
915d522f475Smrg#endif
916d522f475Smrg#if OPT_HP_FUNC_KEYS
91704b94745Smrg    Bres(XtNhpFunctionKeys, XtCHpFunctionKeys, hpFunctionKeys, False),
918d522f475Smrg#endif
919d522f475Smrg#if OPT_SCO_FUNC_KEYS
92004b94745Smrg    Bres(XtNscoFunctionKeys, XtCScoFunctionKeys, scoFunctionKeys, False),
921d522f475Smrg#endif
922d522f475Smrg#if OPT_SUN_FUNC_KEYS
92304b94745Smrg    Bres(XtNsunFunctionKeys, XtCSunFunctionKeys, sunFunctionKeys, False),
924d522f475Smrg#endif
925d522f475Smrg#if OPT_TCAP_FKEYS
92604b94745Smrg    Bres(XtNtcapFunctionKeys, XtCTcapFunctionKeys, termcapKeys, False),
927d522f475Smrg#endif
928d522f475Smrg#if OPT_INITIAL_ERASE
92904b94745Smrg    Bres(XtNptyInitialErase, XtCPtyInitialErase, ptyInitialErase, DEF_INITIAL_ERASE),
93004b94745Smrg    Bres(XtNbackarrowKeyIsErase, XtCBackarrowKeyIsErase, backarrow_is_erase, DEF_BACKARO_ERASE),
931d522f475Smrg#endif
93204b94745Smrg    Bres(XtNuseInsertMode, XtCUseInsertMode, useInsertMode, False),
933d522f475Smrg#if OPT_ZICONBEEP
93404b94745Smrg    Ires(XtNzIconBeep, XtCZIconBeep, zIconBeep, 0),
93504b94745Smrg    Sres(XtNzIconTitleFormat, XtCZIconTitleFormat, zIconFormat, "*** %s"),
936d522f475Smrg#endif
937d522f475Smrg#if OPT_PTY_HANDSHAKE
93804b94745Smrg    Bres(XtNwaitForMap, XtCWaitForMap, wait_for_map, False),
93904b94745Smrg    Bres(XtNptyHandshake, XtCPtyHandshake, ptyHandshake, True),
94004b94745Smrg    Bres(XtNptySttySize, XtCPtySttySize, ptySttySize, DEF_PTY_STTY_SIZE),
941d522f475Smrg#endif
942913cc679Smrg#if OPT_REPORT_CCLASS
94304b94745Smrg    Bres(XtNreportCClass, XtCReportCClass, reportCClass, False),
944913cc679Smrg#endif
945e0a2b6dfSmrg#if OPT_REPORT_COLORS
94604b94745Smrg    Bres(XtNreportColors, XtCReportColors, reportColors, False),
947e0a2b6dfSmrg#endif
948e0a2b6dfSmrg#if OPT_REPORT_FONTS
94904b94745Smrg    Bres(XtNreportFonts, XtCReportFonts, reportFonts, False),
950e0a2b6dfSmrg#endif
951f2e35a3aSmrg#if OPT_REPORT_ICONS
95204b94745Smrg    Bres(XtNreportIcons, XtCReportIcons, reportIcons, False),
953f2e35a3aSmrg#endif
954f2e35a3aSmrg#if OPT_XRES_QUERY
95504b94745Smrg    Bres(XtNreportXRes, XtCReportXRes, reportXRes, False),
956f2e35a3aSmrg#endif
957d522f475Smrg#if OPT_SAME_NAME
95804b94745Smrg    Bres(XtNsameName, XtCSameName, sameName, True),
959d522f475Smrg#endif
960d522f475Smrg#if OPT_SESSION_MGT
96104b94745Smrg    Bres(XtNsessionMgt, XtCSessionMgt, sessionMgt, True),
962d522f475Smrg#endif
963d522f475Smrg#if OPT_TOOLBAR
964d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
965d522f475Smrg#endif
966956cc18dSsnj#if OPT_MAXIMIZE
967956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
968a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
969956cc18dSsnj#endif
970f2e35a3aSmrg#if USE_DOUBLE_BUFFER
971f2e35a3aSmrg    Bres(XtNbuffered, XtCBuffered, buffered, DEF_DOUBLE_BUFFER),
972f2e35a3aSmrg    Ires(XtNbufferedFPS, XtCBufferedFPS, buffered_fps, 40),
973f2e35a3aSmrg#endif
974d522f475Smrg};
975d522f475Smrg
97620d2c4d2Smrgstatic String fallback_resources[] =
977d522f475Smrg{
978e39b573cSmrg#if OPT_TOOLBAR
979e39b573cSmrg    "*toolBar: false",
980e39b573cSmrg#endif
981d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
982d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
983d522f475Smrg    "*SimpleMenu*Sme.height: 16",
984d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
985d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
986d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
987d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
988d522f475Smrg#if OPT_TEK4014
989d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
990d522f475Smrg#endif
991d522f475Smrg    NULL
992d522f475Smrg};
993d522f475Smrg
994d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
995d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
996d522f475Smrg/* *INDENT-OFF* */
997f2e35a3aSmrg#define DATA(option,pattern,type,value) { (char *) option, (char *) pattern, type, (XPointer) value }
99804b94745Smrg#define OPTS(option,pattern_type,value) { (char *) option, (char *) pattern_type, (XPointer) value }
99904b94745Smrg#define UP_ARG(name) "."name, XrmoptionSepArg
100004b94745Smrg#define MY_ARG(name) "*"name, XrmoptionSepArg
100104b94745Smrg#define VT_ARG(name) "*vt100."name, XrmoptionSepArg
100204b94745Smrg#define NO_ARG(name) "*"name, XrmoptionNoArg
1003d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
100404b94745SmrgOPTS("-geometry",	VT_ARG(XtNgeometry),			NULL),
100504b94745SmrgOPTS("-132",		NO_ARG(XtNc132),			"on"),
100604b94745SmrgOPTS("+132",		NO_ARG(XtNc132),			"off"),
100704b94745SmrgOPTS("-ah",		NO_ARG(XtNalwaysHighlight),		"on"),
100804b94745SmrgOPTS("+ah",		NO_ARG(XtNalwaysHighlight),		"off"),
100904b94745SmrgOPTS("-aw",		NO_ARG(XtNautoWrap),			"on"),
101004b94745SmrgOPTS("+aw",		NO_ARG(XtNautoWrap),			"off"),
1011d522f475Smrg#ifndef NO_ACTIVE_ICON
101204b94745SmrgOPTS("-ai",		NO_ARG(XtNactiveIcon),			"off"),
101304b94745SmrgOPTS("+ai",		NO_ARG(XtNactiveIcon),			"on"),
1014d522f475Smrg#endif /* NO_ACTIVE_ICON */
101504b94745SmrgOPTS("-b",		MY_ARG(XtNinternalBorder),		NULL),
101604b94745SmrgOPTS("-barc",		NO_ARG(XtNcursorBar),			"on"),
101704b94745SmrgOPTS("+barc",		NO_ARG(XtNcursorBar),			"off"),
101804b94745SmrgOPTS("-bc",		NO_ARG(XtNcursorBlink),			"on"),
101904b94745SmrgOPTS("+bc",		NO_ARG(XtNcursorBlink),			"off"),
102004b94745SmrgOPTS("-bcf",		MY_ARG(XtNcursorOffTime),		NULL),
102104b94745SmrgOPTS("-bcn",		MY_ARG(XtNcursorOnTime),		NULL),
102204b94745SmrgOPTS("-bdc",		NO_ARG(XtNcolorBDMode),			"off"),
102304b94745SmrgOPTS("+bdc",		NO_ARG(XtNcolorBDMode),			"on"),
102404b94745SmrgOPTS("-cb",		NO_ARG(XtNcutToBeginningOfLine),	"off"),
102504b94745SmrgOPTS("+cb",		NO_ARG(XtNcutToBeginningOfLine),	"on"),
102604b94745SmrgOPTS("-cc",		MY_ARG(XtNcharClass),			NULL),
102704b94745SmrgOPTS("-cm",		NO_ARG(XtNcolorMode),			"off"),
102804b94745SmrgOPTS("+cm",		NO_ARG(XtNcolorMode),			"on"),
102904b94745SmrgOPTS("-cn",		NO_ARG(XtNcutNewline),			"off"),
103004b94745SmrgOPTS("+cn",		NO_ARG(XtNcutNewline),			"on"),
103104b94745SmrgOPTS("-cr",		MY_ARG(XtNcursorColor),			NULL),
103204b94745SmrgOPTS("-cu",		NO_ARG(XtNcurses),			"on"),
103304b94745SmrgOPTS("+cu",		NO_ARG(XtNcurses),			"off"),
103404b94745SmrgOPTS("-dc",		NO_ARG(XtNdynamicColors),		"off"),
103504b94745SmrgOPTS("+dc",		NO_ARG(XtNdynamicColors),		"on"),
103604b94745SmrgOPTS("-fb",		MY_ARG(XtNboldFont),			NULL),
103704b94745SmrgOPTS("-fbb",		NO_ARG(XtNfreeBoldBox),			"off"),
103804b94745SmrgOPTS("+fbb",		NO_ARG(XtNfreeBoldBox),			"on"),
103904b94745SmrgOPTS("-fbx",		NO_ARG(XtNforceBoxChars),		"off"),
104004b94745SmrgOPTS("+fbx",		NO_ARG(XtNforceBoxChars),		"on"),
104104b94745SmrgOPTS("-fc",		MY_ARG(XtNinitialFont),			NULL),
1042d522f475Smrg#ifndef NO_ACTIVE_ICON
104304b94745SmrgOPTS("-fi",		MY_ARG(XtNiconFont),			NULL),
1044d522f475Smrg#endif /* NO_ACTIVE_ICON */
1045d522f475Smrg#if OPT_RENDERFONT
104604b94745SmrgOPTS("-fa",		MY_ARG(XtNfaceName),			NULL),
104704b94745SmrgOPTS("-fd",		MY_ARG(XtNfaceNameDoublesize),		NULL),
104804b94745SmrgOPTS("-fs",		MY_ARG(XtNfaceSize),			NULL),
1049d522f475Smrg#endif
105001037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
105104b94745SmrgOPTS("-itc",		NO_ARG(XtNcolorITMode),			"off"),
105204b94745SmrgOPTS("+itc",		NO_ARG(XtNcolorITMode),			"on"),
105301037d57Smrg#endif
1054d522f475Smrg#if OPT_WIDE_CHARS
105504b94745SmrgOPTS("-fw",		MY_ARG(XtNwideFont),			NULL),
105604b94745SmrgOPTS("-fwb",		MY_ARG(XtNwideBoldFont),		NULL),
1057d522f475Smrg#endif
1058d522f475Smrg#if OPT_INPUT_METHOD
105904b94745SmrgOPTS("-fx",		MY_ARG(XtNximFont),			NULL),
1060d522f475Smrg#endif
1061d522f475Smrg#if OPT_HIGHLIGHT_COLOR
106204b94745SmrgOPTS("-hc",		MY_ARG(XtNhighlightColor),		NULL),
106304b94745SmrgOPTS("-hm",		NO_ARG(XtNhighlightColorMode),		"on"),
106404b94745SmrgOPTS("+hm",		NO_ARG(XtNhighlightColorMode),		"off"),
106504b94745SmrgOPTS("-selfg",		MY_ARG(XtNhighlightTextColor),		NULL),
106604b94745SmrgOPTS("-selbg",		MY_ARG(XtNhighlightColor),		NULL),
1067d522f475Smrg#endif
1068d522f475Smrg#if OPT_HP_FUNC_KEYS
106904b94745SmrgOPTS("-hf",		NO_ARG(XtNhpFunctionKeys),		"on"),
107004b94745SmrgOPTS("+hf",		NO_ARG(XtNhpFunctionKeys),		"off"),
1071d522f475Smrg#endif
107204b94745SmrgOPTS("-hold",		NO_ARG(XtNhold),			"on"),
107304b94745SmrgOPTS("+hold",		NO_ARG(XtNhold),			"off"),
1074d522f475Smrg#if OPT_INITIAL_ERASE
107504b94745SmrgOPTS("-ie",		NO_ARG(XtNptyInitialErase),		"on"),
107604b94745SmrgOPTS("+ie",		NO_ARG(XtNptyInitialErase),		"off"),
1077d522f475Smrg#endif
107804b94745SmrgOPTS("-j",		NO_ARG(XtNjumpScroll),			"on"),
107904b94745SmrgOPTS("+j",		NO_ARG(XtNjumpScroll),			"off"),
108004b94745SmrgOPTS("-jf",		NO_ARG(XtNfastScroll),			"on"),
108104b94745SmrgOPTS("+jf",		NO_ARG(XtNfastScroll),			"off"),
1082d522f475Smrg#if OPT_C1_PRINT
108304b94745SmrgOPTS("-k8",		NO_ARG(XtNallowC1Printable),		"on"),
108404b94745SmrgOPTS("+k8",		NO_ARG(XtNallowC1Printable),		"off"),
1085d522f475Smrg#endif
108604b94745SmrgOPTS("-kt",		MY_ARG(XtNkeyboardType),		NULL),
1087d522f475Smrg/* parse logging options anyway for compatibility */
108804b94745SmrgOPTS("-l",		NO_ARG(XtNlogging),			"on"),
108904b94745SmrgOPTS("+l",		NO_ARG(XtNlogging),			"off"),
109004b94745SmrgOPTS("-lf",		MY_ARG(XtNlogFile),			NULL),
109104b94745SmrgOPTS("-ls",		NO_ARG(XtNloginShell),			"on"),
109204b94745SmrgOPTS("+ls",		NO_ARG(XtNloginShell),			"off"),
109304b94745SmrgOPTS("-mb",		NO_ARG(XtNmarginBell),			"on"),
109404b94745SmrgOPTS("+mb",		NO_ARG(XtNmarginBell),			"off"),
109504b94745SmrgOPTS("-mc",		MY_ARG(XtNmultiClickTime),		NULL),
109604b94745SmrgOPTS("-mesg",		NO_ARG(XtNmessages),			"off"),
109704b94745SmrgOPTS("+mesg",		NO_ARG(XtNmessages),			"on"),
109804b94745SmrgOPTS("-ms",		MY_ARG(XtNpointerColor),		NULL),
109904b94745SmrgOPTS("-nb",		MY_ARG(XtNnMarginBell),			NULL),
110004b94745SmrgOPTS("-nul",		NO_ARG(XtNunderLine),			"off"),
110104b94745SmrgOPTS("+nul",		NO_ARG(XtNunderLine),			"on"),
110204b94745SmrgOPTS("-pc",		NO_ARG(XtNboldColors),			"on"),
110304b94745SmrgOPTS("+pc",		NO_ARG(XtNboldColors),			"off"),
110404b94745SmrgOPTS("-pf",		MY_ARG(XtNpointerFont),			NULL),
110504b94745SmrgOPTS("-rw",		NO_ARG(XtNreverseWrap),			"on"),
110604b94745SmrgOPTS("+rw",		NO_ARG(XtNreverseWrap),			"off"),
110704b94745SmrgOPTS("-s",		NO_ARG(XtNmultiScroll),			"on"),
110804b94745SmrgOPTS("+s",		NO_ARG(XtNmultiScroll),			"off"),
110904b94745SmrgOPTS("-sb",		NO_ARG(XtNscrollBar),			"on"),
111004b94745SmrgOPTS("+sb",		NO_ARG(XtNscrollBar),			"off"),
1111913cc679Smrg#if OPT_REPORT_CCLASS
111204b94745SmrgOPTS("-report-charclass", NO_ARG(XtNreportCClass),		"on"),
1113913cc679Smrg#endif
1114e0a2b6dfSmrg#if OPT_REPORT_COLORS
111504b94745SmrgOPTS("-report-colors",	NO_ARG(XtNreportColors),		"on"),
1116f2e35a3aSmrg#endif
1117f2e35a3aSmrg#if OPT_REPORT_ICONS
111804b94745SmrgOPTS("-report-icons",	NO_ARG(XtNreportIcons),			"on"),
1119e0a2b6dfSmrg#endif
1120e0a2b6dfSmrg#if OPT_REPORT_FONTS
112104b94745SmrgOPTS("-report-fonts",	NO_ARG(XtNreportFonts),			"on"),
1122f2e35a3aSmrg#endif
1123f2e35a3aSmrg#if OPT_XRES_QUERY
112404b94745SmrgOPTS("-report-xres",	NO_ARG(XtNreportXRes),			"on"),
1125e0a2b6dfSmrg#endif
1126d522f475Smrg#ifdef SCROLLBAR_RIGHT
112704b94745SmrgOPTS("-leftbar",	NO_ARG(XtNrightScrollBar),		"off"),
112804b94745SmrgOPTS("-rightbar",	NO_ARG(XtNrightScrollBar),		"on"),
112904b94745Smrg#endif
113004b94745SmrgOPTS("-rvc",		NO_ARG(XtNcolorRVMode),			"off"),
113104b94745SmrgOPTS("+rvc",		NO_ARG(XtNcolorRVMode),			"on"),
113204b94745SmrgOPTS("-sf",		NO_ARG(XtNsunFunctionKeys),		"on"),
113304b94745SmrgOPTS("+sf",		NO_ARG(XtNsunFunctionKeys),		"off"),
113404b94745SmrgOPTS("-sh",		MY_ARG(XtNscaleHeight),			NULL),
113504b94745SmrgOPTS("-si",		NO_ARG(XtNscrollTtyOutput),		"off"),
113604b94745SmrgOPTS("+si",		NO_ARG(XtNscrollTtyOutput),		"on"),
113704b94745SmrgOPTS("-sk",		NO_ARG(XtNscrollKey),			"on"),
113804b94745SmrgOPTS("+sk",		NO_ARG(XtNscrollKey),			"off"),
113904b94745SmrgOPTS("-sl",		MY_ARG(XtNsaveLines),			NULL),
1140d522f475Smrg#if OPT_SUNPC_KBD
114104b94745SmrgOPTS("-sp",		NO_ARG(XtNsunKeyboard),			"on"),
114204b94745SmrgOPTS("+sp",		NO_ARG(XtNsunKeyboard),			"off"),
1143d522f475Smrg#endif
1144d522f475Smrg#if OPT_TEK4014
114504b94745SmrgOPTS("-t",		NO_ARG(XtNtekStartup),			"on"),
114604b94745SmrgOPTS("+t",		NO_ARG(XtNtekStartup),			"off"),
1147d522f475Smrg#endif
114804b94745SmrgOPTS("-ti",		MY_ARG(XtNdecTerminalID),		NULL),
114904b94745SmrgOPTS("-tm",		MY_ARG(XtNttyModes),			NULL),
115004b94745SmrgOPTS("-tn",		MY_ARG(XtNtermName),			NULL),
1151d522f475Smrg#if OPT_WIDE_CHARS
115204b94745SmrgOPTS("-u8",		NO_ARG(XtNutf8),			"2"),
115304b94745SmrgOPTS("+u8",		NO_ARG(XtNutf8),			"0"),
1154d522f475Smrg#endif
1155d522f475Smrg#if OPT_LUIT_PROG
115604b94745SmrgOPTS("-lc",		NO_ARG(XtNlocale),			"on"),
115704b94745SmrgOPTS("+lc",		NO_ARG(XtNlocale),			"off"),
115804b94745SmrgOPTS("-lcc",		MY_ARG(XtNlocaleFilter),		NULL),
115904b94745SmrgOPTS("-en",		MY_ARG(XtNlocale),			NULL),
116004b94745Smrg#endif
116104b94745SmrgOPTS("-uc",		NO_ARG(XtNcursorUnderLine),		"on"),
116204b94745SmrgOPTS("+uc",		NO_ARG(XtNcursorUnderLine),		"off"),
116304b94745SmrgOPTS("-ulc",		NO_ARG(XtNcolorULMode),			"off"),
116404b94745SmrgOPTS("+ulc",		NO_ARG(XtNcolorULMode),			"on"),
116504b94745SmrgOPTS("-ulit",		NO_ARG(XtNitalicULMode),		"off"),
116604b94745SmrgOPTS("+ulit",		NO_ARG(XtNitalicULMode),		"on"),
116704b94745SmrgOPTS("-ut",		NO_ARG(XtNutmpInhibit),			"on"),
116804b94745SmrgOPTS("+ut",		NO_ARG(XtNutmpInhibit),			"off"),
116904b94745SmrgOPTS("-im",		NO_ARG(XtNuseInsertMode),		"on"),
117004b94745SmrgOPTS("+im",		NO_ARG(XtNuseInsertMode),		"off"),
117104b94745SmrgOPTS("-vb",		NO_ARG(XtNvisualBell),			"on"),
117204b94745SmrgOPTS("+vb",		NO_ARG(XtNvisualBell),			"off"),
117304b94745SmrgOPTS("-pob",		NO_ARG(XtNpopOnBell),			"on"),
117404b94745SmrgOPTS("+pob",		NO_ARG(XtNpopOnBell),			"off"),
1175d522f475Smrg#if OPT_WIDE_CHARS
117604b94745SmrgOPTS("-wc",		NO_ARG(XtNwideChars),			"on"),
117704b94745SmrgOPTS("+wc",		NO_ARG(XtNwideChars),			"off"),
117804b94745SmrgOPTS("-mk_width",	NO_ARG(XtNmkWidth),			"on"),
117904b94745SmrgOPTS("+mk_width",	NO_ARG(XtNmkWidth),			"off"),
118004b94745SmrgOPTS("-cjk_width",	NO_ARG(XtNcjkWidth),			"on"),
118104b94745SmrgOPTS("+cjk_width",	NO_ARG(XtNcjkWidth),			"off"),
118204b94745Smrg#endif
118304b94745SmrgOPTS("-wf",		NO_ARG(XtNwaitForMap),			"on"),
118404b94745SmrgOPTS("+wf",		NO_ARG(XtNwaitForMap),			"off"),
1185d522f475Smrg#if OPT_ZICONBEEP
118604b94745SmrgOPTS("-ziconbeep",	MY_ARG(XtNzIconBeep),			NULL),
1187d522f475Smrg#endif
1188d522f475Smrg#if OPT_SAME_NAME
118904b94745SmrgOPTS("-samename",	NO_ARG(XtNsameName),			"on"),
119004b94745SmrgOPTS("+samename",	NO_ARG(XtNsameName),			"off"),
1191d522f475Smrg#endif
1192d522f475Smrg#if OPT_SESSION_MGT
119304b94745SmrgOPTS("-sm",		NO_ARG(XtNsessionMgt),			"on"),
119404b94745SmrgOPTS("+sm",		NO_ARG(XtNsessionMgt),			"off"),
1195d522f475Smrg#endif
1196d522f475Smrg#if OPT_TOOLBAR
119704b94745SmrgOPTS("-tb",		NO_ARG(XtNtoolBar),			"on"),
119804b94745SmrgOPTS("+tb",		NO_ARG(XtNtoolBar),			"off"),
1199d522f475Smrg#endif
1200956cc18dSsnj#if OPT_MAXIMIZE
120104b94745SmrgOPTS("-maximized",	NO_ARG(XtNmaximized),			"on"),
120204b94745SmrgOPTS("+maximized",	NO_ARG(XtNmaximized),			"off"),
120304b94745SmrgOPTS("-fullscreen",	NO_ARG(XtNfullscreen),			"on"),
120404b94745SmrgOPTS("+fullscreen",	NO_ARG(XtNfullscreen),			"off"),
1205956cc18dSsnj#endif
1206d522f475Smrg/* options that we process ourselves */
1207f2e35a3aSmrgDATA("-help",		NULL,		XrmoptionSkipNArgs,	NULL),
1208f2e35a3aSmrgDATA("-version",	NULL,		XrmoptionSkipNArgs,	NULL),
1209f2e35a3aSmrgDATA("-baudrate",	NULL,		XrmoptionSkipArg,	NULL),
1210f2e35a3aSmrgDATA("-class",		NULL,		XrmoptionSkipArg,	NULL),
1211f2e35a3aSmrgDATA("-e",		NULL,		XrmoptionSkipLine,	NULL),
1212f2e35a3aSmrgDATA("-into",		NULL,		XrmoptionSkipArg,	NULL),
1213d522f475Smrg/* bogus old compatibility stuff for which there are
1214d522f475Smrg   standard XtOpenApplication options now */
1215f2e35a3aSmrgDATA("%",		"*tekGeometry",	XrmoptionStickyArg,	NULL),
121604b94745SmrgDATA("#",		".iconGeometry", XrmoptionStickyArg,	NULL),
121704b94745SmrgOPTS("-T",		UP_ARG(XtNtitle),			NULL),
121804b94745SmrgOPTS("-n",		MY_ARG(XtNiconName),			NULL),
121904b94745SmrgOPTS("-r",		NO_ARG(XtNreverseVideo),		"on"),
122004b94745SmrgOPTS("+r",		NO_ARG(XtNreverseVideo),		"off"),
122104b94745SmrgOPTS("-rv",		NO_ARG(XtNreverseVideo),		"on"),
122204b94745SmrgOPTS("+rv",		NO_ARG(XtNreverseVideo),		"off"),
122304b94745SmrgOPTS("-w",		UP_ARG(XtNborderWidth),			NULL),
1224f2e35a3aSmrg#undef DATA
1225d522f475Smrg};
1226d522f475Smrg
1227d522f475Smrgstatic OptionHelp xtermOptions[] = {
1228d522f475Smrg{ "-version",              "print the version number" },
1229d522f475Smrg{ "-help",                 "print out this message" },
1230d522f475Smrg{ "-display displayname",  "X server to contact" },
1231d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1232d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1233d522f475Smrg{ "-bg color",             "background color" },
1234d522f475Smrg{ "-fg color",             "foreground color" },
1235d522f475Smrg{ "-bd color",             "border color" },
1236d522f475Smrg{ "-bw number",            "border width in pixels" },
1237d522f475Smrg{ "-fn fontname",          "normal text font" },
1238d522f475Smrg{ "-fb fontname",          "bold text font" },
1239f2e35a3aSmrg{ "-fc fontmenu",          "start with named fontmenu choice" },
1240d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1241d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1242d522f475Smrg#if OPT_RENDERFONT
1243d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1244d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1245d522f475Smrg{ "-fs size",              "FreeType font-size" },
1246d522f475Smrg#endif
1247d522f475Smrg#if OPT_WIDE_CHARS
1248d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1249d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1250d522f475Smrg#endif
1251d522f475Smrg#if OPT_INPUT_METHOD
1252d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1253d522f475Smrg#endif
1254d522f475Smrg{ "-iconic",               "start iconic" },
1255d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
12562e4f8982Smrg{ "-baudrate rate",        "set line-speed (default 38400)" },
1257d522f475Smrg{ "-class string",         "class string (XTerm)" },
1258d522f475Smrg{ "-title string",         "title string" },
1259d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1260d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1261d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1262d522f475Smrg#ifndef NO_ACTIVE_ICON
1263d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1264d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1265d522f475Smrg#endif /* NO_ACTIVE_ICON */
1266d522f475Smrg{ "-b number",             "internal border in pixels" },
1267d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1268d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1269d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1270d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1271d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1272d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1273d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1274d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1275f2e35a3aSmrg{ "-pf fontname",          "cursor font for text area pointer" },
1276d522f475Smrg{ "-cr color",             "text cursor color" },
1277d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1278d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1279d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1280d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1281d522f475Smrg{ "-selbg color",          "selection background color" },
1282d522f475Smrg{ "-selfg color",          "selection foreground color" },
12830bd37d32Smrg/* -hc is deprecated, not shown in help message */
1284d522f475Smrg#endif
1285d522f475Smrg#if OPT_HP_FUNC_KEYS
1286d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1287d522f475Smrg#endif
1288d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1289d522f475Smrg#if OPT_INITIAL_ERASE
1290d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1291d522f475Smrg#endif
1292d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1293d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1294d522f475Smrg#if OPT_C1_PRINT
1295d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1296d522f475Smrg#endif
1297d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1298d522f475Smrg#ifdef ALLOWLOGGING
1299d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1300f2e35a3aSmrg{ "-lf filename",          "logging filename (use '-' for standard out)" },
1301d522f475Smrg#else
1302d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1303d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1304d522f475Smrg#endif
1305d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1306d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1307d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1308d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1309d522f475Smrg{ "-ms color",             "pointer color" },
1310d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
1311d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1312d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1313d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1314d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1315d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1316d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1317913cc679Smrg#if OPT_REPORT_CCLASS
1318913cc679Smrg{"-report-charclass",      "report \"charClass\" after initialization"},
1319913cc679Smrg#endif
1320e0a2b6dfSmrg#if OPT_REPORT_COLORS
1321e0a2b6dfSmrg{ "-report-colors",        "report colors as they are allocated" },
1322e0a2b6dfSmrg#endif
1323e0a2b6dfSmrg#if OPT_REPORT_FONTS
1324e0a2b6dfSmrg{ "-report-fonts",         "report fonts as loaded to stdout" },
1325e0a2b6dfSmrg#endif
1326f2e35a3aSmrg#if OPT_REPORT_ICONS
132704b94745Smrg{ "-report-icons",         "report title/icon updates" },
1328f2e35a3aSmrg#endif
1329f2e35a3aSmrg#if OPT_XRES_QUERY
1330f2e35a3aSmrg{ "-report-xres",          "report X resources for VT100 widget" },
1331f2e35a3aSmrg#endif
1332d522f475Smrg#ifdef SCROLLBAR_RIGHT
1333d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1334d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1335d522f475Smrg#endif
1336d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1337d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1338894e0ac8Smrg{ "-sh number",            "scale line-height values by the given number" },
1339d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1340d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1341d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1342d522f475Smrg#if OPT_SUNPC_KBD
1343d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1344d522f475Smrg#endif
1345d522f475Smrg#if OPT_TEK4014
1346d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1347d522f475Smrg#endif
1348d522f475Smrg#if OPT_TOOLBAR
1349d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1350d522f475Smrg#endif
1351d522f475Smrg{ "-ti termid",            "terminal identifier" },
1352d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1353d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1354d522f475Smrg#if OPT_WIDE_CHARS
1355d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1356d522f475Smrg#endif
1357d522f475Smrg#if OPT_LUIT_PROG
1358d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1359d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
13600bd37d32Smrg/* -en is deprecated, not shown in help message */
1361d522f475Smrg#endif
13622eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1363d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1364d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1365d522f475Smrg#ifdef HAVE_UTMP
1366d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1367d522f475Smrg#else
1368d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1369d522f475Smrg#endif
1370d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1371d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
137201037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
137301037d57Smrg{ "-/+itc",                "turn off/on display of italic as color"},
137401037d57Smrg#endif
1375d522f475Smrg#if OPT_WIDE_CHARS
1376d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1377d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1378d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1379d522f475Smrg#endif
1380d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1381d522f475Smrg{ "-e command args ...",   "command to execute" },
1382d522f475Smrg#if OPT_TEK4014
1383d522f475Smrg{ "%geom",                 "Tek window geometry" },
1384d522f475Smrg#endif
1385d522f475Smrg{ "#geom",                 "icon window geometry" },
1386d522f475Smrg{ "-T string",             "title name for window" },
1387d522f475Smrg{ "-n string",             "icon name for window" },
1388d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1389d522f475Smrg{ "-C",                    "intercept console messages" },
1390d522f475Smrg#else
1391d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1392d522f475Smrg#endif
1393d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1394d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1395d522f475Smrg#if OPT_ZICONBEEP
1396d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1397d522f475Smrg#endif
1398d522f475Smrg#if OPT_SAME_NAME
1399d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1400d522f475Smrg#endif
1401d522f475Smrg#if OPT_SESSION_MGT
1402d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1403d522f475Smrg#endif
1404956cc18dSsnj#if OPT_MAXIMIZE
1405ad37e533Smrg{"-/+maximized",           "turn on/off maximize on startup" },
1406a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1407956cc18dSsnj#endif
1408d522f475Smrg{ NULL, NULL }};
1409d522f475Smrg/* *INDENT-ON* */
1410d522f475Smrg
141104b94745Smrgstatic const char *const help_message[] =
1412d522f475Smrg{
1413d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1414d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1415d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1416d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1417d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
141804b94745Smrg    NULL
141904b94745Smrg};
142004b94745Smrg
142104b94745Smrgint
142204b94745SmrgxtermDisabledChar(void)
142304b94745Smrg{
142404b94745Smrg    int value = -1;
142504b94745Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
142604b94745Smrg    value = _POSIX_VDISABLE;
142704b94745Smrg#endif
142804b94745Smrg#if defined(_PC_VDISABLE)
142904b94745Smrg    if (value == -1) {
143004b94745Smrg	value = (int) fpathconf(0, _PC_VDISABLE);
143104b94745Smrg	if (value == -1) {
143204b94745Smrg	    if (errno == 0)
143304b94745Smrg		value = 0377;
143404b94745Smrg	}
143504b94745Smrg    }
143604b94745Smrg#elif defined(VDISABLE)
143704b94745Smrg    if (value == -1)
143804b94745Smrg	value = VDISABLE;
143904b94745Smrg#endif
144004b94745Smrg    return value;
144104b94745Smrg}
144204b94745Smrg
144304b94745Smrg/*
144404b94745Smrg * Retrieve (possibly allocating) an atom from the server.  Cache the result.
144504b94745Smrg */
144604b94745SmrgAtom
144704b94745SmrgCachedInternAtom(Display *display, const char *name)
144804b94745Smrg{
144904b94745Smrg    /*
145004b94745Smrg     * Aside from a couple of rarely used atoms, the others are all known.
145104b94745Smrg     */
145204b94745Smrg    static const char *const known_atoms[] =
145304b94745Smrg    {
145404b94745Smrg	"FONT",
145504b94745Smrg	"WM_CLASS",
145604b94745Smrg	"WM_DELETE_WINDOW",
145704b94745Smrg	"_NET_ACTIVE_WINDOW",
145804b94745Smrg	"_NET_FRAME_EXTENTS",
145904b94745Smrg	"_NET_FRAME_EXTENTS",
146004b94745Smrg	"_NET_SUPPORTED",
146104b94745Smrg	"_NET_SUPPORTING_WM_CHECK",
146204b94745Smrg	"_NET_WM_ALLOWED_ACTIONS",
146304b94745Smrg	"_NET_WM_ICON_NAME",
146404b94745Smrg	"_NET_WM_NAME",
146504b94745Smrg	"_NET_WM_PID",
146604b94745Smrg	"_NET_WM_STATE",
146704b94745Smrg	"_NET_WM_STATE_ADD",
146804b94745Smrg	"_NET_WM_STATE_FULLSCREEN",
146904b94745Smrg	"_NET_WM_STATE_HIDDEN",
147004b94745Smrg	"_NET_WM_STATE_MAXIMIZED_HORZ",
147104b94745Smrg	"_NET_WM_STATE_MAXIMIZED_VERT",
147204b94745Smrg	"_NET_WM_STATE_REMOVE",
147304b94745Smrg	"_WIN_SUPPORTING_WM_CHECK",
147404b94745Smrg#if defined(HAVE_XKB_BELL_EXT)
147504b94745Smrg	XkbBN_Info,
147604b94745Smrg	XkbBN_MarginBell,
147704b94745Smrg	XkbBN_MinorError,
147804b94745Smrg	XkbBN_TerminalBell,
147904b94745Smrg#endif
148004b94745Smrg#if defined(HAVE_XKBQUERYEXTENSION)
148104b94745Smrg	"Num Lock",
148204b94745Smrg	"Caps Lock",
148304b94745Smrg	"Scroll Lock",
148404b94745Smrg#endif
148504b94745Smrg    };
148604b94745Smrg
148704b94745Smrg#define NumKnownAtoms  XtNumber(known_atoms)
148804b94745Smrg
148904b94745Smrg    /*
149004b94745Smrg     * The "+1" entry of the array is used for the occasional atom which is not
149104b94745Smrg     * predefined.
149204b94745Smrg     */
149304b94745Smrg    static struct {
149404b94745Smrg	Atom atom;
149504b94745Smrg	const char *name;
149604b94745Smrg    } AtomCache[NumKnownAtoms + 1];
149704b94745Smrg
149804b94745Smrg    Boolean found = False;
149904b94745Smrg    Atom result = None;
150004b94745Smrg    Cardinal i;
150104b94745Smrg
150204b94745Smrg    TRACE(("intern_atom \"%s\"\n", name));
150304b94745Smrg
150404b94745Smrg    /*
150504b94745Smrg     * This should never happen as it implies xterm is aware of multiple
150604b94745Smrg     * displays.
150704b94745Smrg     */
150804b94745Smrg    if (display != XtDisplay(toplevel)) {
150904b94745Smrg	SysError(ERROR_GET_ATOM);
151004b94745Smrg    }
151104b94745Smrg
151204b94745Smrg    if (AtomCache[0].name == NULL) {
151304b94745Smrg	/* pre-load a number of atoms in one request to reduce latency */
151404b94745Smrg	Atom atom_return[NumKnownAtoms];
151504b94745Smrg	int code;
151604b94745Smrg
151704b94745Smrg	TRACE(("initialising atom list\n"));
151804b94745Smrg	code = XInternAtoms(display,
151904b94745Smrg			    (char **) known_atoms,
152004b94745Smrg			    (int) NumKnownAtoms,
152104b94745Smrg			    False,
152204b94745Smrg			    atom_return);
152304b94745Smrg	/*
152404b94745Smrg	 * result should be Success, but actually returns BadRequest.
152504b94745Smrg	 * manpage says XInternAtoms can generate BadAlloc and BadValue errors.
152604b94745Smrg	 */
152704b94745Smrg	if (code > BadRequest)
152804b94745Smrg	    SysError(ERROR_GET_ATOM);
152904b94745Smrg
153004b94745Smrg	for (i = 0; i < NumKnownAtoms; ++i) {
153104b94745Smrg	    AtomCache[i].name = known_atoms[i];
153204b94745Smrg	    AtomCache[i].atom = atom_return[i];
153304b94745Smrg	}
153404b94745Smrg    }
153504b94745Smrg
153604b94745Smrg    /* Linear search is probably OK here, due to the small number of atoms */
153704b94745Smrg    for (i = 0; i < NumKnownAtoms; i++) {
153804b94745Smrg	if (strcmp(name, AtomCache[i].name) == 0) {
153904b94745Smrg	    found = True;
154004b94745Smrg	    result = AtomCache[i].atom;
154104b94745Smrg	    break;
154204b94745Smrg	}
154304b94745Smrg    }
154404b94745Smrg
154504b94745Smrg    if (!found) {
154604b94745Smrg	if (AtomCache[NumKnownAtoms].name == NULL
154704b94745Smrg	    || strcmp(AtomCache[NumKnownAtoms].name, name)) {
154804b94745Smrg	    char *actual = x_strdup(name);
154904b94745Smrg	    free((void *) AtomCache[NumKnownAtoms].name);
155004b94745Smrg	    result = XInternAtom(display, actual, False);
155104b94745Smrg	    AtomCache[NumKnownAtoms].atom = result;
155204b94745Smrg	    AtomCache[NumKnownAtoms].name = actual;
155304b94745Smrg	    TRACE(("...allocated new atom\n"));
155404b94745Smrg	} else {
155504b94745Smrg	    result = AtomCache[NumKnownAtoms].atom;
155604b94745Smrg	    TRACE(("...reused cached atom\n"));
155704b94745Smrg	}
155804b94745Smrg    }
155904b94745Smrg    TRACE(("...intern_atom -> %ld\n", result));
156004b94745Smrg    return result;
156104b94745Smrg}
1562d522f475Smrg
1563d522f475Smrg/*
1564d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1565d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1566d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1567d522f475Smrg */
1568d522f475Smrgstatic int
1569d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1570d522f475Smrg{
1571d522f475Smrg    char *string = *ptr;
1572d522f475Smrg    int value = -1;
1573d522f475Smrg
157420d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1575d522f475Smrg    if (*string == '^') {
1576d522f475Smrg	switch (*++string) {
1577d522f475Smrg	case '?':
1578d522f475Smrg	    value = A2E(ANSI_DEL);
1579d522f475Smrg	    break;
1580d522f475Smrg	case '-':
1581d522f475Smrg	    if (!termcap) {
158204b94745Smrg		value = xtermDisabledChar();
1583d522f475Smrg		break;
1584d522f475Smrg	    }
1585d522f475Smrg	    /* FALLTHRU */
1586d522f475Smrg	default:
1587d522f475Smrg	    value = CONTROL(*string);
1588d522f475Smrg	    break;
1589d522f475Smrg	}
1590d522f475Smrg	++string;
1591d522f475Smrg    } else if (termcap && (*string == '\\')) {
15922e4f8982Smrg	char *s = (string + 1);
1593d522f475Smrg	char *d;
15942e4f8982Smrg	int temp = (int) strtol(s, &d, 8);
15952e4f8982Smrg	if (PartS2L(s, d) && temp > 0) {
1596d522f475Smrg	    value = temp;
1597d522f475Smrg	    string = d;
1598d522f475Smrg	}
1599d522f475Smrg    } else {
1600d522f475Smrg	value = CharOf(*string);
1601d522f475Smrg	++string;
1602d522f475Smrg    }
1603d522f475Smrg    *ptr = string;
160420d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1605d522f475Smrg    return value;
1606d522f475Smrg}
1607d522f475Smrg
1608d522f475Smrgstatic int
16090bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
16100bd37d32Smrg{
16110bd37d32Smrg    int result = -1;
16120bd37d32Smrg    int n;
16130bd37d32Smrg    int ch;
16140bd37d32Smrg
16150bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
16160bd37d32Smrg	if (param[n] == ch) {
16170bd37d32Smrg	    result = n;
16180bd37d32Smrg	} else {
16190bd37d32Smrg	    if (param[n] != '\0')
16200bd37d32Smrg		result = -1;
16210bd37d32Smrg	    break;
16220bd37d32Smrg	}
16230bd37d32Smrg    }
16240bd37d32Smrg
16250bd37d32Smrg    return result;
16260bd37d32Smrg}
16270bd37d32Smrg
16280bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
16290bd37d32Smrgstatic int
16300bd37d32SmrgcountArg(XrmOptionDescRec * item)
1631d522f475Smrg{
16320bd37d32Smrg    int result = 0;
16330bd37d32Smrg
16340bd37d32Smrg    switch (item->argKind) {
16350bd37d32Smrg    case XrmoptionNoArg:
16360bd37d32Smrg	/* FALLTHRU */
16370bd37d32Smrg    case XrmoptionIsArg:
16380bd37d32Smrg	/* FALLTHRU */
16390bd37d32Smrg    case XrmoptionStickyArg:
16400bd37d32Smrg	break;
16410bd37d32Smrg    case XrmoptionSepArg:
16420bd37d32Smrg	/* FALLTHRU */
16430bd37d32Smrg    case XrmoptionResArg:
16440bd37d32Smrg	/* FALLTHRU */
16450bd37d32Smrg    case XrmoptionSkipArg:
16460bd37d32Smrg	result = 1;
16470bd37d32Smrg	break;
16480bd37d32Smrg    case XrmoptionSkipLine:
16490bd37d32Smrg	break;
16500bd37d32Smrg    case XrmoptionSkipNArgs:
16510bd37d32Smrg	result = (int) (long) (item->value);
16520bd37d32Smrg	break;
16530bd37d32Smrg    }
16540bd37d32Smrg    return result;
16550bd37d32Smrg}
16560bd37d32Smrg
16570bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
16580bd37d32Smrg
16590bd37d32Smrg/*
16600bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
16610bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
16620bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
16630bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
16640bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
16650bd37d32Smrg * standard table (something that the X libraries should do).
16660bd37d32Smrg */
16670bd37d32Smrgstatic XrmOptionDescRec *
16680bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
16690bd37d32Smrg{
16700bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
16710bd37d32Smrg    /* *INDENT-OFF* */
16725307cd1aSmrg#define DATA(option,kind) { (char *) option, NULL, kind, (XPointer) 0 }
16730bd37d32Smrg    static XrmOptionDescRec opTable[] = {
16740bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
16750bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
16760bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
16770bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
16780bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
16790bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
16800bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
16810bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
16820bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
16830bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
16840bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
16850bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
16860bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
16870bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
16880bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
16890bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
16900bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
16910bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
16920bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
16930bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
16940bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
16950bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
16960bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
16970bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
16980bd37d32Smrg#endif /* TIOCCONS */
16990bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
17000bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
17010bd37d32Smrg    };
17020bd37d32Smrg#undef DATA
17030bd37d32Smrg    /* *INDENT-ON* */
17040bd37d32Smrg    XrmOptionDescRec *result = 0;
17050bd37d32Smrg    Cardinal inlist;
17060bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
17070bd37d32Smrg    int atbest = -1;
17080bd37d32Smrg    int best = -1;
17090bd37d32Smrg    int test;
17100bd37d32Smrg    Boolean exact = False;
17110bd37d32Smrg    int ambiguous1 = -1;
17120bd37d32Smrg    int ambiguous2 = -1;
17130bd37d32Smrg    char *option;
17140bd37d32Smrg    char *value;
17150bd37d32Smrg
17160bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
17170bd37d32Smrg		 ? &optionDescList[n] \
17180bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
17190bd37d32Smrg
17200bd37d32Smrg    if ((option = argv[*num]) != 0) {
17210bd37d32Smrg	Boolean need_value;
17220bd37d32Smrg	Boolean have_value = False;
17230bd37d32Smrg
17240bd37d32Smrg	TRACE(("parseArg %s\n", option));
17250bd37d32Smrg	if ((value = argv[(*num) + 1]) != 0) {
1726e0a2b6dfSmrg	    have_value = (Boolean) !isOption(value);
17270bd37d32Smrg	}
17280bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
17290bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
17300bd37d32Smrg
17310bd37d32Smrg	    test = matchArg(check, option);
17320bd37d32Smrg	    if (test < 0)
17330bd37d32Smrg		continue;
17340bd37d32Smrg
17350bd37d32Smrg	    /* check for exact match */
17360bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
17370bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
17380bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
17390bd37d32Smrg			exact = True;
17400bd37d32Smrg			atbest = (int) inlist;
17410bd37d32Smrg			break;
17420bd37d32Smrg		    }
17430bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
17440bd37d32Smrg		    exact = True;
17450bd37d32Smrg		    atbest = (int) inlist;
17460bd37d32Smrg		    break;
17470bd37d32Smrg		}
17480bd37d32Smrg	    }
17490bd37d32Smrg
17500bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
17510bd37d32Smrg
17520bd37d32Smrg	    if (need_value && value != 0) {
17530bd37d32Smrg		;
17540bd37d32Smrg	    } else if (need_value ^ have_value) {
17550bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
17560bd37d32Smrg		continue;
17570bd37d32Smrg	    }
17580bd37d32Smrg
17590bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
17600bd37d32Smrg	    if (test > 0
17610bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
17620bd37d32Smrg		atbest = (int) inlist;
1763e0a2b6dfSmrg		if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
1764e0a2b6dfSmrg		    /* in particular, silence a warning about ambiguity */
1765e0a2b6dfSmrg		    exact = 1;
1766e0a2b6dfSmrg		}
17670bd37d32Smrg		break;
17680bd37d32Smrg	    }
17690bd37d32Smrg	    if (test > best) {
17700bd37d32Smrg		best = test;
17710bd37d32Smrg		atbest = (int) inlist;
17720bd37d32Smrg	    } else if (test == best) {
17730bd37d32Smrg		if (atbest >= 0) {
17740bd37d32Smrg		    if (atbest > 0) {
17750bd37d32Smrg			ambiguous1 = (int) inlist;
17760bd37d32Smrg			ambiguous2 = (int) atbest;
17770bd37d32Smrg		    }
17780bd37d32Smrg		    atbest = -1;
17790bd37d32Smrg		}
17800bd37d32Smrg	    }
17810bd37d32Smrg	}
17820bd37d32Smrg    }
17830bd37d32Smrg
17840bd37d32Smrg    *valuep = 0;
17850bd37d32Smrg    if (atbest >= 0) {
17860bd37d32Smrg	result = ITEM(atbest);
17870bd37d32Smrg	if (!exact) {
17880bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
17890bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
17900bd37d32Smrg			     ITEM(ambiguous1)->option,
17910bd37d32Smrg			     ITEM(ambiguous2)->option);
17920bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
17930bd37d32Smrg		result = 0;
17940bd37d32Smrg	    }
17950bd37d32Smrg	}
17960bd37d32Smrg	if (result != 0) {
17970bd37d32Smrg	    TRACE(("...result %s\n", result->option));
17980bd37d32Smrg	    /* expand abbreviations */
17990bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
18000bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
18010bd37d32Smrg		    argv[*num] = x_strdup(result->option);
18020bd37d32Smrg		}
18030bd37d32Smrg	    }
18040bd37d32Smrg
18050bd37d32Smrg	    /* adjust (*num) to skip option value */
18060bd37d32Smrg	    (*num) += countArg(result);
18070bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
18080bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
18090bd37d32Smrg		*valuep = argv[*num];
18100bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
18110bd37d32Smrg	    }
18120bd37d32Smrg	}
18130bd37d32Smrg    }
18140bd37d32Smrg#undef ITEM
18150bd37d32Smrg    return result;
1816d522f475Smrg}
1817d522f475Smrg
1818d522f475Smrgstatic void
1819d522f475SmrgSyntax(char *badOption)
1820d522f475Smrg{
1821d522f475Smrg    OptionHelp *opt;
1822d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1823d522f475Smrg    int col;
1824d522f475Smrg
18250bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
18260bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1827d522f475Smrg
1828d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1829956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1830d522f475Smrg    for (opt = list; opt->opt; opt++) {
1831956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1832d522f475Smrg	if (col + len > 79) {
1833d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1834d522f475Smrg	    col = 3;
1835d522f475Smrg	}
1836d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1837d522f475Smrg	col += len;
1838d522f475Smrg    }
1839d522f475Smrg
1840d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1841d522f475Smrg	    ProgramName);
184204b94745Smrg    exit(ERROR_MISC);
1843d522f475Smrg}
1844d522f475Smrg
1845d522f475Smrgstatic void
1846d522f475SmrgVersion(void)
1847d522f475Smrg{
1848d522f475Smrg    printf("%s\n", xtermVersion());
1849d522f475Smrg    fflush(stdout);
1850d522f475Smrg}
1851d522f475Smrg
1852d522f475Smrgstatic void
1853d522f475SmrgHelp(void)
1854d522f475Smrg{
1855d522f475Smrg    OptionHelp *opt;
1856d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
185701037d57Smrg    const char *const *cpp;
1858d522f475Smrg
1859d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1860d522f475Smrg	   xtermVersion(), ProgramName);
1861d522f475Smrg    printf("where options include:\n");
1862d522f475Smrg    for (opt = list; opt->opt; opt++) {
1863d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1864d522f475Smrg    }
1865d522f475Smrg
1866d522f475Smrg    putchar('\n');
186704b94745Smrg    for (cpp = help_message; *cpp; cpp++)
1868d522f475Smrg	puts(*cpp);
1869d522f475Smrg    putchar('\n');
1870d522f475Smrg    fflush(stdout);
1871d522f475Smrg}
1872d522f475Smrg
1873f2e35a3aSmrgstatic void
1874f2e35a3aSmrgNeedParam(XrmOptionDescRec * option_ptr, const char *option_val)
1875f2e35a3aSmrg{
1876f2e35a3aSmrg    if (IsEmpty(option_val)) {
1877f2e35a3aSmrg	xtermWarning("option %s requires a value\n", option_ptr->option);
187804b94745Smrg	exit(ERROR_MISC);
1879f2e35a3aSmrg    }
1880f2e35a3aSmrg}
1881f2e35a3aSmrg
1882d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1883d522f475Smrg/* ARGSUSED */
1884d522f475Smrgstatic Boolean
1885d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1886894e0ac8Smrg			Atom *selection GCC_UNUSED,
1887894e0ac8Smrg			Atom *target GCC_UNUSED,
1888894e0ac8Smrg			Atom *type GCC_UNUSED,
1889d522f475Smrg			XtPointer *value GCC_UNUSED,
1890d522f475Smrg			unsigned long *length GCC_UNUSED,
1891d522f475Smrg			int *format GCC_UNUSED)
1892d522f475Smrg{
1893d522f475Smrg    /* we don't save console output, so can't offer it */
1894d522f475Smrg    return False;
1895d522f475Smrg}
1896d522f475Smrg#endif /* TIOCCONS */
1897d522f475Smrg
1898d522f475Smrg/*
1899d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1900d522f475Smrg */
1901d522f475Smrg/* ARGSUSED */
1902d522f475Smrgstatic void
1903d522f475SmrgDeleteWindow(Widget w,
1904894e0ac8Smrg	     XEvent *event GCC_UNUSED,
1905e0a2b6dfSmrg	     String *params GCC_UNUSED,
1906d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1907d522f475Smrg{
1908d522f475Smrg#if OPT_TEK4014
1909d522f475Smrg    if (w == toplevel) {
1910d522f475Smrg	if (TEK4014_SHOWN(term))
1911d522f475Smrg	    hide_vt_window();
1912d522f475Smrg	else
1913d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
191420d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1915d522f475Smrg	hide_tek_window();
1916d522f475Smrg    else
1917d522f475Smrg#endif
1918d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1919d522f475Smrg}
1920d522f475Smrg
1921d522f475Smrg/* ARGSUSED */
1922d522f475Smrgstatic void
1923d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1924894e0ac8Smrg		XEvent *event,
1925e0a2b6dfSmrg		String *params GCC_UNUSED,
1926d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1927d522f475Smrg{
1928d522f475Smrg    switch (event->type) {
1929d522f475Smrg    case MappingNotify:
1930d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1931d522f475Smrg	break;
1932d522f475Smrg    }
1933d522f475Smrg}
1934d522f475Smrg
1935d522f475Smrgstatic XtActionsRec actionProcs[] =
1936d522f475Smrg{
1937d522f475Smrg    {"DeleteWindow", DeleteWindow},
1938d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1939d522f475Smrg};
1940d522f475Smrg
1941d522f475Smrg/*
1942d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1943d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1944d522f475Smrg * utmp.
1945d522f475Smrg */
1946d522f475Smrgstatic char *
1947d522f475Smrgmy_pty_name(char *device)
1948d522f475Smrg{
1949d522f475Smrg    size_t len = strlen(device);
1950d522f475Smrg    Bool name = False;
1951d522f475Smrg
1952d522f475Smrg    while (len != 0) {
1953d522f475Smrg	int ch = device[len - 1];
1954d522f475Smrg	if (isdigit(ch)) {
1955d522f475Smrg	    len--;
1956d522f475Smrg	} else if (ch == '/') {
1957d522f475Smrg	    if (name)
1958d522f475Smrg		break;
1959d522f475Smrg	    len--;
19605307cd1aSmrg	} else if (isalpha(CharOf(ch))) {
1961d522f475Smrg	    name = True;
1962d522f475Smrg	    len--;
1963d522f475Smrg	} else {
1964d522f475Smrg	    break;
1965d522f475Smrg	}
1966d522f475Smrg    }
1967d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1968d522f475Smrg    return device + len;
1969d522f475Smrg}
1970d522f475Smrg
1971d522f475Smrg/*
1972d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1973d522f475Smrg * last few characters for a utmp identifier.
1974d522f475Smrg */
1975d522f475Smrgstatic char *
1976d522f475Smrgmy_pty_id(char *device)
1977d522f475Smrg{
1978d522f475Smrg    char *name = my_pty_name(device);
1979d522f475Smrg    char *leaf = x_basename(name);
1980d522f475Smrg
1981d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1982956cc18dSsnj	int len = (int) strlen(leaf);
1983d522f475Smrg	if (PTYCHARLEN < len)
1984d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1985d522f475Smrg    }
1986d522f475Smrg    TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
1987d522f475Smrg    return leaf;
1988d522f475Smrg}
1989d522f475Smrg
1990d522f475Smrg/*
1991d522f475Smrg * Set the tty/pty identifier
1992d522f475Smrg */
1993d522f475Smrgstatic void
1994d522f475Smrgset_pty_id(char *device, char *id)
1995d522f475Smrg{
1996d522f475Smrg    char *name = my_pty_name(device);
1997d522f475Smrg    char *leaf = x_basename(name);
1998d522f475Smrg
1999d522f475Smrg    if (name == leaf) {
2000d522f475Smrg	strcpy(my_pty_id(device), id);
2001d522f475Smrg    } else {
2002d522f475Smrg	strcpy(leaf, id);
2003d522f475Smrg    }
2004d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
2005d522f475Smrg}
2006d522f475Smrg
2007d522f475Smrg/*
2008d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
2009d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
2010d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
2011d522f475Smrg * not, fall-thru to the original logic.
2012d522f475Smrg */
2013d522f475Smrgstatic Bool
2014d522f475SmrgParseSccn(char *option)
2015d522f475Smrg{
2016d522f475Smrg    char *leaf = x_basename(option);
2017d522f475Smrg    Bool code = False;
2018d522f475Smrg
201901037d57Smrg    passedPty = x_strdup(option);
2020d522f475Smrg    if (leaf != option) {
2021d522f475Smrg	if (leaf - option > 0
2022d522f475Smrg	    && isdigit(CharOf(*leaf))
2023d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
2024956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
2025d522f475Smrg	    /*
2026d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
2027d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
2028d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
2029d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
2030d522f475Smrg	     */
2031d522f475Smrg	    passedPty[len] = 0;
2032d522f475Smrg	    code = True;
2033d522f475Smrg	}
2034d522f475Smrg    } else {
2035d522f475Smrg	code = (sscanf(option, "%c%c%d",
2036d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
203701037d57Smrg	passedPty[2] = '\0';
2038d522f475Smrg    }
2039d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
2040d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
2041d522f475Smrg    return code;
2042d522f475Smrg}
2043d522f475Smrg
2044d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
2045d522f475Smrg/*
2046d522f475Smrg * From "man utmp":
2047d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
2048d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
2049d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
2050d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
2051d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
2052d522f475Smrg * ut_time, ut_user and ut_host as well.
2053d522f475Smrg *
2054d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
2055d522f475Smrg * pty implementation allows more than 3 digits.
2056d522f475Smrg */
2057d522f475Smrgstatic char *
2058d522f475Smrgmy_utmp_id(char *device)
2059d522f475Smrg{
2060d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
2061d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
2062d522f475Smrg    static char result[UTIDSIZE + 1];
2063d522f475Smrg
2064d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
2065d522f475Smrg    /*
2066d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
2067d522f475Smrg     * issues, and can use the available space in ut_id differently from the
2068d522f475Smrg     * default convention.
2069d522f475Smrg     *
2070d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
2071d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
2072d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
2073d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
2074d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
2075d522f475Smrg     * last three digits of the device name, regardless of the format of the
2076d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
2077d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
2078d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
2079d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
2080d522f475Smrg     */
2081d522f475Smrg    int len, n;
2082d522f475Smrg
2083d522f475Smrg    len = strlen(device);
2084d522f475Smrg    n = UTIDSIZE;
2085d522f475Smrg    result[n] = '\0';
2086d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
2087d522f475Smrg	result[--n] = device[--len];
2088d522f475Smrg    while (n > 0)
2089d522f475Smrg	result[--n] = '0';
2090d522f475Smrg    result[0] = 'x';
2091d522f475Smrg#else
2092d522f475Smrg    char *name = my_pty_name(device);
2093d522f475Smrg    char *leaf = x_basename(name);
2094d522f475Smrg    size_t len = strlen(leaf);
2095d522f475Smrg
2096d522f475Smrg    if ((UTIDSIZE - 1) < len)
2097d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
2098d522f475Smrg    sprintf(result, "p%s", leaf);
2099d522f475Smrg#endif
2100d522f475Smrg
2101d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
2102d522f475Smrg    return result;
2103d522f475Smrg}
2104d522f475Smrg#endif /* USE_SYSV_UTMP */
2105d522f475Smrg
2106d522f475Smrg#ifdef USE_POSIX_SIGNALS
2107d522f475Smrg
2108d522f475Smrgtypedef void (*sigfunc) (int);
2109d522f475Smrg
2110d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
2111d522f475Smrg   has just been stopped and not actually killed */
2112d522f475Smrg
2113d522f475Smrgstatic sigfunc
2114d522f475Smrgposix_signal(int signo, sigfunc func)
2115d522f475Smrg{
2116d522f475Smrg    struct sigaction act, oact;
2117d522f475Smrg
2118d522f475Smrg    act.sa_handler = func;
2119d522f475Smrg    sigemptyset(&act.sa_mask);
2120d522f475Smrg#ifdef SA_RESTART
2121d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
2122d522f475Smrg#else
2123d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
2124d522f475Smrg#endif
2125d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
2126d522f475Smrg	return (SIG_ERR);
2127d522f475Smrg    return (oact.sa_handler);
2128d522f475Smrg}
2129d522f475Smrg
21300bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
2131d522f475Smrg
2132d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
2133d522f475Smrgstatic void
2134d522f475SmrgdisableSetUid(void)
2135d522f475Smrg{
2136d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
2137d522f475Smrg    if (setuid(save_ruid) == -1) {
21380bd37d32Smrg	xtermWarning("unable to reset uid\n");
213904b94745Smrg	exit(ERROR_MISC);
2140d522f475Smrg    }
2141d522f475Smrg    TRACE_IDS;
2142d522f475Smrg}
2143d522f475Smrg#else
2144d522f475Smrg#define disableSetUid()		/* nothing */
2145d522f475Smrg#endif /* DISABLE_SETUID */
2146d522f475Smrg
2147d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
2148d522f475Smrgstatic void
2149d522f475SmrgdisableSetGid(void)
2150d522f475Smrg{
2151d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
2152d522f475Smrg    if (setegid(save_rgid) == -1) {
21530bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
215404b94745Smrg	exit(ERROR_MISC);
2155d522f475Smrg    }
2156d522f475Smrg    TRACE_IDS;
2157d522f475Smrg}
2158d522f475Smrg#else
2159d522f475Smrg#define disableSetGid()		/* nothing */
2160d522f475Smrg#endif /* DISABLE_SETGID */
2161d522f475Smrg
2162d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
2163d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
2164d522f475Smrgstatic void
2165d522f475SmrgsetEffectiveGroup(gid_t group)
2166d522f475Smrg{
2167d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
2168d522f475Smrg    if (setegid(group) == -1) {
2169d522f475Smrg#ifdef __MVS__
2170d522f475Smrg	if (!(errno == EMVSERR))	/* could happen if _BPX_SHAREAS=REUSE */
2171d522f475Smrg#endif
2172d522f475Smrg	{
21730bd37d32Smrg	    xtermPerror("setegid(%d)", (int) group);
2174d522f475Smrg	}
2175d522f475Smrg    }
2176d522f475Smrg    TRACE_IDS;
2177d522f475Smrg}
2178d522f475Smrg#endif
2179d522f475Smrg
2180d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
2181d522f475Smrgstatic void
2182d522f475SmrgsetEffectiveUser(uid_t user)
2183d522f475Smrg{
2184d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
2185d522f475Smrg    if (seteuid(user) == -1) {
2186d522f475Smrg#ifdef __MVS__
2187d522f475Smrg	if (!(errno == EMVSERR))
2188d522f475Smrg#endif
2189d522f475Smrg	{
21900bd37d32Smrg	    xtermPerror("seteuid(%d)", (int) user);
2191d522f475Smrg	}
2192d522f475Smrg    }
2193d522f475Smrg    TRACE_IDS;
2194d522f475Smrg}
2195d522f475Smrg#endif
2196d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
2197d522f475Smrg
21982e4f8982Smrg#if OPT_LUIT_PROG
21992e4f8982Smrgstatic Boolean
22002e4f8982Smrgcomplex_command(char **args)
22012e4f8982Smrg{
22022e4f8982Smrg    Boolean result = False;
22032e4f8982Smrg    if (x_countargv(args) == 1) {
22042e4f8982Smrg	char *check = xtermFindShell(args[0], False);
22052e4f8982Smrg	if (check == 0) {
22062e4f8982Smrg	    result = True;
22072e4f8982Smrg	} else {
22082e4f8982Smrg	    free(check);
22092e4f8982Smrg	}
22102e4f8982Smrg    }
22112e4f8982Smrg    return result;
22122e4f8982Smrg}
22132e4f8982Smrg#endif
22142e4f8982Smrg
22152e4f8982Smrgstatic unsigned
22162e4f8982Smrglookup_baudrate(const char *value)
22172e4f8982Smrg{
22182e4f8982Smrg    struct speed {
22192e4f8982Smrg	unsigned given_speed;	/* values for 'ospeed' */
22202e4f8982Smrg	unsigned actual_speed;	/* the actual speed */
22212e4f8982Smrg    };
22222e4f8982Smrg
22232e4f8982Smrg#define DATA(number) { B##number, number }
22242e4f8982Smrg
22252e4f8982Smrg    static struct speed const speeds[] =
22262e4f8982Smrg    {
22272e4f8982Smrg	DATA(0),
22282e4f8982Smrg	DATA(50),
22292e4f8982Smrg	DATA(75),
22302e4f8982Smrg	DATA(110),
22312e4f8982Smrg	DATA(134),
22322e4f8982Smrg	DATA(150),
22332e4f8982Smrg	DATA(200),
22342e4f8982Smrg	DATA(300),
22352e4f8982Smrg	DATA(600),
22362e4f8982Smrg	DATA(1200),
22372e4f8982Smrg	DATA(1800),
22382e4f8982Smrg	DATA(2400),
22392e4f8982Smrg	DATA(4800),
22402e4f8982Smrg	DATA(9600),
22412e4f8982Smrg#ifdef B19200
22422e4f8982Smrg	DATA(19200),
22432e4f8982Smrg#elif defined(EXTA)
22442e4f8982Smrg	{EXTA, 19200},
22452e4f8982Smrg#endif
22462e4f8982Smrg#ifdef B28800
22472e4f8982Smrg	DATA(28800),
22482e4f8982Smrg#endif
22492e4f8982Smrg#ifdef B38400
22502e4f8982Smrg	DATA(38400),
22512e4f8982Smrg#elif defined(EXTB)
22522e4f8982Smrg	{EXTB, 38400},
22532e4f8982Smrg#endif
22542e4f8982Smrg#ifdef B57600
22552e4f8982Smrg	DATA(57600),
22562e4f8982Smrg#endif
22572e4f8982Smrg#ifdef B76800
22582e4f8982Smrg	DATA(76800),
22592e4f8982Smrg#endif
22602e4f8982Smrg#ifdef B115200
22612e4f8982Smrg	DATA(115200),
22622e4f8982Smrg#endif
22632e4f8982Smrg#ifdef B153600
22642e4f8982Smrg	DATA(153600),
22652e4f8982Smrg#endif
22662e4f8982Smrg#ifdef B230400
22672e4f8982Smrg	DATA(230400),
22682e4f8982Smrg#endif
22692e4f8982Smrg#ifdef B307200
22702e4f8982Smrg	DATA(307200),
22712e4f8982Smrg#endif
22722e4f8982Smrg#ifdef B460800
22732e4f8982Smrg	DATA(460800),
22742e4f8982Smrg#endif
22752e4f8982Smrg#ifdef B500000
22762e4f8982Smrg	DATA(500000),
22772e4f8982Smrg#endif
22782e4f8982Smrg#ifdef B576000
22792e4f8982Smrg	DATA(576000),
22802e4f8982Smrg#endif
22812e4f8982Smrg#ifdef B921600
22822e4f8982Smrg	DATA(921600),
22832e4f8982Smrg#endif
22842e4f8982Smrg#ifdef B1000000
22852e4f8982Smrg	DATA(1000000),
22862e4f8982Smrg#endif
22872e4f8982Smrg#ifdef B1152000
22882e4f8982Smrg	DATA(1152000),
22892e4f8982Smrg#endif
22902e4f8982Smrg#ifdef B1500000
22912e4f8982Smrg	DATA(1500000),
22922e4f8982Smrg#endif
22932e4f8982Smrg#ifdef B2000000
22942e4f8982Smrg	DATA(2000000),
22952e4f8982Smrg#endif
22962e4f8982Smrg#ifdef B2500000
22972e4f8982Smrg	DATA(2500000),
22982e4f8982Smrg#endif
22992e4f8982Smrg#ifdef B3000000
23002e4f8982Smrg	DATA(3000000),
23012e4f8982Smrg#endif
23022e4f8982Smrg#ifdef B3500000
23032e4f8982Smrg	DATA(3500000),
23042e4f8982Smrg#endif
23052e4f8982Smrg#ifdef B4000000
23062e4f8982Smrg	DATA(4000000),
23072e4f8982Smrg#endif
23082e4f8982Smrg    };
23092e4f8982Smrg#undef DATA
23102e4f8982Smrg    unsigned result = 0;
23112e4f8982Smrg    long check;
23122e4f8982Smrg    char *next;
23132e4f8982Smrg    if (x_toupper(*value) == 'B')
23142e4f8982Smrg	value++;
23152e4f8982Smrg    if (isdigit(CharOf(*value))) {
23162e4f8982Smrg	check = strtol(value, &next, 10);
23172e4f8982Smrg	if (FullS2L(value, next) && (check > 0)) {
23182e4f8982Smrg	    Cardinal n;
23192e4f8982Smrg	    for (n = 0; n < XtNumber(speeds); ++n) {
23202e4f8982Smrg		if (speeds[n].actual_speed == (unsigned) check) {
23212e4f8982Smrg		    result = speeds[n].given_speed;
23222e4f8982Smrg		    break;
23232e4f8982Smrg		}
23242e4f8982Smrg	    }
23252e4f8982Smrg	}
23262e4f8982Smrg    }
23272e4f8982Smrg    if (result == 0) {
23282e4f8982Smrg	fprintf(stderr, "unsupported value for baudrate: %s\n", value);
23292e4f8982Smrg    }
23302e4f8982Smrg    return result;
23312e4f8982Smrg}
23322e4f8982Smrg
23335307cd1aSmrgint
23345307cd1aSmrgget_tty_erase(int fd, int default_erase, const char *tag)
23355307cd1aSmrg{
23365307cd1aSmrg    int result = default_erase;
23375307cd1aSmrg    int rc;
23385307cd1aSmrg
23395307cd1aSmrg#ifdef TERMIO_STRUCT
23405307cd1aSmrg    TERMIO_STRUCT my_tio;
23415307cd1aSmrg    rc = ttyGetAttr(fd, &my_tio);
23425307cd1aSmrg    if (rc == 0)
23435307cd1aSmrg	result = my_tio.c_cc[VERASE];
23445307cd1aSmrg#else /* !TERMIO_STRUCT */
23455307cd1aSmrg    struct sgttyb my_sg;
23465307cd1aSmrg    rc = ioctl(fd, TIOCGETP, (char *) &my_sg);
23475307cd1aSmrg    if (rc == 0)
23485307cd1aSmrg	result = my_sg.sg_erase;
23495307cd1aSmrg#endif /* TERMIO_STRUCT */
23505307cd1aSmrg    TRACE(("%s erase:%d (from %s)\n", (rc == 0) ? "OK" : "FAIL", result, tag));
23515307cd1aSmrg    (void) tag;
23525307cd1aSmrg    return result;
23535307cd1aSmrg}
23545307cd1aSmrg
23555307cd1aSmrgint
23565307cd1aSmrgget_tty_lnext(int fd, int default_lnext, const char *tag)
23575307cd1aSmrg{
23585307cd1aSmrg    int result = default_lnext;
23595307cd1aSmrg    int rc;
23605307cd1aSmrg
23615307cd1aSmrg#ifdef TERMIO_STRUCT
23625307cd1aSmrg    TERMIO_STRUCT my_tio;
23635307cd1aSmrg    rc = ttyGetAttr(fd, &my_tio);
23645307cd1aSmrg    if (rc == 0)
23655307cd1aSmrg	result = my_tio.c_cc[VLNEXT];
23665307cd1aSmrg#elif defined(HAS_LTCHARS)
23675307cd1aSmrg    struct ltchars my_ltc;
23685307cd1aSmrg    rc = ioctl(fd, TIOCGLTC, (char *) &my_ltc);
23695307cd1aSmrg    if (rc == 0)
23705307cd1aSmrg	result = my_ltc.t_lnextc;
23715307cd1aSmrg#else
23725307cd1aSmrg    result = XTERM_LNEXT;
23735307cd1aSmrg#endif /* TERMIO_STRUCT */
23745307cd1aSmrg    TRACE(("%s lnext:%d (from %s)\n", (rc == 0) ? "OK" : "FAIL", result, tag));
23755307cd1aSmrg    (void) tag;
23765307cd1aSmrg    return result;
23775307cd1aSmrg}
23785307cd1aSmrg
2379d522f475Smrgint
2380d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
2381d522f475Smrg{
2382a1f3da82Smrg#if OPT_MAXIMIZE
2383a1f3da82Smrg#define DATA(name) { #name, es##name }
238401037d57Smrg    static const FlagList tblFullscreen[] =
2385a1f3da82Smrg    {
2386a1f3da82Smrg	DATA(Always),
2387a1f3da82Smrg	DATA(Never)
2388a1f3da82Smrg    };
2389a1f3da82Smrg#undef DATA
2390a1f3da82Smrg#endif
2391a1f3da82Smrg
2392d522f475Smrg    Widget form_top, menu_top;
2393d522f475Smrg    Dimension menu_high;
2394d522f475Smrg    TScreen *screen;
2395d522f475Smrg    int mode;
2396e0a2b6dfSmrg    char *my_class = x_strdup(DEFCLASS);
23972e4f8982Smrg    unsigned line_speed = VAL_LINE_SPEED;
2398d522f475Smrg    Window winToEmbedInto = None;
2399f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
2400f2e35a3aSmrg    Xaw3dXftData *xaw3dxft_data;
2401f2e35a3aSmrg#endif
2402d522f475Smrg
2403ae137402Smrg    ProgramName = x_strdup(x_basename(argv[0]));
2404ae137402Smrg    ProgramPath = xtermFindShell(argv[0], True);
2405ae137402Smrg    if (ProgramPath != NULL)
2406ae137402Smrg	argv[0] = ProgramPath;
2407d522f475Smrg
2408d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
2409d522f475Smrg    save_euid = geteuid();
2410d522f475Smrg    save_egid = getegid();
2411d522f475Smrg#endif
2412d522f475Smrg
2413d522f475Smrg    save_ruid = getuid();
2414d522f475Smrg    save_rgid = getgid();
2415d522f475Smrg
2416d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
2417d522f475Smrg#if defined(DISABLE_SETUID)
2418d522f475Smrg    disableSetUid();
2419d522f475Smrg#endif
2420d522f475Smrg#if defined(DISABLE_SETGID)
2421d522f475Smrg    disableSetGid();
2422d522f475Smrg#endif
2423d522f475Smrg    TRACE_IDS;
2424d522f475Smrg#endif
2425d522f475Smrg
2426d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
2427d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
2428d522f475Smrg#ifdef USE_PTY_DEVICE
2429d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
2430d522f475Smrg    if (!ttydev || !ptydev)
2431d522f475Smrg#else
2432d522f475Smrg    if (!ttydev)
2433d522f475Smrg#endif
2434d522f475Smrg    {
24350bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
243604b94745Smrg	exit(ERROR_MISC);
2437d522f475Smrg    }
2438d522f475Smrg    strcpy(ttydev, TTYDEV);
2439d522f475Smrg#ifdef USE_PTY_DEVICE
2440d522f475Smrg    strcpy(ptydev, PTYDEV);
2441d522f475Smrg#endif
2442d522f475Smrg
2443d522f475Smrg#if defined(USE_UTMP_SETGID)
2444d522f475Smrg    get_pty(NULL, NULL);
2445d522f475Smrg    disableSetUid();
2446d522f475Smrg    disableSetGid();
2447d522f475Smrg    TRACE_IDS;
2448d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
2449d522f475Smrg#endif
2450d522f475Smrg
2451d522f475Smrg    /* Do these first, since we may not be able to open the display */
2452d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
2453d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
2454ae137402Smrg    restart_params = 0;
2455d522f475Smrg    if (argc > 1) {
24560bd37d32Smrg	XrmOptionDescRec *option_ptr;
24570bd37d32Smrg	char *option_value;
2458d522f475Smrg	int n;
2459e39b573cSmrg	Bool quit = False;
2460d522f475Smrg
2461d522f475Smrg	for (n = 1; n < argc; n++) {
24620bd37d32Smrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
24630bd37d32Smrg		if (argv[n] == 0) {
24640bd37d32Smrg		    break;
24650bd37d32Smrg		} else if (isOption(argv[n])) {
24660bd37d32Smrg		    Syntax(argv[n]);
24670bd37d32Smrg		} else if (explicit_shname != 0) {
24680bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
24690bd37d32Smrg		    Syntax(argv[n]);
24700bd37d32Smrg		}
24710bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
24720bd37d32Smrg		if (explicit_shname == 0)
24730bd37d32Smrg		    exit(0);
24740bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
2475ae137402Smrg		restart_params = (argc - n);
24760bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
24770bd37d32Smrg		command_to_exec = (argv + n + 1);
24780bd37d32Smrg		if (!command_to_exec[0])
24790bd37d32Smrg		    Syntax(argv[n]);
2480ae137402Smrg		restart_params = (argc - n);
24810bd37d32Smrg		break;
24820bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2483d522f475Smrg		Version();
2484e39b573cSmrg		quit = True;
24850bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2486d522f475Smrg		Help();
2487e39b573cSmrg		quit = True;
24882e4f8982Smrg	    } else if (!strcmp(option_ptr->option, "-baudrate")) {
2489f2e35a3aSmrg		NeedParam(option_ptr, option_value);
24902e4f8982Smrg		if ((line_speed = lookup_baudrate(option_value)) == 0) {
24912e4f8982Smrg		    Help();
24922e4f8982Smrg		    quit = True;
24932e4f8982Smrg		}
24940bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
2495f2e35a3aSmrg		NeedParam(option_ptr, option_value);
2496e0a2b6dfSmrg		free(my_class);
24970bd37d32Smrg		if ((my_class = x_strdup(option_value)) == 0) {
2498d522f475Smrg		    Help();
2499e39b573cSmrg		    quit = True;
2500d522f475Smrg		}
25010bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
25020bd37d32Smrg		char *endPtr;
2503f2e35a3aSmrg		NeedParam(option_ptr, option_value);
25040bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
25052e4f8982Smrg		if (!FullS2L(option_value, endPtr)) {
25062e4f8982Smrg		    Help();
25072e4f8982Smrg		    quit = True;
25082e4f8982Smrg		}
2509d522f475Smrg	    }
2510d522f475Smrg	}
2511d522f475Smrg	if (quit)
2512d522f475Smrg	    exit(0);
25130bd37d32Smrg	/*
25140bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
25150bd37d32Smrg	 * then give up.
25160bd37d32Smrg	 */
25170bd37d32Smrg	if (n < argc && !command_to_exec) {
25180bd37d32Smrg	    Syntax(argv[n]);
25190bd37d32Smrg	}
2520d522f475Smrg    }
2521d522f475Smrg
25220bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2523d522f475Smrg#if OPT_I18N_SUPPORT
2524d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2525d522f475Smrg#endif
2526d522f475Smrg
2527f2e35a3aSmrg    /* enable Xft support in Xaw3DXft */
2528f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
2529f2e35a3aSmrg    GET_XAW3DXFT_DATA(xaw3dxft_data);
2530f2e35a3aSmrg    xaw3dxft_data->encoding = -1;
2531f2e35a3aSmrg#endif
2532f2e35a3aSmrg
2533d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2534d522f475Smrg    /* Initialization is done here rather than above in order
2535d522f475Smrg     * to prevent any assumptions about the order of the contents
2536d522f475Smrg     * of the various terminal structures (which may change from
2537d522f475Smrg     * implementation to implementation).
2538d522f475Smrg     */
2539d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2540d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2541f2e35a3aSmrg    d_tio.c_oflag = TAB3 | D_TIO_FLAGS;
2542d522f475Smrg    {
2543d522f475Smrg	Cardinal nn;
2544d522f475Smrg
2545d522f475Smrg	/* fill in default-values */
2546f2e35a3aSmrg	for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
2547d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2548f2e35a3aSmrg		d_tio.c_cc[ttyChars[nn].sysMode] =
2549f2e35a3aSmrg		    (cc_t) ttyChars[nn].myDefault;
2550d522f475Smrg	    }
2551d522f475Smrg	}
2552d522f475Smrg    }
2553d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
25542e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2555d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2556d522f475Smrg#ifdef ECHOKE
2557d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2558d522f475Smrg#endif
2559d522f475Smrg#ifdef ECHOCTL
2560d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2561d522f475Smrg#endif
2562d522f475Smrg#ifndef USE_TERMIOS		/* { */
2563d522f475Smrg    d_tio.c_line = 0;
2564d522f475Smrg#endif /* } */
2565d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2566d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2567d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2568d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2569d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2570d522f475Smrg    d_ltc.t_werasc = CWERASE;
2571d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2572d522f475Smrg#endif /* } HAS_LTCHARS */
2573d522f475Smrg#ifdef TIOCLSET			/* { */
2574d522f475Smrg    d_lmode = 0;
2575d522f475Smrg#endif /* } TIOCLSET */
2576d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2577d522f475Smrg#ifndef USE_POSIX_TERMIOS
2578d522f475Smrg#ifdef BAUD_0			/* { */
2579d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2580d522f475Smrg#else /* }{ !BAUD_0 */
25812e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2582d522f475Smrg#endif /* } !BAUD_0 */
2583d522f475Smrg#else /* USE_POSIX_TERMIOS */
2584d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
25852e4f8982Smrg    cfsetispeed(&d_tio, line_speed);
25862e4f8982Smrg    cfsetospeed(&d_tio, line_speed);
2587d522f475Smrg#endif
2588d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2589d522f475Smrg#ifdef ECHOKE
2590d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2591d522f475Smrg#endif
2592d522f475Smrg#ifdef ECHOCTL
2593d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2594d522f475Smrg#endif
2595d522f475Smrg#ifndef USE_POSIX_TERMIOS
2596d522f475Smrg#ifdef NTTYDISC
2597d522f475Smrg    d_tio.c_line = NTTYDISC;
2598d522f475Smrg#else
2599d522f475Smrg    d_tio.c_line = 0;
2600d522f475Smrg#endif
2601d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2602d522f475Smrg#ifdef __sgi
2603d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2604d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2605d522f475Smrg#endif
2606d522f475Smrg#ifdef __MVS__
2607d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2608d522f475Smrg#endif
2609d522f475Smrg    {
2610d522f475Smrg	Cardinal nn;
2611d522f475Smrg	int i;
2612d522f475Smrg
2613d522f475Smrg	/* try to inherit tty settings */
2614d522f475Smrg	for (i = 0; i <= 2; i++) {
2615d522f475Smrg	    TERMIO_STRUCT deftio;
2616d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2617f2e35a3aSmrg		for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
2618d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2619f2e35a3aSmrg			d_tio.c_cc[ttyChars[nn].sysMode] =
2620f2e35a3aSmrg			    deftio.c_cc[ttyChars[nn].sysMode];
2621d522f475Smrg		    }
2622d522f475Smrg		}
2623d522f475Smrg		break;
2624d522f475Smrg	    }
2625d522f475Smrg	}
2626d522f475Smrg    }
2627d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2628d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2629d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2630d522f475Smrg#endif /* } */
2631d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2632d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2633d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2634d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2635d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2636d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2637d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2638d522f475Smrg#endif /* } HAS_LTCHARS */
2639d522f475Smrg
2640d522f475Smrg#ifdef TIOCLSET			/* { */
2641d522f475Smrg    d_lmode = 0;
2642d522f475Smrg#endif /* } TIOCLSET */
2643d522f475Smrg#endif /* } macII, ATT, CRAY */
2644d522f475Smrg#endif /* } TERMIO_STRUCT */
2645d522f475Smrg
2646d522f475Smrg    /* Init the Toolkit. */
2647d522f475Smrg    {
2648d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2649d522f475Smrg	setEffectiveGroup(save_rgid);
2650d522f475Smrg	setEffectiveUser(save_ruid);
2651d522f475Smrg	TRACE_IDS;
2652d522f475Smrg#endif
26530bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
26540bd37d32Smrg					my_class,
26550bd37d32Smrg					optionDescList,
26560bd37d32Smrg					XtNumber(optionDescList),
2657f2e35a3aSmrg					&argc, argv,
26580bd37d32Smrg					fallback_resources,
26590bd37d32Smrg					sessionShellWidgetClass,
26600bd37d32Smrg					NULL, 0);
2661ae137402Smrg	TRACE(("created toplevel widget %p, window %#lx\n",
2662ae137402Smrg	       (void *) toplevel, XtWindow(toplevel)));
2663d522f475Smrg
2664d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2665d522f475Smrg				  application_resources,
2666d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2667d522f475Smrg	TRACE_XRES();
2668ad37e533Smrg#ifdef HAVE_LIB_XCURSOR
2669ad37e533Smrg	if (!strcmp(resource.cursorTheme, "none")) {
2670ad37e533Smrg	    TRACE(("startup with no cursorTheme\n"));
2671ad37e533Smrg	    init_colored_cursor(XtDisplay(toplevel));
2672ad37e533Smrg	} else {
2673ad37e533Smrg	    const char *theme = resource.cursorTheme;
2674ad37e533Smrg	    if (IsEmpty(theme))
2675ad37e533Smrg		theme = "default";
2676ad37e533Smrg	    TRACE(("startup with \"%s\" cursorTheme\n", theme));
2677ad37e533Smrg	    xtermSetenv("XCURSOR_THEME", theme);
2678ad37e533Smrg	}
2679ad37e533Smrg#endif
2680f2e35a3aSmrg#if USE_DOUBLE_BUFFER
2681f2e35a3aSmrg	if (resource.buffered_fps <= 0)
2682f2e35a3aSmrg	    resource.buffered_fps = DEF_BUFFER_RATE;
2683f2e35a3aSmrg	if (resource.buffered_fps > 100)
2684f2e35a3aSmrg	    resource.buffered_fps = 100;
2685f2e35a3aSmrg#endif
2686a1f3da82Smrg#if OPT_MAXIMIZE
2687a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2688a1f3da82Smrg					      tblFullscreen,
2689f2e35a3aSmrg					      esLAST);
2690a1f3da82Smrg#endif
2691e39b573cSmrg	VTInitTranslations();
2692d522f475Smrg#if OPT_PTY_HANDSHAKE
2693d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2694d522f475Smrg#endif
2695d522f475Smrg
2696d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2697d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2698d522f475Smrg#if !defined(DISABLE_SETUID)
2699d522f475Smrg	setEffectiveUser(save_euid);
2700d522f475Smrg#endif
2701d522f475Smrg#if !defined(DISABLE_SETGID)
2702d522f475Smrg	setEffectiveGroup(save_egid);
2703d522f475Smrg#endif
2704d522f475Smrg	TRACE_IDS;
2705d522f475Smrg#endif
2706d522f475Smrg#endif
2707d522f475Smrg    }
2708d522f475Smrg
2709d522f475Smrg    /*
2710d522f475Smrg     * ICCCM delete_window.
2711d522f475Smrg     */
2712d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2713d522f475Smrg
2714d522f475Smrg    /*
2715d522f475Smrg     * fill in terminal modes
2716d522f475Smrg     */
2717d522f475Smrg    if (resource.tty_modes) {
2718f2e35a3aSmrg	int n = parse_tty_modes(resource.tty_modes);
2719d522f475Smrg	if (n < 0) {
27200bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2721d522f475Smrg	} else if (n > 0) {
2722d522f475Smrg	    override_tty_modes = True;
2723d522f475Smrg	}
2724d522f475Smrg    }
27250bd37d32Smrg    initZIconBeep();
2726d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2727d522f475Smrg    if (resource.icon_geometry != NULL) {
2728d522f475Smrg	int scr, junk;
2729d522f475Smrg	int ix, iy;
2730d522f475Smrg	Arg args[2];
2731d522f475Smrg
2732d522f475Smrg	for (scr = 0;		/* yyuucchh */
2733d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2734d522f475Smrg	     scr++) ;
2735d522f475Smrg
2736d522f475Smrg	args[0].name = XtNiconX;
2737d522f475Smrg	args[1].name = XtNiconY;
2738d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2739d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2740d522f475Smrg	args[0].value = (XtArgVal) ix;
2741d522f475Smrg	args[1].value = (XtArgVal) iy;
2742d522f475Smrg	XtSetValues(toplevel, args, 2);
2743d522f475Smrg    }
2744d522f475Smrg
2745d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2746d522f475Smrg		number_ourTopLevelShellArgs);
2747d522f475Smrg
2748d522f475Smrg#if OPT_WIDE_CHARS
2749d522f475Smrg    /* seems as good a place as any */
2750d522f475Smrg    init_classtab();
2751d522f475Smrg#endif
2752d522f475Smrg
2753d522f475Smrg    /* Parse the rest of the command line */
2754d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2755d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
27560bd37d32Smrg	if (!isOption(*argv)) {
2757d522f475Smrg#ifdef VMS
2758d522f475Smrg	    Syntax(*argv);
2759d522f475Smrg#else
2760d522f475Smrg	    if (argc > 1)
2761d522f475Smrg		Syntax(*argv);
2762d522f475Smrg	    continue;
2763d522f475Smrg#endif
27640bd37d32Smrg	}
2765d522f475Smrg
2766d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2767d522f475Smrg	switch (argv[0][1]) {
2768d522f475Smrg	case 'C':
2769d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2770d522f475Smrg#ifndef __sgi
2771d522f475Smrg	    {
2772d522f475Smrg		struct stat sbuf;
2773d522f475Smrg
2774d522f475Smrg		/* Must be owner and have read/write permission.
2775d522f475Smrg		   xdm cooperates to give the console the right user. */
2776d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2777d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2778d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2779d522f475Smrg		    Console = True;
2780d522f475Smrg		} else
2781d522f475Smrg		    Console = False;
2782d522f475Smrg	    }
2783d522f475Smrg#else /* __sgi */
2784d522f475Smrg	    Console = True;
2785d522f475Smrg#endif /* __sgi */
2786d522f475Smrg#endif /* TIOCCONS */
2787d522f475Smrg	    continue;
2788d522f475Smrg	case 'S':
2789d522f475Smrg	    if (!ParseSccn(*argv + 2))
2790d522f475Smrg		Syntax(*argv);
2791d522f475Smrg	    continue;
2792d522f475Smrg#ifdef DEBUG
2793d522f475Smrg	case 'D':
2794d522f475Smrg	    debug = True;
2795d522f475Smrg	    continue;
2796d522f475Smrg#endif /* DEBUG */
27972e4f8982Smrg	case 'b':
27982e4f8982Smrg	    if (strcmp(argv[0], "-baudrate"))
27992e4f8982Smrg		Syntax(*argv);
2800f2e35a3aSmrg	    argc--;
2801f2e35a3aSmrg	    argv++;
28022e4f8982Smrg	    continue;
28030bd37d32Smrg	case 'c':
28040bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2805d522f475Smrg		Syntax(*argv);
2806f2e35a3aSmrg	    argc--;
2807f2e35a3aSmrg	    argv++;
2808d522f475Smrg	    continue;
2809d522f475Smrg	case 'e':
28100bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2811d522f475Smrg		Syntax(*argv);
28120bd37d32Smrg	    command_to_exec = (argv + 1);
2813d522f475Smrg	    break;
2814d522f475Smrg	case 'i':
28150bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2816d522f475Smrg		Syntax(*argv);
2817f2e35a3aSmrg	    argc--;
2818f2e35a3aSmrg	    argv++;
2819d522f475Smrg	    continue;
2820d522f475Smrg
2821d522f475Smrg	default:
2822d522f475Smrg	    Syntax(*argv);
2823d522f475Smrg	}
2824d522f475Smrg	break;
2825d522f475Smrg    }
2826d522f475Smrg
2827d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2828d522f475Smrg
2829d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2830d522f475Smrg						 form_top,
2831d522f475Smrg#if OPT_TOOLBAR
2832d522f475Smrg						 XtNmenuBar, menu_top,
2833d522f475Smrg						 XtNresizable, True,
2834d522f475Smrg						 XtNfromVert, menu_top,
2835d522f475Smrg						 XtNleft, XawChainLeft,
2836d522f475Smrg						 XtNright, XawChainRight,
2837d522f475Smrg						 XtNtop, XawChainTop,
2838d522f475Smrg						 XtNbottom, XawChainBottom,
2839d522f475Smrg						 XtNmenuHeight, menu_high,
2840d522f475Smrg#endif
2841d522f475Smrg						 (XtPointer) 0);
2842ae137402Smrg    TRACE(("created vt100 widget %p, window %#lx\n",
2843ae137402Smrg	   (void *) term, XtWindow(term)));
2844d522f475Smrg    decode_keyboard_type(term, &resource);
2845d522f475Smrg
2846d522f475Smrg    screen = TScreenOf(term);
2847d522f475Smrg    screen->inhibit = 0;
2848d522f475Smrg
2849d522f475Smrg#ifdef ALLOWLOGGING
2850d522f475Smrg    if (term->misc.logInhibit)
2851d522f475Smrg	screen->inhibit |= I_LOG;
2852d522f475Smrg#endif
2853d522f475Smrg    if (term->misc.signalInhibit)
2854d522f475Smrg	screen->inhibit |= I_SIGNAL;
2855d522f475Smrg#if OPT_TEK4014
2856d522f475Smrg    if (term->misc.tekInhibit)
2857d522f475Smrg	screen->inhibit |= I_TEK;
2858d522f475Smrg#endif
2859d522f475Smrg
2860d522f475Smrg    /*
2861d522f475Smrg     * We might start by showing the tek4014 window.
2862d522f475Smrg     */
2863d522f475Smrg#if OPT_TEK4014
2864d522f475Smrg    if (screen->inhibit & I_TEK)
2865d522f475Smrg	TEK4014_ACTIVE(term) = False;
2866d522f475Smrg
2867d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2868d522f475Smrg	SysError(ERROR_INIT);
2869d522f475Smrg#endif
2870d522f475Smrg
2871d522f475Smrg    /*
2872d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2873d522f475Smrg     */
2874d522f475Smrg#if OPT_TOOLBAR
2875d522f475Smrg    ShowToolbar(resource.toolBar);
2876d522f475Smrg#endif
2877d522f475Smrg
28780bd37d32Smrg    xtermOpenSession();
2879d522f475Smrg
2880d522f475Smrg    /*
2881d522f475Smrg     * Set title and icon name if not specified
2882d522f475Smrg     */
2883d522f475Smrg    if (command_to_exec) {
2884d522f475Smrg	Arg args[2];
2885d522f475Smrg
28865307cd1aSmrg	if (!resource.title)
28875307cd1aSmrg	    resource.title = x_basename(command_to_exec[0]);
2888d522f475Smrg	if (!resource.icon_name)
2889d522f475Smrg	    resource.icon_name = resource.title;
28905307cd1aSmrg
2891d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2892d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2893d522f475Smrg
28940bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2895d522f475Smrg	       resource.title,
2896d522f475Smrg	       resource.icon_name,
28970bd37d32Smrg	       NonNull(resource.icon_hint),
2898d522f475Smrg	       *command_to_exec));
2899d522f475Smrg
2900d522f475Smrg	XtSetValues(toplevel, args, 2);
29015307cd1aSmrg    } else if (IsEmpty(resource.title) && strcmp(my_class, DEFCLASS)) {
29025307cd1aSmrg	Arg args[2];
29035307cd1aSmrg	int n;
29045307cd1aSmrg
29055307cd1aSmrg	resource.title = x_strdup(my_class);
29065307cd1aSmrg	for (n = 0; resource.title[n]; ++n) {
29075307cd1aSmrg	    if (isalpha(CharOf(resource.title[n])))
29085307cd1aSmrg		resource.title[n] = (char) tolower(resource.title[n]);
29095307cd1aSmrg	}
29105307cd1aSmrg	TRACE(("setting:\n\ttitle \"%s\"\n", resource.title));
29115307cd1aSmrg	XtSetArg(args[0], XtNtitle, resource.title);
29125307cd1aSmrg	XtSetValues(toplevel, args, 1);
2913d522f475Smrg    }
2914d522f475Smrg#if OPT_LUIT_PROG
2915d522f475Smrg    if (term->misc.callfilter) {
29160bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
29170bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
29180bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
29190bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
29200bd37d32Smrg
29210bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
29220bd37d32Smrg						  (count_split
29230bd37d32Smrg						   + count_exec
29240bd37d32Smrg						   + count_using
29250bd37d32Smrg						   + 8));
29260bd37d32Smrg	if (command_to_exec_with_luit == NULL)
29270bd37d32Smrg	    SysError(ERROR_LUMALLOC);
29280bd37d32Smrg
29290bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
29300bd37d32Smrg	if (count_using) {
29310bd37d32Smrg	    char *encoding_opt[4];
29320bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
29330bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
29340bd37d32Smrg	    encoding_opt[2] = 0;
29350bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
29360bd37d32Smrg	}
29370bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
29380bd37d32Smrg	if (count_exec) {
29392e4f8982Smrg	    static char *fixup_shell[] =
2940f2e35a3aSmrg	    {(char *) "sh", (char *) "-c", 0};
29410bd37d32Smrg	    char *delimiter[2];
29420bd37d32Smrg	    delimiter[0] = x_strdup("--");
29430bd37d32Smrg	    delimiter[1] = 0;
29440bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
29452e4f8982Smrg	    if (complex_command(command_to_exec)) {
29462e4f8982Smrg		x_appendargv(command_to_exec_with_luit, fixup_shell);
29472e4f8982Smrg	    }
29480bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2949d522f475Smrg	}
29500bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
29510bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2952d522f475Smrg    }
2953d522f475Smrg#endif
2954d522f475Smrg
29550bd37d32Smrg    if_DEBUG({
2956d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2957d522f475Smrg	   done securely by a privileged xterm process (although we try),
2958d522f475Smrg	   so the debug feature is disabled by default. */
2959e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2960d522f475Smrg	int i = -1;
29610bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
29620bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
29630bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2964d522f475Smrg	}
2965d522f475Smrg	if (i >= 0) {
2966d522f475Smrg	    dup2(i, 2);
2967d522f475Smrg
2968d522f475Smrg	    /* mark this file as close on exec */
2969d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2970d522f475Smrg	}
29710bd37d32Smrg    });
2972d522f475Smrg
29732e4f8982Smrg    spawnXTerm(term, line_speed);
2974d522f475Smrg
2975d522f475Smrg#ifndef VMS
2976d522f475Smrg    /* Child process is out there, let's catch its termination */
2977d522f475Smrg
2978d522f475Smrg#ifdef USE_POSIX_SIGNALS
2979d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2980d522f475Smrg#else
2981d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2982d522f475Smrg#endif
2983d522f475Smrg    /* Realize procs have now been executed */
2984d522f475Smrg
2985d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2986d522f475Smrg	char buf[80];
2987d522f475Smrg
2988d522f475Smrg	buf[0] = '\0';
2989d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
299020d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2991d522f475Smrg    }
2992d522f475Smrg#ifdef AIXV3
2993d522f475Smrg#if (OSMAJORVERSION < 4)
2994d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2995d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2996d522f475Smrg     * to the slave-pty process when xterm exits.
2997d522f475Smrg     */
2998d522f475Smrg
2999d522f475Smrg    {
3000d522f475Smrg	TERMIO_STRUCT tio;
3001d522f475Smrg
3002d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
3003d522f475Smrg	    SysError(ERROR_TIOCGETP);
3004d522f475Smrg
3005d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
3006d522f475Smrg
3007d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
3008d522f475Smrg	    SysError(ERROR_TIOCSETP);
3009d522f475Smrg    }
3010d522f475Smrg#endif
3011d522f475Smrg#endif
301201037d57Smrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__) || defined(__minix)
3013d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
3014d522f475Smrg	SysError(ERROR_F_GETFL);
3015d522f475Smrg#ifdef O_NDELAY
3016d522f475Smrg    mode |= O_NDELAY;
3017d522f475Smrg#else
3018d522f475Smrg    mode |= O_NONBLOCK;
3019d522f475Smrg#endif /* O_NDELAY */
3020d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
3021d522f475Smrg	SysError(ERROR_F_SETFL);
3022d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
3023d522f475Smrg    mode = 1;
3024d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
3025d522f475Smrg	SysError(ERROR_FIONBIO);
3026d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
3027d522f475Smrg
3028d522f475Smrg    /* The erase character is used to delete the current completion */
3029d522f475Smrg#if OPT_DABBREV
3030d522f475Smrg#ifdef TERMIO_STRUCT
3031d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
3032d522f475Smrg#else
3033d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
3034d522f475Smrg#endif
3035d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
3036d522f475Smrg#endif
3037d522f475Smrg
3038d522f475Smrg    FD_ZERO(&pty_mask);
3039d522f475Smrg    FD_ZERO(&X_mask);
3040d522f475Smrg    FD_ZERO(&Select_mask);
3041d522f475Smrg    FD_SET(screen->respond, &pty_mask);
3042d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
3043d522f475Smrg    FD_SET(screen->respond, &Select_mask);
3044d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
3045d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
3046d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
3047d522f475Smrg		 : (1 + screen->respond));
3048d522f475Smrg
3049d522f475Smrg#endif /* !VMS */
30500bd37d32Smrg    if_DEBUG({
30510bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
30520bd37d32Smrg    });
3053d522f475Smrg    XSetErrorHandler(xerror);
3054d522f475Smrg    XSetIOErrorHandler(xioerror);
305501037d57Smrg#if OPT_SESSION_MGT
3056e39b573cSmrg    IceSetIOErrorHandler(ice_error);
305701037d57Smrg#endif
3058d522f475Smrg
3059d522f475Smrg    initPtyData(&VTbuffer);
3060d522f475Smrg#ifdef ALLOWLOGGING
3061d522f475Smrg    if (term->misc.log_on) {
306220d2c4d2Smrg	StartLog(term);
3063d522f475Smrg    }
3064d522f475Smrg#endif
3065d522f475Smrg
30660bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
3067a5ae21e4Smrg
3068a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
3069a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
307020d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
307120d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
3072d522f475Smrg
3073a1f3da82Smrg    if (term->misc.re_verse0) {
3074a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
3075a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
3076a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
3077a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
3078a1f3da82Smrg	} else {
3079a1f3da82Smrg	    ReverseVideo(term);
3080a1f3da82Smrg	}
3081a1f3da82Smrg	term->misc.re_verse = True;
3082a1f3da82Smrg	update_reversevideo();
3083a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
3084a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
3085a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
3086a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
3087a1f3da82Smrg    }
3088956cc18dSsnj#if OPT_MAXIMIZE
3089956cc18dSsnj    if (resource.maximized)
3090956cc18dSsnj	RequestMaximize(term, True);
3091956cc18dSsnj#endif
3092d522f475Smrg    for (;;) {
3093d522f475Smrg#if OPT_TEK4014
3094d522f475Smrg	if (TEK4014_ACTIVE(term))
3095d522f475Smrg	    TekRun();
3096d522f475Smrg	else
3097d522f475Smrg#endif
3098956cc18dSsnj	    VTRun(term);
3099d522f475Smrg    }
3100d522f475Smrg}
3101d522f475Smrg
310204b94745Smrg#if defined(__osf__) || (defined(__linux__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
3103d522f475Smrg#define USE_OPENPTY 1
3104d522f475Smrgstatic int opened_tty = -1;
3105d522f475Smrg#endif
3106d522f475Smrg
3107d522f475Smrg/*
3108d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
3109d522f475Smrg *
3110d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
3111d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
3112d522f475Smrg * so that if a pty master is found and later, we find that the slave
3113d522f475Smrg * has problems, we can re-enter this function and get another one.
3114d522f475Smrg */
3115d522f475Smrgstatic int
3116d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
3117d522f475Smrg{
3118d522f475Smrg    int result = 1;
3119d522f475Smrg
31200bd37d32Smrg#if defined(USE_OPENPTY)
31210bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
31222e4f8982Smrg    if (opened_tty >= 0) {
31232e4f8982Smrg	close(opened_tty);
31242e4f8982Smrg	opened_tty = -1;
31252e4f8982Smrg    }
31260bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
31270bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
31280bd37d32Smrg	char *name = ptsname(*pty);
31290bd37d32Smrg	if (name != 0) {
31300bd37d32Smrg	    strcpy(ttydev, name);
31310bd37d32Smrg	    result = 0;
31320bd37d32Smrg	}
31330bd37d32Smrg    }
31340bd37d32Smrg#ifdef USE_PTY_SEARCH
31350bd37d32Smrg    if (result) {
31360bd37d32Smrg	result = pty_search(pty);
31370bd37d32Smrg    }
31380bd37d32Smrg#endif
31390bd37d32Smrg#elif defined(PUCC_PTYD)
3140d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
3141d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
3142d522f475Smrg			       save_ruid, from)) < 0);
3143d522f475Smrg#elif defined(__QNXNTO__)
3144d522f475Smrg    result = pty_search(pty);
3145d522f475Smrg#else
3146d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
3147f2e35a3aSmrg#if defined(__MVS__)
3148d522f475Smrg    result = pty_search(pty);
3149d522f475Smrg#else
31500bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
3151d522f475Smrg#endif
31520bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
31530bd37d32Smrg    if (!result)
31540bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
3155d522f475Smrg#endif
3156d522f475Smrg
3157d522f475Smrg#elif defined(AIXV3)
3158d522f475Smrg
3159d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
3160d522f475Smrg	strcpy(ttydev, ttyname(*pty));
3161d522f475Smrg	result = 0;
3162d522f475Smrg    }
3163d522f475Smrg#elif defined(__convex__)
3164d522f475Smrg
3165d522f475Smrg    char *pty_name;
3166d522f475Smrg    extern char *getpty(void);
3167d522f475Smrg
3168d522f475Smrg    while ((pty_name = getpty()) != NULL) {
3169d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
3170d522f475Smrg	    strcpy(ptydev, pty_name);
3171d522f475Smrg	    strcpy(ttydev, pty_name);
3172d522f475Smrg	    *x_basename(ttydev) = 't';
3173d522f475Smrg	    result = 0;
3174d522f475Smrg	    break;
3175d522f475Smrg	}
3176d522f475Smrg    }
3177d522f475Smrg
3178d522f475Smrg#elif defined(sequent)
3179d522f475Smrg
3180d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
3181d522f475Smrg
3182d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
3183d522f475Smrg
3184d522f475Smrg    char *tty_name;
3185d522f475Smrg
3186d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
3187d522f475Smrg    if (tty_name != 0) {
3188d522f475Smrg	strcpy(ttydev, tty_name);
3189d522f475Smrg	result = 0;
3190d522f475Smrg    }
3191d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
3192d522f475Smrg
3193d522f475Smrg    struct stat fstat_buf;
3194d522f475Smrg
3195d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
3196d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
3197d522f475Smrg	result = 0;
3198d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
3199d522f475Smrg    }
3200d522f475Smrg#elif defined(__hpux)
3201d522f475Smrg
3202d522f475Smrg    /*
3203d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
3204d522f475Smrg     */
3205d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
3206d522f475Smrg	char *name = ptsname(*pty);
3207d522f475Smrg	if (name != 0) {
3208d522f475Smrg	    strcpy(ttydev, name);
3209d522f475Smrg	    result = 0;
3210d522f475Smrg	} else {		/* permissions, or other unexpected problem */
3211d522f475Smrg	    close(*pty);
3212d522f475Smrg	    *pty = -1;
3213d522f475Smrg	    result = pty_search(pty);
3214d522f475Smrg	}
3215d522f475Smrg    } else {
3216d522f475Smrg	result = pty_search(pty);
3217d522f475Smrg    }
3218d522f475Smrg
3219d522f475Smrg#else
3220d522f475Smrg
3221d522f475Smrg    result = pty_search(pty);
3222d522f475Smrg
3223d522f475Smrg#endif
3224d522f475Smrg#endif
3225d522f475Smrg
3226d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
3227d522f475Smrg	   ttydev != 0 ? ttydev : "?",
3228d522f475Smrg	   ptydev != 0 ? ptydev : "?",
3229d522f475Smrg	   result ? "FAIL" : "OK",
3230d522f475Smrg	   pty != 0 ? *pty : -1));
3231d522f475Smrg    return result;
3232d522f475Smrg}
3233d522f475Smrg
3234d522f475Smrgstatic void
3235e0a2b6dfSmrgset_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
3236d522f475Smrg{
3237d522f475Smrg#ifdef USE_TTY_GROUP
3238d522f475Smrg    struct group *ttygrp;
3239d522f475Smrg
3240d522f475Smrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
3241913cc679Smrg	gid = (unsigned) ttygrp->gr_gid;
3242d522f475Smrg	mode &= 0660U;
3243d522f475Smrg    }
3244d522f475Smrg    endgrent();
3245d522f475Smrg#endif /* USE_TTY_GROUP */
3246d522f475Smrg
3247d522f475Smrg    TRACE_IDS;
3248913cc679Smrg    set_owner(ttydev, (unsigned) uid, gid, mode);
3249d522f475Smrg}
3250d522f475Smrg
3251d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
3252d522f475Smrg#undef get_pty
3253d522f475Smrg/*
3254d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
3255d522f475Smrg * result.
3256d522f475Smrg */
3257d522f475Smrgstatic int
3258d522f475Smrgget_pty(int *pty, char *from)
3259d522f475Smrg{
3260d522f475Smrg    static int m_pty = -1;
3261d522f475Smrg    int result = -1;
3262d522f475Smrg
3263d522f475Smrg    if (pty == NULL) {
3264d522f475Smrg	result = really_get_pty(&m_pty, from);
3265d522f475Smrg
3266d522f475Smrg	seteuid(0);
3267d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
3268d522f475Smrg	seteuid(save_ruid);
3269d522f475Smrg	TRACE_IDS;
3270d522f475Smrg
3271d522f475Smrg    } else if (m_pty != -1) {
3272d522f475Smrg	*pty = m_pty;
3273d522f475Smrg	result = 0;
3274d522f475Smrg    } else {
3275d522f475Smrg	result = -1;
3276d522f475Smrg    }
32770bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
32780bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
32790bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
32800bd37d32Smrg	   result ? "FAIL" : "OK",
32810bd37d32Smrg	   pty != 0 ? *pty : -1));
32822e4f8982Smrg#ifdef USE_OPENPTY
32832e4f8982Smrg    if (opened_tty >= 0) {
32842e4f8982Smrg	close(opened_tty);
32852e4f8982Smrg	opened_tty = -1;
32862e4f8982Smrg    }
32872e4f8982Smrg#endif
3288d522f475Smrg    return result;
3289d522f475Smrg}
3290d522f475Smrg#endif
3291d522f475Smrg
3292d522f475Smrg/*
3293d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
3294d522f475Smrg * we might allocate.  Used on those systems that do not have
3295d522f475Smrg * a functional interface for allocating a pty.
3296d522f475Smrg * Returns 0 if found a pty, 1 if fails.
3297d522f475Smrg */
3298d522f475Smrg#ifdef USE_PTY_SEARCH
3299d522f475Smrgstatic int
3300d522f475Smrgpty_search(int *pty)
3301d522f475Smrg{
3302d522f475Smrg    static int devindex = 0, letter = 0;
3303d522f475Smrg
3304d522f475Smrg#if defined(CRAY) || defined(__MVS__)
3305d522f475Smrg    while (devindex < MAXPTTYS) {
3306d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
3307d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
3308d522f475Smrg	devindex++;
3309d522f475Smrg
3310d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
3311d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
3312d522f475Smrg	    return 0;
3313d522f475Smrg	}
3314d522f475Smrg    }
3315d522f475Smrg#else /* CRAY || __MVS__ */
3316d522f475Smrg    while (PTYCHAR1[letter]) {
3317d522f475Smrg	ttydev[strlen(ttydev) - 2] =
3318d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
3319d522f475Smrg
3320d522f475Smrg	while (PTYCHAR2[devindex]) {
3321d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
3322d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
3323d522f475Smrg	    devindex++;
3324d522f475Smrg
3325d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
3326d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
3327d522f475Smrg#ifdef sun
3328d522f475Smrg		/* Need to check the process group of the pty.
3329d522f475Smrg		 * If it exists, then the slave pty is in use,
3330d522f475Smrg		 * and we need to get another one.
3331d522f475Smrg		 */
3332d522f475Smrg		int pgrp_rtn;
3333d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
3334d522f475Smrg		    close(*pty);
3335d522f475Smrg		    continue;
3336d522f475Smrg		}
3337d522f475Smrg#endif /* sun */
3338d522f475Smrg		return 0;
3339d522f475Smrg	    }
3340d522f475Smrg	}
3341d522f475Smrg	devindex = 0;
3342d522f475Smrg	letter++;
3343d522f475Smrg    }
3344d522f475Smrg#endif /* CRAY else */
3345d522f475Smrg    /*
3346d522f475Smrg     * We were unable to allocate a pty master!  Return an error
3347d522f475Smrg     * condition and let our caller terminate cleanly.
3348d522f475Smrg     */
3349d522f475Smrg    return 1;
3350d522f475Smrg}
3351d522f475Smrg#endif /* USE_PTY_SEARCH */
3352d522f475Smrg
3353d522f475Smrg/*
3354d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
3355d522f475Smrg * the latter has support for switching character sets.  We support the
3356d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
3357d522f475Smrg * choose 4014 over 4015.
3358d522f475Smrg *
3359d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
3360d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
3361d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
3362d522f475Smrg * later Tektronix terminals), and 4 character sizes.
3363d522f475Smrg * All of these are supported by xterm.
3364d522f475Smrg */
3365d522f475Smrg
3366d522f475Smrg#if OPT_TEK4014
336701037d57Smrgstatic const char *const tekterm[] =
3368d522f475Smrg{
3369d522f475Smrg    "tek4014",
3370d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
3371d522f475Smrg    "tek4012",			/* 4010 with lower case */
3372d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
3373d522f475Smrg    "tek4010",			/* small screen, upper-case only */
3374d522f475Smrg    "dumb",
3375d522f475Smrg    0
3376d522f475Smrg};
3377d522f475Smrg#endif
3378d522f475Smrg
3379d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
3380d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
3381d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
3382d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
3383d522f475Smrg * The VT420 has up to 48 lines on the screen.
3384d522f475Smrg */
3385d522f475Smrg
338601037d57Smrgstatic const char *const vtterm[] =
3387d522f475Smrg{
3388d522f475Smrg#ifdef USE_X11TERM
3389d522f475Smrg    "x11term",			/* for people who want special term name */
3390d522f475Smrg#endif
3391d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
3392f2e35a3aSmrg    "xterm",			/* the preferred name, should be fastest */
3393d522f475Smrg    "vt102",
3394d522f475Smrg    "vt100",
3395d522f475Smrg    "ansi",
3396d522f475Smrg    "dumb",
3397d522f475Smrg    0
3398d522f475Smrg};
3399d522f475Smrg
3400d522f475Smrg/* ARGSUSED */
34010bd37d32Smrgstatic void
3402d522f475Smrghungtty(int i GCC_UNUSED)
3403d522f475Smrg{
34040bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
3405d522f475Smrg    siglongjmp(env, 1);
3406d522f475Smrg}
3407d522f475Smrg
3408d522f475Smrg#if OPT_PTY_HANDSHAKE
3409d522f475Smrg#define NO_FDS {-1, -1}
3410d522f475Smrg
3411d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
3412d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
3413d522f475Smrg
3414d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
3415d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
3416d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
3417d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
3418d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
3419d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
3420d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
3421d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
3422d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
3423d522f475Smrg} status_t;
3424d522f475Smrg
3425f2e35a3aSmrg#define HANDSHAKE_LEN	1024
3426f2e35a3aSmrg
3427d522f475Smrgtypedef struct {
3428d522f475Smrg    status_t status;
3429d522f475Smrg    int error;
3430d522f475Smrg    int fatal_error;
3431d522f475Smrg    int tty_slot;
3432d522f475Smrg    int rows;
3433d522f475Smrg    int cols;
3434f2e35a3aSmrg    char buffer[HANDSHAKE_LEN];
3435d522f475Smrg} handshake_t;
3436d522f475Smrg
3437f2e35a3aSmrg/* the buffer is large enough that we can always have a trailing null */
3438f2e35a3aSmrg#define copy_handshake(dst, src) \
3439f2e35a3aSmrg	strncpy(dst.buffer, src, (size_t)HANDSHAKE_LEN - 1)[HANDSHAKE_LEN - 1] = '\0'
3440f2e35a3aSmrg
3441d522f475Smrg#if OPT_TRACE
3442d522f475Smrgstatic void
3443d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
3444d522f475Smrg{
3445d522f475Smrg    const char *status = "?";
3446d522f475Smrg    switch (data->status) {
3447d522f475Smrg    case PTY_BAD:
3448d522f475Smrg	status = "PTY_BAD";
3449d522f475Smrg	break;
3450d522f475Smrg    case PTY_FATALERROR:
3451d522f475Smrg	status = "PTY_FATALERROR";
3452d522f475Smrg	break;
3453d522f475Smrg    case PTY_GOOD:
3454d522f475Smrg	status = "PTY_GOOD";
3455d522f475Smrg	break;
3456d522f475Smrg    case PTY_NEW:
3457d522f475Smrg	status = "PTY_NEW";
3458d522f475Smrg	break;
3459d522f475Smrg    case PTY_NOMORE:
3460d522f475Smrg	status = "PTY_NOMORE";
3461d522f475Smrg	break;
3462d522f475Smrg    case UTMP_ADDED:
3463d522f475Smrg	status = "UTMP_ADDED";
3464d522f475Smrg	break;
3465d522f475Smrg    case UTMP_TTYSLOT:
3466d522f475Smrg	status = "UTMP_TTYSLOT";
3467d522f475Smrg	break;
3468d522f475Smrg    case PTY_EXEC:
3469d522f475Smrg	status = "PTY_EXEC";
3470d522f475Smrg	break;
3471d522f475Smrg    }
3472d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
3473d522f475Smrg	   tag,
3474d522f475Smrg	   status,
3475d522f475Smrg	   data->error,
3476d522f475Smrg	   data->fatal_error,
3477d522f475Smrg	   data->buffer));
3478d522f475Smrg}
3479d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
3480d522f475Smrg#else
3481d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
3482d522f475Smrg#endif
3483d522f475Smrg
3484d522f475Smrg/* HsSysError()
3485d522f475Smrg *
3486d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
3487d522f475Smrg * over the errno and error exit to the master process so that it can
3488d522f475Smrg * display our error message and exit with our exit code so that the
3489d522f475Smrg * user can see it.
3490d522f475Smrg */
3491d522f475Smrg
3492d522f475Smrgstatic void
3493d522f475SmrgHsSysError(int error)
3494d522f475Smrg{
3495d522f475Smrg    handshake_t handshake;
3496d522f475Smrg
3497d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3498d522f475Smrg    handshake.status = PTY_FATALERROR;
3499d522f475Smrg    handshake.error = errno;
3500d522f475Smrg    handshake.fatal_error = error;
3501f2e35a3aSmrg    copy_handshake(handshake, ttydev);
3502d522f475Smrg
3503d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
3504d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
3505d522f475Smrg	       handshake.error,
3506d522f475Smrg	       handshake.fatal_error,
3507d522f475Smrg	       handshake.buffer));
3508d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
350920d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
351020d2c4d2Smrg			(const char *) &handshake,
351120d2c4d2Smrg			sizeof(handshake)));
3512d522f475Smrg    } else {
35130bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
35140bd37d32Smrg		     handshake.error,
35150bd37d32Smrg		     handshake.fatal_error,
35160bd37d32Smrg		     handshake.buffer);
3517d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3518d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3519d522f475Smrg    }
3520d522f475Smrg    exit(error);
3521d522f475Smrg}
3522d522f475Smrg
3523d522f475Smrgvoid
3524d522f475Smrgfirst_map_occurred(void)
3525d522f475Smrg{
3526d522f475Smrg    if (resource.wait_for_map) {
3527913cc679Smrg	if (pc_pipe[1] >= 0) {
3528913cc679Smrg	    handshake_t handshake;
3529913cc679Smrg	    TScreen *screen = TScreenOf(term);
3530d522f475Smrg
3531913cc679Smrg	    memset(&handshake, 0, sizeof(handshake));
3532913cc679Smrg	    handshake.status = PTY_EXEC;
3533913cc679Smrg	    handshake.rows = screen->max_row;
3534913cc679Smrg	    handshake.cols = screen->max_col;
3535d522f475Smrg
3536913cc679Smrg	    TRACE(("first_map_occurred: %dx%d\n", MaxRows(screen), MaxCols(screen)));
3537d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
353820d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
353920d2c4d2Smrg			    (const char *) &handshake,
354020d2c4d2Smrg			    sizeof(handshake)));
3541d522f475Smrg	    close(cp_pipe[0]);
3542d522f475Smrg	    close(pc_pipe[1]);
3543d522f475Smrg	}
3544d522f475Smrg	resource.wait_for_map = False;
3545d522f475Smrg    }
3546d522f475Smrg}
3547d522f475Smrg#else
3548d522f475Smrg/*
3549d522f475Smrg * temporary hack to get xterm working on att ptys
3550d522f475Smrg */
3551d522f475Smrgstatic void
3552d522f475SmrgHsSysError(int error)
3553d522f475Smrg{
35540bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
35550bd37d32Smrg		 error, errno, ttydev);
3556d522f475Smrg    exit(error);
3557d522f475Smrg}
3558d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3559d522f475Smrg
3560d522f475Smrg#ifndef VMS
3561d522f475Smrgstatic void
3562e0a2b6dfSmrgset_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
3563d522f475Smrg{
3564d522f475Smrg    int why;
3565d522f475Smrg
3566d522f475Smrg    TRACE_IDS;
356720d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
35680bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3569d522f475Smrg
3570913cc679Smrg    if (chown(device, (uid_t) uid, (gid_t) gid) < 0) {
3571d522f475Smrg	why = errno;
3572d522f475Smrg	if (why != ENOENT
3573d522f475Smrg	    && save_ruid == 0) {
35740bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
35750bd37d32Smrg			device, (long) uid, (long) gid);
3576d522f475Smrg	}
3577d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3578913cc679Smrg    } else if (chmod(device, (mode_t) mode) < 0) {
3579d522f475Smrg	why = errno;
3580d522f475Smrg	if (why != ENOENT) {
3581d522f475Smrg	    struct stat sb;
3582d522f475Smrg	    if (stat(device, &sb) < 0) {
35830bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
35840bd37d32Smrg			    device, (unsigned) mode);
3585d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
35860bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
35870bd37d32Smrg			    device,
35880bd37d32Smrg			    (unsigned long) mode,
35890bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3590d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
35910bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3592d522f475Smrg	    }
3593d522f475Smrg	}
3594d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3595d522f475Smrg    }
3596d522f475Smrg}
3597d522f475Smrg
3598894e0ac8Smrg/*
3599894e0ac8Smrg * utmp data may not be null-terminated; even if it is, there may be garbage
3600894e0ac8Smrg * after the null.  This fills the unused part of the result with nulls.
3601894e0ac8Smrg */
3602894e0ac8Smrgstatic void
3603894e0ac8Smrgcopy_filled(char *target, const char *source, size_t len)
3604894e0ac8Smrg{
3605894e0ac8Smrg    size_t used = 0;
3606894e0ac8Smrg    while (used < len) {
3607894e0ac8Smrg	if ((target[used] = source[used]) == 0)
3608894e0ac8Smrg	    break;
3609894e0ac8Smrg	++used;
3610894e0ac8Smrg    }
3611894e0ac8Smrg    while (used < len) {
3612894e0ac8Smrg	target[used++] = '\0';
3613894e0ac8Smrg    }
3614894e0ac8Smrg}
3615894e0ac8Smrg
3616d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3617d522f475Smrg/*
3618d522f475Smrg * getutid() only looks at ut_type and ut_id.
3619d522f475Smrg * But we'll also check ut_line in find_utmp().
3620d522f475Smrg */
3621d522f475Smrgstatic void
3622d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3623d522f475Smrg{
3624d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3625913cc679Smrg    tofind->ut_type = (short) type;
3626894e0ac8Smrg    copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3627894e0ac8Smrg    copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3628d522f475Smrg}
3629d522f475Smrg
3630d522f475Smrg/*
3631d522f475Smrg * We could use getutline() if we didn't support old systems.
3632d522f475Smrg */
3633d522f475Smrgstatic struct UTMP_STR *
3634d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3635d522f475Smrg{
3636d522f475Smrg    struct UTMP_STR *result;
36370bd37d32Smrg    struct UTMP_STR limited;
3638d522f475Smrg    struct UTMP_STR working;
3639d522f475Smrg
3640d522f475Smrg    for (;;) {
3641d522f475Smrg	memset(&working, 0, sizeof(working));
3642d522f475Smrg	working.ut_type = tofind->ut_type;
3643894e0ac8Smrg	copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3644d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3645d522f475Smrg	working.ut_type = 0;
3646d522f475Smrg#endif
3647d522f475Smrg	if ((result = call_getutid(&working)) == 0)
3648d522f475Smrg	    break;
3649894e0ac8Smrg	copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line));
36500bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3651d522f475Smrg	    break;
3652d522f475Smrg	/*
3653d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3654d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3655d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3656d522f475Smrg	 */
3657d522f475Smrg	memset(result, 0, sizeof(*result));
3658d522f475Smrg    }
3659d522f475Smrg    return result;
3660d522f475Smrg}
3661d522f475Smrg#endif /* HAVE_UTMP... */
3662d522f475Smrg
3663d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3664d522f475Smrg
366520d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
366620d2c4d2Smrg#define USE_NO_DEV_TTY 1
366720d2c4d2Smrg#else
366820d2c4d2Smrg#define USE_NO_DEV_TTY 0
366920d2c4d2Smrg#endif
367020d2c4d2Smrg
3671e0a2b6dfSmrgstatic int
3672e0a2b6dfSmrgsame_leaf(char *a, char *b)
3673e0a2b6dfSmrg{
3674e0a2b6dfSmrg    char *p = x_basename(a);
3675e0a2b6dfSmrg    char *q = x_basename(b);
3676e0a2b6dfSmrg    return !strcmp(p, q);
3677e0a2b6dfSmrg}
3678e0a2b6dfSmrg
3679e0a2b6dfSmrg/*
3680e0a2b6dfSmrg * "good enough" (inode wouldn't port to Cygwin)
3681e0a2b6dfSmrg */
3682e0a2b6dfSmrgstatic int
3683e0a2b6dfSmrgsame_file(const char *a, const char *b)
3684e0a2b6dfSmrg{
3685e0a2b6dfSmrg    struct stat asb;
3686e0a2b6dfSmrg    struct stat bsb;
3687e0a2b6dfSmrg    int result = 0;
3688e0a2b6dfSmrg
3689e0a2b6dfSmrg    if ((stat(a, &asb) == 0)
3690e0a2b6dfSmrg	&& (stat(b, &bsb) == 0)
3691e0a2b6dfSmrg	&& ((asb.st_mode & S_IFMT) == S_IFREG)
3692e0a2b6dfSmrg	&& ((bsb.st_mode & S_IFMT) == S_IFREG)
3693e0a2b6dfSmrg	&& (asb.st_mtime == bsb.st_mtime)
3694e0a2b6dfSmrg	&& (asb.st_size == bsb.st_size)) {
3695e0a2b6dfSmrg	result = 1;
3696e0a2b6dfSmrg    }
3697e0a2b6dfSmrg    return result;
3698e0a2b6dfSmrg}
3699e0a2b6dfSmrg
3700f2e35a3aSmrgstatic int
3701f2e35a3aSmrgfindValidShell(const char *haystack, const char *needle)
3702f2e35a3aSmrg{
3703f2e35a3aSmrg    int result = -1;
3704f2e35a3aSmrg    int count = -1;
3705f2e35a3aSmrg    const char *s, *t;
3706f2e35a3aSmrg    size_t have;
3707f2e35a3aSmrg    size_t want = strlen(needle);
3708f2e35a3aSmrg
3709f2e35a3aSmrg    TRACE(("findValidShell:\n%s\n", NonNull(haystack)));
3710f2e35a3aSmrg
3711f2e35a3aSmrg    for (s = haystack; (s != 0) && (*s != '\0'); s = t) {
3712f2e35a3aSmrg	++count;
3713f2e35a3aSmrg	if ((t = strchr(s, '\n')) == 0) {
3714f2e35a3aSmrg	    t = s + strlen(s);
3715f2e35a3aSmrg	}
3716f2e35a3aSmrg	have = (size_t) (t - s);
3717f2e35a3aSmrg
3718f2e35a3aSmrg	if ((have >= want) && (*s != '#')) {
37195307cd1aSmrg	    char *p = (char *) malloc(have + 1);
3720f2e35a3aSmrg
3721f2e35a3aSmrg	    if (p != 0) {
3722f2e35a3aSmrg		char *q;
3723f2e35a3aSmrg
3724f2e35a3aSmrg		memcpy(p, s, have);
3725f2e35a3aSmrg		p[have] = '\0';
3726f2e35a3aSmrg		if ((q = x_strtrim(p)) != 0) {
3727f2e35a3aSmrg		    TRACE(("...test %s\n", q));
3728f2e35a3aSmrg		    if (!strcmp(q, needle)) {
3729f2e35a3aSmrg			result = count;
3730f2e35a3aSmrg		    } else if (same_leaf(q, (char *) needle) &&
3731f2e35a3aSmrg			       same_file(q, needle)) {
3732f2e35a3aSmrg			result = count;
3733f2e35a3aSmrg		    }
3734f2e35a3aSmrg		    free(q);
3735f2e35a3aSmrg		}
3736f2e35a3aSmrg		free(p);
3737f2e35a3aSmrg	    }
3738f2e35a3aSmrg	    if (result >= 0)
3739f2e35a3aSmrg		break;
3740f2e35a3aSmrg	}
3741f2e35a3aSmrg	while (*t == '\n') {
3742f2e35a3aSmrg	    ++t;
3743f2e35a3aSmrg	}
3744f2e35a3aSmrg    }
3745f2e35a3aSmrg    return result;
3746f2e35a3aSmrg}
3747f2e35a3aSmrg
3748f2e35a3aSmrgstatic int
3749f2e35a3aSmrgourValidShell(const char *pathname)
3750f2e35a3aSmrg{
375104b94745Smrg    char *trimmed = x_strtrim(resource.valid_shells);
375204b94745Smrg    int result = findValidShell(trimmed, pathname);
375304b94745Smrg    free(trimmed);
375404b94745Smrg    return result;
3755f2e35a3aSmrg}
3756f2e35a3aSmrg
3757f2e35a3aSmrg#if defined(HAVE_GETUSERSHELL) && defined(HAVE_ENDUSERSHELL)
3758f2e35a3aSmrgstatic Boolean
3759f2e35a3aSmrgvalidShell(const char *pathname)
3760f2e35a3aSmrg{
3761f2e35a3aSmrg    int result = -1;
3762f2e35a3aSmrg
3763f2e35a3aSmrg    if (validProgram(pathname)) {
3764f2e35a3aSmrg	char *q;
3765f2e35a3aSmrg	int count = -1;
3766f2e35a3aSmrg
3767f2e35a3aSmrg	TRACE(("validShell:getusershell\n"));
3768f2e35a3aSmrg	while ((q = getusershell()) != 0) {
3769f2e35a3aSmrg	    ++count;
3770f2e35a3aSmrg	    TRACE(("...test \"%s\"\n", q));
3771f2e35a3aSmrg	    if (!strcmp(q, pathname)) {
3772f2e35a3aSmrg		result = count;
3773f2e35a3aSmrg		break;
3774f2e35a3aSmrg	    }
3775f2e35a3aSmrg	}
3776f2e35a3aSmrg	endusershell();
3777f2e35a3aSmrg
3778f2e35a3aSmrg	if (result < 0)
3779f2e35a3aSmrg	    result = ourValidShell(pathname);
3780f2e35a3aSmrg    }
3781f2e35a3aSmrg
3782f2e35a3aSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3783f2e35a3aSmrg    return (result >= 0);
3784f2e35a3aSmrg}
3785f2e35a3aSmrg#else
3786e0a2b6dfSmrg/*
3787e0a2b6dfSmrg * Only set $SHELL for paths found in the standard location.
3788e0a2b6dfSmrg */
3789e0a2b6dfSmrgstatic Boolean
3790e0a2b6dfSmrgvalidShell(const char *pathname)
3791e0a2b6dfSmrg{
3792f2e35a3aSmrg    int result = -1;
3793e0a2b6dfSmrg    const char *ok_shells = "/etc/shells";
3794e0a2b6dfSmrg    char *blob;
3795e0a2b6dfSmrg    struct stat sb;
3796e0a2b6dfSmrg    size_t rc;
3797e0a2b6dfSmrg    FILE *fp;
3798e0a2b6dfSmrg
3799f2e35a3aSmrg    if (validProgram(pathname)) {
3800f2e35a3aSmrg
3801f2e35a3aSmrg	TRACE(("validShell:%s\n", ok_shells));
3802f2e35a3aSmrg
3803f2e35a3aSmrg	if (stat(ok_shells, &sb) == 0
3804f2e35a3aSmrg	    && (sb.st_mode & S_IFMT) == S_IFREG
3805f2e35a3aSmrg	    && ((size_t) sb.st_size > 0)
3806f2e35a3aSmrg	    && ((size_t) sb.st_size < (((size_t) ~0) - 2))
3807f2e35a3aSmrg	    && (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
3808f2e35a3aSmrg
3809f2e35a3aSmrg	    if ((fp = fopen(ok_shells, "r")) != 0) {
3810f2e35a3aSmrg		rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
3811f2e35a3aSmrg		fclose(fp);
3812f2e35a3aSmrg
3813f2e35a3aSmrg		if (rc == (size_t) sb.st_size) {
3814f2e35a3aSmrg		    blob[rc] = '\0';
3815f2e35a3aSmrg		    result = findValidShell(blob, pathname);
3816e0a2b6dfSmrg		}
3817e0a2b6dfSmrg	    }
3818f2e35a3aSmrg	    free(blob);
3819e0a2b6dfSmrg	}
3820f2e35a3aSmrg	if (result < 0)
3821f2e35a3aSmrg	    result = ourValidShell(pathname);
3822e0a2b6dfSmrg    }
3823e0a2b6dfSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3824f2e35a3aSmrg    return (result > 0);
3825e0a2b6dfSmrg}
3826f2e35a3aSmrg#endif
3827e0a2b6dfSmrg
3828e0a2b6dfSmrgstatic char *
3829e0a2b6dfSmrgresetShell(char *oldPath)
3830e0a2b6dfSmrg{
3831e0a2b6dfSmrg    char *newPath = x_strdup("/bin/sh");
3832e0a2b6dfSmrg    char *envPath = getenv("SHELL");
3833f2e35a3aSmrg    free(oldPath);
3834e0a2b6dfSmrg    if (!IsEmpty(envPath))
3835e0a2b6dfSmrg	xtermSetenv("SHELL", newPath);
3836e0a2b6dfSmrg    return newPath;
3837e0a2b6dfSmrg}
3838e0a2b6dfSmrg
38394419d26bSmrg/*
38404419d26bSmrg * Trim unwanted environment variables:
38414419d26bSmrg *
38424419d26bSmrg * DESKTOP_STARTUP_ID
38434419d26bSmrg *	standards.freedesktop.org/startup-notification-spec/
38444419d26bSmrg * notes that this variable is used when a "reliable" mechanism is
38454419d26bSmrg * not available; in practice it must be unset to avoid confusing
38464419d26bSmrg * GTK applications.
38474419d26bSmrg *
38484419d26bSmrg * XCURSOR_PATH
38494419d26bSmrg * We set this temporarily to work around poor design of Xcursor.  Unset it
38504419d26bSmrg * here to avoid confusion.
38514419d26bSmrg *
38524419d26bSmrg * Other...
38534419d26bSmrg * These are set by other terminal emulators or non-standard libraries, and are
38544419d26bSmrg * a nuisance if one starts xterm from a shell inside one of those.
38554419d26bSmrg */
38564419d26bSmrgstatic void
38574419d26bSmrgxtermTrimEnv(void)
38584419d26bSmrg{
38595307cd1aSmrg#define KEEP(wild,name) { 0, wild, #name }
38605307cd1aSmrg#define TRIM(wild,name) { 1, wild, #name }
38615307cd1aSmrg    /* *INDENT-OFF* */
38625307cd1aSmrg    static const struct {
38635307cd1aSmrg	int trim;
38644419d26bSmrg	int wild;
38654419d26bSmrg	const char *name;
38664419d26bSmrg    } table[] = {
38675307cd1aSmrg	TRIM(0, COLUMNS),
38685307cd1aSmrg	TRIM(0, DEFAULT_COLORS),
38695307cd1aSmrg	TRIM(0, DESKTOP_STARTUP_ID),
38705307cd1aSmrg	TRIM(0, LINES),
38715307cd1aSmrg	TRIM(0, SHLVL),		/* ksh, bash */
38725307cd1aSmrg	TRIM(0, STY),		/* screen */
38735307cd1aSmrg	TRIM(0, TERMCAP),
38745307cd1aSmrg	TRIM(0, TMUX),
38755307cd1aSmrg	TRIM(0, TMUX_PANE),
38765307cd1aSmrg	TRIM(0, WCWIDTH_CJK_LEGACY),
38775307cd1aSmrg	TRIM(0, WINDOW),	/* screen */
38785307cd1aSmrg	TRIM(0, XCURSOR_PATH),
38795307cd1aSmrg	KEEP(0, MC_XDG_OPEN),
38805307cd1aSmrg	TRIM(1, COLORFGBG),
38815307cd1aSmrg	TRIM(1, COLORTERM),
38825307cd1aSmrg	TRIM(1, GIO_LAUNCHED_),
38835307cd1aSmrg	TRIM(1, ITERM2_),
38845307cd1aSmrg	TRIM(1, MC_),
38855307cd1aSmrg	TRIM(1, MINTTY_),
38865307cd1aSmrg	TRIM(1, PUTTY),
38875307cd1aSmrg	TRIM(1, RXVT_),
38885307cd1aSmrg	TRIM(1, TERM_),
38895307cd1aSmrg	TRIM(1, URXVT_),
38905307cd1aSmrg	TRIM(1, VTE_),
38915307cd1aSmrg	TRIM(1, XTERM_),
38924419d26bSmrg    };
38935307cd1aSmrg#undef TRIM
38945307cd1aSmrg    /* *INDENT-ON* */
38955307cd1aSmrg    Cardinal j, k;
38965307cd1aSmrg
38975307cd1aSmrg    for (j = 0; environ[j] != NULL; ++j) {
38985307cd1aSmrg	char *equals = strchr(environ[j], '=');
38995307cd1aSmrg	size_t dstlen = strlen(environ[j]);
39005307cd1aSmrg
39015307cd1aSmrg	if (equals != NULL)
39025307cd1aSmrg	    dstlen = (size_t) (equals - environ[j]);
39035307cd1aSmrg
39045307cd1aSmrg	for (k = 0; k < XtNumber(table); ++k) {
39055307cd1aSmrg	    size_t srclen = strlen(table[k].name);
39065307cd1aSmrg	    if (table[k].wild) {
39075307cd1aSmrg		if (dstlen >= srclen &&
39085307cd1aSmrg		    !strncmp(environ[j], table[k].name, srclen)) {
39094419d26bSmrg		    char *my_var;
39105307cd1aSmrg		    if (table[k].trim &&
39115307cd1aSmrg			(my_var = x_strdup(environ[j])) != NULL) {
39124419d26bSmrg			my_var[dstlen] = '\0';
39134419d26bSmrg			xtermUnsetenv(my_var);
39144419d26bSmrg			free(my_var);
391504b94745Smrg			/* When removing an entry, check the same slot again. */
391604b94745Smrg			j--;
39174419d26bSmrg		    }
39185307cd1aSmrg		    break;
39194419d26bSmrg		}
39205307cd1aSmrg	    } else if (dstlen == srclen &&
39215307cd1aSmrg		       !strncmp(environ[j], table[k].name, srclen)) {
392204b94745Smrg		if (table[k].trim) {
39235307cd1aSmrg		    xtermUnsetenv(table[k].name);
392404b94745Smrg		    /* When removing an entry, check the same slot again. */
392504b94745Smrg		    j--;
392604b94745Smrg		}
39275307cd1aSmrg		break;
39284419d26bSmrg	    }
39294419d26bSmrg	}
39304419d26bSmrg    }
39314419d26bSmrg}
39324419d26bSmrg
3933d522f475Smrg/*
3934d522f475Smrg *  Inits pty and tty and forks a login process.
3935d522f475Smrg *  Does not close fd Xsocket.
3936d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3937d522f475Smrg */
3938d522f475Smrgstatic int
39392e4f8982SmrgspawnXTerm(XtermWidget xw, unsigned line_speed)
3940d522f475Smrg{
3941d522f475Smrg    TScreen *screen = TScreenOf(xw);
3942d522f475Smrg    Cardinal nn;
3943d522f475Smrg#if OPT_PTY_HANDSHAKE
3944d522f475Smrg    Bool got_handshake_size = False;
3945d522f475Smrg    handshake_t handshake;
3946d522f475Smrg    int done;
3947d522f475Smrg#endif
3948d522f475Smrg#if OPT_INITIAL_ERASE
39495307cd1aSmrg    int initial_erase = XTERM_ERASE;
3950d522f475Smrg    Bool setInitialErase;
3951d522f475Smrg#endif
3952d522f475Smrg    int rc = 0;
3953d522f475Smrg    int ttyfd = -1;
3954d522f475Smrg    Bool ok_termcap;
3955d522f475Smrg    char *newtc;
3956d522f475Smrg
3957d522f475Smrg#ifdef TERMIO_STRUCT
3958d522f475Smrg    TERMIO_STRUCT tio;
3959d522f475Smrg#ifdef __MVS__
3960d522f475Smrg    TERMIO_STRUCT gio;
3961d522f475Smrg#endif /* __MVS__ */
3962d522f475Smrg#ifdef TIOCLSET
3963d522f475Smrg    unsigned lmode;
3964d522f475Smrg#endif /* TIOCLSET */
3965d522f475Smrg#ifdef HAS_LTCHARS
3966d522f475Smrg    struct ltchars ltc;
3967d522f475Smrg#endif /* HAS_LTCHARS */
3968d522f475Smrg#else /* !TERMIO_STRUCT */
3969d522f475Smrg    int ldisc = 0;
3970d522f475Smrg    int discipline;
3971d522f475Smrg    unsigned lmode;
3972d522f475Smrg    struct tchars tc;
3973d522f475Smrg    struct ltchars ltc;
3974d522f475Smrg    struct sgttyb sg;
3975d522f475Smrg#ifdef sony
3976d522f475Smrg    int jmode;
3977d522f475Smrg    struct jtchars jtc;
3978d522f475Smrg#endif /* sony */
3979d522f475Smrg#endif /* TERMIO_STRUCT */
3980d522f475Smrg
39810bd37d32Smrg    char *shell_path = 0;
39820bd37d32Smrg    char *shname, *shname_minus;
398320d2c4d2Smrg    int i;
398420d2c4d2Smrg#if USE_NO_DEV_TTY
398520d2c4d2Smrg    int no_dev_tty = False;
398620d2c4d2Smrg#endif
398701037d57Smrg    const char *const *envnew;	/* new environment */
3988d522f475Smrg    char buf[64];
3989d522f475Smrg    char *TermName = NULL;
3990d522f475Smrg#ifdef TTYSIZE_STRUCT
3991d522f475Smrg    TTYSIZE_STRUCT ts;
3992d522f475Smrg#endif
39930bd37d32Smrg    struct passwd pw;
3994d522f475Smrg    char *login_name = NULL;
3995d522f475Smrg#ifndef USE_UTEMPTER
3996d522f475Smrg#ifdef HAVE_UTMP
3997d522f475Smrg    struct UTMP_STR utmp;
3998d522f475Smrg#ifdef USE_SYSV_UTMP
3999d522f475Smrg    struct UTMP_STR *utret = NULL;
4000d522f475Smrg#endif
4001d522f475Smrg#ifdef USE_LASTLOG
4002d522f475Smrg    struct lastlog lastlog;
4003d522f475Smrg#endif
4004d522f475Smrg#ifdef USE_LASTLOGX
4005d522f475Smrg    struct lastlogx lastlogx;
4006d522f475Smrg#endif /* USE_LASTLOG */
4007d522f475Smrg#endif /* HAVE_UTMP */
4008d522f475Smrg#endif /* !USE_UTEMPTER */
4009d522f475Smrg
4010e39b573cSmrg#if OPT_TRACE
4011e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
4012e39b573cSmrg#endif
4013e39b573cSmrg
4014d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
4015d522f475Smrg    (void) rc;
4016d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
4017d522f475Smrg    (void) utret;
4018d522f475Smrg#endif
4019d522f475Smrg
4020d522f475Smrg    screen->uid = save_ruid;
4021d522f475Smrg    screen->gid = save_rgid;
4022d522f475Smrg
4023d522f475Smrg#ifdef SIGTTOU
4024d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
4025d522f475Smrg    signal(SIGTTOU, SIG_IGN);
4026d522f475Smrg#endif
4027d522f475Smrg
4028d522f475Smrg#if OPT_PTY_HANDSHAKE
4029d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
4030d522f475Smrg#endif
4031d522f475Smrg
4032d522f475Smrg    if (am_slave >= 0) {
4033d522f475Smrg	screen->respond = am_slave;
4034d522f475Smrg	set_pty_id(ttydev, passedPty);
4035d522f475Smrg#ifdef USE_PTY_DEVICE
4036d522f475Smrg	set_pty_id(ptydev, passedPty);
4037d522f475Smrg#endif
4038d522f475Smrg	if (xtermResetIds(screen) < 0)
403904b94745Smrg	    exit(ERROR_MISC);
4040d522f475Smrg    } else {
4041d522f475Smrg	Bool tty_got_hung;
4042d522f475Smrg
4043d522f475Smrg	/*
4044d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
4045d522f475Smrg	 * that has gone away).  Simply make up some reasonable
4046d522f475Smrg	 * defaults.
4047d522f475Smrg	 */
4048d522f475Smrg
4049d522f475Smrg	if (!sigsetjmp(env, 1)) {
4050913cc679Smrg	    signal(SIGALRM, hungtty);
4051913cc679Smrg	    alarm(2);		/* alarm(1) might return too soon */
4052d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
4053d522f475Smrg	    alarm(0);
4054d522f475Smrg	    tty_got_hung = False;
4055d522f475Smrg	} else {
4056d522f475Smrg	    tty_got_hung = True;
4057d522f475Smrg	    ttyfd = -1;
4058d522f475Smrg	    errno = ENXIO;
4059d522f475Smrg	}
40602e4f8982Smrg	shell_path = 0;
40610bd37d32Smrg	memset(&pw, 0, sizeof(pw));
4062d522f475Smrg#if OPT_PTY_HANDSHAKE
4063d522f475Smrg	got_handshake_size = False;
4064d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4065d522f475Smrg#if OPT_INITIAL_ERASE
40665307cd1aSmrg	initial_erase = XTERM_ERASE;
4067d522f475Smrg#endif
4068d522f475Smrg	signal(SIGALRM, SIG_DFL);
4069d522f475Smrg
4070d522f475Smrg	/*
4071d522f475Smrg	 * Check results and ignore current control terminal if
4072d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
4073d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
4074d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
40750bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
40760bd37d32Smrg	 * if xterm is run within a jail.
4077d522f475Smrg	 */
407820d2c4d2Smrg#if USE_NO_DEV_TTY
4079d522f475Smrg	no_dev_tty = False;
408020d2c4d2Smrg#endif
4081d522f475Smrg	if (ttyfd < 0) {
4082d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
40830bd37d32Smrg		errno == ENOENT ||
4084d522f475Smrg#ifdef ENODEV
4085d522f475Smrg		errno == ENODEV ||
4086d522f475Smrg#endif
4087d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
408820d2c4d2Smrg#if USE_NO_DEV_TTY
4089d522f475Smrg		no_dev_tty = True;
409020d2c4d2Smrg#endif
4091d522f475Smrg#ifdef HAS_LTCHARS
4092d522f475Smrg		ltc = d_ltc;
4093d522f475Smrg#endif /* HAS_LTCHARS */
4094d522f475Smrg#ifdef TIOCLSET
4095d522f475Smrg		lmode = d_lmode;
4096d522f475Smrg#endif /* TIOCLSET */
4097d522f475Smrg#ifdef TERMIO_STRUCT
4098d522f475Smrg		tio = d_tio;
4099d522f475Smrg#else /* !TERMIO_STRUCT */
4100d522f475Smrg		sg = d_sg;
4101d522f475Smrg		tc = d_tc;
4102d522f475Smrg		discipline = d_disipline;
4103d522f475Smrg#ifdef sony
4104d522f475Smrg		jmode = d_jmode;
4105d522f475Smrg		jtc = d_jtc;
4106d522f475Smrg#endif /* sony */
4107d522f475Smrg#endif /* TERMIO_STRUCT */
4108d522f475Smrg	    } else {
4109d522f475Smrg		SysError(ERROR_OPDEVTTY);
4110d522f475Smrg	    }
4111d522f475Smrg	} else {
4112d522f475Smrg
4113d522f475Smrg	    /* Get a copy of the current terminal's state,
4114d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
4115d522f475Smrg	     * may not have a controlling terminal at this point
4116d522f475Smrg	     * if started directly from xdm or xinit,
4117d522f475Smrg	     * in which case we just use the defaults as above.
4118d522f475Smrg	     */
4119d522f475Smrg#ifdef HAS_LTCHARS
4120d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
4121d522f475Smrg		ltc = d_ltc;
4122d522f475Smrg#endif /* HAS_LTCHARS */
4123d522f475Smrg#ifdef TIOCLSET
4124d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
4125d522f475Smrg		lmode = d_lmode;
4126d522f475Smrg#endif /* TIOCLSET */
4127d522f475Smrg#ifdef TERMIO_STRUCT
412820d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
412920d2c4d2Smrg	    if (rc == -1)
4130d522f475Smrg		tio = d_tio;
4131d522f475Smrg#else /* !TERMIO_STRUCT */
413220d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
413320d2c4d2Smrg	    if (rc == -1)
4134d522f475Smrg		sg = d_sg;
4135d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
4136d522f475Smrg		tc = d_tc;
4137d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
4138d522f475Smrg		discipline = d_disipline;
4139d522f475Smrg#ifdef sony
4140d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
4141d522f475Smrg		jmode = d_jmode;
4142d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
4143d522f475Smrg		jtc = d_jtc;
4144d522f475Smrg#endif /* sony */
4145d522f475Smrg#endif /* TERMIO_STRUCT */
4146d522f475Smrg
4147d522f475Smrg	    /*
4148d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
4149d522f475Smrg	     * erase value.  Just in case that will fail, first get
4150d522f475Smrg	     * the value from /dev/tty, so we will have something
4151d522f475Smrg	     * at least.
4152d522f475Smrg	     */
4153d522f475Smrg#if OPT_INITIAL_ERASE
4154d522f475Smrg	    if (resource.ptyInitialErase) {
4155d522f475Smrg#ifdef TERMIO_STRUCT
4156d522f475Smrg		initial_erase = tio.c_cc[VERASE];
4157d522f475Smrg#else /* !TERMIO_STRUCT */
4158d522f475Smrg		initial_erase = sg.sg_erase;
4159d522f475Smrg#endif /* TERMIO_STRUCT */
4160d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
4161d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
4162d522f475Smrg		       initial_erase));
4163d522f475Smrg	    }
4164d522f475Smrg#endif
4165d522f475Smrg#ifdef __MVS__
4166d522f475Smrg	    if (ttyGetAttr(ttyfd, &gio) == 0) {
4167d522f475Smrg		gio.c_cflag &= ~(HUPCL | PARENB);
4168d522f475Smrg		ttySetAttr(ttyfd, &gio);
4169d522f475Smrg	    }
4170d522f475Smrg#endif /* __MVS__ */
4171d522f475Smrg
4172d522f475Smrg	    close_fd(ttyfd);
4173d522f475Smrg	}
4174d522f475Smrg
4175d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
4176d522f475Smrg	    SysError(ERROR_PTYS);
4177d522f475Smrg	}
4178913cc679Smrg	TRACE_GET_TTYSIZE(screen->respond, "after get_pty");
4179d522f475Smrg#if OPT_INITIAL_ERASE
4180d522f475Smrg	if (resource.ptyInitialErase) {
41815307cd1aSmrg	    initial_erase = get_tty_erase(screen->respond,
41825307cd1aSmrg					  initial_erase,
41835307cd1aSmrg					  "pty");
4184d522f475Smrg	}
4185d522f475Smrg#endif /* OPT_INITIAL_ERASE */
4186d522f475Smrg    }
4187d522f475Smrg
4188d522f475Smrg    /* avoid double MapWindow requests */
4189d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
4190d522f475Smrg
419104b94745Smrg    wm_delete_window = CachedInternAtom(XtDisplay(toplevel),
419204b94745Smrg					"WM_DELETE_WINDOW");
4193d522f475Smrg
4194d522f475Smrg    if (!TEK4014_ACTIVE(xw))
4195956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
4196d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4197d522f475Smrg    if (Console) {
4198d522f475Smrg	/*
4199d522f475Smrg	 * Inform any running xconsole program
4200d522f475Smrg	 * that we are going to steal the console.
4201d522f475Smrg	 */
4202d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
420304b94745Smrg	TRACE(("getting for console name property \"%s\"\n", mit_console_name));
420404b94745Smrg	mit_console = CachedInternAtom(screen->display, mit_console_name);
4205d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
4206d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
4207d522f475Smrg		       mit_console, CurrentTime,
4208d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
4209d522f475Smrg    }
4210d522f475Smrg#endif
4211d522f475Smrg#if OPT_TEK4014
4212d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
4213d522f475Smrg	envnew = tekterm;
4214d522f475Smrg    } else
4215d522f475Smrg#endif
4216d522f475Smrg    {
4217d522f475Smrg	envnew = vtterm;
4218d522f475Smrg    }
4219d522f475Smrg
4220d522f475Smrg    /*
4221d522f475Smrg     * This used to exit if no termcap entry was found for the specified
4222d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
4223d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
4224d522f475Smrg     * entry is not found.
4225d522f475Smrg     */
4226d522f475Smrg    ok_termcap = True;
422720d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
422820d2c4d2Smrg	const char *last = NULL;
422920d2c4d2Smrg	char *next;
423020d2c4d2Smrg
423120d2c4d2Smrg	TermName = x_strdup(*envnew);
4232d522f475Smrg	ok_termcap = False;
4233d522f475Smrg	while (*envnew != NULL) {
423420d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
423520d2c4d2Smrg		next = x_strdup(*envnew);
423620d2c4d2Smrg		if (get_termcap(xw, next)) {
423720d2c4d2Smrg		    free(TermName);
423820d2c4d2Smrg		    TermName = next;
42390bd37d32Smrg		    ok_termcap = True + 1;
424020d2c4d2Smrg		    break;
424120d2c4d2Smrg		} else {
424220d2c4d2Smrg		    free(next);
424320d2c4d2Smrg		}
4244d522f475Smrg	    }
4245d522f475Smrg	    last = *envnew;
4246d522f475Smrg	    envnew++;
4247d522f475Smrg	}
4248d522f475Smrg    }
4249d522f475Smrg    if (ok_termcap) {
4250f2e35a3aSmrg	resource.term_name = x_strdup(TermName);
425120d2c4d2Smrg	resize_termcap(xw);
4252d522f475Smrg    }
4253d522f475Smrg
4254d522f475Smrg    /*
4255d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
4256d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
4257d522f475Smrg     */
4258d522f475Smrg#if OPT_INITIAL_ERASE
4259d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
4260d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
4261d522f475Smrg    setInitialErase = False;
4262f2e35a3aSmrg    if (override_tty_modes && ttyModes[XTTYMODE_erase].set) {
4263f2e35a3aSmrg	initial_erase = ttyModes[XTTYMODE_erase].value;
4264d522f475Smrg	setInitialErase = True;
4265d522f475Smrg    } else if (resource.ptyInitialErase) {
4266a1f3da82Smrg	/* EMPTY */ ;
4267d522f475Smrg    } else if (ok_termcap) {
426820d2c4d2Smrg	char *s = get_tcap_erase(xw);
4269d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
4270d522f475Smrg	if (s != 0) {
427120d2c4d2Smrg	    char *save = s;
4272d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
4273d522f475Smrg	    setInitialErase = True;
427420d2c4d2Smrg	    free(save);
4275d522f475Smrg	}
4276d522f475Smrg    }
4277d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
4278d522f475Smrg
4279d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
4280d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
4281d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
4282d522f475Smrg	if (initial_erase == ANSI_DEL) {
428320d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
4284d522f475Smrg	} else {
4285d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
4286d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
4287d522f475Smrg	}
4288d522f475Smrg	TRACE(("...sets DECBKM %s\n",
4289d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
4290d522f475Smrg    } else {
4291d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
4292d522f475Smrg    }
4293d522f475Smrg#endif /* OPT_INITIAL_ERASE */
4294d522f475Smrg
4295d522f475Smrg#ifdef TTYSIZE_STRUCT
4296d522f475Smrg    /* tell tty how big window is */
4297d522f475Smrg#if OPT_TEK4014
4298d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
4299913cc679Smrg	setup_winsize(ts, TDefaultRows, TDefaultCols,
4300913cc679Smrg		      TFullHeight(TekScreenOf(tekWidget)),
4301913cc679Smrg		      TFullWidth(TekScreenOf(tekWidget)));
4302d522f475Smrg    } else
4303d522f475Smrg#endif
4304d522f475Smrg    {
4305913cc679Smrg	setup_winsize(ts, MaxRows(screen), MaxCols(screen),
4306913cc679Smrg		      FullHeight(screen), FullWidth(screen));
4307d522f475Smrg    }
430820d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
4309d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
4310d522f475Smrg	   TTYSIZE_ROWS(ts),
4311d522f475Smrg	   TTYSIZE_COLS(ts), i));
4312d522f475Smrg#endif /* TTYSIZE_STRUCT */
4313d522f475Smrg
43140bd37d32Smrg#if !defined(USE_OPENPTY)
43150bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
43160bd37d32Smrg    /*
43170bd37d32Smrg     * utempter checks the ownership of the device; some implementations
43180bd37d32Smrg     * set ownership in grantpt - do this first.
43190bd37d32Smrg     */
43200bd37d32Smrg    grantpt(screen->respond);
43210bd37d32Smrg#endif
43220bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
43230bd37d32Smrg    unlockpt(screen->respond);
4324913cc679Smrg    TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
43250bd37d32Smrg#endif
43260bd37d32Smrg#endif /* !USE_OPENPTY */
43270bd37d32Smrg
4328d522f475Smrg    added_utmp_entry = False;
4329d522f475Smrg#if defined(USE_UTEMPTER)
4330d522f475Smrg#undef UTMP
43312e4f8982Smrg    if ((xw->misc.login_shell || !command_to_exec) && !resource.utmpInhibit) {
4332d522f475Smrg	struct UTMP_STR dummy;
4333d522f475Smrg
4334d522f475Smrg	/* Note: utempter may trim it anyway */
4335d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
43360bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
43370bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
4338f2e35a3aSmrg	UTEMPTER_ADD(ttydev, dummy.ut_host, screen->respond);
4339d522f475Smrg	added_utmp_entry = True;
4340d522f475Smrg    }
4341d522f475Smrg#endif
4342d522f475Smrg
4343d522f475Smrg    if (am_slave < 0) {
4344d522f475Smrg#if OPT_PTY_HANDSHAKE
4345d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
4346d522f475Smrg	    SysError(ERROR_FORK);
4347d522f475Smrg#endif
4348d522f475Smrg	TRACE(("Forking...\n"));
4349d522f475Smrg	if ((screen->pid = fork()) == -1)
4350d522f475Smrg	    SysError(ERROR_FORK);
4351d522f475Smrg
4352d522f475Smrg	if (screen->pid == 0) {
4353d522f475Smrg#ifdef USE_USG_PTYS
435420d2c4d2Smrg	    int ptyfd = -1;
4355d522f475Smrg	    char *pty_name;
4356d522f475Smrg#endif
4357d522f475Smrg	    /*
4358d522f475Smrg	     * now in child process
4359d522f475Smrg	     */
436004b94745Smrg#ifdef HAVE_SETSID
4361d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
4362d522f475Smrg#else
4363d522f475Smrg	    int pgrp = getpid();
4364d522f475Smrg#endif
436504b94745Smrg	    TRACE_CHILD;
4366d522f475Smrg
4367d522f475Smrg#ifdef USE_USG_PTYS
43680bd37d32Smrg#ifdef HAVE_SETPGID
436904b94745Smrg	    setpgid(0, 0);
43700bd37d32Smrg#else
437104b94745Smrg	    setpgrp();
43720bd37d32Smrg#endif
43730bd37d32Smrg	    unlockpt(screen->respond);
4374913cc679Smrg	    TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
43750bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
43760bd37d32Smrg		SysError(ERROR_PTSNAME);
43770bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
43780bd37d32Smrg		SysError(ERROR_OPPTSNAME);
43790bd37d32Smrg	    }
4380d522f475Smrg#ifdef I_PUSH
43812e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ptem")) {
43820bd37d32Smrg		SysError(ERROR_PTEM);
43830bd37d32Smrg	    }
4384d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
43850bd37d32Smrg	    else if (!x_getenv("CONSEM")
43862e4f8982Smrg		     && PUSH_FAILS(ptyfd, "consem")) {
43870bd37d32Smrg		SysError(ERROR_CONSEM);
43880bd37d32Smrg	    }
4389d522f475Smrg#endif /* !SVR4 */
43902e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ldterm")) {
43910bd37d32Smrg		SysError(ERROR_LDTERM);
43920bd37d32Smrg	    }
4393d522f475Smrg#ifdef SVR4			/* from Sony */
43942e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ttcompat")) {
43950bd37d32Smrg		SysError(ERROR_TTCOMPAT);
43960bd37d32Smrg	    }
4397d522f475Smrg#endif /* SVR4 */
4398d522f475Smrg#endif /* I_PUSH */
43990bd37d32Smrg	    ttyfd = ptyfd;
4400d522f475Smrg#ifndef __MVS__
44010bd37d32Smrg	    close_fd(screen->respond);
4402d522f475Smrg#endif /* __MVS__ */
4403d522f475Smrg
4404d522f475Smrg#ifdef TTYSIZE_STRUCT
44050bd37d32Smrg	    /* tell tty how big window is */
4406d522f475Smrg#if OPT_TEK4014
44070bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
4408913cc679Smrg		setup_winsize(ts, TDefaultRows, TDefaultCols,
4409913cc679Smrg			      TFullHeight(TekScreenOf(tekWidget)),
4410913cc679Smrg			      TFullWidth(TekScreenOf(tekWidget)));
44110bd37d32Smrg	    } else
4412d522f475Smrg#endif /* OPT_TEK4014 */
44130bd37d32Smrg	    {
4414913cc679Smrg		setup_winsize(ts, MaxRows(screen), MaxCols(screen),
4415913cc679Smrg			      FullHeight(screen), FullWidth(screen));
44160bd37d32Smrg	    }
4417913cc679Smrg	    trace_winsize(ts, "initial tty size");
4418d522f475Smrg#endif /* TTYSIZE_STRUCT */
4419d522f475Smrg
4420d522f475Smrg#endif /* USE_USG_PTYS */
4421d522f475Smrg
44220bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
4423d522f475Smrg
4424d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
44250bd37d32Smrg	    if (resource.ptyHandshake) {
44260bd37d32Smrg		char *ptr;
4427d522f475Smrg
44280bd37d32Smrg		/* close parent's sides of the pipes */
44290bd37d32Smrg		close(cp_pipe[0]);
44300bd37d32Smrg		close(pc_pipe[1]);
44310bd37d32Smrg
44320bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
44330bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
44340bd37d32Smrg		 * or err.
44350bd37d32Smrg		 */
44360bd37d32Smrg		if (cp_pipe[1] <= 2) {
44370bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
44380bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
44390bd37d32Smrg			cp_pipe[1] = i;
4440d522f475Smrg		    }
44410bd37d32Smrg		}
44420bd37d32Smrg		if (pc_pipe[0] <= 2) {
44430bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
44440bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
44450bd37d32Smrg			pc_pipe[0] = i;
4446d522f475Smrg		    }
44470bd37d32Smrg		}
4448d522f475Smrg
44490bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
44500bd37d32Smrg		close(ConnectionNumber(screen->display));
4451d522f475Smrg#ifndef __MVS__
4452894e0ac8Smrg		if (screen->respond >= 0)
4453894e0ac8Smrg		    close(screen->respond);
4454d522f475Smrg#endif /* __MVS__ */
4455d522f475Smrg
44560bd37d32Smrg		/* Now is the time to set up our process group and
44570bd37d32Smrg		 * open up the pty slave.
44580bd37d32Smrg		 */
4459d522f475Smrg#ifdef USE_SYSV_PGRP
4460d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
44610bd37d32Smrg		IGNORE_RC(setsid());
4462d522f475Smrg#else
44630bd37d32Smrg		IGNORE_RC(setpgrp());
4464d522f475Smrg#endif
4465d522f475Smrg#endif /* USE_SYSV_PGRP */
4466d522f475Smrg
4467d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
44680bd37d32Smrg		qsetlogin(getlogin(), ttydev);
4469d522f475Smrg#endif
44700bd37d32Smrg		if (ttyfd >= 0) {
4471d522f475Smrg#ifdef __MVS__
44720bd37d32Smrg		    if (ttyGetAttr(ttyfd, &gio) == 0) {
44730bd37d32Smrg			gio.c_cflag &= ~(HUPCL | PARENB);
44740bd37d32Smrg			ttySetAttr(ttyfd, &gio);
44750bd37d32Smrg		    }
4476d522f475Smrg#else /* !__MVS__ */
44770bd37d32Smrg		    close_fd(ttyfd);
4478d522f475Smrg#endif /* __MVS__ */
44790bd37d32Smrg		}
4480d522f475Smrg
44810bd37d32Smrg		for (;;) {
448220d2c4d2Smrg#if USE_NO_DEV_TTY
44830bd37d32Smrg		    if (!no_dev_tty
44840bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
44850bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
44860bd37d32Smrg			close_fd(ttyfd);
44870bd37d32Smrg		    }
448820d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
4489d522f475Smrg#ifdef CSRG_BASED
44900bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
4491d522f475Smrg#endif
44920bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
4493913cc679Smrg			TRACE_GET_TTYSIZE(ttyfd, "after open");
44940bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
4495913cc679Smrg			TRACE_GET_TTYSIZE(ttyfd, "after SET_TTYSIZE fixup");
4496d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
44970bd37d32Smrg			/* make /dev/tty work */
44980bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
4499d522f475Smrg#endif
4500d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
45010bd37d32Smrg			/* make /dev/tty work */
45020bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
4503d522f475Smrg#endif
4504d522f475Smrg#ifdef USE_SYSV_PGRP
45050bd37d32Smrg			/* We need to make sure that we are actually
45060bd37d32Smrg			 * the process group leader for the pty.  If
45070bd37d32Smrg			 * we are, then we should now be able to open
45080bd37d32Smrg			 * /dev/tty.
45090bd37d32Smrg			 */
45100bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
45110bd37d32Smrg			    /* success! */
45120bd37d32Smrg			    close(i);
4513d522f475Smrg			    break;
4514d522f475Smrg			}
45150bd37d32Smrg#else /* USE_SYSV_PGRP */
45160bd37d32Smrg			break;
45170bd37d32Smrg#endif /* USE_SYSV_PGRP */
45180bd37d32Smrg		    }
45190bd37d32Smrg		    perror("open ttydev");
4520d522f475Smrg#ifdef TIOCSCTTY
45210bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
4522d522f475Smrg#endif
45230bd37d32Smrg		    /* let our master know that the open failed */
45240bd37d32Smrg		    handshake.status = PTY_BAD;
45250bd37d32Smrg		    handshake.error = errno;
4526f2e35a3aSmrg		    copy_handshake(handshake, ttydev);
45270bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
45280bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
45290bd37d32Smrg				    (const char *) &handshake,
45300bd37d32Smrg				    sizeof(handshake)));
4531d522f475Smrg
45320bd37d32Smrg		    /* get reply from parent */
45330bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
45340bd37d32Smrg				   sizeof(handshake));
45350bd37d32Smrg		    if (i <= 0) {
45360bd37d32Smrg			/* parent terminated */
453704b94745Smrg			exit(ERROR_MISC);
4538d522f475Smrg		    }
4539d522f475Smrg
45400bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
45410bd37d32Smrg			/* No more ptys, let's shutdown. */
454204b94745Smrg			exit(ERROR_MISC);
4543d522f475Smrg		    }
45440bd37d32Smrg
45450bd37d32Smrg		    /* We have a new pty to try */
45460bd37d32Smrg		    if (ttyfd >= 0)
45470bd37d32Smrg			close(ttyfd);
45480bd37d32Smrg		    free(ttydev);
4549f2e35a3aSmrg		    handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
45500bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
4551d522f475Smrg		}
4552d522f475Smrg
45530bd37d32Smrg		/* use the same tty name that everyone else will use
45540bd37d32Smrg		 * (from ttyname)
45550bd37d32Smrg		 */
45560bd37d32Smrg		if ((ptr = ttyname(ttyfd)) != 0) {
45570bd37d32Smrg		    free(ttydev);
45580bd37d32Smrg		    ttydev = x_strdup(ptr);
45590bd37d32Smrg		}
45600bd37d32Smrg	    }
45610bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
4562d522f475Smrg
4563d522f475Smrg	    set_pty_permissions(screen->uid,
4564913cc679Smrg				(unsigned) screen->gid,
4565d522f475Smrg				(resource.messages
4566d522f475Smrg				 ? 0622U
4567d522f475Smrg				 : 0600U));
4568d522f475Smrg
4569d522f475Smrg	    /*
4570d522f475Smrg	     * set up the tty modes
4571d522f475Smrg	     */
4572d522f475Smrg	    {
4573d522f475Smrg#ifdef TERMIO_STRUCT
457404b94745Smrg#if defined(umips) || defined(CRAY) || defined(__linux__)
4575d522f475Smrg		/* If the control tty had its modes screwed around with,
4576d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
4577d522f475Smrg		   will have bad values.  Let's just get termio from the
4578d522f475Smrg		   new tty and tailor it.  */
4579d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4580d522f475Smrg		    SysError(ERROR_TIOCGETP);
4581d522f475Smrg		tio.c_lflag |= ECHOE;
4582d522f475Smrg#endif /* umips */
4583d522f475Smrg		/* Now is also the time to change the modes of the
4584d522f475Smrg		 * child pty.
4585d522f475Smrg		 */
4586d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
458720d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
4588d522f475Smrg		tio.c_iflag |= ICRNL;
45890bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
4590d522f475Smrg#if OPT_LUIT_PROG
4591d522f475Smrg		if (command_to_exec_with_luit == 0)
4592d522f475Smrg#endif
4593d522f475Smrg		    if (screen->utf8_mode)
4594d522f475Smrg			tio.c_iflag |= IUTF8;
4595d522f475Smrg#endif
4596f2e35a3aSmrg		/* output: cr->cr, nl is not return, no delays, ln->cr/nl */
4597d522f475Smrg#ifndef USE_POSIX_TERMIOS
459820d2c4d2Smrg		UIntClr(tio.c_oflag,
459920d2c4d2Smrg			(OCRNL
460020d2c4d2Smrg			 | ONLRET
460120d2c4d2Smrg			 | NLDLY
460220d2c4d2Smrg			 | CRDLY
460320d2c4d2Smrg			 | TABDLY
460420d2c4d2Smrg			 | BSDLY
460520d2c4d2Smrg			 | VTDLY
460620d2c4d2Smrg			 | FFDLY));
4607d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4608f2e35a3aSmrg		tio.c_oflag |= D_TIO_FLAGS;
4609d522f475Smrg#ifndef USE_POSIX_TERMIOS
4610d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
4611d522f475Smrg#  define CBAUD V_CBAUD
4612d522f475Smrg# endif
461320d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
4614d522f475Smrg#ifdef BAUD_0
4615d522f475Smrg		/* baud rate is 0 (don't care) */
4616d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
46172e4f8982Smrg		tio.c_ispeed = tio.c_ospeed = line_speed;
4618d522f475Smrg#else /* !BAUD_0 */
46192e4f8982Smrg		tio.c_cflag |= line_speed;
4620d522f475Smrg#endif /* !BAUD_0 */
4621d522f475Smrg#else /* USE_POSIX_TERMIOS */
46222e4f8982Smrg		cfsetispeed(&tio, line_speed);
46232e4f8982Smrg		cfsetospeed(&tio, line_speed);
4624d522f475Smrg#ifdef __MVS__
4625d522f475Smrg		/* turn off bits that can't be set from the slave side */
4626d522f475Smrg		tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
4627d522f475Smrg#endif /* __MVS__ */
4628d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
4629d522f475Smrg		   when the xterm ends */
46302e4f8982Smrg		tio.c_cflag &= (unsigned) ~CLOCAL;
4631d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4632d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
4633d522f475Smrg		 * echo
4634d522f475Smrg		 */
4635d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
4636d522f475Smrg#ifdef ECHOKE
4637d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
4638d522f475Smrg#endif
4639d522f475Smrg#ifdef ECHOCTL
4640d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
4641d522f475Smrg#endif
4642f2e35a3aSmrg		for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
4643d522f475Smrg		    if (validTtyChar(tio, nn)) {
4644f2e35a3aSmrg			int sysMode = ttyChars[nn].sysMode;
4645d522f475Smrg#ifdef __MVS__
4646d522f475Smrg			if (tio.c_cc[sysMode] != 0) {
4647d522f475Smrg			    switch (sysMode) {
4648d522f475Smrg			    case VEOL:
4649d522f475Smrg			    case VEOF:
4650d522f475Smrg				continue;
4651d522f475Smrg			    }
4652d522f475Smrg			}
4653d522f475Smrg#endif
4654f2e35a3aSmrg			tio.c_cc[sysMode] = (cc_t) ttyChars[nn].myDefault;
4655d522f475Smrg		    }
4656d522f475Smrg		}
4657d522f475Smrg
4658d522f475Smrg		if (override_tty_modes) {
4659f2e35a3aSmrg		    TRACE(("applying termios ttyModes\n"));
4660f2e35a3aSmrg		    for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
4661d522f475Smrg			if (validTtyChar(tio, nn)) {
4662f2e35a3aSmrg			    TMODE(ttyChars[nn].myMode,
4663f2e35a3aSmrg				  tio.c_cc[ttyChars[nn].sysMode]);
4664f2e35a3aSmrg			} else if (isTabMode(nn)) {
4665f2e35a3aSmrg			    unsigned tmp = (unsigned) tio.c_oflag;
4666f2e35a3aSmrg			    tmp = tmp & (unsigned) ~TABDLY;
4667f2e35a3aSmrg			    tmp |= (unsigned) ttyModes[ttyChars[nn].myMode].value;
4668f2e35a3aSmrg			    tio.c_oflag = tmp;
4669d522f475Smrg			}
4670d522f475Smrg		    }
4671d522f475Smrg#ifdef HAS_LTCHARS
4672d522f475Smrg		    /* both SYSV and BSD have ltchars */
4673d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4674d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4675d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4676d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4677d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4678d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4679d522f475Smrg#endif
4680d522f475Smrg		}
4681d522f475Smrg#ifdef HAS_LTCHARS
4682d522f475Smrg#ifdef __hpux
4683d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
4684d522f475Smrg		 * are not set to _POSIX_VDISABLE */
4685913cc679Smrg		ltc.t_rprntc = _POSIX_VDISABLE;
4686913cc679Smrg		ltc.t_rprntc = _POSIX_VDISABLE;
4687913cc679Smrg		ltc.t_flushc = _POSIX_VDISABLE;
4688913cc679Smrg		ltc.t_werasc = _POSIX_VDISABLE;
4689913cc679Smrg		ltc.t_lnextc = _POSIX_VDISABLE;
4690d522f475Smrg#endif /* __hpux */
4691d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
4692d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4693d522f475Smrg#endif /* HAS_LTCHARS */
4694d522f475Smrg#ifdef TIOCLSET
4695d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4696d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4697d522f475Smrg#endif /* TIOCLSET */
4698d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
4699d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4700d522f475Smrg
4701d522f475Smrg		/* ignore errors here - some platforms don't work */
470220d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
4703d522f475Smrg		if (screen->input_eight_bits)
4704d522f475Smrg		    tio.c_cflag |= CS8;
4705d522f475Smrg		else
4706d522f475Smrg		    tio.c_cflag |= CS7;
4707d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
4708d522f475Smrg
4709d522f475Smrg#else /* !TERMIO_STRUCT */
4710d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
4711d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
4712d522f475Smrg		/* make sure speed is set on pty so that editors work right */
47132e4f8982Smrg		sg.sg_ispeed = line_speed;
47142e4f8982Smrg		sg.sg_ospeed = line_speed;
4715d522f475Smrg		/* reset t_brkc to default value */
4716d522f475Smrg		tc.t_brkc = -1;
4717d522f475Smrg#ifdef LPASS8
4718d522f475Smrg		if (screen->input_eight_bits)
4719d522f475Smrg		    lmode |= LPASS8;
4720d522f475Smrg		else
4721d522f475Smrg		    lmode &= ~(LPASS8);
4722d522f475Smrg#endif
4723d522f475Smrg#ifdef sony
4724d522f475Smrg		jmode &= ~KM_KANJI;
4725d522f475Smrg#endif /* sony */
4726d522f475Smrg
4727d522f475Smrg		ltc = d_ltc;
4728d522f475Smrg
4729d522f475Smrg		if (override_tty_modes) {
4730f2e35a3aSmrg		    TRACE(("applying sgtty ttyModes\n"));
4731d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
4732d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
4733d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
4734d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
4735d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
4736d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
4737d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
4738d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
4739d522f475Smrg		    /* both SYSV and BSD have ltchars */
4740d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4741d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4742d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4743d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4744d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4745d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4746f2e35a3aSmrg		    if (ttyModes[XTTYMODE_tabs].set
4747f2e35a3aSmrg			|| ttyModes[XTTYMODE__tabs].set) {
4748f2e35a3aSmrg			sg.sg_flags &= ~XTABS;
4749f2e35a3aSmrg			if (ttyModes[XTTYMODE__tabs].set.set)
4750f2e35a3aSmrg			    sg.sg_flags |= XTABS;
4751f2e35a3aSmrg		    }
4752d522f475Smrg		}
4753d522f475Smrg
4754d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
4755d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4756d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
4757d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4758d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
4759d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
4760d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
4761d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
4762d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4763d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4764d522f475Smrg#ifdef sony
4765d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
4766d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
4767d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
4768d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
4769d522f475Smrg#endif /* sony */
4770d522f475Smrg#endif /* TERMIO_STRUCT */
4771d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4772d522f475Smrg		if (Console) {
4773d522f475Smrg#ifdef TIOCCONS
4774d522f475Smrg		    int on = 1;
4775d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
47760bd37d32Smrg			xtermPerror("cannot open console");
4777d522f475Smrg#endif
4778d522f475Smrg#ifdef SRIOCSREDIR
4779d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4780d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
47810bd37d32Smrg			xtermPerror("cannot open console");
478220d2c4d2Smrg		    IGNORE_RC(close(fd));
4783d522f475Smrg#endif
4784d522f475Smrg		}
4785d522f475Smrg#endif /* TIOCCONS */
4786d522f475Smrg	    }
4787d522f475Smrg
4788d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4789d522f475Smrg#ifdef USE_SYSV_SIGHUP
4790d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4791d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4792d522f475Smrg#else
4793d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4794d522f475Smrg#endif
4795d522f475Smrg	    /* restore various signals to their defaults */
4796d522f475Smrg	    signal(SIGINT, SIG_DFL);
4797d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4798d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4799d522f475Smrg
4800d522f475Smrg	    /*
4801d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4802d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4803d522f475Smrg	     * the terminal's erase mode from our best guess.
4804d522f475Smrg	     */
4805d522f475Smrg#if OPT_INITIAL_ERASE
4806d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4807d522f475Smrg		   initial_erase,
4808d522f475Smrg		   setInitialErase ? "YES" : "NO",
4809d522f475Smrg		   resource.ptyInitialErase,
4810d522f475Smrg		   override_tty_modes,
4811f2e35a3aSmrg		   ttyModes[XTTYMODE_erase].set));
4812d522f475Smrg	    if (setInitialErase) {
4813d522f475Smrg#if OPT_TRACE
4814d522f475Smrg		int old_erase;
4815d522f475Smrg#endif
4816d522f475Smrg#ifdef TERMIO_STRUCT
4817d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4818d522f475Smrg		    tio = d_tio;
4819d522f475Smrg#if OPT_TRACE
4820d522f475Smrg		old_erase = tio.c_cc[VERASE];
4821d522f475Smrg#endif
48220bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
482320d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4824d522f475Smrg#else /* !TERMIO_STRUCT */
4825d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4826d522f475Smrg		    sg = d_sg;
4827d522f475Smrg#if OPT_TRACE
4828d522f475Smrg		old_erase = sg.sg_erase;
4829d522f475Smrg#endif
4830d522f475Smrg		sg.sg_erase = initial_erase;
4831d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4832d522f475Smrg#endif /* TERMIO_STRUCT */
4833d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4834d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4835d522f475Smrg	    }
4836d522f475Smrg#endif
4837d522f475Smrg
4838d522f475Smrg	    xtermCopyEnv(environ);
48394419d26bSmrg	    xtermTrimEnv();
48400bd37d32Smrg
4841a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4842a1f3da82Smrg	    if (!resource.term_name)
484320d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4844d522f475Smrg
4845d522f475Smrg	    sprintf(buf, "%lu",
4846d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4847d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4848d522f475Smrg
4849d522f475Smrg	    /* put the display into the environment of the shell */
4850d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4851d522f475Smrg
4852d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4853d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4854d522f475Smrg
4855e39b573cSmrg	    /*
4856e39b573cSmrg	     * For debugging only, add environment variables that can be used
4857e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4858e39b573cSmrg	     * processes.
4859e39b573cSmrg	     */
4860e39b573cSmrg#if OPT_TRACE
4861e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4862e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4863e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4864e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4865e39b573cSmrg#endif
4866e39b573cSmrg
4867d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4868d522f475Smrg
4869d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4870d522f475Smrg	     */
4871d522f475Smrg	    {
4872d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4873d522f475Smrg		close_fd(ttyfd);
4874d522f475Smrg
487520d2c4d2Smrg		IGNORE_RC(close(0));
4876d522f475Smrg
4877d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4878d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4879d522f475Smrg		}
488020d2c4d2Smrg		IGNORE_RC(close(1));
488120d2c4d2Smrg		IGNORE_RC(close(2));
4882d522f475Smrg		dup(0);
4883d522f475Smrg		dup(0);
4884d522f475Smrg#else
4885d522f475Smrg		/* dup the tty */
4886d522f475Smrg		for (i = 0; i <= 2; i++)
4887d522f475Smrg		    if (i != ttyfd) {
488820d2c4d2Smrg			IGNORE_RC(close(i));
488920d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4890d522f475Smrg		    }
4891d522f475Smrg#ifndef ATT
4892d522f475Smrg		/* and close the tty */
4893d522f475Smrg		if (ttyfd > 2)
4894d522f475Smrg		    close_fd(ttyfd);
4895d522f475Smrg#endif
4896d522f475Smrg#endif /* CRAY */
4897d522f475Smrg	    }
4898d522f475Smrg
4899d522f475Smrg#if !defined(USE_SYSV_PGRP)
4900d522f475Smrg#ifdef TIOCSCTTY
4901d522f475Smrg	    setsid();
4902d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4903d522f475Smrg#endif
4904d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4905d522f475Smrg	    setpgrp(0, 0);
4906d522f475Smrg	    close(open(ttydev, O_WRONLY));
4907d522f475Smrg	    setpgrp(0, pgrp);
4908d522f475Smrg#if defined(__QNX__)
4909d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4910d522f475Smrg#endif
4911d522f475Smrg#endif /* !USE_SYSV_PGRP */
4912d522f475Smrg
4913d522f475Smrg#ifdef Lynx
4914d522f475Smrg	    {
4915d522f475Smrg		TERMIO_STRUCT t;
4916d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4917d522f475Smrg		    /* this gets lost somewhere on our way... */
4918d522f475Smrg		    t.c_oflag |= OPOST;
4919d522f475Smrg		    ttySetAttr(0, &t);
4920d522f475Smrg		}
4921d522f475Smrg	    }
4922d522f475Smrg#endif
4923d522f475Smrg
4924d522f475Smrg#ifdef HAVE_UTMP
4925d522f475Smrg	    login_name = NULL;
49260bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
49270bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4928d522f475Smrg	    }
4929d522f475Smrg	    if (login_name != NULL) {
4930d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4931d522f475Smrg	    }
4932d522f475Smrg#ifndef USE_UTEMPTER
4933d522f475Smrg#ifdef USE_UTMP_SETGID
4934d522f475Smrg	    setEffectiveGroup(save_egid);
4935d522f475Smrg	    TRACE_IDS;
4936d522f475Smrg#endif
4937d522f475Smrg#ifdef USE_SYSV_UTMP
4938d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4939d522f475Smrg	     * for the following reasons:
4940d522f475Smrg	     *   - It needs to have our correct process id (for
4941d522f475Smrg	     *     login).
4942d522f475Smrg	     *   - If our parent was to set it after the fork(),
4943d522f475Smrg	     *     it might make it out before we need it.
4944d522f475Smrg	     *   - We need to do it before we go and change our
4945d522f475Smrg	     *     user and group id's.
4946d522f475Smrg	     */
4947d522f475Smrg	    (void) call_setutent();
4948d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4949d522f475Smrg
4950d522f475Smrg	    /* position to entry in utmp file */
4951d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
495220d2c4d2Smrg	    utret = find_utmp(&utmp);
495320d2c4d2Smrg	    if (utret == 0) {
4954d522f475Smrg		(void) call_setutent();
4955d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
495620d2c4d2Smrg		utret = find_utmp(&utmp);
495720d2c4d2Smrg		if (utret == 0) {
4958d522f475Smrg		    (void) call_setutent();
4959d522f475Smrg		}
4960d522f475Smrg	    }
4961d522f475Smrg#if OPT_TRACE
4962d522f475Smrg	    if (!utret)
4963d522f475Smrg		TRACE(("getutid: NULL\n"));
4964d522f475Smrg	    else
49650bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
496620d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
49670bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
49680bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4969d522f475Smrg#endif
4970d522f475Smrg
4971d522f475Smrg	    /* set up the new entry */
4972d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4973d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4974d522f475Smrg	    utmp.ut_xstatus = 2;
4975d522f475Smrg#endif
4976894e0ac8Smrg	    copy_filled(utmp.ut_user,
4977894e0ac8Smrg			(login_name != NULL) ? login_name : "????",
4978894e0ac8Smrg			sizeof(utmp.ut_user));
4979d522f475Smrg	    /* why are we copying this string again?  (see above) */
4980894e0ac8Smrg	    copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4981894e0ac8Smrg	    copy_filled(utmp.ut_line,
4982894e0ac8Smrg			my_pty_name(ttydev), sizeof(utmp.ut_line));
4983d522f475Smrg
4984d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4985d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4986d522f475Smrg#endif
4987d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4988d522f475Smrg	    SetUtmpSysLen(utmp);
4989d522f475Smrg#endif
4990d522f475Smrg
4991894e0ac8Smrg	    copy_filled(utmp.ut_name,
4992894e0ac8Smrg			(login_name) ? login_name : "????",
4993894e0ac8Smrg			sizeof(utmp.ut_name));
4994d522f475Smrg
4995d522f475Smrg	    utmp.ut_pid = getpid();
4996d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4997d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4998d522f475Smrg	    utmp.ut_session = getsid(0);
4999d522f475Smrg#endif
5000d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
5001d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
5002d522f475Smrg#else
5003d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
5004d522f475Smrg#endif
5005d522f475Smrg
5006d522f475Smrg	    /* write out the entry */
5007d522f475Smrg	    if (!resource.utmpInhibit) {
5008d522f475Smrg		errno = 0;
5009d522f475Smrg		call_pututline(&utmp);
50100bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
50110bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
50120bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
5013d522f475Smrg		       (long) utmp.ut_pid,
5014d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
5015d522f475Smrg	    }
5016d522f475Smrg#ifdef WTMP
5017d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
5018d522f475Smrg	    if (xw->misc.login_shell)
5019d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
502004b94745Smrg#elif defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
5021d522f475Smrg	    if (xw->misc.login_shell)
5022d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
5023d522f475Smrg#else
5024d522f475Smrg	    if (xw->misc.login_shell &&
5025d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
50260bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
5027d522f475Smrg		close(i);
5028d522f475Smrg	    }
5029d522f475Smrg#endif
5030d522f475Smrg#endif
5031d522f475Smrg	    /* close the file */
5032d522f475Smrg	    (void) call_endutent();
5033d522f475Smrg
5034d522f475Smrg#else /* USE_SYSV_UTMP */
5035d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
5036d522f475Smrg	     * utmp entry.
5037d522f475Smrg	     */
5038d522f475Smrg	    tslot = ttyslot();
5039d522f475Smrg	    added_utmp_entry = False;
5040d522f475Smrg	    {
50410bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
5042d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
5043956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
5044894e0ac8Smrg		    copy_filled(utmp.ut_line,
5045894e0ac8Smrg				my_pty_name(ttydev),
5046894e0ac8Smrg				sizeof(utmp.ut_line));
5047894e0ac8Smrg		    copy_filled(utmp.ut_name, login_name,
5048894e0ac8Smrg				sizeof(utmp.ut_name));
5049d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
5050d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
5051d522f475Smrg#endif
5052d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
5053d522f475Smrg		    SetUtmpSysLen(utmp);
5054d522f475Smrg#endif
5055d522f475Smrg
5056d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
5057d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
50580bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
5059d522f475Smrg		    close(i);
5060d522f475Smrg		    added_utmp_entry = True;
5061d522f475Smrg#if defined(WTMP)
5062d522f475Smrg		    if (xw->misc.login_shell &&
5063d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
5064d522f475Smrg			int status;
5065d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
5066d522f475Smrg			status = close(i);
5067d522f475Smrg		    }
5068d522f475Smrg#elif defined(MNX_LASTLOG)
5069d522f475Smrg		    if (xw->misc.login_shell &&
5070d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
5071d522f475Smrg			lseek(i, (long) (screen->uid *
5072d522f475Smrg					 sizeof(utmp)), 0);
50730bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
5074d522f475Smrg			close(i);
5075d522f475Smrg		    }
5076d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
5077d522f475Smrg		} else
5078d522f475Smrg		    tslot = -tslot;
5079d522f475Smrg	    }
5080d522f475Smrg
5081d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
5082d522f475Smrg	     * clean up after us.
5083d522f475Smrg	     */
5084d522f475Smrg#if OPT_PTY_HANDSHAKE
5085d522f475Smrg	    if (resource.ptyHandshake) {
5086d522f475Smrg		handshake.tty_slot = tslot;
5087d522f475Smrg	    }
5088d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5089d522f475Smrg#endif /* USE_SYSV_UTMP */
5090d522f475Smrg
5091d522f475Smrg#ifdef USE_LASTLOGX
5092d522f475Smrg	    if (xw->misc.login_shell) {
5093956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
5094f2e35a3aSmrg		copy_filled(lastlogx.ll_line,
5095f2e35a3aSmrg			    my_pty_name(ttydev),
5096f2e35a3aSmrg			    sizeof(lastlogx.ll_line));
5097d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
5098d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
5099d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
5100d522f475Smrg	    }
5101d522f475Smrg#endif
5102d522f475Smrg
5103d522f475Smrg#ifdef USE_LASTLOG
5104d522f475Smrg	    if (xw->misc.login_shell &&
5105d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
5106d522f475Smrg		size_t size = sizeof(struct lastlog);
5107913cc679Smrg		off_t offset = (off_t) ((size_t) screen->uid * size);
5108d522f475Smrg
5109956cc18dSsnj		memset(&lastlog, 0, size);
5110f2e35a3aSmrg		copy_filled(lastlog.ll_line,
5111f2e35a3aSmrg			    my_pty_name(ttydev),
5112f2e35a3aSmrg			    sizeof(lastlog.ll_line));
5113d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
5114d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
5115d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
51160bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
5117d522f475Smrg		}
5118d522f475Smrg		close(i);
5119d522f475Smrg	    }
5120d522f475Smrg#endif /* USE_LASTLOG */
5121d522f475Smrg
5122d522f475Smrg#if defined(USE_UTMP_SETGID)
5123d522f475Smrg	    disableSetGid();
5124d522f475Smrg	    TRACE_IDS;
5125d522f475Smrg#endif
5126d522f475Smrg
5127d522f475Smrg#if OPT_PTY_HANDSHAKE
5128d522f475Smrg	    /* Let our parent know that we set up our utmp entry
5129d522f475Smrg	     * so that it can clean up after us.
5130d522f475Smrg	     */
5131d522f475Smrg	    if (resource.ptyHandshake) {
5132d522f475Smrg		handshake.status = UTMP_ADDED;
5133d522f475Smrg		handshake.error = 0;
5134f2e35a3aSmrg		copy_handshake(handshake, ttydev);
5135d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
513620d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
5137d522f475Smrg	    }
5138d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5139d522f475Smrg#endif /* USE_UTEMPTER */
5140d522f475Smrg#endif /* HAVE_UTMP */
5141d522f475Smrg
514220d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
5143d522f475Smrg	    TRACE_IDS;
5144e0a2b6dfSmrg#ifdef HAVE_INITGROUPS
51450bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
51460bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
5147d522f475Smrg		    perror("initgroups failed");
5148d522f475Smrg		    SysError(ERROR_INIGROUPS);
5149d522f475Smrg		}
5150d522f475Smrg	    }
5151d522f475Smrg#endif
5152d522f475Smrg	    if (setuid(screen->uid)) {
5153d522f475Smrg		SysError(ERROR_SETUID);
5154d522f475Smrg	    }
5155d522f475Smrg	    TRACE_IDS;
5156d522f475Smrg#if OPT_PTY_HANDSHAKE
5157d522f475Smrg	    if (resource.ptyHandshake) {
5158d522f475Smrg		/* mark the pipes as close on exec */
51590bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
51600bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
5161d522f475Smrg
5162d522f475Smrg		/* We are at the point where we are going to
5163d522f475Smrg		 * exec our shell (or whatever).  Let our parent
5164d522f475Smrg		 * know we arrived safely.
5165d522f475Smrg		 */
5166d522f475Smrg		handshake.status = PTY_GOOD;
5167d522f475Smrg		handshake.error = 0;
5168f2e35a3aSmrg		copy_handshake(handshake, ttydev);
5169d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
517020d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
517120d2c4d2Smrg				(const char *) &handshake,
517220d2c4d2Smrg				sizeof(handshake)));
5173d522f475Smrg
5174d522f475Smrg		if (resource.wait_for_map) {
517520d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
517620d2c4d2Smrg				   sizeof(handshake));
5177d522f475Smrg		    if (i != sizeof(handshake) ||
5178d522f475Smrg			handshake.status != PTY_EXEC) {
5179d522f475Smrg			/* some very bad problem occurred */
5180d522f475Smrg			exit(ERROR_PTY_EXEC);
5181d522f475Smrg		    }
5182d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
5183913cc679Smrg			TRACE(("handshake read ttysize: %dx%d\n",
5184d522f475Smrg			       handshake.rows, handshake.cols));
5185d522f475Smrg			set_max_row(screen, handshake.rows);
5186d522f475Smrg			set_max_col(screen, handshake.cols);
5187d522f475Smrg#ifdef TTYSIZE_STRUCT
5188d522f475Smrg			got_handshake_size = True;
5189913cc679Smrg			setup_winsize(ts, MaxRows(screen), MaxCols(screen),
5190913cc679Smrg				      FullHeight(screen), FullWidth(screen));
5191913cc679Smrg			trace_winsize(ts, "got handshake");
5192d522f475Smrg#endif /* TTYSIZE_STRUCT */
5193d522f475Smrg		    }
5194d522f475Smrg		}
5195d522f475Smrg	    }
5196d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5197d522f475Smrg
5198d522f475Smrg#ifdef USE_SYSV_ENVVARS
5199d522f475Smrg	    {
5200d522f475Smrg		char numbuf[12];
5201d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
5202d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
5203d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
5204d522f475Smrg		xtermSetenv("LINES", numbuf);
5205d522f475Smrg	    }
5206d522f475Smrg#ifdef HAVE_UTMP
52070bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
5208d522f475Smrg		if (!x_getenv("HOME"))
52090bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
5210d522f475Smrg		if (!x_getenv("SHELL"))
52110bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
5212d522f475Smrg	    }
5213d522f475Smrg#endif /* HAVE_UTMP */
5214d522f475Smrg#else /* USE_SYSV_ENVVARS */
521520d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
521620d2c4d2Smrg		resize_termcap(xw);
521720d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
521820d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
521920d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
522020d2c4d2Smrg		}
522120d2c4d2Smrg		/*
522220d2c4d2Smrg		 * work around broken termcap entries */
522320d2c4d2Smrg		if (resource.useInsertMode) {
522420d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
522520d2c4d2Smrg		    /* don't get duplicates */
522620d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
522720d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
522820d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
522920d2c4d2Smrg		    if (*newtc)
523020d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
523120d2c4d2Smrg		}
523220d2c4d2Smrg		if (*newtc) {
5233d522f475Smrg#if OPT_INITIAL_ERASE
52345307cd1aSmrg#define TERMCAP_ERASE "kb"
523520d2c4d2Smrg		    unsigned len;
523620d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
523720d2c4d2Smrg		    len = (unsigned) strlen(newtc);
523820d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
523920d2c4d2Smrg			len--;
524020d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
524120d2c4d2Smrg			    TERMCAP_ERASE,
524220d2c4d2Smrg			    CharOf(initial_erase));
524320d2c4d2Smrg#endif
524420d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
524520d2c4d2Smrg		}
5246d522f475Smrg	    }
5247d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5248913cc679Smrg#ifdef OWN_TERMINFO_ENV
5249913cc679Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
5250913cc679Smrg#endif
5251d522f475Smrg
5252d522f475Smrg#if OPT_PTY_HANDSHAKE
5253d522f475Smrg	    /*
5254d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
5255d522f475Smrg	     *
5256d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
5257d522f475Smrg	     * use that to prevent races.
5258d522f475Smrg	     */
5259913cc679Smrg	    TRACE(("should we reset screensize after pty-handshake?\n"));
5260913cc679Smrg	    TRACE(("... ptyHandshake      :%d\n", resource.ptyHandshake));
5261913cc679Smrg	    TRACE(("... ptySttySize       :%d\n", resource.ptySttySize));
5262913cc679Smrg	    TRACE(("... got_handshake_size:%d\n", got_handshake_size));
5263913cc679Smrg	    TRACE(("... wait_for_map0     :%d\n", resource.wait_for_map0));
5264d522f475Smrg	    if (resource.ptyHandshake
5265d522f475Smrg		&& resource.ptySttySize
5266d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
5267d522f475Smrg#ifdef TTYSIZE_STRUCT
526820d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
5269913cc679Smrg		trace_winsize(ts, "ptyHandshake SET_TTYSIZE");
5270d522f475Smrg#endif /* TTYSIZE_STRUCT */
5271d522f475Smrg	    }
5272d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5273d522f475Smrg	    signal(SIGHUP, SIG_DFL);
5274d522f475Smrg
52750bd37d32Smrg	    /*
5276e0a2b6dfSmrg	     * If we have an explicit shell to run, make that set $SHELL.
5277e0a2b6dfSmrg	     * Next, allow an existing setting of $SHELL, for absolute paths.
52780bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
52790bd37d32Smrg	     * password information, if possible.
52800bd37d32Smrg	     *
52810bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
52820bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
52830bd37d32Smrg	     */
5284e0a2b6dfSmrg	    if (validShell(explicit_shname)) {
5285e0a2b6dfSmrg		xtermSetenv("SHELL", explicit_shname);
5286e0a2b6dfSmrg	    } else if (validProgram(shell_path = x_getenv("SHELL"))) {
5287e0a2b6dfSmrg		if (!validShell(shell_path)) {
5288e0a2b6dfSmrg		    xtermUnsetenv("SHELL");
5289d522f475Smrg		}
5290e0a2b6dfSmrg	    } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
5291e0a2b6dfSmrg		       || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
5292e0a2b6dfSmrg		shell_path = resetShell(shell_path);
5293e0a2b6dfSmrg	    } else if (validShell(shell_path)) {
5294e0a2b6dfSmrg		xtermSetenv("SHELL", shell_path);
5295d522f475Smrg	    } else {
5296e0a2b6dfSmrg		shell_path = resetShell(shell_path);
5297d522f475Smrg	    }
5298e0a2b6dfSmrg
5299e0a2b6dfSmrg	    /*
5300e0a2b6dfSmrg	     * Set $XTERM_SHELL, which is not necessarily a valid shell, but
5301e0a2b6dfSmrg	     * is executable.
5302e0a2b6dfSmrg	     */
5303e0a2b6dfSmrg	    if (validProgram(explicit_shname)) {
5304e0a2b6dfSmrg		shell_path = explicit_shname;
5305e0a2b6dfSmrg	    } else if (shell_path == 0) {
5306e0a2b6dfSmrg		/* this could happen if the explicit shname lost a race */
5307e0a2b6dfSmrg		shell_path = resetShell(shell_path);
53080bd37d32Smrg	    }
53090bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
5310d522f475Smrg
53110bd37d32Smrg	    shname = x_basename(shell_path);
53120bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
5313d522f475Smrg
5314d522f475Smrg#if OPT_LUIT_PROG
5315d522f475Smrg	    /*
5316d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
5317d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
5318d522f475Smrg	     * to command that the user gave anyway.
5319d522f475Smrg	     */
53202eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
53210bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
53220bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
53230bd37d32Smrg		free(myShell);
53240bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
5325d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
53260bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
53270bd37d32Smrg		xtermWarning("cannot support your locale.\n");
5328d522f475Smrg	    }
5329d522f475Smrg#endif
5330d522f475Smrg	    if (command_to_exec) {
53310bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
53320bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
53330bd37d32Smrg		free(myShell);
53340bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
5335d522f475Smrg		execvp(*command_to_exec, command_to_exec);
5336d522f475Smrg		if (command_to_exec[1] == 0)
53370bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
53380bd37d32Smrg			   (void *) 0);
53390bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
5340d522f475Smrg	    }
5341d522f475Smrg#ifdef USE_SYSV_SIGHUP
5342d522f475Smrg	    /* fix pts sh hanging around */
5343d522f475Smrg	    signal(SIGHUP, SIG_DFL);
5344d522f475Smrg#endif
5345d522f475Smrg
53465307cd1aSmrg	    if ((shname_minus = (char *) malloc(strlen(shname) + 2)) != 0) {
534701037d57Smrg		(void) strcpy(shname_minus, "-");
534801037d57Smrg		(void) strcat(shname_minus, shname);
534901037d57Smrg	    } else {
535001037d57Smrg		static char default_minus[] = "-sh";
535101037d57Smrg		shname_minus = default_minus;
535201037d57Smrg	    }
5353d522f475Smrg#ifndef TERMIO_STRUCT
53540bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
53550bd37d32Smrg		     ? NTTYDISC
53560bd37d32Smrg		     : 0);
5357d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
5358d522f475Smrg#endif /* !TERMIO_STRUCT */
5359d522f475Smrg
5360d522f475Smrg#ifdef USE_LOGIN_DASH_P
53610bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
5362d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
5363d522f475Smrg#endif
53642eaa94a1Schristos
53652eaa94a1Schristos#if OPT_LUIT_PROG
53662eaa94a1Schristos	    if (command_to_exec_with_luit) {
53672eaa94a1Schristos		if (xw->misc.login_shell) {
53680bd37d32Smrg		    char *params[4];
53690bd37d32Smrg		    params[0] = x_strdup("-argv0");
53700bd37d32Smrg		    params[1] = shname_minus;
53710bd37d32Smrg		    params[2] = NULL;
53720bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
53730bd37d32Smrg				 + command_length_with_luit,
53740bd37d32Smrg				 params);
53752eaa94a1Schristos		}
53760bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
53772eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
53782eaa94a1Schristos		/* Exec failed. */
53790bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
53802eaa94a1Schristos	    }
53812eaa94a1Schristos#endif
53820bd37d32Smrg	    execlp(shell_path,
5383d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
5384d522f475Smrg		   (void *) 0);
5385d522f475Smrg
5386d522f475Smrg	    /* Exec failed. */
53870bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
538820d2c4d2Smrg	    IGNORE_RC(sleep(5));
53890bd37d32Smrg	    free(shell_path);
5390d522f475Smrg	    exit(ERROR_EXEC);
5391d522f475Smrg	}
5392d522f475Smrg	/* end if in child after fork */
5393d522f475Smrg#if OPT_PTY_HANDSHAKE
5394d522f475Smrg	if (resource.ptyHandshake) {
5395d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
5396d522f475Smrg	     * child process.
5397d522f475Smrg	     */
5398d522f475Smrg
5399d522f475Smrg	    /* close childs's sides of the pipes */
5400d522f475Smrg	    close(cp_pipe[1]);
5401d522f475Smrg	    close(pc_pipe[0]);
5402d522f475Smrg
5403d522f475Smrg	    for (done = 0; !done;) {
5404d522f475Smrg		if (read(cp_pipe[0],
5405d522f475Smrg			 (char *) &handshake,
5406d522f475Smrg			 sizeof(handshake)) <= 0) {
5407d522f475Smrg		    /* Our child is done talking to us.  If it terminated
5408d522f475Smrg		     * due to an error, we will catch the death of child
5409d522f475Smrg		     * and clean up.
5410d522f475Smrg		     */
5411d522f475Smrg		    break;
5412d522f475Smrg		}
5413d522f475Smrg
5414d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
5415d522f475Smrg		switch (handshake.status) {
5416d522f475Smrg		case PTY_GOOD:
5417d522f475Smrg		    /* Success!  Let's free up resources and
5418d522f475Smrg		     * continue.
5419d522f475Smrg		     */
5420d522f475Smrg		    done = 1;
5421d522f475Smrg		    break;
5422d522f475Smrg
5423d522f475Smrg		case PTY_BAD:
5424d522f475Smrg		    /* The open of the pty failed!  Let's get
5425d522f475Smrg		     * another one.
5426d522f475Smrg		     */
542720d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
5428d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
5429d522f475Smrg			/* no more ptys! */
54300bd37d32Smrg			xtermPerror("child process can find no available ptys");
5431d522f475Smrg			handshake.status = PTY_NOMORE;
5432d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
543320d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
543420d2c4d2Smrg					(const char *) &handshake,
543520d2c4d2Smrg					sizeof(handshake)));
5436d522f475Smrg			exit(ERROR_PTYS);
5437d522f475Smrg		    }
5438d522f475Smrg		    handshake.status = PTY_NEW;
5439f2e35a3aSmrg		    copy_handshake(handshake, ttydev);
5440d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
544120d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
544220d2c4d2Smrg				    (const char *) &handshake,
544320d2c4d2Smrg				    sizeof(handshake)));
5444d522f475Smrg		    break;
5445d522f475Smrg
5446d522f475Smrg		case PTY_FATALERROR:
5447d522f475Smrg		    errno = handshake.error;
5448d522f475Smrg		    close(cp_pipe[0]);
5449d522f475Smrg		    close(pc_pipe[1]);
5450d522f475Smrg		    SysError(handshake.fatal_error);
5451d522f475Smrg		    /*NOTREACHED */
5452d522f475Smrg
5453d522f475Smrg		case UTMP_ADDED:
5454d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
5455d522f475Smrg		     * this so that we can reset it later.
5456d522f475Smrg		     */
5457d522f475Smrg		    added_utmp_entry = True;
5458d522f475Smrg#ifndef	USE_SYSV_UTMP
5459d522f475Smrg		    tslot = handshake.tty_slot;
5460d522f475Smrg#endif /* USE_SYSV_UTMP */
5461d522f475Smrg		    free(ttydev);
5462f2e35a3aSmrg		    handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
5463d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
5464d522f475Smrg		    break;
5465d522f475Smrg		case PTY_NEW:
5466d522f475Smrg		case PTY_NOMORE:
5467d522f475Smrg		case UTMP_TTYSLOT:
5468d522f475Smrg		case PTY_EXEC:
5469d522f475Smrg		default:
54700bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
54710bd37d32Smrg				 (int) handshake.status);
5472d522f475Smrg		}
5473d522f475Smrg	    }
5474d522f475Smrg	    /* close our sides of the pipes */
5475d522f475Smrg	    if (!resource.wait_for_map) {
5476d522f475Smrg		close(cp_pipe[0]);
5477d522f475Smrg		close(pc_pipe[1]);
5478d522f475Smrg	    }
5479d522f475Smrg	}
5480d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5481d522f475Smrg    }
5482d522f475Smrg
5483d522f475Smrg    /* end if no slave */
5484d522f475Smrg    /*
5485d522f475Smrg     * still in parent (xterm process)
5486d522f475Smrg     */
5487d522f475Smrg#ifdef USE_SYSV_SIGHUP
5488d522f475Smrg    /* hung sh problem? */
5489d522f475Smrg    signal(SIGHUP, SIG_DFL);
5490d522f475Smrg#else
5491d522f475Smrg    signal(SIGHUP, SIG_IGN);
5492d522f475Smrg#endif
5493d522f475Smrg
5494d522f475Smrg/*
5495d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
5496d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
5497d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
5498d522f475Smrg * don't ignore the signals.  This is annoying.
5499d522f475Smrg */
5500d522f475Smrg
5501d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
5502d522f475Smrg    signal(SIGINT, SIG_IGN);
5503d522f475Smrg
5504d522f475Smrg#ifndef SYSV
5505d522f475Smrg    /* hung shell problem */
5506d522f475Smrg    signal(SIGQUIT, SIG_IGN);
5507d522f475Smrg#endif
5508d522f475Smrg    signal(SIGTERM, SIG_IGN);
5509d522f475Smrg#elif defined(SYSV) || defined(__osf__)
5510d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
5511d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
5512d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
5513d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
5514d522f475Smrg     * tank on everything.
5515d522f475Smrg     */
5516d522f475Smrg    if (getpid() == getpgrp()) {
5517d522f475Smrg	(void) signal(SIGINT, Exit);
5518d522f475Smrg	(void) signal(SIGQUIT, Exit);
5519d522f475Smrg	(void) signal(SIGTERM, Exit);
5520d522f475Smrg    } else {
5521d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
5522d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
5523d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
5524d522f475Smrg    }
5525d522f475Smrg    (void) signal(SIGPIPE, Exit);
5526d522f475Smrg#else /* SYSV */
5527d522f475Smrg    signal(SIGINT, Exit);
5528d522f475Smrg    signal(SIGQUIT, Exit);
5529d522f475Smrg    signal(SIGTERM, Exit);
5530d522f475Smrg    signal(SIGPIPE, Exit);
5531d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
55320bd37d32Smrg#ifdef NO_LEAKS
55330bd37d32Smrg    if (ok_termcap != True)
55340bd37d32Smrg	free(TermName);
55350bd37d32Smrg#endif
5536d522f475Smrg
5537d522f475Smrg    return 0;
5538d522f475Smrg}				/* end spawnXTerm */
5539d522f475Smrg
55400bd37d32Smrgvoid
5541d522f475SmrgExit(int n)
5542d522f475Smrg{
554320d2c4d2Smrg    XtermWidget xw = term;
554420d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
5545d522f475Smrg
5546d522f475Smrg#ifdef USE_UTEMPTER
55470bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
55480bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
55490bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
5550f2e35a3aSmrg	UTEMPTER_DEL();
55510bd37d32Smrg    }
5552d522f475Smrg#elif defined(HAVE_UTMP)
5553d522f475Smrg#ifdef USE_SYSV_UTMP
5554d522f475Smrg    struct UTMP_STR utmp;
5555d522f475Smrg    struct UTMP_STR *utptr;
5556d522f475Smrg
55570bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
5558d522f475Smrg    /* don't do this more than once */
55590bd37d32Smrg    if (xterm_exiting) {
55600bd37d32Smrg	exit(n);
55610bd37d32Smrg    }
5562d522f475Smrg    xterm_exiting = True;
5563d522f475Smrg
5564d522f475Smrg#ifdef PUCC_PTYD
5565d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
5566d522f475Smrg#endif /* PUCC_PTYD */
5567d522f475Smrg
5568d522f475Smrg    /* cleanup the utmp entry we forged earlier */
5569d522f475Smrg    if (!resource.utmpInhibit
5570d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
5571d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
5572d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5573d522f475Smrg	) {
5574d522f475Smrg#if defined(USE_UTMP_SETGID)
5575d522f475Smrg	setEffectiveGroup(save_egid);
5576d522f475Smrg	TRACE_IDS;
5577d522f475Smrg#endif
5578d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
5579d522f475Smrg	(void) call_setutent();
5580d522f475Smrg
5581d522f475Smrg	/*
5582d522f475Smrg	 * We could use getutline() if we didn't support old systems.
5583d522f475Smrg	 */
5584d522f475Smrg	while ((utptr = find_utmp(&utmp)) != 0) {
5585d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
5586d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
5587d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
5588d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
5589d522f475Smrg		utptr->ut_session = getsid(0);
5590d522f475Smrg#endif
5591d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
5592d522f475Smrg		utptr->ut_tv.tv_usec = 0;
5593d522f475Smrg#else
5594d522f475Smrg		*utptr->ut_user = 0;
5595d522f475Smrg		utptr->ut_time = time((time_t *) 0);
5596d522f475Smrg#endif
5597d522f475Smrg		(void) call_pututline(utptr);
5598d522f475Smrg#ifdef WTMP
5599d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
560020d2c4d2Smrg		if (xw->misc.login_shell)
5601d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
560204b94745Smrg#elif defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
5603894e0ac8Smrg		copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
560420d2c4d2Smrg		if (xw->misc.login_shell)
5605d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
5606d522f475Smrg#else
5607d522f475Smrg		/* set wtmp entry if wtmp file exists */
560820d2c4d2Smrg		if (xw->misc.login_shell) {
5609d522f475Smrg		    int fd;
5610d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
56110bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
5612d522f475Smrg			close(fd);
5613d522f475Smrg		    }
5614d522f475Smrg		}
5615d522f475Smrg#endif
5616d522f475Smrg#endif
5617d522f475Smrg		break;
5618d522f475Smrg	    }
5619d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
5620d522f475Smrg	}
5621d522f475Smrg	(void) call_endutent();
5622d522f475Smrg#ifdef USE_UTMP_SETGID
5623d522f475Smrg	disableSetGid();
5624d522f475Smrg	TRACE_IDS;
5625d522f475Smrg#endif
5626d522f475Smrg    }
5627d522f475Smrg#else /* not USE_SYSV_UTMP */
5628d522f475Smrg    int wfd;
5629d522f475Smrg    struct utmp utmp;
5630d522f475Smrg
56310bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
5632d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
5633d522f475Smrg	(am_slave < 0 && tslot > 0)) {
5634d522f475Smrg#if defined(USE_UTMP_SETGID)
5635d522f475Smrg	setEffectiveGroup(save_egid);
5636d522f475Smrg	TRACE_IDS;
5637d522f475Smrg#endif
5638d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
5639956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
5640d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
56410bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5642d522f475Smrg	    close(wfd);
5643d522f475Smrg	}
5644d522f475Smrg#ifdef WTMP
564520d2c4d2Smrg	if (xw->misc.login_shell &&
5646d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
5647894e0ac8Smrg	    copy_filled(utmp.ut_line,
5648894e0ac8Smrg			my_pty_name(ttydev),
5649894e0ac8Smrg			sizeof(utmp.ut_line));
5650d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
56510bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5652d522f475Smrg	    close(wfd);
5653d522f475Smrg	}
5654d522f475Smrg#endif /* WTMP */
5655d522f475Smrg#ifdef USE_UTMP_SETGID
5656d522f475Smrg	disableSetGid();
5657d522f475Smrg	TRACE_IDS;
5658d522f475Smrg#endif
5659d522f475Smrg    }
5660d522f475Smrg#endif /* USE_SYSV_UTMP */
5661d522f475Smrg#endif /* HAVE_UTMP */
5662d522f475Smrg
5663e0a2b6dfSmrg    cleanup_colored_cursor();
5664e0a2b6dfSmrg
5665d522f475Smrg    /*
5666d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
5667d522f475Smrg     * in the middle of the data.
5668d522f475Smrg     */
5669d522f475Smrg    ttyFlush(screen->respond);
5670d522f475Smrg
5671e39b573cSmrg#ifdef USE_PTY_SEARCH
5672d522f475Smrg    if (am_slave < 0) {
5673d522f475Smrg	TRACE_IDS;
5674d522f475Smrg	/* restore ownership of tty and pty */
5675d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
5676d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
5677d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
5678d522f475Smrg#endif
5679d522f475Smrg    }
5680e39b573cSmrg#endif
5681d522f475Smrg
5682d522f475Smrg    /*
56830bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
5684d522f475Smrg     * grabbing it, and *then* having us release ownership....
5685d522f475Smrg     */
5686d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
5687d522f475Smrg#ifdef ALLOWLOGGING
5688d522f475Smrg    if (screen->logging)
568920d2c4d2Smrg	CloseLog(xw);
5690d522f475Smrg#endif
5691d522f475Smrg
5692e39b573cSmrg    xtermPrintOnXError(xw, n);
5693e39b573cSmrg
5694d522f475Smrg#ifdef NO_LEAKS
5695d522f475Smrg    if (n == 0) {
56960bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
56970bd37d32Smrg
5698d522f475Smrg	TRACE(("Freeing memory leaks\n"));
5699d522f475Smrg
57000bd37d32Smrg	if (toplevel) {
57010bd37d32Smrg	    XtDestroyWidget(toplevel);
57020bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
57030bd37d32Smrg	}
57040bd37d32Smrg	sortedOpts(0, 0, 0);
57050bd37d32Smrg	noleaks_charproc();
57060bd37d32Smrg	noleaks_ptydata();
5707894e0ac8Smrg#if OPT_GRAPHICS
57084419d26bSmrg	noleaks_graphics(dpy);
5709894e0ac8Smrg#endif
5710d522f475Smrg#if OPT_WIDE_CHARS
57110bd37d32Smrg	noleaks_CharacterClass();
5712d522f475Smrg#endif
57130bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
57140bd37d32Smrg	XtCloseDisplay(dpy);
57150bd37d32Smrg	XtDestroyApplicationContext(app_con);
57160bd37d32Smrg	xtermCloseSession();
57170bd37d32Smrg	TRACE(("closed display\n"));
57180bd37d32Smrg
571920d2c4d2Smrg	TRACE_CLOSE();
5720d522f475Smrg    }
5721d522f475Smrg#endif
5722d522f475Smrg
5723d522f475Smrg    exit(n);
5724d522f475Smrg}
5725d522f475Smrg
5726d522f475Smrg/* ARGSUSED */
5727d522f475Smrgstatic void
572820d2c4d2Smrgresize_termcap(XtermWidget xw)
5729d522f475Smrg{
573020d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
573120d2c4d2Smrg
5732d522f475Smrg#ifndef USE_SYSV_ENVVARS
573304b94745Smrg    if (!TEK4014_ACTIVE(xw) && newtc != NULL && *newtc) {
5734d522f475Smrg	TScreen *screen = TScreenOf(xw);
5735d522f475Smrg	char *ptr1, *ptr2;
5736d522f475Smrg	size_t i;
5737d522f475Smrg	int li_first = 0;
5738d522f475Smrg	char *temp;
5739d522f475Smrg	char oldtc[TERMCAP_SIZE];
5740d522f475Smrg
5741d522f475Smrg	strcpy(oldtc, newtc);
5742d522f475Smrg	TRACE(("resize %s\n", oldtc));
5743d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
5744d522f475Smrg	    strcat(oldtc, "co#80:");
5745d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
5746d522f475Smrg	}
5747d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
5748d522f475Smrg	    strcat(oldtc, "li#24:");
5749d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
5750d522f475Smrg	}
5751d522f475Smrg	if (ptr1 > ptr2) {
5752d522f475Smrg	    li_first++;
5753d522f475Smrg	    temp = ptr1;
5754d522f475Smrg	    ptr1 = ptr2;
5755d522f475Smrg	    ptr2 = temp;
5756d522f475Smrg	}
5757d522f475Smrg	ptr1 += 3;
5758d522f475Smrg	ptr2 += 3;
5759956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
576004b94745Smrg	if (i >= TERMCAP_SIZE - 10) {
576104b94745Smrg	    TRACE(("...insufficient space: %lu\n", (unsigned long) i));
576204b94745Smrg	    return;
576304b94745Smrg	}
5764d522f475Smrg	temp = newtc + i;
5765d522f475Smrg	sprintf(temp, "%d", (li_first
5766d522f475Smrg			     ? MaxRows(screen)
5767d522f475Smrg			     : MaxCols(screen)));
5768d522f475Smrg	temp += strlen(temp);
57690bd37d32Smrg	if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) {
57700bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
57710bd37d32Smrg	    temp += i;
57720bd37d32Smrg	    sprintf(temp, "%d", (li_first
57730bd37d32Smrg				 ? MaxCols(screen)
57740bd37d32Smrg				 : MaxRows(screen)));
57750bd37d32Smrg	    if ((ptr2 = strchr(ptr2, ':')) != 0) {
57760bd37d32Smrg		strcat(temp, ptr2);
57770bd37d32Smrg	    }
57780bd37d32Smrg	}
5779d522f475Smrg	TRACE(("   ==> %s\n", newtc));
5780d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
5781d522f475Smrg    }
5782d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5783d522f475Smrg}
5784d522f475Smrg
5785d522f475Smrg#endif /* ! VMS */
5786d522f475Smrg
5787d522f475Smrg/*
5788d522f475Smrg * Does a non-blocking wait for a child process.  If the system
5789d522f475Smrg * doesn't support non-blocking wait, do nothing.
5790d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
5791d522f475Smrg */
5792d522f475Smrgint
5793d522f475Smrgnonblocking_wait(void)
5794d522f475Smrg{
5795d522f475Smrg#ifdef USE_POSIX_WAIT
5796d522f475Smrg    pid_t pid;
5797d522f475Smrg
5798d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5799d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5800d522f475Smrg    /* cannot do non-blocking wait */
5801d522f475Smrg    int pid = 0;
5802d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5803d522f475Smrg#if defined(Lynx)
5804d522f475Smrg    int status;
5805d522f475Smrg#else
5806d522f475Smrg    union wait status;
5807d522f475Smrg#endif
5808d522f475Smrg    int pid;
5809d522f475Smrg
5810d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5811d522f475Smrg#endif /* USE_POSIX_WAIT else */
5812d522f475Smrg    return pid;
5813d522f475Smrg}
5814d522f475Smrg
5815d522f475Smrg#ifndef VMS
5816d522f475Smrg
5817d522f475Smrg/* ARGSUSED */
58180bd37d32Smrgstatic void
5819d522f475Smrgreapchild(int n GCC_UNUSED)
5820d522f475Smrg{
5821d522f475Smrg    int olderrno = errno;
5822d522f475Smrg    int pid;
5823d522f475Smrg
58240bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
58250bd37d32Smrg
5826d522f475Smrg    pid = wait(NULL);
5827d522f475Smrg
5828d522f475Smrg#ifdef USE_SYSV_SIGNALS
5829d522f475Smrg    /* cannot re-enable signal before waiting for child
5830d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5831d522f475Smrg     */
5832d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5833d522f475Smrg#endif
5834d522f475Smrg
5835d522f475Smrg    do {
583620d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
58370bd37d32Smrg	    DEBUG_MSG("Exiting\n");
58382e4f8982Smrg	    if (hold_screen)
58392e4f8982Smrg		caught_intr = True;
58402e4f8982Smrg	    else
5841d522f475Smrg		need_cleanup = True;
5842d522f475Smrg	}
5843d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5844d522f475Smrg
5845d522f475Smrg    errno = olderrno;
5846d522f475Smrg}
5847d522f475Smrg#endif /* !VMS */
5848d522f475Smrg
5849d522f475Smrgstatic void
585020d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5851d522f475Smrg{
5852d522f475Smrg    char *base = buf;
5853d522f475Smrg    char *first = base;
5854d522f475Smrg    int count = 0;
5855d522f475Smrg    size_t len = strlen(str);
5856d522f475Smrg
5857d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5858d522f475Smrg
5859d522f475Smrg    while (*buf != 0) {
5860d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5861d522f475Smrg	    while (*buf != 0) {
5862d522f475Smrg		if (*buf == '\\')
5863d522f475Smrg		    buf++;
5864d522f475Smrg		else if (*buf == ':')
5865d522f475Smrg		    break;
5866d522f475Smrg		if (*buf != 0)
5867d522f475Smrg		    buf++;
5868d522f475Smrg	    }
58690bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
58700bd37d32Smrg		;
58710bd37d32Smrg	    }
5872d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5873d522f475Smrg	    return;
5874d522f475Smrg	} else if (*buf == '\\') {
5875d522f475Smrg	    buf++;
5876d522f475Smrg	} else if (*buf == ':') {
5877d522f475Smrg	    first = buf;
5878d522f475Smrg	    count = 0;
5879d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5880d522f475Smrg	    count++;
5881d522f475Smrg	}
5882d522f475Smrg	if (*buf != 0)
5883d522f475Smrg	    buf++;
5884d522f475Smrg    }
5885d522f475Smrg    TRACE(("...cannot remove\n"));
5886d522f475Smrg}
5887d522f475Smrg
5888d522f475Smrg/*
5889d522f475Smrg * parse_tty_modes accepts lines of the following form:
5890d522f475Smrg *
5891d522f475Smrg *         [SETTING] ...
5892d522f475Smrg *
5893f2e35a3aSmrg * where setting consists of the words in the ttyModes[] array followed by a
5894f2e35a3aSmrg * character or ^char.
5895d522f475Smrg */
5896d522f475Smrgstatic int
5897f2e35a3aSmrgparse_tty_modes(char *s)
5898d522f475Smrg{
5899d522f475Smrg    int c;
5900f2e35a3aSmrg    Cardinal j, k;
5901d522f475Smrg    int count = 0;
5902f2e35a3aSmrg    Boolean found;
5903d522f475Smrg
5904d522f475Smrg    TRACE(("parse_tty_modes\n"));
5905a1f3da82Smrg    for (;;) {
5906d522f475Smrg	size_t len;
5907d522f475Smrg
5908f2e35a3aSmrg	while (*s && isspace(CharOf(*s))) {
5909d522f475Smrg	    s++;
5910f2e35a3aSmrg	}
5911f2e35a3aSmrg	if (!*s) {
5912d522f475Smrg	    return count;
5913f2e35a3aSmrg	}
5914d522f475Smrg
5915f2e35a3aSmrg	for (len = 0; s[len] && !isspace(CharOf(s[len])); ++len) {
5916f2e35a3aSmrg	    ;
5917f2e35a3aSmrg	}
5918f2e35a3aSmrg	found = False;
5919f2e35a3aSmrg	for (j = 0; j < XtNumber(ttyModes); ++j) {
5920f2e35a3aSmrg	    if (len == ttyModes[j].len
5921f2e35a3aSmrg		&& strncmp(s,
5922f2e35a3aSmrg			   ttyModes[j].name,
5923f2e35a3aSmrg			   ttyModes[j].len) == 0) {
5924f2e35a3aSmrg		found = True;
5925d522f475Smrg		break;
5926f2e35a3aSmrg	    }
5927d522f475Smrg	}
5928f2e35a3aSmrg	if (!found) {
5929d522f475Smrg	    return -1;
5930f2e35a3aSmrg	}
5931d522f475Smrg
5932f2e35a3aSmrg	s += ttyModes[j].len;
5933f2e35a3aSmrg	while (*s && isspace(CharOf(*s))) {
5934d522f475Smrg	    s++;
5935f2e35a3aSmrg	}
5936d522f475Smrg
5937f2e35a3aSmrg	/* check if this needs a parameter */
5938f2e35a3aSmrg	found = False;
5939f2e35a3aSmrg	for (k = 0, c = 0; k < XtNumber(ttyChars); ++k) {
5940f2e35a3aSmrg	    if ((int) j == ttyChars[k].myMode) {
5941f2e35a3aSmrg		if (ttyChars[k].sysMode < 0) {
5942f2e35a3aSmrg		    found = True;
5943f2e35a3aSmrg		    c = ttyChars[k].myDefault;
5944f2e35a3aSmrg		}
5945f2e35a3aSmrg		break;
5946f2e35a3aSmrg	    }
5947f2e35a3aSmrg	}
5948f2e35a3aSmrg
5949f2e35a3aSmrg	if (!found) {
5950f2e35a3aSmrg	    if (!*s
5951f2e35a3aSmrg		|| (c = decode_keyvalue(&s, False)) == -1) {
5952f2e35a3aSmrg		return -1;
5953f2e35a3aSmrg	    }
5954d522f475Smrg	}
5955f2e35a3aSmrg	ttyModes[j].value = c;
5956f2e35a3aSmrg	ttyModes[j].set = 1;
5957f2e35a3aSmrg	count++;
5958f2e35a3aSmrg	TRACE(("...parsed #%d: %s=%#x\n", count, ttyModes[j].name, c));
5959d522f475Smrg    }
5960d522f475Smrg}
5961d522f475Smrg
596204b94745Smrg#ifndef GetBytesAvailable
5963d522f475Smrgint
596404b94745SmrgGetBytesAvailable(Display *dpy)
5965d522f475Smrg{
596604b94745Smrg    int fd = ConnectionNumber(dpy);
596704b94745Smrg    int result;
5968d522f475Smrg#if defined(FIONREAD)
596904b94745Smrg    ioctl(fd, FIONREAD, (char *) &result);
5970d522f475Smrg#elif defined(__CYGWIN__)
5971d522f475Smrg    fd_set set;
597220d2c4d2Smrg    struct timeval select_timeout =
5973d522f475Smrg    {0, 0};
5974d522f475Smrg
5975d522f475Smrg    FD_ZERO(&set);
5976d522f475Smrg    FD_SET(fd, &set);
597704b94745Smrg    result = (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0) ? 1 : 0;
597804b94745Smrg#else
5979d522f475Smrg    struct pollfd pollfds[1];
5980d522f475Smrg
5981d522f475Smrg    pollfds[0].fd = fd;
5982d522f475Smrg    pollfds[0].events = POLLIN;
598304b94745Smrg    result = poll(pollfds, 1, 0);
5984d522f475Smrg#endif
598504b94745Smrg    return result;
5986d522f475Smrg}
5987d522f475Smrg#endif /* !VMS */
5988d522f475Smrg
5989d522f475Smrg/* Utility function to try to hide system differences from
5990d522f475Smrg   everybody who used to call killpg() */
5991d522f475Smrg
5992d522f475Smrgint
5993d522f475Smrgkill_process_group(int pid, int sig)
5994d522f475Smrg{
5995d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5996d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5997d522f475Smrg    return kill(-pid, sig);
5998d522f475Smrg#else
5999d522f475Smrg    return killpg(pid, sig);
6000d522f475Smrg#endif
6001d522f475Smrg}
6002d522f475Smrg
6003d522f475Smrg#if OPT_EBCDIC
6004d522f475Smrgint
6005d522f475SmrgA2E(int x)
6006d522f475Smrg{
6007d522f475Smrg    char c;
6008d522f475Smrg    c = x;
6009d522f475Smrg    __atoe_l(&c, 1);
6010d522f475Smrg    return c;
6011d522f475Smrg}
6012d522f475Smrg
6013d522f475Smrgint
6014d522f475SmrgE2A(int x)
6015d522f475Smrg{
6016d522f475Smrg    char c;
6017d522f475Smrg    c = x;
6018d522f475Smrg    __etoa_l(&c, 1);
6019d522f475Smrg    return c;
6020d522f475Smrg}
6021d522f475Smrg#endif
6022d522f475Smrg
6023d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
6024d522f475Smrg#include <sys/types.h>
6025d522f475Smrg#include <sys/proc_msg.h>
6026d522f475Smrg#include <sys/kernel.h>
6027d522f475Smrg#include <string.h>
6028d522f475Smrg#include <errno.h>
6029d522f475Smrg
6030d522f475Smrgstruct _proc_session ps;
6031d522f475Smrgstruct _proc_session_reply rps;
6032d522f475Smrg
6033d522f475Smrgint
6034d522f475Smrgqsetlogin(char *login, char *ttyname)
6035d522f475Smrg{
6036d522f475Smrg    int v = getsid(getpid());
6037d522f475Smrg
6038d522f475Smrg    memset(&ps, 0, sizeof(ps));
6039d522f475Smrg    memset(&rps, 0, sizeof(rps));
6040d522f475Smrg
6041d522f475Smrg    ps.type = _PROC_SESSION;
6042d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
6043d522f475Smrg    ps.sid = v;
6044d522f475Smrg    strcpy(ps.name, login);
6045d522f475Smrg
6046d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
6047d522f475Smrg
6048d522f475Smrg    if (rps.status < 0)
6049d522f475Smrg	return (rps.status);
6050d522f475Smrg
6051d522f475Smrg    ps.type = _PROC_SESSION;
6052d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
6053d522f475Smrg    ps.sid = v;
6054d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
6055d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
6056d522f475Smrg
6057d522f475Smrg    return (rps.status);
6058d522f475Smrg}
6059d522f475Smrg#endif
606001037d57Smrg
606101037d57Smrg#ifdef __minix
606201037d57Smrgint
606301037d57Smrgsetpgrp(void)
606401037d57Smrg{
606501037d57Smrg    return 0;
606601037d57Smrg}
606701037d57Smrg
606801037d57Smrgvoid
606901037d57Smrg_longjmp(jmp_buf _env, int _val)
607001037d57Smrg{
607101037d57Smrg    longjmp(_env, _val);
607201037d57Smrg}
607301037d57Smrg#endif
6074