15104ee6eSmrg/* $XTermId: main.c,v 1.930 2024/12/01 19:57:13 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 __CYGWIN__
185d522f475Smrg#define WTMP
186d522f475Smrg#endif
187d522f475Smrg
188d522f475Smrg#ifdef __SCO__
189d522f475Smrg#ifndef _SVID3
190d522f475Smrg#define _SVID3
191d522f475Smrg#endif
192d522f475Smrg#endif
193d522f475Smrg
19404b94745Smrg#if defined(__GLIBC__) && !defined(__linux__)
195d522f475Smrg#define USE_SYSV_PGRP
196d522f475Smrg#define WTMP
197d522f475Smrg#endif
198d522f475Smrg
199f2e35a3aSmrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID) || defined(HAVE_INITGROUPS)
200d522f475Smrg#include <grp.h>
201d522f475Smrg#endif
202d522f475Smrg
203d522f475Smrg#ifndef TTY_GROUP_NAME
204d522f475Smrg#define TTY_GROUP_NAME "tty"
205d522f475Smrg#endif
206d522f475Smrg
207d522f475Smrg#include <sys/stat.h>
208d522f475Smrg
209d522f475Smrg#ifdef Lynx
210d522f475Smrg#ifndef BSDLY
211d522f475Smrg#define BSDLY	0
212d522f475Smrg#endif
213d522f475Smrg#ifndef VTDLY
214d522f475Smrg#define VTDLY	0
215d522f475Smrg#endif
216d522f475Smrg#ifndef FFDLY
217d522f475Smrg#define FFDLY	0
218d522f475Smrg#endif
219d522f475Smrg#endif
220d522f475Smrg
221d522f475Smrg#ifdef SYSV			/* { */
222d522f475Smrg
223d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
224d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
225d522f475Smrg#include <poll.h>		/* for POLLIN */
226d522f475Smrg#endif /* USE_USG_PTYS */
227d522f475Smrg
228d522f475Smrg#define USE_SYSV_SIGNALS
229d522f475Smrg#define	USE_SYSV_PGRP
230d522f475Smrg
231d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
232d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
233d522f475Smrg#endif
234d522f475Smrg
235d522f475Smrg/*
236d522f475Smrg * now get system-specific includes
237d522f475Smrg */
238d522f475Smrg#ifdef macII
239d522f475Smrg#include <sys/ttychars.h>
240d522f475Smrg#undef USE_SYSV_ENVVARS
241d522f475Smrg#undef FIOCLEX
242d522f475Smrg#undef FIONCLEX
243d522f475Smrg#define setpgrp2 setpgrp
244d522f475Smrg#include <sgtty.h>
245d522f475Smrg#include <sys/resource.h>
246d522f475Smrg#endif
247d522f475Smrg
248d522f475Smrg#ifdef __hpux
249d522f475Smrg#include <sys/ptyio.h>
250d522f475Smrg#endif /* __hpux */
251d522f475Smrg
252d522f475Smrg#ifdef __osf__
253d522f475Smrg#undef  USE_SYSV_PGRP
254d522f475Smrg#define setpgrp setpgid
255d522f475Smrg#endif
256d522f475Smrg
257d522f475Smrg#ifdef __sgi
258d522f475Smrg#include <sys/sysmacros.h>
259d522f475Smrg#endif /* __sgi */
260d522f475Smrg
261d522f475Smrg#ifdef sun
262d522f475Smrg#include <sys/strredir.h>
263d522f475Smrg#endif
264d522f475Smrg
265e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
266d522f475Smrg
267d522f475Smrg#ifdef __QNX__
268d522f475Smrg
269d522f475Smrg#ifndef __QNXNTO__
270d522f475Smrg#define ttyslot() 1
271d522f475Smrg#else
272d522f475Smrg#define USE_SYSV_PGRP
273d522f475Smrgextern __inline__
274d522f475Smrgint
275d522f475Smrgttyslot(void)
276d522f475Smrg{
277d522f475Smrg    return 1;			/* yuk */
278d522f475Smrg}
279d522f475Smrg#endif
280d522f475Smrg
281d522f475Smrg#else
282d522f475Smrg
283d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
284d522f475Smrg#define setpgrp setpgid
285d522f475Smrg#endif
286d522f475Smrg
28704b94745Smrg#ifndef __linux__
288d522f475Smrg#ifndef USE_POSIX_TERMIOS
289d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
290d522f475Smrg#include <sgtty.h>
291d522f475Smrg#endif
292d522f475Smrg#endif /* USE_POSIX_TERMIOS */
293d522f475Smrg#ifdef Lynx
294d522f475Smrg#include <resource.h>
295d522f475Smrg#else
296d522f475Smrg#include <sys/resource.h>
297d522f475Smrg#endif
29804b94745Smrg#endif /* !__linux__ */
299d522f475Smrg
300d522f475Smrg#endif /* __QNX__ */
301d522f475Smrg
302d522f475Smrg#endif /* } !SYSV */
303d522f475Smrg
304d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
305d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
306d522f475Smrg#ifndef NOFILE
307d522f475Smrg#define NOFILE OPEN_MAX
308d522f475Smrg#endif
3095104ee6eSmrg#elif !(defined(WIN32) || defined(Lynx) || defined(__GNU__))
310d522f475Smrg#include <sys/param.h>		/* for NOFILE */
311d522f475Smrg#endif
312d522f475Smrg
313d522f475Smrg#if defined(BSD) && (BSD >= 199103)
314d522f475Smrg#define WTMP
315d522f475Smrg#endif
316d522f475Smrg
317d522f475Smrg#include <stdio.h>
31804b94745Smrg#include <math.h>
319d522f475Smrg
320d522f475Smrg#ifdef __hpux
321d522f475Smrg#include <sys/utsname.h>
322d522f475Smrg#endif /* __hpux */
323d522f475Smrg
324d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
325d522f475Smrg#define ttyslot() 1
326d522f475Smrg#endif /* apollo */
327d522f475Smrg
328d522f475Smrg#if defined(UTMPX_FOR_UTMP)
329d522f475Smrg#define UTMP_STR utmpx
330d522f475Smrg#else
331d522f475Smrg#define UTMP_STR utmp
332d522f475Smrg#endif
333d522f475Smrg
334d522f475Smrg#if defined(USE_UTEMPTER)
335d522f475Smrg#include <utempter.h>
336f2e35a3aSmrg#if 1
337f2e35a3aSmrg#define UTEMPTER_ADD(pty,hostname,master_fd) utempter_add_record(master_fd, hostname)
338f2e35a3aSmrg#define UTEMPTER_DEL()                       utempter_remove_added_record ()
339f2e35a3aSmrg#else
340f2e35a3aSmrg#define UTEMPTER_ADD(pty,hostname,master_fd) addToUtmp(pty, hostname, master_fd)
341f2e35a3aSmrg#define UTEMPTER_DEL()                       removeFromUtmp()
342f2e35a3aSmrg#endif
343d522f475Smrg#endif
344d522f475Smrg
3452e4f8982Smrg#if defined(I_FIND) && defined(I_PUSH)
3462e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_FIND, name) == 0 \
3472e4f8982Smrg			 && ioctl(fd, I_PUSH, name) < 0
3482e4f8982Smrg#else
3492e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_PUSH, name) < 0
3502e4f8982Smrg#endif
3512e4f8982Smrg
352d522f475Smrg#if defined(UTMPX_FOR_UTMP)
353d522f475Smrg
354d522f475Smrg#include <utmpx.h>
355d522f475Smrg
356d522f475Smrg#define call_endutent  endutxent
357d522f475Smrg#define call_getutid   getutxid
358d522f475Smrg#define call_pututline pututxline
359d522f475Smrg#define call_setutent  setutxent
360d522f475Smrg#define call_updwtmp   updwtmpx
361d522f475Smrg
362d522f475Smrg#elif defined(HAVE_UTMP)
363d522f475Smrg
364d522f475Smrg#include <utmp.h>
365d522f475Smrg
366d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
367d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
368d522f475Smrg#endif
369d522f475Smrg
370d522f475Smrg#define call_endutent  endutent
371d522f475Smrg#define call_getutid   getutid
372d522f475Smrg#define call_pututline pututline
373d522f475Smrg#define call_setutent  setutent
374d522f475Smrg#define call_updwtmp   updwtmp
375d522f475Smrg
376d522f475Smrg#endif
377d522f475Smrg
378d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
379d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
380d522f475Smrg#endif
381d522f475Smrg
382d522f475Smrg#ifndef USE_LASTLOGX
383d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
384d522f475Smrg#define USE_LASTLOGX 1
385d522f475Smrg#endif
386d522f475Smrg#endif
387d522f475Smrg
388d522f475Smrg#ifdef  PUCC_PTYD
389d522f475Smrg#include <local/openpty.h>
390d522f475Smrg#endif /* PUCC_PTYD */
391d522f475Smrg
392d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
393d522f475Smrg#include <util.h>		/* openpty() */
394d522f475Smrg#endif
395d522f475Smrg
396956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
397d522f475Smrg#include <libutil.h>		/* openpty() */
398d522f475Smrg#endif
399d522f475Smrg
400d522f475Smrg#if !defined(UTMP_FILENAME)
401d522f475Smrg#if defined(UTMP_FILE)
402d522f475Smrg#define UTMP_FILENAME UTMP_FILE
403d522f475Smrg#elif defined(_PATH_UTMP)
404d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
405d522f475Smrg#else
406d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
407d522f475Smrg#endif
408d522f475Smrg#endif
409d522f475Smrg
410d522f475Smrg#ifndef LASTLOG_FILENAME
411d522f475Smrg#ifdef _PATH_LASTLOG
412d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
413d522f475Smrg#else
414d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
415d522f475Smrg#endif
416d522f475Smrg#endif
417d522f475Smrg
418d522f475Smrg#if !defined(WTMP_FILENAME)
419d522f475Smrg#if defined(WTMP_FILE)
420d522f475Smrg#define WTMP_FILENAME WTMP_FILE
421d522f475Smrg#elif defined(_PATH_WTMP)
422d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
423d522f475Smrg#elif defined(SYSV)
424d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
425d522f475Smrg#else
426d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
427d522f475Smrg#endif
428d522f475Smrg#endif
429d522f475Smrg
430d522f475Smrg#include <signal.h>
431d522f475Smrg
43204b94745Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_VERSION))
433d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
434d522f475Smrg#endif
435d522f475Smrg
436d522f475Smrg#ifdef SIGTSTP
437d522f475Smrg#include <sys/wait.h>
438d522f475Smrg#endif
439d522f475Smrg
440d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
441d522f475Smrg#undef ECHOKE
442d522f475Smrg#undef ECHOCTL
443d522f475Smrg#endif
444d522f475Smrg
445d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
446d522f475Smrg#include <sys/ttydefaults.h>
447d522f475Smrg#endif
448d522f475Smrg
449d522f475Smrg#ifdef X_NOT_POSIX
450d522f475Smrgextern long lseek();
451d522f475Smrg#if defined(USG) || defined(SVR4)
452d522f475Smrgextern unsigned sleep();
453d522f475Smrg#else
454d522f475Smrgextern void sleep();
455d522f475Smrg#endif
456d522f475Smrgextern char *ttyname();
457d522f475Smrg#endif
458d522f475Smrg
459d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
460d522f475Smrgextern char *ptsname(int);
461d522f475Smrg#endif
462d522f475Smrg
4630bd37d32Smrgstatic void reapchild(int /* n */ );
4642e4f8982Smrgstatic int spawnXTerm(XtermWidget	/* xw */
4652e4f8982Smrg		      ,unsigned /* line_speed */ );
46620d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
467d522f475Smrg#ifdef USE_PTY_SEARCH
46820d2c4d2Smrgstatic int pty_search(int * /* pty */ );
469d522f475Smrg#endif
470d522f475Smrg
471d522f475Smrgstatic int get_pty(int *pty, char *from);
47220d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
473e0a2b6dfSmrgstatic void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
474d522f475Smrg
475d522f475Smrgstatic Bool added_utmp_entry = False;
476d522f475Smrg
477d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
478d522f475Smrgstatic uid_t save_euid;
479d522f475Smrgstatic gid_t save_egid;
480d522f475Smrg#endif
481d522f475Smrg
482d522f475Smrgstatic uid_t save_ruid;
483d522f475Smrgstatic gid_t save_rgid;
484d522f475Smrg
485d522f475Smrg#if defined(USE_UTMP_SETGID)
486d522f475Smrgstatic int really_get_pty(int *pty, char *from);
487d522f475Smrg#endif
488d522f475Smrg
489d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
490d522f475Smrgstatic Bool xterm_exiting = False;
491d522f475Smrg#endif
492d522f475Smrg
493d522f475Smrgstatic char *explicit_shname = NULL;
494d522f475Smrg
495d522f475Smrg/*
496d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
497d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
498d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
499d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
500d522f475Smrg** SEGV.
501d522f475Smrg*/
502d522f475Smrgstatic char **command_to_exec = NULL;
503d522f475Smrg
504d522f475Smrg#if OPT_LUIT_PROG
505d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
5060bd37d32Smrgstatic unsigned command_length_with_luit = 0;
507d522f475Smrg#endif
508d522f475Smrg
509d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
510d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
511d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
512d522f475Smrg * about padding generally store the code in a short, which does not have
513d522f475Smrg * enough bits for the extended values.
514d522f475Smrg */
515d522f475Smrg#ifdef B38400			/* everyone should define this */
516d522f475Smrg#define VAL_LINE_SPEED B38400
517d522f475Smrg#else /* ...but xterm's used this for a long time */
518d522f475Smrg#define VAL_LINE_SPEED B9600
519d522f475Smrg#endif
520d522f475Smrg
521d522f475Smrg/*
522d522f475Smrg * Allow use of system default characters if defined and reasonable.
523d522f475Smrg * These are based on the BSD ttydefaults.h
524d522f475Smrg */
525d522f475Smrg#ifndef CBRK
526d522f475Smrg#define CBRK     0xff		/* was 0 */
527d522f475Smrg#endif
528d522f475Smrg#ifndef CDISCARD
529d522f475Smrg#define CDISCARD CONTROL('O')
530d522f475Smrg#endif
531d522f475Smrg#ifndef CDSUSP
532d522f475Smrg#define CDSUSP   CONTROL('Y')
533d522f475Smrg#endif
534d522f475Smrg#ifndef CEOF
535d522f475Smrg#define CEOF     CONTROL('D')
536d522f475Smrg#endif
537d522f475Smrg#ifndef CEOL
538d522f475Smrg#define CEOL	 0xff		/* was 0 */
539d522f475Smrg#endif
540d522f475Smrg#ifndef CERASE
541d522f475Smrg#define CERASE   0177
542d522f475Smrg#endif
543d522f475Smrg#ifndef CERASE2
544d522f475Smrg#define	CERASE2  CONTROL('H')
545d522f475Smrg#endif
546d522f475Smrg#ifndef CFLUSH
547d522f475Smrg#define CFLUSH   CONTROL('O')
548d522f475Smrg#endif
549d522f475Smrg#ifndef CINTR
550d522f475Smrg#define CINTR    CONTROL('C')
551d522f475Smrg#endif
552d522f475Smrg#ifndef CKILL
553d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
554d522f475Smrg#endif
555d522f475Smrg#ifndef CLNEXT
556d522f475Smrg#define CLNEXT   CONTROL('V')
557d522f475Smrg#endif
558d522f475Smrg#ifndef CNUL
559d522f475Smrg#define CNUL     0
560d522f475Smrg#endif
561d522f475Smrg#ifndef CQUIT
562d522f475Smrg#define CQUIT    CONTROL('\\')
563d522f475Smrg#endif
564d522f475Smrg#ifndef CRPRNT
565d522f475Smrg#define CRPRNT   CONTROL('R')
566d522f475Smrg#endif
567d522f475Smrg#ifndef CREPRINT
568d522f475Smrg#define CREPRINT CRPRNT
569d522f475Smrg#endif
570d522f475Smrg#ifndef CSTART
571d522f475Smrg#define CSTART   CONTROL('Q')
572d522f475Smrg#endif
573d522f475Smrg#ifndef CSTATUS
574d522f475Smrg#define	CSTATUS  CONTROL('T')
575d522f475Smrg#endif
576d522f475Smrg#ifndef CSTOP
577d522f475Smrg#define CSTOP    CONTROL('S')
578d522f475Smrg#endif
579d522f475Smrg#ifndef CSUSP
580d522f475Smrg#define CSUSP    CONTROL('Z')
581d522f475Smrg#endif
582d522f475Smrg#ifndef CSWTCH
583d522f475Smrg#define CSWTCH   0
584d522f475Smrg#endif
585d522f475Smrg#ifndef CWERASE
586d522f475Smrg#define CWERASE  CONTROL('W')
587d522f475Smrg#endif
588d522f475Smrg
589d522f475Smrg#ifdef TERMIO_STRUCT
590d522f475Smrg/* The following structures are initialized in main() in order
591d522f475Smrg** to eliminate any assumptions about the internal order of their
592d522f475Smrg** contents.
593d522f475Smrg*/
594d522f475Smrgstatic TERMIO_STRUCT d_tio;
595d522f475Smrg
596f2e35a3aSmrg#ifndef ONLCR
597f2e35a3aSmrg#define ONLCR 0
598f2e35a3aSmrg#endif
599f2e35a3aSmrg
600f2e35a3aSmrg#ifndef OPOST
601f2e35a3aSmrg#define OPOST 0
602f2e35a3aSmrg#endif
603f2e35a3aSmrg
604f2e35a3aSmrg#define D_TIO_FLAGS (OPOST | ONLCR)
605f2e35a3aSmrg
606d522f475Smrg#ifdef HAS_LTCHARS
607d522f475Smrgstatic struct ltchars d_ltc;
608d522f475Smrg#endif /* HAS_LTCHARS */
609d522f475Smrg
610d522f475Smrg#ifdef TIOCLSET
611d522f475Smrgstatic unsigned int d_lmode;
612d522f475Smrg#endif /* TIOCLSET */
613d522f475Smrg
614d522f475Smrg#else /* !TERMIO_STRUCT */
615f2e35a3aSmrg
616f2e35a3aSmrg#define D_SG_FLAGS (EVENP | ODDP | ECHO | CRMOD)
617f2e35a3aSmrg
618d522f475Smrgstatic struct sgttyb d_sg =
619d522f475Smrg{
620f2e35a3aSmrg    0, 0, 0177, CKILL, (D_SG_FLAGS | XTABS)
621d522f475Smrg};
622d522f475Smrgstatic struct tchars d_tc =
623d522f475Smrg{
624d522f475Smrg    CINTR, CQUIT, CSTART,
625d522f475Smrg    CSTOP, CEOF, CBRK
626d522f475Smrg};
627d522f475Smrgstatic struct ltchars d_ltc =
628d522f475Smrg{
629d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
630d522f475Smrg    CFLUSH, CWERASE, CLNEXT
631d522f475Smrg};
632d522f475Smrgstatic int d_disipline = NTTYDISC;
633d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
634d522f475Smrg#ifdef sony
635d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
636d522f475Smrgstatic struct jtchars d_jtc =
637d522f475Smrg{
638d522f475Smrg    'J', 'B'
639d522f475Smrg};
640d522f475Smrg#endif /* sony */
641d522f475Smrg#endif /* TERMIO_STRUCT */
642d522f475Smrg
643d522f475Smrg/*
644d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
645d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
646d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
647d522f475Smrg */
648d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
649d522f475Smrgstatic Boolean override_tty_modes = False;
650d522f475Smrg/* *INDENT-OFF* */
651f2e35a3aSmrgstatic struct {
65220d2c4d2Smrg    const char *name;
653d522f475Smrg    size_t len;
654d522f475Smrg    int set;
655d522f475Smrg    int value;
656f2e35a3aSmrg} ttyModes[] = {
657d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
658d522f475Smrg#define XTTYMODE_intr	0
659d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
660d522f475Smrg#define XTTYMODE_quit	1
661d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
662d522f475Smrg#define XTTYMODE_erase	2
663d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
664d522f475Smrg#define XTTYMODE_kill	3
665d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
666d522f475Smrg#define XTTYMODE_eof	4
667d522f475Smrg    TTYMODE("eol"),		/* VEOL */
668d522f475Smrg#define XTTYMODE_eol	5
669d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
670d522f475Smrg#define XTTYMODE_swtch	6
671d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
672d522f475Smrg#define XTTYMODE_start	7
673d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
674d522f475Smrg#define XTTYMODE_stop	8
675d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
676d522f475Smrg#define XTTYMODE_brk	9
677d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
678d522f475Smrg#define XTTYMODE_susp	10
679d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
680d522f475Smrg#define XTTYMODE_dsusp	11
681d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
682d522f475Smrg#define XTTYMODE_rprnt	12
683d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
684d522f475Smrg#define XTTYMODE_flush	13
685d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
686d522f475Smrg#define XTTYMODE_weras	14
687d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
688d522f475Smrg#define XTTYMODE_lnext	15
689d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
690d522f475Smrg#define XTTYMODE_status	16
691d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
692d522f475Smrg#define XTTYMODE_erase2	17
693d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
694d522f475Smrg#define XTTYMODE_eol2	18
695f2e35a3aSmrg    TTYMODE("tabs"),		/* TAB0 */
696f2e35a3aSmrg#define XTTYMODE_tabs	19
697f2e35a3aSmrg    TTYMODE("-tabs"),		/* TAB3 */
698f2e35a3aSmrg#define XTTYMODE__tabs	20
699d522f475Smrg};
700d522f475Smrg
701f2e35a3aSmrg#ifndef TAB0
702f2e35a3aSmrg#define TAB0 0
703f2e35a3aSmrg#endif
704f2e35a3aSmrg
705f2e35a3aSmrg#ifndef TAB3
706f2e35a3aSmrg#if defined(OXTABS)
707f2e35a3aSmrg#define TAB3 OXTABS
708f2e35a3aSmrg#elif defined(XTABS)
709f2e35a3aSmrg#define TAB3 XTABS
710f2e35a3aSmrg#endif
711f2e35a3aSmrg#endif
712f2e35a3aSmrg
713f2e35a3aSmrg#ifndef TABDLY
714f2e35a3aSmrg#define TABDLY (TAB0|TAB3)
715f2e35a3aSmrg#endif
716f2e35a3aSmrg
717f2e35a3aSmrg#define isTtyMode(p,q) (ttyChars[p].myMode == q && ttyModes[q].set)
718f2e35a3aSmrg
719f2e35a3aSmrg#define isTabMode(n) \
720f2e35a3aSmrg	(isTtyMode(n, XTTYMODE_tabs) || \
721f2e35a3aSmrg	 isTtyMode(n, XTTYMODE__tabs))
722f2e35a3aSmrg
723f2e35a3aSmrg#define TMODE(ind,var) \
724f2e35a3aSmrg	if (ttyModes[ind].set) \
725f2e35a3aSmrg	    var = (cc_t) ttyModes[ind].value
726f2e35a3aSmrg
727d522f475Smrg#define validTtyChar(data, n) \
728f2e35a3aSmrg	    (ttyChars[n].sysMode >= 0 && \
729f2e35a3aSmrg	     ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
730d522f475Smrg
731d522f475Smrgstatic const struct {
732d522f475Smrg    int sysMode;
733d522f475Smrg    int myMode;
734d522f475Smrg    int myDefault;
735f2e35a3aSmrg} ttyChars[] = {
736d522f475Smrg#ifdef VINTR
737d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
738d522f475Smrg#endif
739d522f475Smrg#ifdef VQUIT
740d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
741d522f475Smrg#endif
742d522f475Smrg#ifdef VERASE
743d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
744d522f475Smrg#endif
745d522f475Smrg#ifdef VKILL
746d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
747d522f475Smrg#endif
748d522f475Smrg#ifdef VEOF
749d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
750d522f475Smrg#endif
751d522f475Smrg#ifdef VEOL
752d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
753d522f475Smrg#endif
754d522f475Smrg#ifdef VSWTCH
755d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
756d522f475Smrg#endif
757d522f475Smrg#ifdef VSTART
758d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
759d522f475Smrg#endif
760d522f475Smrg#ifdef VSTOP
761d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
762d522f475Smrg#endif
763d522f475Smrg#ifdef VSUSP
764d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
765d522f475Smrg#endif
766d522f475Smrg#ifdef VDSUSP
767d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
768d522f475Smrg#endif
769d522f475Smrg#ifdef VREPRINT
770d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
771d522f475Smrg#endif
772d522f475Smrg#ifdef VDISCARD
773d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
774d522f475Smrg#endif
775d522f475Smrg#ifdef VWERASE
776d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
777d522f475Smrg#endif
778d522f475Smrg#ifdef VLNEXT
779d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
780d522f475Smrg#endif
781d522f475Smrg#ifdef VSTATUS
782d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
783d522f475Smrg#endif
784d522f475Smrg#ifdef VERASE2
785d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
786d522f475Smrg#endif
787d522f475Smrg#ifdef VEOL2
788d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
789d522f475Smrg#endif
790f2e35a3aSmrg    { -1,       XTTYMODE_tabs,   TAB0 },
791f2e35a3aSmrg    { -1,       XTTYMODE__tabs,  TAB3 },
792d522f475Smrg};
793d522f475Smrg/* *INDENT-ON* */
794d522f475Smrg
795f2e35a3aSmrgstatic int parse_tty_modes(char *s);
796d522f475Smrg
797d522f475Smrg#ifndef USE_UTEMPTER
798d522f475Smrg#ifdef USE_SYSV_UTMP
799d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
800d522f475Smrgextern struct utmp *getutid();
801d522f475Smrg#endif /* AIXV3 */
802d522f475Smrg
803d522f475Smrg#else /* not USE_SYSV_UTMP */
804d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
805d522f475Smrg#endif /* USE_SYSV_UTMP */
806d522f475Smrg
807d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
808d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
809d522f475Smrg#else
810d522f475Smrg#undef USE_LASTLOG
811d522f475Smrg#endif
812d522f475Smrg
813d522f475Smrg#ifdef WTMP
814d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
815d522f475Smrg#endif
816d522f475Smrg#endif /* !USE_UTEMPTER */
817d522f475Smrg
818d522f475Smrg/*
819d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
820d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
821d522f475Smrg * WTMP and USE_LASTLOG.
822d522f475Smrg */
823d522f475Smrg#ifdef USE_LOGIN_DASH_P
824d522f475Smrg#ifndef LOGIN_FILENAME
825d522f475Smrg#define LOGIN_FILENAME "/bin/login"
826d522f475Smrg#endif
827d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
828d522f475Smrg#endif
829d522f475Smrg
83001037d57Smrgstatic char noPassedPty[2];
83101037d57Smrgstatic char *passedPty = noPassedPty;	/* name if pty if slave */
832d522f475Smrg
833d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
834d522f475Smrgstatic int Console;
835d522f475Smrg#include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
836d522f475Smrg#define MIT_CONSOLE_LEN	12
837d522f475Smrg#define MIT_CONSOLE "MIT_CONSOLE_"
838d522f475Smrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
839d522f475Smrgstatic Atom mit_console;
840d522f475Smrg#endif /* TIOCCONS */
841d522f475Smrg
842d522f475Smrg#ifndef USE_SYSV_UTMP
843d522f475Smrgstatic int tslot;
844d522f475Smrg#endif /* USE_SYSV_UTMP */
845d522f475Smrgstatic sigjmp_buf env;
846d522f475Smrg
847d522f475Smrg#define SetUtmpHost(dst, screen) \
848d522f475Smrg	{ \
849d522f475Smrg	    char host[sizeof(dst) + 1]; \
850f2e35a3aSmrg	    strncpy(host, DisplayString(screen->display), sizeof(host) - 1); \
851f2e35a3aSmrg	    host[sizeof(dst)] = '\0'; \
852d522f475Smrg	    TRACE(("DisplayString(%s)\n", host)); \
853d522f475Smrg	    if (!resource.utmpDisplayId) { \
854d522f475Smrg		char *endptr = strrchr(host, ':'); \
855d522f475Smrg		if (endptr) { \
856d522f475Smrg		    TRACE(("trimming display-id '%s'\n", host)); \
857d522f475Smrg		    *endptr = '\0'; \
858d522f475Smrg		} \
859d522f475Smrg	    } \
860894e0ac8Smrg	    copy_filled(dst, host, sizeof(dst)); \
861d522f475Smrg	}
862d522f475Smrg
863d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
864d522f475Smrg#  define SetUtmpSysLen(utmp) 			   \
865d522f475Smrg	{ \
866d522f475Smrg	    utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
867f2e35a3aSmrg	    utmp.ut_syslen = (short) ((int) strlen(utmp.ut_host) + 1); \
868d522f475Smrg	}
869d522f475Smrg#endif
870d522f475Smrg
871d522f475Smrg/* used by VT (charproc.c) */
872d522f475Smrg
873d522f475Smrgstatic XtResource application_resources[] =
874d522f475Smrg{
87504b94745Smrg    Sres(XtNiconGeometry, XtCIconGeometry, icon_geometry, NULL),
876d522f475Smrg    Sres(XtNtitle, XtCTitle, title, NULL),
8770bd37d32Smrg    Sres(XtNiconHint, XtCIconHint, icon_hint, NULL),
878d522f475Smrg    Sres(XtNiconName, XtCIconName, icon_name, NULL),
87904b94745Smrg    Sres(XtNtermName, XtCTermName, term_name, NULL),
88004b94745Smrg    Sres(XtNttyModes, XtCTtyModes, tty_modes, NULL),
88104b94745Smrg    Sres(XtNvalidShells, XtCValidShells, valid_shells, NULL),
88204b94745Smrg    Bres(XtNhold, XtCHold, hold_screen, False),
88304b94745Smrg    Bres(XtNutmpInhibit, XtCUtmpInhibit, utmpInhibit, False),
88404b94745Smrg    Bres(XtNutmpDisplayId, XtCUtmpDisplayId, utmpDisplayId, True),
88504b94745Smrg    Bres(XtNmessages, XtCMessages, messages, True),
88604b94745Smrg    Ires(XtNminBufSize, XtCMinBufSize, minBufSize, 4096),
88704b94745Smrg    Ires(XtNmaxBufSize, XtCMaxBufSize, maxBufSize, 32768),
88804b94745Smrg    Sres(XtNmenuLocale, XtCMenuLocale, menuLocale, DEF_MENU_LOCALE),
8895104ee6eSmrg    Bres(XtNnotMapped, XtCNotMapped, notMapped, False),
89004b94745Smrg    Sres(XtNomitTranslation, XtCOmitTranslation, omitTranslation, NULL),
89104b94745Smrg    Sres(XtNkeyboardType, XtCKeyboardType, keyboardType, "unknown"),
892ad37e533Smrg#ifdef HAVE_LIB_XCURSOR
89304b94745Smrg    Sres(XtNcursorTheme, XtCCursorTheme, cursorTheme, "none"),
894ad37e533Smrg#endif
895e39b573cSmrg#if OPT_PRINT_ON_EXIT
89604b94745Smrg    Ires(XtNprintModeImmediate, XtCPrintModeImmediate, printModeNow, 0),
89704b94745Smrg    Ires(XtNprintOptsImmediate, XtCPrintOptsImmediate, printOptsNow, 9),
89804b94745Smrg    Sres(XtNprintFileImmediate, XtCPrintFileImmediate, printFileNow, NULL),
89904b94745Smrg    Ires(XtNprintModeOnXError, XtCPrintModeOnXError, printModeOnXError, 0),
90004b94745Smrg    Ires(XtNprintOptsOnXError, XtCPrintOptsOnXError, printOptsOnXError, 9),
90104b94745Smrg    Sres(XtNprintFileOnXError, XtCPrintFileOnXError, printFileOnXError, NULL),
902e39b573cSmrg#endif
903d522f475Smrg#if OPT_SUNPC_KBD
90404b94745Smrg    Bres(XtNsunKeyboard, XtCSunKeyboard, sunKeyboard, False),
905d522f475Smrg#endif
906d522f475Smrg#if OPT_HP_FUNC_KEYS
90704b94745Smrg    Bres(XtNhpFunctionKeys, XtCHpFunctionKeys, hpFunctionKeys, False),
908d522f475Smrg#endif
909d522f475Smrg#if OPT_SCO_FUNC_KEYS
91004b94745Smrg    Bres(XtNscoFunctionKeys, XtCScoFunctionKeys, scoFunctionKeys, False),
911d522f475Smrg#endif
912d522f475Smrg#if OPT_SUN_FUNC_KEYS
91304b94745Smrg    Bres(XtNsunFunctionKeys, XtCSunFunctionKeys, sunFunctionKeys, False),
914d522f475Smrg#endif
915d522f475Smrg#if OPT_TCAP_FKEYS
91604b94745Smrg    Bres(XtNtcapFunctionKeys, XtCTcapFunctionKeys, termcapKeys, False),
917d522f475Smrg#endif
918d522f475Smrg#if OPT_INITIAL_ERASE
91904b94745Smrg    Bres(XtNptyInitialErase, XtCPtyInitialErase, ptyInitialErase, DEF_INITIAL_ERASE),
92004b94745Smrg    Bres(XtNbackarrowKeyIsErase, XtCBackarrowKeyIsErase, backarrow_is_erase, DEF_BACKARO_ERASE),
921d522f475Smrg#endif
92204b94745Smrg    Bres(XtNuseInsertMode, XtCUseInsertMode, useInsertMode, False),
923d522f475Smrg#if OPT_ZICONBEEP
92404b94745Smrg    Ires(XtNzIconBeep, XtCZIconBeep, zIconBeep, 0),
92504b94745Smrg    Sres(XtNzIconTitleFormat, XtCZIconTitleFormat, zIconFormat, "*** %s"),
926d522f475Smrg#endif
927d522f475Smrg#if OPT_PTY_HANDSHAKE
92804b94745Smrg    Bres(XtNwaitForMap, XtCWaitForMap, wait_for_map, False),
92904b94745Smrg    Bres(XtNptyHandshake, XtCPtyHandshake, ptyHandshake, True),
93004b94745Smrg    Bres(XtNptySttySize, XtCPtySttySize, ptySttySize, DEF_PTY_STTY_SIZE),
931d522f475Smrg#endif
932913cc679Smrg#if OPT_REPORT_CCLASS
93304b94745Smrg    Bres(XtNreportCClass, XtCReportCClass, reportCClass, False),
934913cc679Smrg#endif
935e0a2b6dfSmrg#if OPT_REPORT_COLORS
93604b94745Smrg    Bres(XtNreportColors, XtCReportColors, reportColors, False),
937e0a2b6dfSmrg#endif
938e0a2b6dfSmrg#if OPT_REPORT_FONTS
93904b94745Smrg    Bres(XtNreportFonts, XtCReportFonts, reportFonts, False),
940e0a2b6dfSmrg#endif
941f2e35a3aSmrg#if OPT_REPORT_ICONS
94204b94745Smrg    Bres(XtNreportIcons, XtCReportIcons, reportIcons, False),
943f2e35a3aSmrg#endif
944f2e35a3aSmrg#if OPT_XRES_QUERY
94504b94745Smrg    Bres(XtNreportXRes, XtCReportXRes, reportXRes, False),
946f2e35a3aSmrg#endif
947d522f475Smrg#if OPT_SAME_NAME
94804b94745Smrg    Bres(XtNsameName, XtCSameName, sameName, True),
949d522f475Smrg#endif
950d522f475Smrg#if OPT_SESSION_MGT
95104b94745Smrg    Bres(XtNsessionMgt, XtCSessionMgt, sessionMgt, True),
952d522f475Smrg#endif
953d522f475Smrg#if OPT_TOOLBAR
954d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
955d522f475Smrg#endif
956956cc18dSsnj#if OPT_MAXIMIZE
957956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
958a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
959956cc18dSsnj#endif
960f2e35a3aSmrg#if USE_DOUBLE_BUFFER
961f2e35a3aSmrg    Bres(XtNbuffered, XtCBuffered, buffered, DEF_DOUBLE_BUFFER),
962f2e35a3aSmrg    Ires(XtNbufferedFPS, XtCBufferedFPS, buffered_fps, 40),
963f2e35a3aSmrg#endif
964d522f475Smrg};
965d522f475Smrg
96620d2c4d2Smrgstatic String fallback_resources[] =
967d522f475Smrg{
968e39b573cSmrg#if OPT_TOOLBAR
969e39b573cSmrg    "*toolBar: false",
970e39b573cSmrg#endif
971d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
972d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
973d522f475Smrg    "*SimpleMenu*Sme.height: 16",
974d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
975d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
976d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
977d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
978d522f475Smrg#if OPT_TEK4014
979d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
980d522f475Smrg#endif
981d522f475Smrg    NULL
982d522f475Smrg};
983d522f475Smrg
984d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
985d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
986d522f475Smrg/* *INDENT-OFF* */
987f2e35a3aSmrg#define DATA(option,pattern,type,value) { (char *) option, (char *) pattern, type, (XPointer) value }
98804b94745Smrg#define OPTS(option,pattern_type,value) { (char *) option, (char *) pattern_type, (XPointer) value }
98904b94745Smrg#define UP_ARG(name) "."name, XrmoptionSepArg
99004b94745Smrg#define MY_ARG(name) "*"name, XrmoptionSepArg
99104b94745Smrg#define VT_ARG(name) "*vt100."name, XrmoptionSepArg
99204b94745Smrg#define NO_ARG(name) "*"name, XrmoptionNoArg
993d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
99404b94745SmrgOPTS("-geometry",	VT_ARG(XtNgeometry),			NULL),
99504b94745SmrgOPTS("-132",		NO_ARG(XtNc132),			"on"),
99604b94745SmrgOPTS("+132",		NO_ARG(XtNc132),			"off"),
99704b94745SmrgOPTS("-ah",		NO_ARG(XtNalwaysHighlight),		"on"),
99804b94745SmrgOPTS("+ah",		NO_ARG(XtNalwaysHighlight),		"off"),
99904b94745SmrgOPTS("-aw",		NO_ARG(XtNautoWrap),			"on"),
100004b94745SmrgOPTS("+aw",		NO_ARG(XtNautoWrap),			"off"),
1001d522f475Smrg#ifndef NO_ACTIVE_ICON
100204b94745SmrgOPTS("-ai",		NO_ARG(XtNactiveIcon),			"off"),
100304b94745SmrgOPTS("+ai",		NO_ARG(XtNactiveIcon),			"on"),
1004d522f475Smrg#endif /* NO_ACTIVE_ICON */
100504b94745SmrgOPTS("-b",		MY_ARG(XtNinternalBorder),		NULL),
100604b94745SmrgOPTS("-barc",		NO_ARG(XtNcursorBar),			"on"),
100704b94745SmrgOPTS("+barc",		NO_ARG(XtNcursorBar),			"off"),
100804b94745SmrgOPTS("-bc",		NO_ARG(XtNcursorBlink),			"on"),
100904b94745SmrgOPTS("+bc",		NO_ARG(XtNcursorBlink),			"off"),
101004b94745SmrgOPTS("-bcf",		MY_ARG(XtNcursorOffTime),		NULL),
101104b94745SmrgOPTS("-bcn",		MY_ARG(XtNcursorOnTime),		NULL),
101204b94745SmrgOPTS("-bdc",		NO_ARG(XtNcolorBDMode),			"off"),
101304b94745SmrgOPTS("+bdc",		NO_ARG(XtNcolorBDMode),			"on"),
101404b94745SmrgOPTS("-cb",		NO_ARG(XtNcutToBeginningOfLine),	"off"),
101504b94745SmrgOPTS("+cb",		NO_ARG(XtNcutToBeginningOfLine),	"on"),
101604b94745SmrgOPTS("-cc",		MY_ARG(XtNcharClass),			NULL),
101704b94745SmrgOPTS("-cm",		NO_ARG(XtNcolorMode),			"off"),
101804b94745SmrgOPTS("+cm",		NO_ARG(XtNcolorMode),			"on"),
101904b94745SmrgOPTS("-cn",		NO_ARG(XtNcutNewline),			"off"),
102004b94745SmrgOPTS("+cn",		NO_ARG(XtNcutNewline),			"on"),
102104b94745SmrgOPTS("-cr",		MY_ARG(XtNcursorColor),			NULL),
102204b94745SmrgOPTS("-cu",		NO_ARG(XtNcurses),			"on"),
102304b94745SmrgOPTS("+cu",		NO_ARG(XtNcurses),			"off"),
102404b94745SmrgOPTS("-dc",		NO_ARG(XtNdynamicColors),		"off"),
102504b94745SmrgOPTS("+dc",		NO_ARG(XtNdynamicColors),		"on"),
102604b94745SmrgOPTS("-fb",		MY_ARG(XtNboldFont),			NULL),
102704b94745SmrgOPTS("-fbb",		NO_ARG(XtNfreeBoldBox),			"off"),
102804b94745SmrgOPTS("+fbb",		NO_ARG(XtNfreeBoldBox),			"on"),
102904b94745SmrgOPTS("-fbx",		NO_ARG(XtNforceBoxChars),		"off"),
103004b94745SmrgOPTS("+fbx",		NO_ARG(XtNforceBoxChars),		"on"),
103104b94745SmrgOPTS("-fc",		MY_ARG(XtNinitialFont),			NULL),
1032d522f475Smrg#ifndef NO_ACTIVE_ICON
103304b94745SmrgOPTS("-fi",		MY_ARG(XtNiconFont),			NULL),
1034d522f475Smrg#endif /* NO_ACTIVE_ICON */
1035d522f475Smrg#if OPT_RENDERFONT
103604b94745SmrgOPTS("-fa",		MY_ARG(XtNfaceName),			NULL),
103704b94745SmrgOPTS("-fd",		MY_ARG(XtNfaceNameDoublesize),		NULL),
103804b94745SmrgOPTS("-fs",		MY_ARG(XtNfaceSize),			NULL),
1039d522f475Smrg#endif
104001037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
104104b94745SmrgOPTS("-itc",		NO_ARG(XtNcolorITMode),			"off"),
104204b94745SmrgOPTS("+itc",		NO_ARG(XtNcolorITMode),			"on"),
104301037d57Smrg#endif
1044d522f475Smrg#if OPT_WIDE_CHARS
104504b94745SmrgOPTS("-fw",		MY_ARG(XtNwideFont),			NULL),
104604b94745SmrgOPTS("-fwb",		MY_ARG(XtNwideBoldFont),		NULL),
1047d522f475Smrg#endif
1048d522f475Smrg#if OPT_INPUT_METHOD
104904b94745SmrgOPTS("-fx",		MY_ARG(XtNximFont),			NULL),
1050d522f475Smrg#endif
1051d522f475Smrg#if OPT_HIGHLIGHT_COLOR
105204b94745SmrgOPTS("-hc",		MY_ARG(XtNhighlightColor),		NULL),
105304b94745SmrgOPTS("-hm",		NO_ARG(XtNhighlightColorMode),		"on"),
105404b94745SmrgOPTS("+hm",		NO_ARG(XtNhighlightColorMode),		"off"),
105504b94745SmrgOPTS("-selfg",		MY_ARG(XtNhighlightTextColor),		NULL),
105604b94745SmrgOPTS("-selbg",		MY_ARG(XtNhighlightColor),		NULL),
1057d522f475Smrg#endif
1058d522f475Smrg#if OPT_HP_FUNC_KEYS
105904b94745SmrgOPTS("-hf",		NO_ARG(XtNhpFunctionKeys),		"on"),
106004b94745SmrgOPTS("+hf",		NO_ARG(XtNhpFunctionKeys),		"off"),
1061d522f475Smrg#endif
106204b94745SmrgOPTS("-hold",		NO_ARG(XtNhold),			"on"),
106304b94745SmrgOPTS("+hold",		NO_ARG(XtNhold),			"off"),
1064d522f475Smrg#if OPT_INITIAL_ERASE
106504b94745SmrgOPTS("-ie",		NO_ARG(XtNptyInitialErase),		"on"),
106604b94745SmrgOPTS("+ie",		NO_ARG(XtNptyInitialErase),		"off"),
1067d522f475Smrg#endif
106804b94745SmrgOPTS("-j",		NO_ARG(XtNjumpScroll),			"on"),
106904b94745SmrgOPTS("+j",		NO_ARG(XtNjumpScroll),			"off"),
107004b94745SmrgOPTS("-jf",		NO_ARG(XtNfastScroll),			"on"),
107104b94745SmrgOPTS("+jf",		NO_ARG(XtNfastScroll),			"off"),
1072d522f475Smrg#if OPT_C1_PRINT
107304b94745SmrgOPTS("-k8",		NO_ARG(XtNallowC1Printable),		"on"),
107404b94745SmrgOPTS("+k8",		NO_ARG(XtNallowC1Printable),		"off"),
1075d522f475Smrg#endif
107604b94745SmrgOPTS("-kt",		MY_ARG(XtNkeyboardType),		NULL),
1077d522f475Smrg/* parse logging options anyway for compatibility */
107804b94745SmrgOPTS("-l",		NO_ARG(XtNlogging),			"on"),
107904b94745SmrgOPTS("+l",		NO_ARG(XtNlogging),			"off"),
108004b94745SmrgOPTS("-lf",		MY_ARG(XtNlogFile),			NULL),
108104b94745SmrgOPTS("-ls",		NO_ARG(XtNloginShell),			"on"),
108204b94745SmrgOPTS("+ls",		NO_ARG(XtNloginShell),			"off"),
108304b94745SmrgOPTS("-mb",		NO_ARG(XtNmarginBell),			"on"),
108404b94745SmrgOPTS("+mb",		NO_ARG(XtNmarginBell),			"off"),
108504b94745SmrgOPTS("-mc",		MY_ARG(XtNmultiClickTime),		NULL),
108604b94745SmrgOPTS("-mesg",		NO_ARG(XtNmessages),			"off"),
108704b94745SmrgOPTS("+mesg",		NO_ARG(XtNmessages),			"on"),
108804b94745SmrgOPTS("-ms",		MY_ARG(XtNpointerColor),		NULL),
108904b94745SmrgOPTS("-nb",		MY_ARG(XtNnMarginBell),			NULL),
10905104ee6eSmrgOPTS("-nomap",		NO_ARG(XtNnotMapped),			"on"),
10915104ee6eSmrgOPTS("+nomap",		NO_ARG(XtNnotMapped),			"off"),
109204b94745SmrgOPTS("-nul",		NO_ARG(XtNunderLine),			"off"),
109304b94745SmrgOPTS("+nul",		NO_ARG(XtNunderLine),			"on"),
109404b94745SmrgOPTS("-pc",		NO_ARG(XtNboldColors),			"on"),
109504b94745SmrgOPTS("+pc",		NO_ARG(XtNboldColors),			"off"),
109604b94745SmrgOPTS("-pf",		MY_ARG(XtNpointerFont),			NULL),
109704b94745SmrgOPTS("-rw",		NO_ARG(XtNreverseWrap),			"on"),
109804b94745SmrgOPTS("+rw",		NO_ARG(XtNreverseWrap),			"off"),
109904b94745SmrgOPTS("-s",		NO_ARG(XtNmultiScroll),			"on"),
110004b94745SmrgOPTS("+s",		NO_ARG(XtNmultiScroll),			"off"),
110104b94745SmrgOPTS("-sb",		NO_ARG(XtNscrollBar),			"on"),
110204b94745SmrgOPTS("+sb",		NO_ARG(XtNscrollBar),			"off"),
1103913cc679Smrg#if OPT_REPORT_CCLASS
110404b94745SmrgOPTS("-report-charclass", NO_ARG(XtNreportCClass),		"on"),
1105913cc679Smrg#endif
1106e0a2b6dfSmrg#if OPT_REPORT_COLORS
110704b94745SmrgOPTS("-report-colors",	NO_ARG(XtNreportColors),		"on"),
1108f2e35a3aSmrg#endif
1109f2e35a3aSmrg#if OPT_REPORT_ICONS
111004b94745SmrgOPTS("-report-icons",	NO_ARG(XtNreportIcons),			"on"),
1111e0a2b6dfSmrg#endif
1112e0a2b6dfSmrg#if OPT_REPORT_FONTS
111304b94745SmrgOPTS("-report-fonts",	NO_ARG(XtNreportFonts),			"on"),
1114f2e35a3aSmrg#endif
1115f2e35a3aSmrg#if OPT_XRES_QUERY
111604b94745SmrgOPTS("-report-xres",	NO_ARG(XtNreportXRes),			"on"),
1117e0a2b6dfSmrg#endif
1118d522f475Smrg#ifdef SCROLLBAR_RIGHT
111904b94745SmrgOPTS("-leftbar",	NO_ARG(XtNrightScrollBar),		"off"),
112004b94745SmrgOPTS("-rightbar",	NO_ARG(XtNrightScrollBar),		"on"),
112104b94745Smrg#endif
112204b94745SmrgOPTS("-rvc",		NO_ARG(XtNcolorRVMode),			"off"),
112304b94745SmrgOPTS("+rvc",		NO_ARG(XtNcolorRVMode),			"on"),
112404b94745SmrgOPTS("-sf",		NO_ARG(XtNsunFunctionKeys),		"on"),
112504b94745SmrgOPTS("+sf",		NO_ARG(XtNsunFunctionKeys),		"off"),
112604b94745SmrgOPTS("-sh",		MY_ARG(XtNscaleHeight),			NULL),
112704b94745SmrgOPTS("-si",		NO_ARG(XtNscrollTtyOutput),		"off"),
112804b94745SmrgOPTS("+si",		NO_ARG(XtNscrollTtyOutput),		"on"),
112904b94745SmrgOPTS("-sk",		NO_ARG(XtNscrollKey),			"on"),
113004b94745SmrgOPTS("+sk",		NO_ARG(XtNscrollKey),			"off"),
113104b94745SmrgOPTS("-sl",		MY_ARG(XtNsaveLines),			NULL),
1132d522f475Smrg#if OPT_SUNPC_KBD
113304b94745SmrgOPTS("-sp",		NO_ARG(XtNsunKeyboard),			"on"),
113404b94745SmrgOPTS("+sp",		NO_ARG(XtNsunKeyboard),			"off"),
1135d522f475Smrg#endif
1136d522f475Smrg#if OPT_TEK4014
113704b94745SmrgOPTS("-t",		NO_ARG(XtNtekStartup),			"on"),
113804b94745SmrgOPTS("+t",		NO_ARG(XtNtekStartup),			"off"),
1139d522f475Smrg#endif
114004b94745SmrgOPTS("-ti",		MY_ARG(XtNdecTerminalID),		NULL),
114104b94745SmrgOPTS("-tm",		MY_ARG(XtNttyModes),			NULL),
114204b94745SmrgOPTS("-tn",		MY_ARG(XtNtermName),			NULL),
1143d522f475Smrg#if OPT_WIDE_CHARS
114404b94745SmrgOPTS("-u8",		NO_ARG(XtNutf8),			"2"),
114504b94745SmrgOPTS("+u8",		NO_ARG(XtNutf8),			"0"),
1146d522f475Smrg#endif
1147d522f475Smrg#if OPT_LUIT_PROG
114804b94745SmrgOPTS("-lc",		NO_ARG(XtNlocale),			"on"),
114904b94745SmrgOPTS("+lc",		NO_ARG(XtNlocale),			"off"),
115004b94745SmrgOPTS("-lcc",		MY_ARG(XtNlocaleFilter),		NULL),
115104b94745SmrgOPTS("-en",		MY_ARG(XtNlocale),			NULL),
115204b94745Smrg#endif
115304b94745SmrgOPTS("-uc",		NO_ARG(XtNcursorUnderLine),		"on"),
115404b94745SmrgOPTS("+uc",		NO_ARG(XtNcursorUnderLine),		"off"),
115504b94745SmrgOPTS("-ulc",		NO_ARG(XtNcolorULMode),			"off"),
115604b94745SmrgOPTS("+ulc",		NO_ARG(XtNcolorULMode),			"on"),
115704b94745SmrgOPTS("-ulit",		NO_ARG(XtNitalicULMode),		"off"),
115804b94745SmrgOPTS("+ulit",		NO_ARG(XtNitalicULMode),		"on"),
115904b94745SmrgOPTS("-ut",		NO_ARG(XtNutmpInhibit),			"on"),
116004b94745SmrgOPTS("+ut",		NO_ARG(XtNutmpInhibit),			"off"),
116104b94745SmrgOPTS("-im",		NO_ARG(XtNuseInsertMode),		"on"),
116204b94745SmrgOPTS("+im",		NO_ARG(XtNuseInsertMode),		"off"),
116304b94745SmrgOPTS("-vb",		NO_ARG(XtNvisualBell),			"on"),
116404b94745SmrgOPTS("+vb",		NO_ARG(XtNvisualBell),			"off"),
116504b94745SmrgOPTS("-pob",		NO_ARG(XtNpopOnBell),			"on"),
116604b94745SmrgOPTS("+pob",		NO_ARG(XtNpopOnBell),			"off"),
1167d522f475Smrg#if OPT_WIDE_CHARS
116804b94745SmrgOPTS("-wc",		NO_ARG(XtNwideChars),			"on"),
116904b94745SmrgOPTS("+wc",		NO_ARG(XtNwideChars),			"off"),
117004b94745SmrgOPTS("-mk_width",	NO_ARG(XtNmkWidth),			"on"),
117104b94745SmrgOPTS("+mk_width",	NO_ARG(XtNmkWidth),			"off"),
117204b94745SmrgOPTS("-cjk_width",	NO_ARG(XtNcjkWidth),			"on"),
117304b94745SmrgOPTS("+cjk_width",	NO_ARG(XtNcjkWidth),			"off"),
117404b94745Smrg#endif
117504b94745SmrgOPTS("-wf",		NO_ARG(XtNwaitForMap),			"on"),
117604b94745SmrgOPTS("+wf",		NO_ARG(XtNwaitForMap),			"off"),
1177d522f475Smrg#if OPT_ZICONBEEP
117804b94745SmrgOPTS("-ziconbeep",	MY_ARG(XtNzIconBeep),			NULL),
1179d522f475Smrg#endif
1180d522f475Smrg#if OPT_SAME_NAME
118104b94745SmrgOPTS("-samename",	NO_ARG(XtNsameName),			"on"),
118204b94745SmrgOPTS("+samename",	NO_ARG(XtNsameName),			"off"),
1183d522f475Smrg#endif
1184d522f475Smrg#if OPT_SESSION_MGT
118504b94745SmrgOPTS("-sm",		NO_ARG(XtNsessionMgt),			"on"),
118604b94745SmrgOPTS("+sm",		NO_ARG(XtNsessionMgt),			"off"),
1187d522f475Smrg#endif
1188d522f475Smrg#if OPT_TOOLBAR
118904b94745SmrgOPTS("-tb",		NO_ARG(XtNtoolBar),			"on"),
119004b94745SmrgOPTS("+tb",		NO_ARG(XtNtoolBar),			"off"),
1191d522f475Smrg#endif
1192956cc18dSsnj#if OPT_MAXIMIZE
119304b94745SmrgOPTS("-maximized",	NO_ARG(XtNmaximized),			"on"),
119404b94745SmrgOPTS("+maximized",	NO_ARG(XtNmaximized),			"off"),
119504b94745SmrgOPTS("-fullscreen",	NO_ARG(XtNfullscreen),			"on"),
119604b94745SmrgOPTS("+fullscreen",	NO_ARG(XtNfullscreen),			"off"),
1197956cc18dSsnj#endif
1198d522f475Smrg/* options that we process ourselves */
1199f2e35a3aSmrgDATA("-help",		NULL,		XrmoptionSkipNArgs,	NULL),
1200f2e35a3aSmrgDATA("-version",	NULL,		XrmoptionSkipNArgs,	NULL),
1201f2e35a3aSmrgDATA("-baudrate",	NULL,		XrmoptionSkipArg,	NULL),
1202f2e35a3aSmrgDATA("-class",		NULL,		XrmoptionSkipArg,	NULL),
1203f2e35a3aSmrgDATA("-e",		NULL,		XrmoptionSkipLine,	NULL),
1204f2e35a3aSmrgDATA("-into",		NULL,		XrmoptionSkipArg,	NULL),
1205d522f475Smrg/* bogus old compatibility stuff for which there are
1206d522f475Smrg   standard XtOpenApplication options now */
1207f2e35a3aSmrgDATA("%",		"*tekGeometry",	XrmoptionStickyArg,	NULL),
120804b94745SmrgDATA("#",		".iconGeometry", XrmoptionStickyArg,	NULL),
120904b94745SmrgOPTS("-T",		UP_ARG(XtNtitle),			NULL),
121004b94745SmrgOPTS("-n",		MY_ARG(XtNiconName),			NULL),
121104b94745SmrgOPTS("-r",		NO_ARG(XtNreverseVideo),		"on"),
121204b94745SmrgOPTS("+r",		NO_ARG(XtNreverseVideo),		"off"),
121304b94745SmrgOPTS("-rv",		NO_ARG(XtNreverseVideo),		"on"),
121404b94745SmrgOPTS("+rv",		NO_ARG(XtNreverseVideo),		"off"),
121504b94745SmrgOPTS("-w",		UP_ARG(XtNborderWidth),			NULL),
1216f2e35a3aSmrg#undef DATA
1217d522f475Smrg};
1218d522f475Smrg
1219d522f475Smrgstatic OptionHelp xtermOptions[] = {
1220d522f475Smrg{ "-version",              "print the version number" },
1221d522f475Smrg{ "-help",                 "print out this message" },
1222d522f475Smrg{ "-display displayname",  "X server to contact" },
1223d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1224d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1225d522f475Smrg{ "-bg color",             "background color" },
1226d522f475Smrg{ "-fg color",             "foreground color" },
1227d522f475Smrg{ "-bd color",             "border color" },
1228d522f475Smrg{ "-bw number",            "border width in pixels" },
1229d522f475Smrg{ "-fn fontname",          "normal text font" },
1230d522f475Smrg{ "-fb fontname",          "bold text font" },
1231f2e35a3aSmrg{ "-fc fontmenu",          "start with named fontmenu choice" },
1232d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1233d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1234d522f475Smrg#if OPT_RENDERFONT
1235d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1236d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1237d522f475Smrg{ "-fs size",              "FreeType font-size" },
1238d522f475Smrg#endif
1239d522f475Smrg#if OPT_WIDE_CHARS
1240d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1241d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1242d522f475Smrg#endif
1243d522f475Smrg#if OPT_INPUT_METHOD
1244d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1245d522f475Smrg#endif
1246d522f475Smrg{ "-iconic",               "start iconic" },
1247d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
12482e4f8982Smrg{ "-baudrate rate",        "set line-speed (default 38400)" },
1249d522f475Smrg{ "-class string",         "class string (XTerm)" },
1250d522f475Smrg{ "-title string",         "title string" },
1251d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1252d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1253d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1254d522f475Smrg#ifndef NO_ACTIVE_ICON
1255d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1256d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1257d522f475Smrg#endif /* NO_ACTIVE_ICON */
1258d522f475Smrg{ "-b number",             "internal border in pixels" },
1259d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1260d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1261d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1262d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1263d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1264d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1265d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1266d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1267f2e35a3aSmrg{ "-pf fontname",          "cursor font for text area pointer" },
1268d522f475Smrg{ "-cr color",             "text cursor color" },
1269d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1270d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1271d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1272d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1273d522f475Smrg{ "-selbg color",          "selection background color" },
1274d522f475Smrg{ "-selfg color",          "selection foreground color" },
12750bd37d32Smrg/* -hc is deprecated, not shown in help message */
1276d522f475Smrg#endif
1277d522f475Smrg#if OPT_HP_FUNC_KEYS
1278d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1279d522f475Smrg#endif
1280d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1281d522f475Smrg#if OPT_INITIAL_ERASE
1282d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1283d522f475Smrg#endif
1284d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1285d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1286d522f475Smrg#if OPT_C1_PRINT
1287d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1288d522f475Smrg#endif
1289d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1290d522f475Smrg#ifdef ALLOWLOGGING
1291d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1292f2e35a3aSmrg{ "-lf filename",          "logging filename (use '-' for standard out)" },
1293d522f475Smrg#else
1294d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1295d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1296d522f475Smrg#endif
1297d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1298d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1299d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1300d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1301d522f475Smrg{ "-ms color",             "pointer color" },
1302d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
13035104ee6eSmrg{ "-/+nomap",              "turn off/on initial mapping of window" },
1304d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1305d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1306d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1307d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1308d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1309d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1310913cc679Smrg#if OPT_REPORT_CCLASS
1311913cc679Smrg{"-report-charclass",      "report \"charClass\" after initialization"},
1312913cc679Smrg#endif
1313e0a2b6dfSmrg#if OPT_REPORT_COLORS
1314e0a2b6dfSmrg{ "-report-colors",        "report colors as they are allocated" },
1315e0a2b6dfSmrg#endif
1316e0a2b6dfSmrg#if OPT_REPORT_FONTS
1317e0a2b6dfSmrg{ "-report-fonts",         "report fonts as loaded to stdout" },
1318e0a2b6dfSmrg#endif
1319f2e35a3aSmrg#if OPT_REPORT_ICONS
132004b94745Smrg{ "-report-icons",         "report title/icon updates" },
1321f2e35a3aSmrg#endif
1322f2e35a3aSmrg#if OPT_XRES_QUERY
1323f2e35a3aSmrg{ "-report-xres",          "report X resources for VT100 widget" },
1324f2e35a3aSmrg#endif
1325d522f475Smrg#ifdef SCROLLBAR_RIGHT
1326d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1327d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1328d522f475Smrg#endif
1329d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1330d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1331894e0ac8Smrg{ "-sh number",            "scale line-height values by the given number" },
1332d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1333d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1334d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1335d522f475Smrg#if OPT_SUNPC_KBD
1336d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1337d522f475Smrg#endif
1338d522f475Smrg#if OPT_TEK4014
1339d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1340d522f475Smrg#endif
1341d522f475Smrg#if OPT_TOOLBAR
1342d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1343d522f475Smrg#endif
1344d522f475Smrg{ "-ti termid",            "terminal identifier" },
1345d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1346d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1347d522f475Smrg#if OPT_WIDE_CHARS
1348d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1349d522f475Smrg#endif
1350d522f475Smrg#if OPT_LUIT_PROG
1351d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1352d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
13530bd37d32Smrg/* -en is deprecated, not shown in help message */
1354d522f475Smrg#endif
13552eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1356d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1357d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1358d522f475Smrg#ifdef HAVE_UTMP
1359d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1360d522f475Smrg#else
1361d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1362d522f475Smrg#endif
1363d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1364d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
136501037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
136601037d57Smrg{ "-/+itc",                "turn off/on display of italic as color"},
136701037d57Smrg#endif
1368d522f475Smrg#if OPT_WIDE_CHARS
1369d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1370d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1371d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1372d522f475Smrg#endif
1373d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1374d522f475Smrg{ "-e command args ...",   "command to execute" },
1375d522f475Smrg#if OPT_TEK4014
1376d522f475Smrg{ "%geom",                 "Tek window geometry" },
1377d522f475Smrg#endif
1378d522f475Smrg{ "#geom",                 "icon window geometry" },
1379d522f475Smrg{ "-T string",             "title name for window" },
1380d522f475Smrg{ "-n string",             "icon name for window" },
1381d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1382d522f475Smrg{ "-C",                    "intercept console messages" },
1383d522f475Smrg#else
1384d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1385d522f475Smrg#endif
1386d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1387d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1388d522f475Smrg#if OPT_ZICONBEEP
1389d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1390d522f475Smrg#endif
1391d522f475Smrg#if OPT_SAME_NAME
1392d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1393d522f475Smrg#endif
1394d522f475Smrg#if OPT_SESSION_MGT
1395d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1396d522f475Smrg#endif
1397956cc18dSsnj#if OPT_MAXIMIZE
1398ad37e533Smrg{"-/+maximized",           "turn on/off maximize on startup" },
1399a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1400956cc18dSsnj#endif
1401d522f475Smrg{ NULL, NULL }};
1402d522f475Smrg/* *INDENT-ON* */
1403d522f475Smrg
140404b94745Smrgstatic const char *const help_message[] =
1405d522f475Smrg{
1406d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1407d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1408d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1409d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1410d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
141104b94745Smrg    NULL
141204b94745Smrg};
141304b94745Smrg
141404b94745Smrgint
141504b94745SmrgxtermDisabledChar(void)
141604b94745Smrg{
141704b94745Smrg    int value = -1;
141804b94745Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
141904b94745Smrg    value = _POSIX_VDISABLE;
142004b94745Smrg#endif
142104b94745Smrg#if defined(_PC_VDISABLE)
142204b94745Smrg    if (value == -1) {
142304b94745Smrg	value = (int) fpathconf(0, _PC_VDISABLE);
142404b94745Smrg	if (value == -1) {
142504b94745Smrg	    if (errno == 0)
142604b94745Smrg		value = 0377;
142704b94745Smrg	}
142804b94745Smrg    }
142904b94745Smrg#elif defined(VDISABLE)
143004b94745Smrg    if (value == -1)
143104b94745Smrg	value = VDISABLE;
143204b94745Smrg#endif
143304b94745Smrg    return value;
143404b94745Smrg}
143504b94745Smrg
143604b94745Smrg/*
143704b94745Smrg * Retrieve (possibly allocating) an atom from the server.  Cache the result.
143804b94745Smrg */
143904b94745SmrgAtom
144004b94745SmrgCachedInternAtom(Display *display, const char *name)
144104b94745Smrg{
144204b94745Smrg    /*
144304b94745Smrg     * Aside from a couple of rarely used atoms, the others are all known.
144404b94745Smrg     */
144504b94745Smrg    static const char *const known_atoms[] =
144604b94745Smrg    {
144704b94745Smrg	"FONT",
144804b94745Smrg	"WM_CLASS",
144904b94745Smrg	"WM_DELETE_WINDOW",
145004b94745Smrg	"_NET_ACTIVE_WINDOW",
145104b94745Smrg	"_NET_FRAME_EXTENTS",
145204b94745Smrg	"_NET_FRAME_EXTENTS",
145304b94745Smrg	"_NET_SUPPORTED",
145404b94745Smrg	"_NET_SUPPORTING_WM_CHECK",
145504b94745Smrg	"_NET_WM_ALLOWED_ACTIONS",
145604b94745Smrg	"_NET_WM_ICON_NAME",
145704b94745Smrg	"_NET_WM_NAME",
145804b94745Smrg	"_NET_WM_PID",
145904b94745Smrg	"_NET_WM_STATE",
146004b94745Smrg	"_NET_WM_STATE_ADD",
146104b94745Smrg	"_NET_WM_STATE_FULLSCREEN",
146204b94745Smrg	"_NET_WM_STATE_HIDDEN",
146304b94745Smrg	"_NET_WM_STATE_MAXIMIZED_HORZ",
146404b94745Smrg	"_NET_WM_STATE_MAXIMIZED_VERT",
146504b94745Smrg	"_NET_WM_STATE_REMOVE",
146604b94745Smrg	"_WIN_SUPPORTING_WM_CHECK",
146704b94745Smrg#if defined(HAVE_XKB_BELL_EXT)
146804b94745Smrg	XkbBN_Info,
146904b94745Smrg	XkbBN_MarginBell,
147004b94745Smrg	XkbBN_MinorError,
147104b94745Smrg	XkbBN_TerminalBell,
147204b94745Smrg#endif
147304b94745Smrg#if defined(HAVE_XKBQUERYEXTENSION)
147404b94745Smrg	"Num Lock",
147504b94745Smrg	"Caps Lock",
147604b94745Smrg	"Scroll Lock",
147704b94745Smrg#endif
147804b94745Smrg    };
147904b94745Smrg
148004b94745Smrg#define NumKnownAtoms  XtNumber(known_atoms)
148104b94745Smrg
148204b94745Smrg    /*
148304b94745Smrg     * The "+1" entry of the array is used for the occasional atom which is not
148404b94745Smrg     * predefined.
148504b94745Smrg     */
148604b94745Smrg    static struct {
148704b94745Smrg	Atom atom;
148804b94745Smrg	const char *name;
148904b94745Smrg    } AtomCache[NumKnownAtoms + 1];
149004b94745Smrg
149104b94745Smrg    Boolean found = False;
149204b94745Smrg    Atom result = None;
149304b94745Smrg    Cardinal i;
149404b94745Smrg
149504b94745Smrg    TRACE(("intern_atom \"%s\"\n", name));
149604b94745Smrg
149704b94745Smrg    /*
149804b94745Smrg     * This should never happen as it implies xterm is aware of multiple
149904b94745Smrg     * displays.
150004b94745Smrg     */
150104b94745Smrg    if (display != XtDisplay(toplevel)) {
150204b94745Smrg	SysError(ERROR_GET_ATOM);
150304b94745Smrg    }
150404b94745Smrg
150504b94745Smrg    if (AtomCache[0].name == NULL) {
150604b94745Smrg	/* pre-load a number of atoms in one request to reduce latency */
150704b94745Smrg	Atom atom_return[NumKnownAtoms];
150804b94745Smrg	int code;
150904b94745Smrg
151004b94745Smrg	TRACE(("initialising atom list\n"));
151104b94745Smrg	code = XInternAtoms(display,
151204b94745Smrg			    (char **) known_atoms,
151304b94745Smrg			    (int) NumKnownAtoms,
151404b94745Smrg			    False,
151504b94745Smrg			    atom_return);
151604b94745Smrg	/*
151704b94745Smrg	 * result should be Success, but actually returns BadRequest.
151804b94745Smrg	 * manpage says XInternAtoms can generate BadAlloc and BadValue errors.
151904b94745Smrg	 */
152004b94745Smrg	if (code > BadRequest)
152104b94745Smrg	    SysError(ERROR_GET_ATOM);
152204b94745Smrg
152304b94745Smrg	for (i = 0; i < NumKnownAtoms; ++i) {
152404b94745Smrg	    AtomCache[i].name = known_atoms[i];
152504b94745Smrg	    AtomCache[i].atom = atom_return[i];
152604b94745Smrg	}
152704b94745Smrg    }
152804b94745Smrg
152904b94745Smrg    /* Linear search is probably OK here, due to the small number of atoms */
153004b94745Smrg    for (i = 0; i < NumKnownAtoms; i++) {
153104b94745Smrg	if (strcmp(name, AtomCache[i].name) == 0) {
153204b94745Smrg	    found = True;
153304b94745Smrg	    result = AtomCache[i].atom;
153404b94745Smrg	    break;
153504b94745Smrg	}
153604b94745Smrg    }
153704b94745Smrg
153804b94745Smrg    if (!found) {
153904b94745Smrg	if (AtomCache[NumKnownAtoms].name == NULL
154004b94745Smrg	    || strcmp(AtomCache[NumKnownAtoms].name, name)) {
154104b94745Smrg	    char *actual = x_strdup(name);
154204b94745Smrg	    free((void *) AtomCache[NumKnownAtoms].name);
154304b94745Smrg	    result = XInternAtom(display, actual, False);
154404b94745Smrg	    AtomCache[NumKnownAtoms].atom = result;
154504b94745Smrg	    AtomCache[NumKnownAtoms].name = actual;
154604b94745Smrg	    TRACE(("...allocated new atom\n"));
154704b94745Smrg	} else {
154804b94745Smrg	    result = AtomCache[NumKnownAtoms].atom;
154904b94745Smrg	    TRACE(("...reused cached atom\n"));
155004b94745Smrg	}
155104b94745Smrg    }
155204b94745Smrg    TRACE(("...intern_atom -> %ld\n", result));
155304b94745Smrg    return result;
155404b94745Smrg}
1555d522f475Smrg
1556d522f475Smrg/*
1557d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1558d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1559d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1560d522f475Smrg */
1561d522f475Smrgstatic int
1562d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1563d522f475Smrg{
1564d522f475Smrg    char *string = *ptr;
1565d522f475Smrg    int value = -1;
1566d522f475Smrg
156720d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1568d522f475Smrg    if (*string == '^') {
1569d522f475Smrg	switch (*++string) {
1570d522f475Smrg	case '?':
15715104ee6eSmrg	    value = ANSI_DEL;
1572d522f475Smrg	    break;
1573d522f475Smrg	case '-':
1574d522f475Smrg	    if (!termcap) {
157504b94745Smrg		value = xtermDisabledChar();
1576d522f475Smrg		break;
1577d522f475Smrg	    }
1578d522f475Smrg	    /* FALLTHRU */
1579d522f475Smrg	default:
1580d522f475Smrg	    value = CONTROL(*string);
1581d522f475Smrg	    break;
1582d522f475Smrg	}
1583d522f475Smrg	++string;
1584d522f475Smrg    } else if (termcap && (*string == '\\')) {
15852e4f8982Smrg	char *s = (string + 1);
1586d522f475Smrg	char *d;
15872e4f8982Smrg	int temp = (int) strtol(s, &d, 8);
15882e4f8982Smrg	if (PartS2L(s, d) && temp > 0) {
1589d522f475Smrg	    value = temp;
1590d522f475Smrg	    string = d;
1591d522f475Smrg	}
1592d522f475Smrg    } else {
1593d522f475Smrg	value = CharOf(*string);
1594d522f475Smrg	++string;
1595d522f475Smrg    }
1596d522f475Smrg    *ptr = string;
159720d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1598d522f475Smrg    return value;
1599d522f475Smrg}
1600d522f475Smrg
1601d522f475Smrgstatic int
16020bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
16030bd37d32Smrg{
16040bd37d32Smrg    int result = -1;
16050bd37d32Smrg    int n;
16060bd37d32Smrg    int ch;
16070bd37d32Smrg
16080bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
16090bd37d32Smrg	if (param[n] == ch) {
16100bd37d32Smrg	    result = n;
16110bd37d32Smrg	} else {
16120bd37d32Smrg	    if (param[n] != '\0')
16130bd37d32Smrg		result = -1;
16140bd37d32Smrg	    break;
16150bd37d32Smrg	}
16160bd37d32Smrg    }
16170bd37d32Smrg
16180bd37d32Smrg    return result;
16190bd37d32Smrg}
16200bd37d32Smrg
16210bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
16220bd37d32Smrgstatic int
16230bd37d32SmrgcountArg(XrmOptionDescRec * item)
1624d522f475Smrg{
16250bd37d32Smrg    int result = 0;
16260bd37d32Smrg
16270bd37d32Smrg    switch (item->argKind) {
16280bd37d32Smrg    case XrmoptionNoArg:
16290bd37d32Smrg	/* FALLTHRU */
16300bd37d32Smrg    case XrmoptionIsArg:
16310bd37d32Smrg	/* FALLTHRU */
16320bd37d32Smrg    case XrmoptionStickyArg:
16330bd37d32Smrg	break;
16340bd37d32Smrg    case XrmoptionSepArg:
16350bd37d32Smrg	/* FALLTHRU */
16360bd37d32Smrg    case XrmoptionResArg:
16370bd37d32Smrg	/* FALLTHRU */
16380bd37d32Smrg    case XrmoptionSkipArg:
16390bd37d32Smrg	result = 1;
16400bd37d32Smrg	break;
16410bd37d32Smrg    case XrmoptionSkipLine:
16420bd37d32Smrg	break;
16430bd37d32Smrg    case XrmoptionSkipNArgs:
16440bd37d32Smrg	result = (int) (long) (item->value);
16450bd37d32Smrg	break;
16460bd37d32Smrg    }
16470bd37d32Smrg    return result;
16480bd37d32Smrg}
16490bd37d32Smrg
16500bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
16510bd37d32Smrg
16520bd37d32Smrg/*
16530bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
16540bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
16550bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
16560bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
16570bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
16580bd37d32Smrg * standard table (something that the X libraries should do).
16590bd37d32Smrg */
16600bd37d32Smrgstatic XrmOptionDescRec *
16610bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
16620bd37d32Smrg{
16630bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
16640bd37d32Smrg    /* *INDENT-OFF* */
16655307cd1aSmrg#define DATA(option,kind) { (char *) option, NULL, kind, (XPointer) 0 }
16660bd37d32Smrg    static XrmOptionDescRec opTable[] = {
16670bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
16680bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
16690bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
16700bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
16710bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
16720bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
16730bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
16740bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
16750bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
16760bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
16770bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
16780bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
16790bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
16800bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
16810bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
16820bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
16830bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
16840bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
16850bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
16860bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
16870bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
16880bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
16890bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
16900bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
16910bd37d32Smrg#endif /* TIOCCONS */
16920bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
16930bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
16940bd37d32Smrg    };
16950bd37d32Smrg#undef DATA
16960bd37d32Smrg    /* *INDENT-ON* */
16975104ee6eSmrg    XrmOptionDescRec *result = NULL;
16980bd37d32Smrg    Cardinal inlist;
16990bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
17000bd37d32Smrg    int atbest = -1;
17010bd37d32Smrg    Boolean exact = False;
17020bd37d32Smrg    int ambiguous1 = -1;
17030bd37d32Smrg    int ambiguous2 = -1;
17040bd37d32Smrg    char *option;
17050bd37d32Smrg
17060bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
17070bd37d32Smrg		 ? &optionDescList[n] \
17080bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
17090bd37d32Smrg
17105104ee6eSmrg    if ((option = argv[*num]) != NULL) {
17110bd37d32Smrg	Boolean need_value;
17120bd37d32Smrg	Boolean have_value = False;
17135104ee6eSmrg	int best = -1;
17145104ee6eSmrg	char *value;
17150bd37d32Smrg
17160bd37d32Smrg	TRACE(("parseArg %s\n", option));
17175104ee6eSmrg	if ((value = argv[(*num) + 1]) != NULL) {
1718e0a2b6dfSmrg	    have_value = (Boolean) !isOption(value);
17190bd37d32Smrg	}
17200bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
17210bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
17225104ee6eSmrg	    int test;
17230bd37d32Smrg
17240bd37d32Smrg	    test = matchArg(check, option);
17250bd37d32Smrg	    if (test < 0)
17260bd37d32Smrg		continue;
17270bd37d32Smrg
17280bd37d32Smrg	    /* check for exact match */
17290bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
17300bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
17310bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
17320bd37d32Smrg			exact = True;
17330bd37d32Smrg			atbest = (int) inlist;
17340bd37d32Smrg			break;
17350bd37d32Smrg		    }
17360bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
17370bd37d32Smrg		    exact = True;
17380bd37d32Smrg		    atbest = (int) inlist;
17390bd37d32Smrg		    break;
17400bd37d32Smrg		}
17410bd37d32Smrg	    }
17420bd37d32Smrg
17430bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
17440bd37d32Smrg
17455104ee6eSmrg	    if (need_value && value != NULL) {
17460bd37d32Smrg		;
17470bd37d32Smrg	    } else if (need_value ^ have_value) {
17480bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
17490bd37d32Smrg		continue;
17500bd37d32Smrg	    }
17510bd37d32Smrg
17520bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
17530bd37d32Smrg	    if (test > 0
17540bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
17550bd37d32Smrg		atbest = (int) inlist;
1756e0a2b6dfSmrg		if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
1757e0a2b6dfSmrg		    /* in particular, silence a warning about ambiguity */
1758e0a2b6dfSmrg		    exact = 1;
1759e0a2b6dfSmrg		}
17600bd37d32Smrg		break;
17610bd37d32Smrg	    }
17620bd37d32Smrg	    if (test > best) {
17630bd37d32Smrg		best = test;
17640bd37d32Smrg		atbest = (int) inlist;
17650bd37d32Smrg	    } else if (test == best) {
17660bd37d32Smrg		if (atbest >= 0) {
17670bd37d32Smrg		    if (atbest > 0) {
17680bd37d32Smrg			ambiguous1 = (int) inlist;
17690bd37d32Smrg			ambiguous2 = (int) atbest;
17700bd37d32Smrg		    }
17710bd37d32Smrg		    atbest = -1;
17720bd37d32Smrg		}
17730bd37d32Smrg	    }
17740bd37d32Smrg	}
17750bd37d32Smrg    }
17760bd37d32Smrg
17775104ee6eSmrg    *valuep = NULL;
17780bd37d32Smrg    if (atbest >= 0) {
17790bd37d32Smrg	result = ITEM(atbest);
17800bd37d32Smrg	if (!exact) {
17810bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
17820bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
17830bd37d32Smrg			     ITEM(ambiguous1)->option,
17840bd37d32Smrg			     ITEM(ambiguous2)->option);
17850bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
17865104ee6eSmrg		result = NULL;
17870bd37d32Smrg	    }
17880bd37d32Smrg	}
17895104ee6eSmrg	if (result != NULL) {
17900bd37d32Smrg	    TRACE(("...result %s\n", result->option));
17910bd37d32Smrg	    /* expand abbreviations */
17920bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
17930bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
17940bd37d32Smrg		    argv[*num] = x_strdup(result->option);
17950bd37d32Smrg		}
17960bd37d32Smrg	    }
17970bd37d32Smrg
17980bd37d32Smrg	    /* adjust (*num) to skip option value */
17990bd37d32Smrg	    (*num) += countArg(result);
18000bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
18010bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
18020bd37d32Smrg		*valuep = argv[*num];
18030bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
18040bd37d32Smrg	    }
18050bd37d32Smrg	}
18060bd37d32Smrg    }
18070bd37d32Smrg#undef ITEM
18080bd37d32Smrg    return result;
1809d522f475Smrg}
1810d522f475Smrg
1811d522f475Smrgstatic void
1812d522f475SmrgSyntax(char *badOption)
1813d522f475Smrg{
1814d522f475Smrg    OptionHelp *opt;
1815d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1816d522f475Smrg    int col;
1817d522f475Smrg
18180bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
18190bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1820d522f475Smrg
1821d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1822956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1823d522f475Smrg    for (opt = list; opt->opt; opt++) {
1824956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1825d522f475Smrg	if (col + len > 79) {
1826d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1827d522f475Smrg	    col = 3;
1828d522f475Smrg	}
1829d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1830d522f475Smrg	col += len;
1831d522f475Smrg    }
1832d522f475Smrg
1833d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1834d522f475Smrg	    ProgramName);
183504b94745Smrg    exit(ERROR_MISC);
1836d522f475Smrg}
1837d522f475Smrg
1838d522f475Smrgstatic void
1839d522f475SmrgVersion(void)
1840d522f475Smrg{
1841d522f475Smrg    printf("%s\n", xtermVersion());
1842d522f475Smrg    fflush(stdout);
1843d522f475Smrg}
1844d522f475Smrg
1845d522f475Smrgstatic void
1846d522f475SmrgHelp(void)
1847d522f475Smrg{
1848d522f475Smrg    OptionHelp *opt;
1849d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
185001037d57Smrg    const char *const *cpp;
1851d522f475Smrg
1852d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1853d522f475Smrg	   xtermVersion(), ProgramName);
1854d522f475Smrg    printf("where options include:\n");
1855d522f475Smrg    for (opt = list; opt->opt; opt++) {
1856d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1857d522f475Smrg    }
1858d522f475Smrg
1859d522f475Smrg    putchar('\n');
186004b94745Smrg    for (cpp = help_message; *cpp; cpp++)
1861d522f475Smrg	puts(*cpp);
1862d522f475Smrg    putchar('\n');
1863d522f475Smrg    fflush(stdout);
1864d522f475Smrg}
1865d522f475Smrg
1866f2e35a3aSmrgstatic void
1867f2e35a3aSmrgNeedParam(XrmOptionDescRec * option_ptr, const char *option_val)
1868f2e35a3aSmrg{
1869f2e35a3aSmrg    if (IsEmpty(option_val)) {
1870f2e35a3aSmrg	xtermWarning("option %s requires a value\n", option_ptr->option);
187104b94745Smrg	exit(ERROR_MISC);
1872f2e35a3aSmrg    }
1873f2e35a3aSmrg}
1874f2e35a3aSmrg
1875d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1876d522f475Smrg/* ARGSUSED */
1877d522f475Smrgstatic Boolean
1878d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1879894e0ac8Smrg			Atom *selection GCC_UNUSED,
1880894e0ac8Smrg			Atom *target GCC_UNUSED,
1881894e0ac8Smrg			Atom *type GCC_UNUSED,
1882d522f475Smrg			XtPointer *value GCC_UNUSED,
1883d522f475Smrg			unsigned long *length GCC_UNUSED,
1884d522f475Smrg			int *format GCC_UNUSED)
1885d522f475Smrg{
1886d522f475Smrg    /* we don't save console output, so can't offer it */
1887d522f475Smrg    return False;
1888d522f475Smrg}
1889d522f475Smrg#endif /* TIOCCONS */
1890d522f475Smrg
1891d522f475Smrg/*
1892d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1893d522f475Smrg */
1894d522f475Smrg/* ARGSUSED */
1895d522f475Smrgstatic void
1896d522f475SmrgDeleteWindow(Widget w,
1897894e0ac8Smrg	     XEvent *event GCC_UNUSED,
1898e0a2b6dfSmrg	     String *params GCC_UNUSED,
1899d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1900d522f475Smrg{
1901d522f475Smrg#if OPT_TEK4014
1902d522f475Smrg    if (w == toplevel) {
1903d522f475Smrg	if (TEK4014_SHOWN(term))
1904d522f475Smrg	    hide_vt_window();
1905d522f475Smrg	else
1906d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
190720d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1908d522f475Smrg	hide_tek_window();
1909d522f475Smrg    else
1910d522f475Smrg#endif
1911d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1912d522f475Smrg}
1913d522f475Smrg
1914d522f475Smrg/* ARGSUSED */
1915d522f475Smrgstatic void
1916d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1917894e0ac8Smrg		XEvent *event,
1918e0a2b6dfSmrg		String *params GCC_UNUSED,
1919d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1920d522f475Smrg{
1921d522f475Smrg    switch (event->type) {
1922d522f475Smrg    case MappingNotify:
1923d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1924d522f475Smrg	break;
1925d522f475Smrg    }
1926d522f475Smrg}
1927d522f475Smrg
1928d522f475Smrgstatic XtActionsRec actionProcs[] =
1929d522f475Smrg{
1930d522f475Smrg    {"DeleteWindow", DeleteWindow},
1931d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1932d522f475Smrg};
1933d522f475Smrg
1934d522f475Smrg/*
1935d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1936d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1937d522f475Smrg * utmp.
1938d522f475Smrg */
1939d522f475Smrgstatic char *
1940d522f475Smrgmy_pty_name(char *device)
1941d522f475Smrg{
1942d522f475Smrg    size_t len = strlen(device);
1943d522f475Smrg    Bool name = False;
1944d522f475Smrg
1945d522f475Smrg    while (len != 0) {
1946d522f475Smrg	int ch = device[len - 1];
1947d522f475Smrg	if (isdigit(ch)) {
1948d522f475Smrg	    len--;
1949d522f475Smrg	} else if (ch == '/') {
1950d522f475Smrg	    if (name)
1951d522f475Smrg		break;
1952d522f475Smrg	    len--;
19535307cd1aSmrg	} else if (isalpha(CharOf(ch))) {
1954d522f475Smrg	    name = True;
1955d522f475Smrg	    len--;
1956d522f475Smrg	} else {
1957d522f475Smrg	    break;
1958d522f475Smrg	}
1959d522f475Smrg    }
1960d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1961d522f475Smrg    return device + len;
1962d522f475Smrg}
1963d522f475Smrg
1964d522f475Smrg/*
1965d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1966d522f475Smrg * last few characters for a utmp identifier.
1967d522f475Smrg */
1968d522f475Smrgstatic char *
1969d522f475Smrgmy_pty_id(char *device)
1970d522f475Smrg{
1971d522f475Smrg    char *name = my_pty_name(device);
1972d522f475Smrg    char *leaf = x_basename(name);
1973d522f475Smrg
1974d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1975956cc18dSsnj	int len = (int) strlen(leaf);
1976d522f475Smrg	if (PTYCHARLEN < len)
1977d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1978d522f475Smrg    }
19795104ee6eSmrg    TRACE(("my_pty_id  (%s) -> '%s'\n", NonNull(device), NonNull(leaf)));
1980d522f475Smrg    return leaf;
1981d522f475Smrg}
1982d522f475Smrg
1983d522f475Smrg/*
1984d522f475Smrg * Set the tty/pty identifier
1985d522f475Smrg */
1986d522f475Smrgstatic void
1987d522f475Smrgset_pty_id(char *device, char *id)
1988d522f475Smrg{
1989d522f475Smrg    char *name = my_pty_name(device);
1990d522f475Smrg    char *leaf = x_basename(name);
1991d522f475Smrg
1992d522f475Smrg    if (name == leaf) {
1993d522f475Smrg	strcpy(my_pty_id(device), id);
1994d522f475Smrg    } else {
1995d522f475Smrg	strcpy(leaf, id);
1996d522f475Smrg    }
1997d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
1998d522f475Smrg}
1999d522f475Smrg
2000d522f475Smrg/*
2001d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
2002d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
2003d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
2004d522f475Smrg * not, fall-thru to the original logic.
2005d522f475Smrg */
2006d522f475Smrgstatic Bool
2007d522f475SmrgParseSccn(char *option)
2008d522f475Smrg{
2009d522f475Smrg    char *leaf = x_basename(option);
2010d522f475Smrg    Bool code = False;
2011d522f475Smrg
201201037d57Smrg    passedPty = x_strdup(option);
2013d522f475Smrg    if (leaf != option) {
2014d522f475Smrg	if (leaf - option > 0
2015d522f475Smrg	    && isdigit(CharOf(*leaf))
2016d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
2017956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
2018d522f475Smrg	    /*
2019d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
2020d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
2021d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
2022d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
2023d522f475Smrg	     */
2024d522f475Smrg	    passedPty[len] = 0;
2025d522f475Smrg	    code = True;
2026d522f475Smrg	}
2027d522f475Smrg    } else {
2028d522f475Smrg	code = (sscanf(option, "%c%c%d",
2029d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
203001037d57Smrg	passedPty[2] = '\0';
2031d522f475Smrg    }
2032d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
2033d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
2034d522f475Smrg    return code;
2035d522f475Smrg}
2036d522f475Smrg
2037d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
2038d522f475Smrg/*
2039d522f475Smrg * From "man utmp":
2040d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
2041d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
2042d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
2043d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
2044d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
2045d522f475Smrg * ut_time, ut_user and ut_host as well.
2046d522f475Smrg *
2047d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
2048d522f475Smrg * pty implementation allows more than 3 digits.
2049d522f475Smrg */
2050d522f475Smrgstatic char *
2051d522f475Smrgmy_utmp_id(char *device)
2052d522f475Smrg{
2053d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
2054d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
2055d522f475Smrg    static char result[UTIDSIZE + 1];
2056d522f475Smrg
2057d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
2058d522f475Smrg    /*
2059d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
2060d522f475Smrg     * issues, and can use the available space in ut_id differently from the
2061d522f475Smrg     * default convention.
2062d522f475Smrg     *
2063d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
2064d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
2065d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
2066d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
2067d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
2068d522f475Smrg     * last three digits of the device name, regardless of the format of the
2069d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
2070d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
2071d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
2072d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
2073d522f475Smrg     */
2074d522f475Smrg    int len, n;
2075d522f475Smrg
2076d522f475Smrg    len = strlen(device);
2077d522f475Smrg    n = UTIDSIZE;
2078d522f475Smrg    result[n] = '\0';
2079d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
2080d522f475Smrg	result[--n] = device[--len];
2081d522f475Smrg    while (n > 0)
2082d522f475Smrg	result[--n] = '0';
2083d522f475Smrg    result[0] = 'x';
2084d522f475Smrg#else
2085d522f475Smrg    char *name = my_pty_name(device);
2086d522f475Smrg    char *leaf = x_basename(name);
2087d522f475Smrg    size_t len = strlen(leaf);
2088d522f475Smrg
2089d522f475Smrg    if ((UTIDSIZE - 1) < len)
2090d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
2091d522f475Smrg    sprintf(result, "p%s", leaf);
2092d522f475Smrg#endif
2093d522f475Smrg
2094d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
2095d522f475Smrg    return result;
2096d522f475Smrg}
2097d522f475Smrg#endif /* USE_SYSV_UTMP */
2098d522f475Smrg
2099d522f475Smrg#ifdef USE_POSIX_SIGNALS
2100d522f475Smrg
2101d522f475Smrgtypedef void (*sigfunc) (int);
2102d522f475Smrg
2103d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
2104d522f475Smrg   has just been stopped and not actually killed */
2105d522f475Smrg
2106d522f475Smrgstatic sigfunc
2107d522f475Smrgposix_signal(int signo, sigfunc func)
2108d522f475Smrg{
2109d522f475Smrg    struct sigaction act, oact;
2110d522f475Smrg
2111d522f475Smrg    act.sa_handler = func;
2112d522f475Smrg    sigemptyset(&act.sa_mask);
2113d522f475Smrg#ifdef SA_RESTART
2114d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
2115d522f475Smrg#else
2116d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
2117d522f475Smrg#endif
2118d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
2119d522f475Smrg	return (SIG_ERR);
2120d522f475Smrg    return (oact.sa_handler);
2121d522f475Smrg}
2122d522f475Smrg
21230bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
2124d522f475Smrg
2125d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
2126d522f475Smrgstatic void
2127d522f475SmrgdisableSetUid(void)
2128d522f475Smrg{
2129d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
2130d522f475Smrg    if (setuid(save_ruid) == -1) {
21310bd37d32Smrg	xtermWarning("unable to reset uid\n");
213204b94745Smrg	exit(ERROR_MISC);
2133d522f475Smrg    }
2134d522f475Smrg    TRACE_IDS;
2135d522f475Smrg}
2136d522f475Smrg#else
2137d522f475Smrg#define disableSetUid()		/* nothing */
2138d522f475Smrg#endif /* DISABLE_SETUID */
2139d522f475Smrg
2140d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
2141d522f475Smrgstatic void
2142d522f475SmrgdisableSetGid(void)
2143d522f475Smrg{
2144d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
2145d522f475Smrg    if (setegid(save_rgid) == -1) {
21460bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
214704b94745Smrg	exit(ERROR_MISC);
2148d522f475Smrg    }
2149d522f475Smrg    TRACE_IDS;
2150d522f475Smrg}
2151d522f475Smrg#else
2152d522f475Smrg#define disableSetGid()		/* nothing */
2153d522f475Smrg#endif /* DISABLE_SETGID */
2154d522f475Smrg
2155d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
2156d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
2157d522f475Smrgstatic void
2158d522f475SmrgsetEffectiveGroup(gid_t group)
2159d522f475Smrg{
2160d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
2161d522f475Smrg    if (setegid(group) == -1) {
21625104ee6eSmrg	xtermPerror("setegid(%d)", (int) group);
2163d522f475Smrg    }
2164d522f475Smrg    TRACE_IDS;
2165d522f475Smrg}
2166d522f475Smrg#endif
2167d522f475Smrg
2168d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
2169d522f475Smrgstatic void
2170d522f475SmrgsetEffectiveUser(uid_t user)
2171d522f475Smrg{
2172d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
2173d522f475Smrg    if (seteuid(user) == -1) {
21745104ee6eSmrg	xtermPerror("seteuid(%d)", (int) user);
2175d522f475Smrg    }
2176d522f475Smrg    TRACE_IDS;
2177d522f475Smrg}
2178d522f475Smrg#endif
2179d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
2180d522f475Smrg
21812e4f8982Smrg#if OPT_LUIT_PROG
21822e4f8982Smrgstatic Boolean
21832e4f8982Smrgcomplex_command(char **args)
21842e4f8982Smrg{
21852e4f8982Smrg    Boolean result = False;
21862e4f8982Smrg    if (x_countargv(args) == 1) {
21872e4f8982Smrg	char *check = xtermFindShell(args[0], False);
21885104ee6eSmrg	if (check == NULL) {
21892e4f8982Smrg	    result = True;
21902e4f8982Smrg	} else {
21912e4f8982Smrg	    free(check);
21922e4f8982Smrg	}
21932e4f8982Smrg    }
21942e4f8982Smrg    return result;
21952e4f8982Smrg}
21962e4f8982Smrg#endif
21972e4f8982Smrg
21982e4f8982Smrgstatic unsigned
21992e4f8982Smrglookup_baudrate(const char *value)
22002e4f8982Smrg{
22012e4f8982Smrg    struct speed {
22022e4f8982Smrg	unsigned given_speed;	/* values for 'ospeed' */
22032e4f8982Smrg	unsigned actual_speed;	/* the actual speed */
22042e4f8982Smrg    };
22052e4f8982Smrg
22062e4f8982Smrg#define DATA(number) { B##number, number }
22072e4f8982Smrg
22082e4f8982Smrg    static struct speed const speeds[] =
22092e4f8982Smrg    {
22102e4f8982Smrg	DATA(0),
22112e4f8982Smrg	DATA(50),
22122e4f8982Smrg	DATA(75),
22132e4f8982Smrg	DATA(110),
22142e4f8982Smrg	DATA(134),
22152e4f8982Smrg	DATA(150),
22162e4f8982Smrg	DATA(200),
22172e4f8982Smrg	DATA(300),
22182e4f8982Smrg	DATA(600),
22192e4f8982Smrg	DATA(1200),
22202e4f8982Smrg	DATA(1800),
22212e4f8982Smrg	DATA(2400),
22222e4f8982Smrg	DATA(4800),
22232e4f8982Smrg	DATA(9600),
22242e4f8982Smrg#ifdef B19200
22252e4f8982Smrg	DATA(19200),
22262e4f8982Smrg#elif defined(EXTA)
22272e4f8982Smrg	{EXTA, 19200},
22282e4f8982Smrg#endif
22292e4f8982Smrg#ifdef B28800
22302e4f8982Smrg	DATA(28800),
22312e4f8982Smrg#endif
22322e4f8982Smrg#ifdef B38400
22332e4f8982Smrg	DATA(38400),
22342e4f8982Smrg#elif defined(EXTB)
22352e4f8982Smrg	{EXTB, 38400},
22362e4f8982Smrg#endif
22372e4f8982Smrg#ifdef B57600
22382e4f8982Smrg	DATA(57600),
22392e4f8982Smrg#endif
22402e4f8982Smrg#ifdef B76800
22412e4f8982Smrg	DATA(76800),
22422e4f8982Smrg#endif
22432e4f8982Smrg#ifdef B115200
22442e4f8982Smrg	DATA(115200),
22452e4f8982Smrg#endif
22462e4f8982Smrg#ifdef B153600
22472e4f8982Smrg	DATA(153600),
22482e4f8982Smrg#endif
22492e4f8982Smrg#ifdef B230400
22502e4f8982Smrg	DATA(230400),
22512e4f8982Smrg#endif
22522e4f8982Smrg#ifdef B307200
22532e4f8982Smrg	DATA(307200),
22542e4f8982Smrg#endif
22552e4f8982Smrg#ifdef B460800
22562e4f8982Smrg	DATA(460800),
22572e4f8982Smrg#endif
22582e4f8982Smrg#ifdef B500000
22592e4f8982Smrg	DATA(500000),
22602e4f8982Smrg#endif
22612e4f8982Smrg#ifdef B576000
22622e4f8982Smrg	DATA(576000),
22632e4f8982Smrg#endif
22642e4f8982Smrg#ifdef B921600
22652e4f8982Smrg	DATA(921600),
22662e4f8982Smrg#endif
22672e4f8982Smrg#ifdef B1000000
22682e4f8982Smrg	DATA(1000000),
22692e4f8982Smrg#endif
22702e4f8982Smrg#ifdef B1152000
22712e4f8982Smrg	DATA(1152000),
22722e4f8982Smrg#endif
22732e4f8982Smrg#ifdef B1500000
22742e4f8982Smrg	DATA(1500000),
22752e4f8982Smrg#endif
22762e4f8982Smrg#ifdef B2000000
22772e4f8982Smrg	DATA(2000000),
22782e4f8982Smrg#endif
22792e4f8982Smrg#ifdef B2500000
22802e4f8982Smrg	DATA(2500000),
22812e4f8982Smrg#endif
22822e4f8982Smrg#ifdef B3000000
22832e4f8982Smrg	DATA(3000000),
22842e4f8982Smrg#endif
22852e4f8982Smrg#ifdef B3500000
22862e4f8982Smrg	DATA(3500000),
22872e4f8982Smrg#endif
22882e4f8982Smrg#ifdef B4000000
22892e4f8982Smrg	DATA(4000000),
22902e4f8982Smrg#endif
22912e4f8982Smrg    };
22922e4f8982Smrg#undef DATA
22932e4f8982Smrg    unsigned result = 0;
22945104ee6eSmrg
22952e4f8982Smrg    if (x_toupper(*value) == 'B')
22962e4f8982Smrg	value++;
22975104ee6eSmrg
22982e4f8982Smrg    if (isdigit(CharOf(*value))) {
22995104ee6eSmrg	char *next;
23005104ee6eSmrg	long check = strtol(value, &next, 10);
23015104ee6eSmrg
23022e4f8982Smrg	if (FullS2L(value, next) && (check > 0)) {
23032e4f8982Smrg	    Cardinal n;
23042e4f8982Smrg	    for (n = 0; n < XtNumber(speeds); ++n) {
23052e4f8982Smrg		if (speeds[n].actual_speed == (unsigned) check) {
23062e4f8982Smrg		    result = speeds[n].given_speed;
23072e4f8982Smrg		    break;
23082e4f8982Smrg		}
23092e4f8982Smrg	    }
23102e4f8982Smrg	}
23112e4f8982Smrg    }
23122e4f8982Smrg    if (result == 0) {
23132e4f8982Smrg	fprintf(stderr, "unsupported value for baudrate: %s\n", value);
23142e4f8982Smrg    }
23152e4f8982Smrg    return result;
23162e4f8982Smrg}
23172e4f8982Smrg
23185307cd1aSmrgint
23195307cd1aSmrgget_tty_erase(int fd, int default_erase, const char *tag)
23205307cd1aSmrg{
23215307cd1aSmrg    int result = default_erase;
23225307cd1aSmrg    int rc;
23235307cd1aSmrg
23245307cd1aSmrg#ifdef TERMIO_STRUCT
23255307cd1aSmrg    TERMIO_STRUCT my_tio;
23265307cd1aSmrg    rc = ttyGetAttr(fd, &my_tio);
23275307cd1aSmrg    if (rc == 0)
23285307cd1aSmrg	result = my_tio.c_cc[VERASE];
23295307cd1aSmrg#else /* !TERMIO_STRUCT */
23305307cd1aSmrg    struct sgttyb my_sg;
23315307cd1aSmrg    rc = ioctl(fd, TIOCGETP, (char *) &my_sg);
23325307cd1aSmrg    if (rc == 0)
23335307cd1aSmrg	result = my_sg.sg_erase;
23345307cd1aSmrg#endif /* TERMIO_STRUCT */
23355307cd1aSmrg    TRACE(("%s erase:%d (from %s)\n", (rc == 0) ? "OK" : "FAIL", result, tag));
23365307cd1aSmrg    (void) tag;
23375307cd1aSmrg    return result;
23385307cd1aSmrg}
23395307cd1aSmrg
23405307cd1aSmrgint
23415307cd1aSmrgget_tty_lnext(int fd, int default_lnext, const char *tag)
23425307cd1aSmrg{
23435307cd1aSmrg#ifdef TERMIO_STRUCT
23445307cd1aSmrg    TERMIO_STRUCT my_tio;
23455104ee6eSmrg    int rc = ttyGetAttr(fd, &my_tio);
23465104ee6eSmrg    int result = (rc == 0) ? my_tio.c_cc[VLNEXT] : default_lnext;
23475307cd1aSmrg#elif defined(HAS_LTCHARS)
23485307cd1aSmrg    struct ltchars my_ltc;
23495104ee6eSmrg    int rc = ioctl(fd, TIOCGLTC, (char *) &my_ltc);
23505104ee6eSmrg    int result = (rc == 0) ? my_ltc.t_lnextc : default_lnext;
23515307cd1aSmrg#else
23525104ee6eSmrg    int result = XTERM_LNEXT;
23535307cd1aSmrg#endif /* TERMIO_STRUCT */
23545307cd1aSmrg    TRACE(("%s lnext:%d (from %s)\n", (rc == 0) ? "OK" : "FAIL", result, tag));
23555307cd1aSmrg    (void) tag;
23565307cd1aSmrg    return result;
23575307cd1aSmrg}
23585307cd1aSmrg
2359d522f475Smrgint
2360d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
2361d522f475Smrg{
2362a1f3da82Smrg#if OPT_MAXIMIZE
2363a1f3da82Smrg#define DATA(name) { #name, es##name }
236401037d57Smrg    static const FlagList tblFullscreen[] =
2365a1f3da82Smrg    {
2366a1f3da82Smrg	DATA(Always),
2367a1f3da82Smrg	DATA(Never)
2368a1f3da82Smrg    };
2369a1f3da82Smrg#undef DATA
2370a1f3da82Smrg#endif
2371a1f3da82Smrg
2372d522f475Smrg    Widget form_top, menu_top;
2373d522f475Smrg    Dimension menu_high;
2374d522f475Smrg    TScreen *screen;
2375d522f475Smrg    int mode;
2376e0a2b6dfSmrg    char *my_class = x_strdup(DEFCLASS);
23772e4f8982Smrg    unsigned line_speed = VAL_LINE_SPEED;
2378d522f475Smrg    Window winToEmbedInto = None;
2379f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
2380f2e35a3aSmrg    Xaw3dXftData *xaw3dxft_data;
2381f2e35a3aSmrg#endif
2382d522f475Smrg
2383ae137402Smrg    ProgramName = x_strdup(x_basename(argv[0]));
2384ae137402Smrg    ProgramPath = xtermFindShell(argv[0], True);
2385ae137402Smrg    if (ProgramPath != NULL)
2386ae137402Smrg	argv[0] = ProgramPath;
2387d522f475Smrg
2388d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
2389d522f475Smrg    save_euid = geteuid();
2390d522f475Smrg    save_egid = getegid();
2391d522f475Smrg#endif
2392d522f475Smrg
2393d522f475Smrg    save_ruid = getuid();
2394d522f475Smrg    save_rgid = getgid();
2395d522f475Smrg
2396d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
2397d522f475Smrg#if defined(DISABLE_SETUID)
2398d522f475Smrg    disableSetUid();
2399d522f475Smrg#endif
2400d522f475Smrg#if defined(DISABLE_SETGID)
2401d522f475Smrg    disableSetGid();
2402d522f475Smrg#endif
2403d522f475Smrg    TRACE_IDS;
2404d522f475Smrg#endif
2405d522f475Smrg
2406d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
2407d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
2408d522f475Smrg#ifdef USE_PTY_DEVICE
2409d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
2410d522f475Smrg    if (!ttydev || !ptydev)
2411d522f475Smrg#else
2412d522f475Smrg    if (!ttydev)
2413d522f475Smrg#endif
2414d522f475Smrg    {
24150bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
241604b94745Smrg	exit(ERROR_MISC);
2417d522f475Smrg    }
2418d522f475Smrg    strcpy(ttydev, TTYDEV);
2419d522f475Smrg#ifdef USE_PTY_DEVICE
2420d522f475Smrg    strcpy(ptydev, PTYDEV);
2421d522f475Smrg#endif
2422d522f475Smrg
2423d522f475Smrg#if defined(USE_UTMP_SETGID)
2424d522f475Smrg    get_pty(NULL, NULL);
2425d522f475Smrg    disableSetUid();
2426d522f475Smrg    disableSetGid();
2427d522f475Smrg    TRACE_IDS;
2428d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
2429d522f475Smrg#endif
2430d522f475Smrg
2431d522f475Smrg    /* Do these first, since we may not be able to open the display */
2432d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
2433d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
2434ae137402Smrg    restart_params = 0;
2435d522f475Smrg    if (argc > 1) {
2436d522f475Smrg	int n;
2437e39b573cSmrg	Bool quit = False;
2438d522f475Smrg
2439d522f475Smrg	for (n = 1; n < argc; n++) {
24405104ee6eSmrg	    XrmOptionDescRec *option_ptr;
24415104ee6eSmrg	    char *option_value;
24425104ee6eSmrg
24435104ee6eSmrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == NULL) {
24445104ee6eSmrg		if (argv[n] == NULL) {
24450bd37d32Smrg		    break;
24460bd37d32Smrg		} else if (isOption(argv[n])) {
24470bd37d32Smrg		    Syntax(argv[n]);
24485104ee6eSmrg		} else if (explicit_shname != NULL) {
24490bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
24500bd37d32Smrg		    Syntax(argv[n]);
24510bd37d32Smrg		}
24520bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
24535104ee6eSmrg		if (explicit_shname == NULL)
24540bd37d32Smrg		    exit(0);
24550bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
2456ae137402Smrg		restart_params = (argc - n);
24570bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
24580bd37d32Smrg		command_to_exec = (argv + n + 1);
24590bd37d32Smrg		if (!command_to_exec[0])
24600bd37d32Smrg		    Syntax(argv[n]);
2461ae137402Smrg		restart_params = (argc - n);
24620bd37d32Smrg		break;
24630bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2464d522f475Smrg		Version();
2465e39b573cSmrg		quit = True;
24660bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2467d522f475Smrg		Help();
2468e39b573cSmrg		quit = True;
24692e4f8982Smrg	    } else if (!strcmp(option_ptr->option, "-baudrate")) {
2470f2e35a3aSmrg		NeedParam(option_ptr, option_value);
24712e4f8982Smrg		if ((line_speed = lookup_baudrate(option_value)) == 0) {
24722e4f8982Smrg		    Help();
24732e4f8982Smrg		    quit = True;
24742e4f8982Smrg		}
24750bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
2476f2e35a3aSmrg		NeedParam(option_ptr, option_value);
2477e0a2b6dfSmrg		free(my_class);
24785104ee6eSmrg		if ((my_class = x_strdup(option_value)) == NULL) {
2479d522f475Smrg		    Help();
2480e39b573cSmrg		    quit = True;
2481d522f475Smrg		}
24820bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
24830bd37d32Smrg		char *endPtr;
2484f2e35a3aSmrg		NeedParam(option_ptr, option_value);
24850bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
24862e4f8982Smrg		if (!FullS2L(option_value, endPtr)) {
24872e4f8982Smrg		    Help();
24882e4f8982Smrg		    quit = True;
24892e4f8982Smrg		}
2490d522f475Smrg	    }
2491d522f475Smrg	}
2492d522f475Smrg	if (quit)
2493d522f475Smrg	    exit(0);
24940bd37d32Smrg	/*
24950bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
24960bd37d32Smrg	 * then give up.
24970bd37d32Smrg	 */
24980bd37d32Smrg	if (n < argc && !command_to_exec) {
24990bd37d32Smrg	    Syntax(argv[n]);
25000bd37d32Smrg	}
2501d522f475Smrg    }
2502d522f475Smrg
25030bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2504d522f475Smrg#if OPT_I18N_SUPPORT
2505d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2506d522f475Smrg#endif
2507d522f475Smrg
2508f2e35a3aSmrg    /* enable Xft support in Xaw3DXft */
2509f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
2510f2e35a3aSmrg    GET_XAW3DXFT_DATA(xaw3dxft_data);
2511f2e35a3aSmrg    xaw3dxft_data->encoding = -1;
2512f2e35a3aSmrg#endif
2513f2e35a3aSmrg
2514d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2515d522f475Smrg    /* Initialization is done here rather than above in order
2516d522f475Smrg     * to prevent any assumptions about the order of the contents
2517d522f475Smrg     * of the various terminal structures (which may change from
2518d522f475Smrg     * implementation to implementation).
2519d522f475Smrg     */
2520d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2521d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2522f2e35a3aSmrg    d_tio.c_oflag = TAB3 | D_TIO_FLAGS;
2523d522f475Smrg    {
2524d522f475Smrg	Cardinal nn;
2525d522f475Smrg
2526d522f475Smrg	/* fill in default-values */
2527f2e35a3aSmrg	for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
2528d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2529f2e35a3aSmrg		d_tio.c_cc[ttyChars[nn].sysMode] =
2530f2e35a3aSmrg		    (cc_t) ttyChars[nn].myDefault;
2531d522f475Smrg	    }
2532d522f475Smrg	}
2533d522f475Smrg    }
2534d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
25352e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2536d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2537d522f475Smrg#ifdef ECHOKE
2538d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2539d522f475Smrg#endif
2540d522f475Smrg#ifdef ECHOCTL
2541d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2542d522f475Smrg#endif
2543d522f475Smrg#ifndef USE_TERMIOS		/* { */
2544d522f475Smrg    d_tio.c_line = 0;
2545d522f475Smrg#endif /* } */
2546d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2547d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2548d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2549d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2550d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2551d522f475Smrg    d_ltc.t_werasc = CWERASE;
2552d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2553d522f475Smrg#endif /* } HAS_LTCHARS */
2554d522f475Smrg#ifdef TIOCLSET			/* { */
2555d522f475Smrg    d_lmode = 0;
2556d522f475Smrg#endif /* } TIOCLSET */
2557d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2558d522f475Smrg#ifndef USE_POSIX_TERMIOS
2559d522f475Smrg#ifdef BAUD_0			/* { */
2560d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2561d522f475Smrg#else /* }{ !BAUD_0 */
25622e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2563d522f475Smrg#endif /* } !BAUD_0 */
2564d522f475Smrg#else /* USE_POSIX_TERMIOS */
2565d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
25662e4f8982Smrg    cfsetispeed(&d_tio, line_speed);
25672e4f8982Smrg    cfsetospeed(&d_tio, line_speed);
2568d522f475Smrg#endif
2569d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2570d522f475Smrg#ifdef ECHOKE
2571d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2572d522f475Smrg#endif
2573d522f475Smrg#ifdef ECHOCTL
2574d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2575d522f475Smrg#endif
2576d522f475Smrg#ifndef USE_POSIX_TERMIOS
2577d522f475Smrg#ifdef NTTYDISC
2578d522f475Smrg    d_tio.c_line = NTTYDISC;
2579d522f475Smrg#else
2580d522f475Smrg    d_tio.c_line = 0;
2581d522f475Smrg#endif
2582d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2583d522f475Smrg#ifdef __sgi
2584d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2585d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2586d522f475Smrg#endif
2587d522f475Smrg    {
2588d522f475Smrg	Cardinal nn;
2589d522f475Smrg	int i;
2590d522f475Smrg
2591d522f475Smrg	/* try to inherit tty settings */
2592d522f475Smrg	for (i = 0; i <= 2; i++) {
2593d522f475Smrg	    TERMIO_STRUCT deftio;
2594d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2595f2e35a3aSmrg		for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
2596d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2597f2e35a3aSmrg			d_tio.c_cc[ttyChars[nn].sysMode] =
2598f2e35a3aSmrg			    deftio.c_cc[ttyChars[nn].sysMode];
2599d522f475Smrg		    }
2600d522f475Smrg		}
2601d522f475Smrg		break;
2602d522f475Smrg	    }
2603d522f475Smrg	}
2604d522f475Smrg    }
2605d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2606d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2607d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2608d522f475Smrg#endif /* } */
2609d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2610d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2611d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2612d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2613d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2614d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2615d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2616d522f475Smrg#endif /* } HAS_LTCHARS */
2617d522f475Smrg
2618d522f475Smrg#ifdef TIOCLSET			/* { */
2619d522f475Smrg    d_lmode = 0;
2620d522f475Smrg#endif /* } TIOCLSET */
2621d522f475Smrg#endif /* } macII, ATT, CRAY */
2622d522f475Smrg#endif /* } TERMIO_STRUCT */
2623d522f475Smrg
2624d522f475Smrg    /* Init the Toolkit. */
2625d522f475Smrg    {
2626d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2627d522f475Smrg	setEffectiveGroup(save_rgid);
2628d522f475Smrg	setEffectiveUser(save_ruid);
2629d522f475Smrg	TRACE_IDS;
2630d522f475Smrg#endif
26310bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
26320bd37d32Smrg					my_class,
26330bd37d32Smrg					optionDescList,
26340bd37d32Smrg					XtNumber(optionDescList),
2635f2e35a3aSmrg					&argc, argv,
26360bd37d32Smrg					fallback_resources,
26370bd37d32Smrg					sessionShellWidgetClass,
26380bd37d32Smrg					NULL, 0);
2639ae137402Smrg	TRACE(("created toplevel widget %p, window %#lx\n",
2640ae137402Smrg	       (void *) toplevel, XtWindow(toplevel)));
2641d522f475Smrg
2642d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2643d522f475Smrg				  application_resources,
2644d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2645d522f475Smrg	TRACE_XRES();
2646ad37e533Smrg#ifdef HAVE_LIB_XCURSOR
2647ad37e533Smrg	if (!strcmp(resource.cursorTheme, "none")) {
2648ad37e533Smrg	    TRACE(("startup with no cursorTheme\n"));
2649ad37e533Smrg	    init_colored_cursor(XtDisplay(toplevel));
2650ad37e533Smrg	} else {
2651ad37e533Smrg	    const char *theme = resource.cursorTheme;
2652ad37e533Smrg	    if (IsEmpty(theme))
2653ad37e533Smrg		theme = "default";
2654ad37e533Smrg	    TRACE(("startup with \"%s\" cursorTheme\n", theme));
2655ad37e533Smrg	    xtermSetenv("XCURSOR_THEME", theme);
2656ad37e533Smrg	}
2657ad37e533Smrg#endif
2658f2e35a3aSmrg#if USE_DOUBLE_BUFFER
2659f2e35a3aSmrg	if (resource.buffered_fps <= 0)
2660f2e35a3aSmrg	    resource.buffered_fps = DEF_BUFFER_RATE;
2661f2e35a3aSmrg	if (resource.buffered_fps > 100)
2662f2e35a3aSmrg	    resource.buffered_fps = 100;
2663f2e35a3aSmrg#endif
2664a1f3da82Smrg#if OPT_MAXIMIZE
2665a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2666a1f3da82Smrg					      tblFullscreen,
2667f2e35a3aSmrg					      esLAST);
2668a1f3da82Smrg#endif
2669e39b573cSmrg	VTInitTranslations();
2670d522f475Smrg#if OPT_PTY_HANDSHAKE
2671d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2672d522f475Smrg#endif
2673d522f475Smrg
2674d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2675d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2676d522f475Smrg#if !defined(DISABLE_SETUID)
2677d522f475Smrg	setEffectiveUser(save_euid);
2678d522f475Smrg#endif
2679d522f475Smrg#if !defined(DISABLE_SETGID)
2680d522f475Smrg	setEffectiveGroup(save_egid);
2681d522f475Smrg#endif
2682d522f475Smrg	TRACE_IDS;
2683d522f475Smrg#endif
2684d522f475Smrg#endif
2685d522f475Smrg    }
2686d522f475Smrg
2687d522f475Smrg    /*
2688d522f475Smrg     * ICCCM delete_window.
2689d522f475Smrg     */
2690d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2691d522f475Smrg
2692d522f475Smrg    /*
2693d522f475Smrg     * fill in terminal modes
2694d522f475Smrg     */
2695d522f475Smrg    if (resource.tty_modes) {
2696f2e35a3aSmrg	int n = parse_tty_modes(resource.tty_modes);
2697d522f475Smrg	if (n < 0) {
26980bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2699d522f475Smrg	} else if (n > 0) {
2700d522f475Smrg	    override_tty_modes = True;
2701d522f475Smrg	}
2702d522f475Smrg    }
27030bd37d32Smrg    initZIconBeep();
2704d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2705d522f475Smrg    if (resource.icon_geometry != NULL) {
2706d522f475Smrg	int scr, junk;
2707d522f475Smrg	int ix, iy;
2708d522f475Smrg	Arg args[2];
2709d522f475Smrg
2710d522f475Smrg	for (scr = 0;		/* yyuucchh */
2711d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2712d522f475Smrg	     scr++) ;
2713d522f475Smrg
2714d522f475Smrg	args[0].name = XtNiconX;
2715d522f475Smrg	args[1].name = XtNiconY;
2716d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2717d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2718d522f475Smrg	args[0].value = (XtArgVal) ix;
2719d522f475Smrg	args[1].value = (XtArgVal) iy;
2720d522f475Smrg	XtSetValues(toplevel, args, 2);
2721d522f475Smrg    }
2722d522f475Smrg
2723d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2724d522f475Smrg		number_ourTopLevelShellArgs);
2725d522f475Smrg
2726d522f475Smrg#if OPT_WIDE_CHARS
2727d522f475Smrg    /* seems as good a place as any */
2728d522f475Smrg    init_classtab();
2729d522f475Smrg#endif
2730d522f475Smrg
2731d522f475Smrg    /* Parse the rest of the command line */
2732d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2733d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
27340bd37d32Smrg	if (!isOption(*argv)) {
2735d522f475Smrg	    if (argc > 1)
2736d522f475Smrg		Syntax(*argv);
2737d522f475Smrg	    continue;
27380bd37d32Smrg	}
2739d522f475Smrg
2740d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2741d522f475Smrg	switch (argv[0][1]) {
2742d522f475Smrg	case 'C':
2743d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2744d522f475Smrg#ifndef __sgi
2745d522f475Smrg	    {
2746d522f475Smrg		struct stat sbuf;
2747d522f475Smrg
2748d522f475Smrg		/* Must be owner and have read/write permission.
2749d522f475Smrg		   xdm cooperates to give the console the right user. */
2750d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2751d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2752d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2753d522f475Smrg		    Console = True;
2754d522f475Smrg		} else
2755d522f475Smrg		    Console = False;
2756d522f475Smrg	    }
2757d522f475Smrg#else /* __sgi */
2758d522f475Smrg	    Console = True;
2759d522f475Smrg#endif /* __sgi */
2760d522f475Smrg#endif /* TIOCCONS */
2761d522f475Smrg	    continue;
2762d522f475Smrg	case 'S':
2763d522f475Smrg	    if (!ParseSccn(*argv + 2))
2764d522f475Smrg		Syntax(*argv);
2765d522f475Smrg	    continue;
2766d522f475Smrg#ifdef DEBUG
2767d522f475Smrg	case 'D':
2768d522f475Smrg	    debug = True;
2769d522f475Smrg	    continue;
2770d522f475Smrg#endif /* DEBUG */
27712e4f8982Smrg	case 'b':
27722e4f8982Smrg	    if (strcmp(argv[0], "-baudrate"))
27732e4f8982Smrg		Syntax(*argv);
2774f2e35a3aSmrg	    argc--;
2775f2e35a3aSmrg	    argv++;
27762e4f8982Smrg	    continue;
27770bd37d32Smrg	case 'c':
27780bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2779d522f475Smrg		Syntax(*argv);
2780f2e35a3aSmrg	    argc--;
2781f2e35a3aSmrg	    argv++;
2782d522f475Smrg	    continue;
2783d522f475Smrg	case 'e':
27840bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2785d522f475Smrg		Syntax(*argv);
27860bd37d32Smrg	    command_to_exec = (argv + 1);
2787d522f475Smrg	    break;
2788d522f475Smrg	case 'i':
27890bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2790d522f475Smrg		Syntax(*argv);
2791f2e35a3aSmrg	    argc--;
2792f2e35a3aSmrg	    argv++;
2793d522f475Smrg	    continue;
2794d522f475Smrg
2795d522f475Smrg	default:
2796d522f475Smrg	    Syntax(*argv);
2797d522f475Smrg	}
2798d522f475Smrg	break;
2799d522f475Smrg    }
2800d522f475Smrg
2801d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2802d522f475Smrg
2803d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2804d522f475Smrg						 form_top,
2805d522f475Smrg#if OPT_TOOLBAR
2806d522f475Smrg						 XtNmenuBar, menu_top,
2807d522f475Smrg						 XtNresizable, True,
2808d522f475Smrg						 XtNfromVert, menu_top,
2809d522f475Smrg						 XtNleft, XawChainLeft,
2810d522f475Smrg						 XtNright, XawChainRight,
2811d522f475Smrg						 XtNtop, XawChainTop,
2812d522f475Smrg						 XtNbottom, XawChainBottom,
2813d522f475Smrg						 XtNmenuHeight, menu_high,
2814d522f475Smrg#endif
2815d522f475Smrg						 (XtPointer) 0);
2816ae137402Smrg    TRACE(("created vt100 widget %p, window %#lx\n",
2817ae137402Smrg	   (void *) term, XtWindow(term)));
2818d522f475Smrg    decode_keyboard_type(term, &resource);
2819d522f475Smrg
2820d522f475Smrg    screen = TScreenOf(term);
2821d522f475Smrg    screen->inhibit = 0;
2822d522f475Smrg
2823d522f475Smrg#ifdef ALLOWLOGGING
2824d522f475Smrg    if (term->misc.logInhibit)
2825d522f475Smrg	screen->inhibit |= I_LOG;
2826d522f475Smrg#endif
2827d522f475Smrg    if (term->misc.signalInhibit)
2828d522f475Smrg	screen->inhibit |= I_SIGNAL;
2829d522f475Smrg#if OPT_TEK4014
2830d522f475Smrg    if (term->misc.tekInhibit)
2831d522f475Smrg	screen->inhibit |= I_TEK;
2832d522f475Smrg#endif
2833d522f475Smrg
2834d522f475Smrg    /*
2835d522f475Smrg     * We might start by showing the tek4014 window.
2836d522f475Smrg     */
2837d522f475Smrg#if OPT_TEK4014
2838d522f475Smrg    if (screen->inhibit & I_TEK)
2839d522f475Smrg	TEK4014_ACTIVE(term) = False;
2840d522f475Smrg
2841d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2842d522f475Smrg	SysError(ERROR_INIT);
2843d522f475Smrg#endif
2844d522f475Smrg
2845d522f475Smrg    /*
2846d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2847d522f475Smrg     */
2848d522f475Smrg#if OPT_TOOLBAR
2849d522f475Smrg    ShowToolbar(resource.toolBar);
2850d522f475Smrg#endif
2851d522f475Smrg
28520bd37d32Smrg    xtermOpenSession();
2853d522f475Smrg
2854d522f475Smrg    /*
2855d522f475Smrg     * Set title and icon name if not specified
2856d522f475Smrg     */
2857d522f475Smrg    if (command_to_exec) {
2858d522f475Smrg	Arg args[2];
2859d522f475Smrg
28605307cd1aSmrg	if (!resource.title)
28615307cd1aSmrg	    resource.title = x_basename(command_to_exec[0]);
2862d522f475Smrg	if (!resource.icon_name)
2863d522f475Smrg	    resource.icon_name = resource.title;
28645307cd1aSmrg
2865d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2866d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2867d522f475Smrg
28680bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2869d522f475Smrg	       resource.title,
2870d522f475Smrg	       resource.icon_name,
28710bd37d32Smrg	       NonNull(resource.icon_hint),
2872d522f475Smrg	       *command_to_exec));
2873d522f475Smrg
2874d522f475Smrg	XtSetValues(toplevel, args, 2);
28755307cd1aSmrg    } else if (IsEmpty(resource.title) && strcmp(my_class, DEFCLASS)) {
28765307cd1aSmrg	Arg args[2];
28775307cd1aSmrg	int n;
28785307cd1aSmrg
28795307cd1aSmrg	resource.title = x_strdup(my_class);
28805307cd1aSmrg	for (n = 0; resource.title[n]; ++n) {
28815307cd1aSmrg	    if (isalpha(CharOf(resource.title[n])))
28825104ee6eSmrg		resource.title[n] = (char) tolower(CharOf(resource.title[n]));
28835307cd1aSmrg	}
28845307cd1aSmrg	TRACE(("setting:\n\ttitle \"%s\"\n", resource.title));
28855307cd1aSmrg	XtSetArg(args[0], XtNtitle, resource.title);
28865307cd1aSmrg	XtSetValues(toplevel, args, 1);
2887d522f475Smrg    }
2888d522f475Smrg#if OPT_LUIT_PROG
2889d522f475Smrg    if (term->misc.callfilter) {
28900bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
28910bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
28920bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
28930bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
28940bd37d32Smrg
28950bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
28960bd37d32Smrg						  (count_split
28970bd37d32Smrg						   + count_exec
28980bd37d32Smrg						   + count_using
28990bd37d32Smrg						   + 8));
29000bd37d32Smrg	if (command_to_exec_with_luit == NULL)
29010bd37d32Smrg	    SysError(ERROR_LUMALLOC);
29020bd37d32Smrg
29030bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
29040bd37d32Smrg	if (count_using) {
29050bd37d32Smrg	    char *encoding_opt[4];
29060bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
29070bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
29085104ee6eSmrg	    encoding_opt[2] = NULL;
29090bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
29100bd37d32Smrg	}
29110bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
29120bd37d32Smrg	if (count_exec) {
29130bd37d32Smrg	    char *delimiter[2];
29140bd37d32Smrg	    delimiter[0] = x_strdup("--");
29155104ee6eSmrg	    delimiter[1] = NULL;
29160bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
29172e4f8982Smrg	    if (complex_command(command_to_exec)) {
29185104ee6eSmrg		static char shell_name[] = "sh";
29195104ee6eSmrg		static char c_option[] = "-c";
29205104ee6eSmrg		static char *fixup_shell[] =
29215104ee6eSmrg		{
29225104ee6eSmrg		    shell_name,
29235104ee6eSmrg		    c_option,
29245104ee6eSmrg		    NULL
29255104ee6eSmrg		};
29262e4f8982Smrg		x_appendargv(command_to_exec_with_luit, fixup_shell);
29272e4f8982Smrg	    }
29280bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2929d522f475Smrg	}
29300bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
29310bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2932d522f475Smrg    }
2933d522f475Smrg#endif
2934d522f475Smrg
29350bd37d32Smrg    if_DEBUG({
2936d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2937d522f475Smrg	   done securely by a privileged xterm process (although we try),
2938d522f475Smrg	   so the debug feature is disabled by default. */
2939e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2940d522f475Smrg	int i = -1;
29410bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
29420bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
29430bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2944d522f475Smrg	}
2945d522f475Smrg	if (i >= 0) {
2946d522f475Smrg	    dup2(i, 2);
2947d522f475Smrg
2948d522f475Smrg	    /* mark this file as close on exec */
2949d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2950d522f475Smrg	}
29510bd37d32Smrg    });
2952d522f475Smrg
29532e4f8982Smrg    spawnXTerm(term, line_speed);
2954d522f475Smrg
2955d522f475Smrg    /* Child process is out there, let's catch its termination */
2956d522f475Smrg
2957d522f475Smrg#ifdef USE_POSIX_SIGNALS
2958d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2959d522f475Smrg#else
2960d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2961d522f475Smrg#endif
2962d522f475Smrg    /* Realize procs have now been executed */
2963d522f475Smrg
2964d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2965d522f475Smrg	char buf[80];
2966d522f475Smrg
2967d522f475Smrg	buf[0] = '\0';
2968d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
296920d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2970d522f475Smrg    }
2971d522f475Smrg#ifdef AIXV3
2972d522f475Smrg#if (OSMAJORVERSION < 4)
2973d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2974d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2975d522f475Smrg     * to the slave-pty process when xterm exits.
2976d522f475Smrg     */
2977d522f475Smrg
2978d522f475Smrg    {
2979d522f475Smrg	TERMIO_STRUCT tio;
2980d522f475Smrg
2981d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
2982d522f475Smrg	    SysError(ERROR_TIOCGETP);
2983d522f475Smrg
2984d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
2985d522f475Smrg
2986d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
2987d522f475Smrg	    SysError(ERROR_TIOCSETP);
2988d522f475Smrg    }
2989d522f475Smrg#endif
2990d522f475Smrg#endif
29915104ee6eSmrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__minix)
2992d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
2993d522f475Smrg	SysError(ERROR_F_GETFL);
2994d522f475Smrg#ifdef O_NDELAY
2995d522f475Smrg    mode |= O_NDELAY;
2996d522f475Smrg#else
2997d522f475Smrg    mode |= O_NONBLOCK;
2998d522f475Smrg#endif /* O_NDELAY */
2999d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
3000d522f475Smrg	SysError(ERROR_F_SETFL);
3001d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
3002d522f475Smrg    mode = 1;
3003d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
3004d522f475Smrg	SysError(ERROR_FIONBIO);
3005d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
3006d522f475Smrg
3007d522f475Smrg    /* The erase character is used to delete the current completion */
3008d522f475Smrg#if OPT_DABBREV
3009d522f475Smrg#ifdef TERMIO_STRUCT
3010d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
3011d522f475Smrg#else
3012d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
3013d522f475Smrg#endif
3014d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
3015d522f475Smrg#endif
3016d522f475Smrg
3017d522f475Smrg    FD_ZERO(&pty_mask);
3018d522f475Smrg    FD_ZERO(&X_mask);
3019d522f475Smrg    FD_ZERO(&Select_mask);
3020d522f475Smrg    FD_SET(screen->respond, &pty_mask);
3021d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
3022d522f475Smrg    FD_SET(screen->respond, &Select_mask);
3023d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
3024d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
3025d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
3026d522f475Smrg		 : (1 + screen->respond));
3027d522f475Smrg
30280bd37d32Smrg    if_DEBUG({
30290bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
30300bd37d32Smrg    });
3031d522f475Smrg    XSetErrorHandler(xerror);
3032d522f475Smrg    XSetIOErrorHandler(xioerror);
303301037d57Smrg#if OPT_SESSION_MGT
3034e39b573cSmrg    IceSetIOErrorHandler(ice_error);
303501037d57Smrg#endif
3036d522f475Smrg
3037d522f475Smrg    initPtyData(&VTbuffer);
3038d522f475Smrg#ifdef ALLOWLOGGING
3039d522f475Smrg    if (term->misc.log_on) {
304020d2c4d2Smrg	StartLog(term);
3041d522f475Smrg    }
3042d522f475Smrg#endif
3043d522f475Smrg
30440bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
3045a5ae21e4Smrg
3046a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
3047a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
304820d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
304920d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
3050d522f475Smrg
3051a1f3da82Smrg    if (term->misc.re_verse0) {
3052a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
3053a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
3054a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
3055a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
3056a1f3da82Smrg	} else {
3057a1f3da82Smrg	    ReverseVideo(term);
3058a1f3da82Smrg	}
3059a1f3da82Smrg	term->misc.re_verse = True;
3060a1f3da82Smrg	update_reversevideo();
3061a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
3062a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
3063a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
3064a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
3065a1f3da82Smrg    }
3066956cc18dSsnj#if OPT_MAXIMIZE
3067956cc18dSsnj    if (resource.maximized)
3068956cc18dSsnj	RequestMaximize(term, True);
3069956cc18dSsnj#endif
3070d522f475Smrg    for (;;) {
3071d522f475Smrg#if OPT_TEK4014
3072d522f475Smrg	if (TEK4014_ACTIVE(term))
3073d522f475Smrg	    TekRun();
3074d522f475Smrg	else
3075d522f475Smrg#endif
3076956cc18dSsnj	    VTRun(term);
3077d522f475Smrg    }
3078d522f475Smrg}
3079d522f475Smrg
308004b94745Smrg#if defined(__osf__) || (defined(__linux__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
3081d522f475Smrg#define USE_OPENPTY 1
3082d522f475Smrgstatic int opened_tty = -1;
3083d522f475Smrg#endif
3084d522f475Smrg
3085d522f475Smrg/*
3086d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
3087d522f475Smrg *
3088d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
3089d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
3090d522f475Smrg * so that if a pty master is found and later, we find that the slave
3091d522f475Smrg * has problems, we can re-enter this function and get another one.
3092d522f475Smrg */
3093d522f475Smrgstatic int
3094d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
3095d522f475Smrg{
3096d522f475Smrg    int result = 1;
3097d522f475Smrg
30980bd37d32Smrg#if defined(USE_OPENPTY)
30990bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
31002e4f8982Smrg    if (opened_tty >= 0) {
31012e4f8982Smrg	close(opened_tty);
31022e4f8982Smrg	opened_tty = -1;
31032e4f8982Smrg    }
31040bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
31050bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
31060bd37d32Smrg	char *name = ptsname(*pty);
31070bd37d32Smrg	if (name != 0) {
31080bd37d32Smrg	    strcpy(ttydev, name);
31090bd37d32Smrg	    result = 0;
31100bd37d32Smrg	}
31110bd37d32Smrg    }
31120bd37d32Smrg#ifdef USE_PTY_SEARCH
31130bd37d32Smrg    if (result) {
31140bd37d32Smrg	result = pty_search(pty);
31150bd37d32Smrg    }
31160bd37d32Smrg#endif
31170bd37d32Smrg#elif defined(PUCC_PTYD)
3118d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
3119d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
3120d522f475Smrg			       save_ruid, from)) < 0);
3121d522f475Smrg#elif defined(__QNXNTO__)
3122d522f475Smrg    result = pty_search(pty);
3123d522f475Smrg#else
3124d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
31250bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
31260bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
31270bd37d32Smrg    if (!result)
31280bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
3129d522f475Smrg#endif
3130d522f475Smrg
3131d522f475Smrg#elif defined(AIXV3)
3132d522f475Smrg
3133d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
3134d522f475Smrg	strcpy(ttydev, ttyname(*pty));
3135d522f475Smrg	result = 0;
3136d522f475Smrg    }
3137d522f475Smrg#elif defined(__convex__)
3138d522f475Smrg
3139d522f475Smrg    char *pty_name;
3140d522f475Smrg    extern char *getpty(void);
3141d522f475Smrg
3142d522f475Smrg    while ((pty_name = getpty()) != NULL) {
3143d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
3144d522f475Smrg	    strcpy(ptydev, pty_name);
3145d522f475Smrg	    strcpy(ttydev, pty_name);
3146d522f475Smrg	    *x_basename(ttydev) = 't';
3147d522f475Smrg	    result = 0;
3148d522f475Smrg	    break;
3149d522f475Smrg	}
3150d522f475Smrg    }
3151d522f475Smrg
3152d522f475Smrg#elif defined(sequent)
3153d522f475Smrg
3154d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
3155d522f475Smrg
3156d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
3157d522f475Smrg
3158d522f475Smrg    char *tty_name;
3159d522f475Smrg
3160d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
3161d522f475Smrg    if (tty_name != 0) {
3162d522f475Smrg	strcpy(ttydev, tty_name);
3163d522f475Smrg	result = 0;
3164d522f475Smrg    }
3165d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
3166d522f475Smrg
3167d522f475Smrg    struct stat fstat_buf;
3168d522f475Smrg
3169d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
3170d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
3171d522f475Smrg	result = 0;
3172d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
3173d522f475Smrg    }
3174d522f475Smrg#elif defined(__hpux)
3175d522f475Smrg
3176d522f475Smrg    /*
3177d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
3178d522f475Smrg     */
3179d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
3180d522f475Smrg	char *name = ptsname(*pty);
3181d522f475Smrg	if (name != 0) {
3182d522f475Smrg	    strcpy(ttydev, name);
3183d522f475Smrg	    result = 0;
3184d522f475Smrg	} else {		/* permissions, or other unexpected problem */
3185d522f475Smrg	    close(*pty);
3186d522f475Smrg	    *pty = -1;
3187d522f475Smrg	    result = pty_search(pty);
3188d522f475Smrg	}
3189d522f475Smrg    } else {
3190d522f475Smrg	result = pty_search(pty);
3191d522f475Smrg    }
3192d522f475Smrg
3193d522f475Smrg#else
3194d522f475Smrg
3195d522f475Smrg    result = pty_search(pty);
3196d522f475Smrg
3197d522f475Smrg#endif
3198d522f475Smrg#endif
3199d522f475Smrg
3200d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
32015104ee6eSmrg	   ttydev != NULL ? ttydev : "?",
32025104ee6eSmrg	   ptydev != NULL ? ptydev : "?",
3203d522f475Smrg	   result ? "FAIL" : "OK",
32045104ee6eSmrg	   pty != NULL ? *pty : -1));
3205d522f475Smrg    return result;
3206d522f475Smrg}
3207d522f475Smrg
3208d522f475Smrgstatic void
3209e0a2b6dfSmrgset_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
3210d522f475Smrg{
3211d522f475Smrg#ifdef USE_TTY_GROUP
3212d522f475Smrg    struct group *ttygrp;
3213d522f475Smrg
32145104ee6eSmrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != NULL) {
3215913cc679Smrg	gid = (unsigned) ttygrp->gr_gid;
3216d522f475Smrg	mode &= 0660U;
3217d522f475Smrg    }
3218d522f475Smrg    endgrent();
3219d522f475Smrg#endif /* USE_TTY_GROUP */
3220d522f475Smrg
3221d522f475Smrg    TRACE_IDS;
3222913cc679Smrg    set_owner(ttydev, (unsigned) uid, gid, mode);
3223d522f475Smrg}
3224d522f475Smrg
3225d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
3226d522f475Smrg#undef get_pty
3227d522f475Smrg/*
3228d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
3229d522f475Smrg * result.
3230d522f475Smrg */
3231d522f475Smrgstatic int
3232d522f475Smrgget_pty(int *pty, char *from)
3233d522f475Smrg{
3234d522f475Smrg    static int m_pty = -1;
3235d522f475Smrg    int result = -1;
3236d522f475Smrg
3237d522f475Smrg    if (pty == NULL) {
3238d522f475Smrg	result = really_get_pty(&m_pty, from);
3239d522f475Smrg
3240d522f475Smrg	seteuid(0);
3241d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
3242d522f475Smrg	seteuid(save_ruid);
3243d522f475Smrg	TRACE_IDS;
3244d522f475Smrg
3245d522f475Smrg    } else if (m_pty != -1) {
3246d522f475Smrg	*pty = m_pty;
3247d522f475Smrg	result = 0;
3248d522f475Smrg    } else {
3249d522f475Smrg	result = -1;
3250d522f475Smrg    }
32510bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
32520bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
32530bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
32540bd37d32Smrg	   result ? "FAIL" : "OK",
32550bd37d32Smrg	   pty != 0 ? *pty : -1));
32562e4f8982Smrg#ifdef USE_OPENPTY
32572e4f8982Smrg    if (opened_tty >= 0) {
32582e4f8982Smrg	close(opened_tty);
32592e4f8982Smrg	opened_tty = -1;
32602e4f8982Smrg    }
32612e4f8982Smrg#endif
3262d522f475Smrg    return result;
3263d522f475Smrg}
3264d522f475Smrg#endif
3265d522f475Smrg
3266d522f475Smrg/*
3267d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
3268d522f475Smrg * we might allocate.  Used on those systems that do not have
3269d522f475Smrg * a functional interface for allocating a pty.
3270d522f475Smrg * Returns 0 if found a pty, 1 if fails.
3271d522f475Smrg */
3272d522f475Smrg#ifdef USE_PTY_SEARCH
3273d522f475Smrgstatic int
3274d522f475Smrgpty_search(int *pty)
3275d522f475Smrg{
3276d522f475Smrg    static int devindex = 0, letter = 0;
3277d522f475Smrg
32785104ee6eSmrg#if defined(CRAY)
3279d522f475Smrg    while (devindex < MAXPTTYS) {
3280d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
3281d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
3282d522f475Smrg	devindex++;
3283d522f475Smrg
3284d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
3285d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
3286d522f475Smrg	    return 0;
3287d522f475Smrg	}
3288d522f475Smrg    }
32895104ee6eSmrg#else /* CRAY */
3290d522f475Smrg    while (PTYCHAR1[letter]) {
3291d522f475Smrg	ttydev[strlen(ttydev) - 2] =
3292d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
3293d522f475Smrg
3294d522f475Smrg	while (PTYCHAR2[devindex]) {
3295d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
3296d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
3297d522f475Smrg	    devindex++;
3298d522f475Smrg
3299d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
3300d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
3301d522f475Smrg#ifdef sun
3302d522f475Smrg		/* Need to check the process group of the pty.
3303d522f475Smrg		 * If it exists, then the slave pty is in use,
3304d522f475Smrg		 * and we need to get another one.
3305d522f475Smrg		 */
3306d522f475Smrg		int pgrp_rtn;
3307d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
3308d522f475Smrg		    close(*pty);
3309d522f475Smrg		    continue;
3310d522f475Smrg		}
3311d522f475Smrg#endif /* sun */
3312d522f475Smrg		return 0;
3313d522f475Smrg	    }
3314d522f475Smrg	}
3315d522f475Smrg	devindex = 0;
3316d522f475Smrg	letter++;
3317d522f475Smrg    }
3318d522f475Smrg#endif /* CRAY else */
3319d522f475Smrg    /*
3320d522f475Smrg     * We were unable to allocate a pty master!  Return an error
3321d522f475Smrg     * condition and let our caller terminate cleanly.
3322d522f475Smrg     */
3323d522f475Smrg    return 1;
3324d522f475Smrg}
3325d522f475Smrg#endif /* USE_PTY_SEARCH */
3326d522f475Smrg
3327d522f475Smrg/*
3328d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
3329d522f475Smrg * the latter has support for switching character sets.  We support the
3330d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
3331d522f475Smrg * choose 4014 over 4015.
3332d522f475Smrg *
3333d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
3334d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
3335d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
3336d522f475Smrg * later Tektronix terminals), and 4 character sizes.
3337d522f475Smrg * All of these are supported by xterm.
3338d522f475Smrg */
3339d522f475Smrg
3340d522f475Smrg#if OPT_TEK4014
334101037d57Smrgstatic const char *const tekterm[] =
3342d522f475Smrg{
3343d522f475Smrg    "tek4014",
3344d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
3345d522f475Smrg    "tek4012",			/* 4010 with lower case */
3346d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
3347d522f475Smrg    "tek4010",			/* small screen, upper-case only */
3348d522f475Smrg    "dumb",
33495104ee6eSmrg    NULL
3350d522f475Smrg};
3351d522f475Smrg#endif
3352d522f475Smrg
3353d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
3354d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
3355d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
3356d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
3357d522f475Smrg * The VT420 has up to 48 lines on the screen.
3358d522f475Smrg */
3359d522f475Smrg
336001037d57Smrgstatic const char *const vtterm[] =
3361d522f475Smrg{
3362d522f475Smrg#ifdef USE_X11TERM
3363d522f475Smrg    "x11term",			/* for people who want special term name */
3364d522f475Smrg#endif
3365d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
3366f2e35a3aSmrg    "xterm",			/* the preferred name, should be fastest */
3367d522f475Smrg    "vt102",
3368d522f475Smrg    "vt100",
3369d522f475Smrg    "ansi",
3370d522f475Smrg    "dumb",
33715104ee6eSmrg    NULL
3372d522f475Smrg};
3373d522f475Smrg
3374d522f475Smrg/* ARGSUSED */
33750bd37d32Smrgstatic void
3376d522f475Smrghungtty(int i GCC_UNUSED)
3377d522f475Smrg{
33780bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
3379d522f475Smrg    siglongjmp(env, 1);
3380d522f475Smrg}
3381d522f475Smrg
3382d522f475Smrg#if OPT_PTY_HANDSHAKE
3383d522f475Smrg#define NO_FDS {-1, -1}
3384d522f475Smrg
3385d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
3386d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
3387d522f475Smrg
3388d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
3389d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
3390d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
3391d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
3392d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
3393d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
3394d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
3395d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
3396d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
3397d522f475Smrg} status_t;
3398d522f475Smrg
3399f2e35a3aSmrg#define HANDSHAKE_LEN	1024
3400f2e35a3aSmrg
3401d522f475Smrgtypedef struct {
3402d522f475Smrg    status_t status;
3403d522f475Smrg    int error;
3404d522f475Smrg    int fatal_error;
3405d522f475Smrg    int tty_slot;
3406d522f475Smrg    int rows;
3407d522f475Smrg    int cols;
3408f2e35a3aSmrg    char buffer[HANDSHAKE_LEN];
3409d522f475Smrg} handshake_t;
3410d522f475Smrg
3411f2e35a3aSmrg/* the buffer is large enough that we can always have a trailing null */
3412f2e35a3aSmrg#define copy_handshake(dst, src) \
3413f2e35a3aSmrg	strncpy(dst.buffer, src, (size_t)HANDSHAKE_LEN - 1)[HANDSHAKE_LEN - 1] = '\0'
3414f2e35a3aSmrg
3415d522f475Smrg#if OPT_TRACE
3416d522f475Smrgstatic void
3417d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
3418d522f475Smrg{
3419d522f475Smrg    const char *status = "?";
3420d522f475Smrg    switch (data->status) {
3421d522f475Smrg    case PTY_BAD:
3422d522f475Smrg	status = "PTY_BAD";
3423d522f475Smrg	break;
3424d522f475Smrg    case PTY_FATALERROR:
3425d522f475Smrg	status = "PTY_FATALERROR";
3426d522f475Smrg	break;
3427d522f475Smrg    case PTY_GOOD:
3428d522f475Smrg	status = "PTY_GOOD";
3429d522f475Smrg	break;
3430d522f475Smrg    case PTY_NEW:
3431d522f475Smrg	status = "PTY_NEW";
3432d522f475Smrg	break;
3433d522f475Smrg    case PTY_NOMORE:
3434d522f475Smrg	status = "PTY_NOMORE";
3435d522f475Smrg	break;
3436d522f475Smrg    case UTMP_ADDED:
3437d522f475Smrg	status = "UTMP_ADDED";
3438d522f475Smrg	break;
3439d522f475Smrg    case UTMP_TTYSLOT:
3440d522f475Smrg	status = "UTMP_TTYSLOT";
3441d522f475Smrg	break;
3442d522f475Smrg    case PTY_EXEC:
3443d522f475Smrg	status = "PTY_EXEC";
3444d522f475Smrg	break;
3445d522f475Smrg    }
3446d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
3447d522f475Smrg	   tag,
3448d522f475Smrg	   status,
3449d522f475Smrg	   data->error,
3450d522f475Smrg	   data->fatal_error,
3451d522f475Smrg	   data->buffer));
3452d522f475Smrg}
3453d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
3454d522f475Smrg#else
3455d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
3456d522f475Smrg#endif
3457d522f475Smrg
3458d522f475Smrg/* HsSysError()
3459d522f475Smrg *
3460d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
3461d522f475Smrg * over the errno and error exit to the master process so that it can
3462d522f475Smrg * display our error message and exit with our exit code so that the
3463d522f475Smrg * user can see it.
3464d522f475Smrg */
3465d522f475Smrg
3466d522f475Smrgstatic void
3467d522f475SmrgHsSysError(int error)
3468d522f475Smrg{
3469d522f475Smrg    handshake_t handshake;
3470d522f475Smrg
3471d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3472d522f475Smrg    handshake.status = PTY_FATALERROR;
3473d522f475Smrg    handshake.error = errno;
3474d522f475Smrg    handshake.fatal_error = error;
3475f2e35a3aSmrg    copy_handshake(handshake, ttydev);
3476d522f475Smrg
3477d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
3478d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
3479d522f475Smrg	       handshake.error,
3480d522f475Smrg	       handshake.fatal_error,
3481d522f475Smrg	       handshake.buffer));
3482d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
348320d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
348420d2c4d2Smrg			(const char *) &handshake,
348520d2c4d2Smrg			sizeof(handshake)));
3486d522f475Smrg    } else {
34870bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
34880bd37d32Smrg		     handshake.error,
34890bd37d32Smrg		     handshake.fatal_error,
34900bd37d32Smrg		     handshake.buffer);
3491d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3492d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3493d522f475Smrg    }
3494d522f475Smrg    exit(error);
3495d522f475Smrg}
3496d522f475Smrg
3497d522f475Smrgvoid
3498d522f475Smrgfirst_map_occurred(void)
3499d522f475Smrg{
3500d522f475Smrg    if (resource.wait_for_map) {
3501913cc679Smrg	if (pc_pipe[1] >= 0) {
3502913cc679Smrg	    handshake_t handshake;
3503913cc679Smrg	    TScreen *screen = TScreenOf(term);
3504d522f475Smrg
3505913cc679Smrg	    memset(&handshake, 0, sizeof(handshake));
3506913cc679Smrg	    handshake.status = PTY_EXEC;
3507913cc679Smrg	    handshake.rows = screen->max_row;
3508913cc679Smrg	    handshake.cols = screen->max_col;
3509d522f475Smrg
3510913cc679Smrg	    TRACE(("first_map_occurred: %dx%d\n", MaxRows(screen), MaxCols(screen)));
3511d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
351220d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
351320d2c4d2Smrg			    (const char *) &handshake,
351420d2c4d2Smrg			    sizeof(handshake)));
3515d522f475Smrg	    close(cp_pipe[0]);
3516d522f475Smrg	    close(pc_pipe[1]);
3517d522f475Smrg	}
3518d522f475Smrg	resource.wait_for_map = False;
3519d522f475Smrg    }
3520d522f475Smrg}
3521d522f475Smrg#else
3522d522f475Smrg/*
3523d522f475Smrg * temporary hack to get xterm working on att ptys
3524d522f475Smrg */
3525d522f475Smrgstatic void
3526d522f475SmrgHsSysError(int error)
3527d522f475Smrg{
35280bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
35290bd37d32Smrg		 error, errno, ttydev);
3530d522f475Smrg    exit(error);
3531d522f475Smrg}
3532d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3533d522f475Smrg
3534d522f475Smrgstatic void
3535e0a2b6dfSmrgset_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
3536d522f475Smrg{
3537d522f475Smrg    int why;
3538d522f475Smrg
3539d522f475Smrg    TRACE_IDS;
354020d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
35410bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3542d522f475Smrg
3543913cc679Smrg    if (chown(device, (uid_t) uid, (gid_t) gid) < 0) {
3544d522f475Smrg	why = errno;
3545d522f475Smrg	if (why != ENOENT
3546d522f475Smrg	    && save_ruid == 0) {
35470bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
35480bd37d32Smrg			device, (long) uid, (long) gid);
3549d522f475Smrg	}
3550d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3551913cc679Smrg    } else if (chmod(device, (mode_t) mode) < 0) {
3552d522f475Smrg	why = errno;
3553d522f475Smrg	if (why != ENOENT) {
3554d522f475Smrg	    struct stat sb;
3555d522f475Smrg	    if (stat(device, &sb) < 0) {
35560bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
35570bd37d32Smrg			    device, (unsigned) mode);
3558d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
35590bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
35600bd37d32Smrg			    device,
35610bd37d32Smrg			    (unsigned long) mode,
35620bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3563d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
35640bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3565d522f475Smrg	    }
3566d522f475Smrg	}
3567d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3568d522f475Smrg    }
3569d522f475Smrg}
3570d522f475Smrg
3571894e0ac8Smrg/*
3572894e0ac8Smrg * utmp data may not be null-terminated; even if it is, there may be garbage
3573894e0ac8Smrg * after the null.  This fills the unused part of the result with nulls.
3574894e0ac8Smrg */
3575894e0ac8Smrgstatic void
3576894e0ac8Smrgcopy_filled(char *target, const char *source, size_t len)
3577894e0ac8Smrg{
3578894e0ac8Smrg    size_t used = 0;
3579894e0ac8Smrg    while (used < len) {
3580894e0ac8Smrg	if ((target[used] = source[used]) == 0)
3581894e0ac8Smrg	    break;
3582894e0ac8Smrg	++used;
3583894e0ac8Smrg    }
3584894e0ac8Smrg    while (used < len) {
3585894e0ac8Smrg	target[used++] = '\0';
3586894e0ac8Smrg    }
3587894e0ac8Smrg}
3588894e0ac8Smrg
3589d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3590d522f475Smrg/*
3591d522f475Smrg * getutid() only looks at ut_type and ut_id.
3592d522f475Smrg * But we'll also check ut_line in find_utmp().
3593d522f475Smrg */
3594d522f475Smrgstatic void
3595d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3596d522f475Smrg{
3597d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3598913cc679Smrg    tofind->ut_type = (short) type;
3599894e0ac8Smrg    copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3600894e0ac8Smrg    copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3601d522f475Smrg}
3602d522f475Smrg
3603d522f475Smrg/*
3604d522f475Smrg * We could use getutline() if we didn't support old systems.
3605d522f475Smrg */
3606d522f475Smrgstatic struct UTMP_STR *
3607d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3608d522f475Smrg{
3609d522f475Smrg    struct UTMP_STR *result;
36100bd37d32Smrg    struct UTMP_STR limited;
3611d522f475Smrg    struct UTMP_STR working;
3612d522f475Smrg
3613d522f475Smrg    for (;;) {
3614d522f475Smrg	memset(&working, 0, sizeof(working));
3615d522f475Smrg	working.ut_type = tofind->ut_type;
3616894e0ac8Smrg	copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3617d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3618d522f475Smrg	working.ut_type = 0;
3619d522f475Smrg#endif
36205104ee6eSmrg	if ((result = call_getutid(&working)) == NULL)
3621d522f475Smrg	    break;
3622894e0ac8Smrg	copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line));
36230bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3624d522f475Smrg	    break;
3625d522f475Smrg	/*
3626d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3627d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3628d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3629d522f475Smrg	 */
3630d522f475Smrg	memset(result, 0, sizeof(*result));
3631d522f475Smrg    }
3632d522f475Smrg    return result;
3633d522f475Smrg}
3634d522f475Smrg#endif /* HAVE_UTMP... */
3635d522f475Smrg
3636d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3637d522f475Smrg
363820d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
363920d2c4d2Smrg#define USE_NO_DEV_TTY 1
364020d2c4d2Smrg#else
364120d2c4d2Smrg#define USE_NO_DEV_TTY 0
364220d2c4d2Smrg#endif
364320d2c4d2Smrg
3644e0a2b6dfSmrgstatic int
3645e0a2b6dfSmrgsame_leaf(char *a, char *b)
3646e0a2b6dfSmrg{
3647e0a2b6dfSmrg    char *p = x_basename(a);
3648e0a2b6dfSmrg    char *q = x_basename(b);
3649e0a2b6dfSmrg    return !strcmp(p, q);
3650e0a2b6dfSmrg}
3651e0a2b6dfSmrg
3652e0a2b6dfSmrg/*
3653e0a2b6dfSmrg * "good enough" (inode wouldn't port to Cygwin)
3654e0a2b6dfSmrg */
3655e0a2b6dfSmrgstatic int
3656e0a2b6dfSmrgsame_file(const char *a, const char *b)
3657e0a2b6dfSmrg{
3658e0a2b6dfSmrg    struct stat asb;
3659e0a2b6dfSmrg    struct stat bsb;
3660e0a2b6dfSmrg    int result = 0;
3661e0a2b6dfSmrg
3662e0a2b6dfSmrg    if ((stat(a, &asb) == 0)
3663e0a2b6dfSmrg	&& (stat(b, &bsb) == 0)
3664e0a2b6dfSmrg	&& ((asb.st_mode & S_IFMT) == S_IFREG)
3665e0a2b6dfSmrg	&& ((bsb.st_mode & S_IFMT) == S_IFREG)
3666e0a2b6dfSmrg	&& (asb.st_mtime == bsb.st_mtime)
3667e0a2b6dfSmrg	&& (asb.st_size == bsb.st_size)) {
3668e0a2b6dfSmrg	result = 1;
3669e0a2b6dfSmrg    }
3670e0a2b6dfSmrg    return result;
3671e0a2b6dfSmrg}
3672e0a2b6dfSmrg
3673f2e35a3aSmrgstatic int
3674f2e35a3aSmrgfindValidShell(const char *haystack, const char *needle)
3675f2e35a3aSmrg{
3676f2e35a3aSmrg    int result = -1;
3677f2e35a3aSmrg    int count = -1;
3678f2e35a3aSmrg    const char *s, *t;
3679f2e35a3aSmrg    size_t want = strlen(needle);
3680f2e35a3aSmrg
3681f2e35a3aSmrg    TRACE(("findValidShell:\n%s\n", NonNull(haystack)));
3682f2e35a3aSmrg
36835104ee6eSmrg    for (s = haystack; (s != NULL) && (*s != '\0'); s = t) {
36845104ee6eSmrg	size_t have;
36855104ee6eSmrg
3686f2e35a3aSmrg	++count;
36875104ee6eSmrg	if ((t = strchr(s, '\n')) == NULL) {
3688f2e35a3aSmrg	    t = s + strlen(s);
3689f2e35a3aSmrg	}
3690f2e35a3aSmrg	have = (size_t) (t - s);
3691f2e35a3aSmrg
3692f2e35a3aSmrg	if ((have >= want) && (*s != '#')) {
36935307cd1aSmrg	    char *p = (char *) malloc(have + 1);
3694f2e35a3aSmrg
36955104ee6eSmrg	    if (p != NULL) {
3696f2e35a3aSmrg		char *q;
3697f2e35a3aSmrg
3698f2e35a3aSmrg		memcpy(p, s, have);
3699f2e35a3aSmrg		p[have] = '\0';
37005104ee6eSmrg		if ((q = x_strtrim(p)) != NULL) {
3701f2e35a3aSmrg		    TRACE(("...test %s\n", q));
3702f2e35a3aSmrg		    if (!strcmp(q, needle)) {
3703f2e35a3aSmrg			result = count;
3704f2e35a3aSmrg		    } else if (same_leaf(q, (char *) needle) &&
3705f2e35a3aSmrg			       same_file(q, needle)) {
3706f2e35a3aSmrg			result = count;
3707f2e35a3aSmrg		    }
3708f2e35a3aSmrg		    free(q);
3709f2e35a3aSmrg		}
3710f2e35a3aSmrg		free(p);
3711f2e35a3aSmrg	    }
3712f2e35a3aSmrg	    if (result >= 0)
3713f2e35a3aSmrg		break;
3714f2e35a3aSmrg	}
3715f2e35a3aSmrg	while (*t == '\n') {
3716f2e35a3aSmrg	    ++t;
3717f2e35a3aSmrg	}
3718f2e35a3aSmrg    }
3719f2e35a3aSmrg    return result;
3720f2e35a3aSmrg}
3721f2e35a3aSmrg
3722f2e35a3aSmrgstatic int
3723f2e35a3aSmrgourValidShell(const char *pathname)
3724f2e35a3aSmrg{
372504b94745Smrg    char *trimmed = x_strtrim(resource.valid_shells);
372604b94745Smrg    int result = findValidShell(trimmed, pathname);
372704b94745Smrg    free(trimmed);
372804b94745Smrg    return result;
3729f2e35a3aSmrg}
3730f2e35a3aSmrg
3731f2e35a3aSmrg#if defined(HAVE_GETUSERSHELL) && defined(HAVE_ENDUSERSHELL)
3732f2e35a3aSmrgstatic Boolean
3733f2e35a3aSmrgvalidShell(const char *pathname)
3734f2e35a3aSmrg{
3735f2e35a3aSmrg    int result = -1;
3736f2e35a3aSmrg
3737f2e35a3aSmrg    if (validProgram(pathname)) {
3738f2e35a3aSmrg	char *q;
3739f2e35a3aSmrg	int count = -1;
3740f2e35a3aSmrg
3741f2e35a3aSmrg	TRACE(("validShell:getusershell\n"));
37425104ee6eSmrg	while ((q = getusershell()) != NULL) {
3743f2e35a3aSmrg	    ++count;
3744f2e35a3aSmrg	    TRACE(("...test \"%s\"\n", q));
3745f2e35a3aSmrg	    if (!strcmp(q, pathname)) {
3746f2e35a3aSmrg		result = count;
3747f2e35a3aSmrg		break;
3748f2e35a3aSmrg	    }
3749f2e35a3aSmrg	}
3750f2e35a3aSmrg	endusershell();
3751f2e35a3aSmrg
3752f2e35a3aSmrg	if (result < 0)
3753f2e35a3aSmrg	    result = ourValidShell(pathname);
3754f2e35a3aSmrg    }
3755f2e35a3aSmrg
3756f2e35a3aSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3757f2e35a3aSmrg    return (result >= 0);
3758f2e35a3aSmrg}
3759f2e35a3aSmrg#else
3760e0a2b6dfSmrg/*
3761e0a2b6dfSmrg * Only set $SHELL for paths found in the standard location.
3762e0a2b6dfSmrg */
3763e0a2b6dfSmrgstatic Boolean
3764e0a2b6dfSmrgvalidShell(const char *pathname)
3765e0a2b6dfSmrg{
3766f2e35a3aSmrg    int result = -1;
3767e0a2b6dfSmrg    const char *ok_shells = "/etc/shells";
3768e0a2b6dfSmrg    char *blob;
3769e0a2b6dfSmrg    struct stat sb;
3770e0a2b6dfSmrg    size_t rc;
3771e0a2b6dfSmrg    FILE *fp;
3772e0a2b6dfSmrg
3773f2e35a3aSmrg    if (validProgram(pathname)) {
3774f2e35a3aSmrg
3775f2e35a3aSmrg	TRACE(("validShell:%s\n", ok_shells));
3776f2e35a3aSmrg
3777f2e35a3aSmrg	if (stat(ok_shells, &sb) == 0
3778f2e35a3aSmrg	    && (sb.st_mode & S_IFMT) == S_IFREG
3779f2e35a3aSmrg	    && ((size_t) sb.st_size > 0)
3780f2e35a3aSmrg	    && ((size_t) sb.st_size < (((size_t) ~0) - 2))
3781f2e35a3aSmrg	    && (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
3782f2e35a3aSmrg
3783f2e35a3aSmrg	    if ((fp = fopen(ok_shells, "r")) != 0) {
3784f2e35a3aSmrg		rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
3785f2e35a3aSmrg		fclose(fp);
3786f2e35a3aSmrg
3787f2e35a3aSmrg		if (rc == (size_t) sb.st_size) {
3788f2e35a3aSmrg		    blob[rc] = '\0';
3789f2e35a3aSmrg		    result = findValidShell(blob, pathname);
3790e0a2b6dfSmrg		}
3791e0a2b6dfSmrg	    }
3792f2e35a3aSmrg	    free(blob);
3793e0a2b6dfSmrg	}
3794f2e35a3aSmrg	if (result < 0)
3795f2e35a3aSmrg	    result = ourValidShell(pathname);
3796e0a2b6dfSmrg    }
3797e0a2b6dfSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3798f2e35a3aSmrg    return (result > 0);
3799e0a2b6dfSmrg}
3800f2e35a3aSmrg#endif
3801e0a2b6dfSmrg
3802e0a2b6dfSmrgstatic char *
3803e0a2b6dfSmrgresetShell(char *oldPath)
3804e0a2b6dfSmrg{
3805e0a2b6dfSmrg    char *newPath = x_strdup("/bin/sh");
3806e0a2b6dfSmrg    char *envPath = getenv("SHELL");
3807f2e35a3aSmrg    free(oldPath);
3808e0a2b6dfSmrg    if (!IsEmpty(envPath))
3809e0a2b6dfSmrg	xtermSetenv("SHELL", newPath);
3810e0a2b6dfSmrg    return newPath;
3811e0a2b6dfSmrg}
3812e0a2b6dfSmrg
38134419d26bSmrg/*
38144419d26bSmrg * Trim unwanted environment variables:
38154419d26bSmrg *
38164419d26bSmrg * DESKTOP_STARTUP_ID
38174419d26bSmrg *	standards.freedesktop.org/startup-notification-spec/
38184419d26bSmrg * notes that this variable is used when a "reliable" mechanism is
38194419d26bSmrg * not available; in practice it must be unset to avoid confusing
38204419d26bSmrg * GTK applications.
38214419d26bSmrg *
38224419d26bSmrg * XCURSOR_PATH
38234419d26bSmrg * We set this temporarily to work around poor design of Xcursor.  Unset it
38244419d26bSmrg * here to avoid confusion.
38254419d26bSmrg *
38264419d26bSmrg * Other...
38274419d26bSmrg * These are set by other terminal emulators or non-standard libraries, and are
38284419d26bSmrg * a nuisance if one starts xterm from a shell inside one of those.
38294419d26bSmrg */
38304419d26bSmrgstatic void
38314419d26bSmrgxtermTrimEnv(void)
38324419d26bSmrg{
38335307cd1aSmrg#define KEEP(wild,name) { 0, wild, #name }
38345307cd1aSmrg#define TRIM(wild,name) { 1, wild, #name }
38355307cd1aSmrg    /* *INDENT-OFF* */
38365307cd1aSmrg    static const struct {
38375307cd1aSmrg	int trim;
38384419d26bSmrg	int wild;
38394419d26bSmrg	const char *name;
38404419d26bSmrg    } table[] = {
38415307cd1aSmrg	TRIM(0, COLUMNS),
38425307cd1aSmrg	TRIM(0, DEFAULT_COLORS),
38435307cd1aSmrg	TRIM(0, DESKTOP_STARTUP_ID),
38445307cd1aSmrg	TRIM(0, LINES),
38455307cd1aSmrg	TRIM(0, SHLVL),		/* ksh, bash */
38465307cd1aSmrg	TRIM(0, STY),		/* screen */
38475307cd1aSmrg	TRIM(0, TERMCAP),
38485307cd1aSmrg	TRIM(0, TMUX),
38495307cd1aSmrg	TRIM(0, TMUX_PANE),
38505307cd1aSmrg	TRIM(0, WCWIDTH_CJK_LEGACY),
38515307cd1aSmrg	TRIM(0, WINDOW),	/* screen */
38525307cd1aSmrg	TRIM(0, XCURSOR_PATH),
38535307cd1aSmrg	KEEP(0, MC_XDG_OPEN),
38545104ee6eSmrg	KEEP(0, TERM_INGRES),
38555307cd1aSmrg	TRIM(1, COLORFGBG),
38565307cd1aSmrg	TRIM(1, COLORTERM),
38575307cd1aSmrg	TRIM(1, GIO_LAUNCHED_),
38585307cd1aSmrg	TRIM(1, ITERM2_),
38595307cd1aSmrg	TRIM(1, MC_),
38605307cd1aSmrg	TRIM(1, MINTTY_),
38615307cd1aSmrg	TRIM(1, PUTTY),
38625307cd1aSmrg	TRIM(1, RXVT_),
38635307cd1aSmrg	TRIM(1, TERM_),
38645307cd1aSmrg	TRIM(1, URXVT_),
38655307cd1aSmrg	TRIM(1, VTE_),
38665307cd1aSmrg	TRIM(1, XTERM_),
38674419d26bSmrg    };
38685307cd1aSmrg#undef TRIM
38695307cd1aSmrg    /* *INDENT-ON* */
38705307cd1aSmrg    Cardinal j, k;
38715307cd1aSmrg
38725307cd1aSmrg    for (j = 0; environ[j] != NULL; ++j) {
38735307cd1aSmrg	char *equals = strchr(environ[j], '=');
38745307cd1aSmrg	size_t dstlen = strlen(environ[j]);
38755307cd1aSmrg
38765307cd1aSmrg	if (equals != NULL)
38775307cd1aSmrg	    dstlen = (size_t) (equals - environ[j]);
38785307cd1aSmrg
38795307cd1aSmrg	for (k = 0; k < XtNumber(table); ++k) {
38805307cd1aSmrg	    size_t srclen = strlen(table[k].name);
38815307cd1aSmrg	    if (table[k].wild) {
38825307cd1aSmrg		if (dstlen >= srclen &&
38835307cd1aSmrg		    !strncmp(environ[j], table[k].name, srclen)) {
38844419d26bSmrg		    char *my_var;
38855307cd1aSmrg		    if (table[k].trim &&
38865307cd1aSmrg			(my_var = x_strdup(environ[j])) != NULL) {
38874419d26bSmrg			my_var[dstlen] = '\0';
38884419d26bSmrg			xtermUnsetenv(my_var);
38894419d26bSmrg			free(my_var);
389004b94745Smrg			/* When removing an entry, check the same slot again. */
389104b94745Smrg			j--;
38924419d26bSmrg		    }
38935307cd1aSmrg		    break;
38944419d26bSmrg		}
38955307cd1aSmrg	    } else if (dstlen == srclen &&
38965307cd1aSmrg		       !strncmp(environ[j], table[k].name, srclen)) {
389704b94745Smrg		if (table[k].trim) {
38985307cd1aSmrg		    xtermUnsetenv(table[k].name);
389904b94745Smrg		    /* When removing an entry, check the same slot again. */
390004b94745Smrg		    j--;
390104b94745Smrg		}
39025307cd1aSmrg		break;
39034419d26bSmrg	    }
39044419d26bSmrg	}
39054419d26bSmrg    }
39064419d26bSmrg}
39074419d26bSmrg
3908d522f475Smrg/*
3909d522f475Smrg *  Inits pty and tty and forks a login process.
3910d522f475Smrg *  Does not close fd Xsocket.
3911d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3912d522f475Smrg */
3913d522f475Smrgstatic int
39142e4f8982SmrgspawnXTerm(XtermWidget xw, unsigned line_speed)
3915d522f475Smrg{
3916d522f475Smrg    TScreen *screen = TScreenOf(xw);
3917d522f475Smrg#if OPT_PTY_HANDSHAKE
3918d522f475Smrg    Bool got_handshake_size = False;
3919d522f475Smrg    handshake_t handshake;
3920d522f475Smrg    int done;
3921d522f475Smrg#endif
3922d522f475Smrg#if OPT_INITIAL_ERASE
39235307cd1aSmrg    int initial_erase = XTERM_ERASE;
3924d522f475Smrg    Bool setInitialErase;
3925d522f475Smrg#endif
3926d522f475Smrg    int rc = 0;
3927d522f475Smrg    int ttyfd = -1;
3928d522f475Smrg    Bool ok_termcap;
3929d522f475Smrg    char *newtc;
3930d522f475Smrg
3931d522f475Smrg#ifdef TERMIO_STRUCT
39325104ee6eSmrg    Cardinal nn;
3933d522f475Smrg    TERMIO_STRUCT tio;
3934d522f475Smrg#ifdef TIOCLSET
3935d522f475Smrg    unsigned lmode;
3936d522f475Smrg#endif /* TIOCLSET */
3937d522f475Smrg#ifdef HAS_LTCHARS
3938d522f475Smrg    struct ltchars ltc;
3939d522f475Smrg#endif /* HAS_LTCHARS */
3940d522f475Smrg#else /* !TERMIO_STRUCT */
3941d522f475Smrg    int ldisc = 0;
3942d522f475Smrg    int discipline;
3943d522f475Smrg    unsigned lmode;
3944d522f475Smrg    struct tchars tc;
3945d522f475Smrg    struct ltchars ltc;
3946d522f475Smrg    struct sgttyb sg;
3947d522f475Smrg#ifdef sony
3948d522f475Smrg    int jmode;
3949d522f475Smrg    struct jtchars jtc;
3950d522f475Smrg#endif /* sony */
3951d522f475Smrg#endif /* TERMIO_STRUCT */
3952d522f475Smrg
39535104ee6eSmrg    char *shell_path = NULL;
39540bd37d32Smrg    char *shname, *shname_minus;
395520d2c4d2Smrg    int i;
395620d2c4d2Smrg#if USE_NO_DEV_TTY
395720d2c4d2Smrg    int no_dev_tty = False;
395820d2c4d2Smrg#endif
395901037d57Smrg    const char *const *envnew;	/* new environment */
3960d522f475Smrg    char buf[64];
3961d522f475Smrg    char *TermName = NULL;
3962d522f475Smrg#ifdef TTYSIZE_STRUCT
3963d522f475Smrg    TTYSIZE_STRUCT ts;
3964d522f475Smrg#endif
39650bd37d32Smrg    struct passwd pw;
3966d522f475Smrg    char *login_name = NULL;
3967d522f475Smrg#ifndef USE_UTEMPTER
3968d522f475Smrg#ifdef HAVE_UTMP
3969d522f475Smrg    struct UTMP_STR utmp;
3970d522f475Smrg#ifdef USE_SYSV_UTMP
3971d522f475Smrg    struct UTMP_STR *utret = NULL;
3972d522f475Smrg#endif
3973d522f475Smrg#ifdef USE_LASTLOG
3974d522f475Smrg    struct lastlog lastlog;
3975d522f475Smrg#endif
3976d522f475Smrg#ifdef USE_LASTLOGX
3977d522f475Smrg    struct lastlogx lastlogx;
3978d522f475Smrg#endif /* USE_LASTLOG */
3979d522f475Smrg#endif /* HAVE_UTMP */
3980d522f475Smrg#endif /* !USE_UTEMPTER */
3981d522f475Smrg
3982e39b573cSmrg#if OPT_TRACE
3983e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
3984e39b573cSmrg#endif
3985e39b573cSmrg
3986d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
3987d522f475Smrg    (void) rc;
3988d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3989d522f475Smrg    (void) utret;
3990d522f475Smrg#endif
3991d522f475Smrg
3992d522f475Smrg    screen->uid = save_ruid;
3993d522f475Smrg    screen->gid = save_rgid;
3994d522f475Smrg
3995d522f475Smrg#ifdef SIGTTOU
3996d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
3997d522f475Smrg    signal(SIGTTOU, SIG_IGN);
3998d522f475Smrg#endif
3999d522f475Smrg
4000d522f475Smrg#if OPT_PTY_HANDSHAKE
4001d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
4002d522f475Smrg#endif
4003d522f475Smrg
4004d522f475Smrg    if (am_slave >= 0) {
4005d522f475Smrg	screen->respond = am_slave;
4006d522f475Smrg	set_pty_id(ttydev, passedPty);
4007d522f475Smrg#ifdef USE_PTY_DEVICE
4008d522f475Smrg	set_pty_id(ptydev, passedPty);
4009d522f475Smrg#endif
4010d522f475Smrg	if (xtermResetIds(screen) < 0)
401104b94745Smrg	    exit(ERROR_MISC);
4012d522f475Smrg    } else {
4013d522f475Smrg	Bool tty_got_hung;
4014d522f475Smrg
4015d522f475Smrg	/*
4016d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
4017d522f475Smrg	 * that has gone away).  Simply make up some reasonable
4018d522f475Smrg	 * defaults.
4019d522f475Smrg	 */
4020d522f475Smrg
4021d522f475Smrg	if (!sigsetjmp(env, 1)) {
4022913cc679Smrg	    signal(SIGALRM, hungtty);
4023913cc679Smrg	    alarm(2);		/* alarm(1) might return too soon */
4024d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
4025d522f475Smrg	    alarm(0);
4026d522f475Smrg	    tty_got_hung = False;
4027d522f475Smrg	} else {
4028d522f475Smrg	    tty_got_hung = True;
4029d522f475Smrg	    ttyfd = -1;
4030d522f475Smrg	    errno = ENXIO;
4031d522f475Smrg	}
40325104ee6eSmrg	shell_path = NULL;
40330bd37d32Smrg	memset(&pw, 0, sizeof(pw));
4034d522f475Smrg#if OPT_PTY_HANDSHAKE
4035d522f475Smrg	got_handshake_size = False;
4036d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4037d522f475Smrg#if OPT_INITIAL_ERASE
40385307cd1aSmrg	initial_erase = XTERM_ERASE;
4039d522f475Smrg#endif
4040d522f475Smrg	signal(SIGALRM, SIG_DFL);
4041d522f475Smrg
4042d522f475Smrg	/*
4043d522f475Smrg	 * Check results and ignore current control terminal if
4044d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
4045d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
4046d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
40470bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
40480bd37d32Smrg	 * if xterm is run within a jail.
4049d522f475Smrg	 */
405020d2c4d2Smrg#if USE_NO_DEV_TTY
4051d522f475Smrg	no_dev_tty = False;
405220d2c4d2Smrg#endif
4053d522f475Smrg	if (ttyfd < 0) {
4054d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
40550bd37d32Smrg		errno == ENOENT ||
4056d522f475Smrg#ifdef ENODEV
4057d522f475Smrg		errno == ENODEV ||
4058d522f475Smrg#endif
4059d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
406020d2c4d2Smrg#if USE_NO_DEV_TTY
4061d522f475Smrg		no_dev_tty = True;
406220d2c4d2Smrg#endif
4063d522f475Smrg#ifdef HAS_LTCHARS
4064d522f475Smrg		ltc = d_ltc;
4065d522f475Smrg#endif /* HAS_LTCHARS */
4066d522f475Smrg#ifdef TIOCLSET
4067d522f475Smrg		lmode = d_lmode;
4068d522f475Smrg#endif /* TIOCLSET */
4069d522f475Smrg#ifdef TERMIO_STRUCT
4070d522f475Smrg		tio = d_tio;
4071d522f475Smrg#else /* !TERMIO_STRUCT */
4072d522f475Smrg		sg = d_sg;
4073d522f475Smrg		tc = d_tc;
4074d522f475Smrg		discipline = d_disipline;
4075d522f475Smrg#ifdef sony
4076d522f475Smrg		jmode = d_jmode;
4077d522f475Smrg		jtc = d_jtc;
4078d522f475Smrg#endif /* sony */
4079d522f475Smrg#endif /* TERMIO_STRUCT */
4080d522f475Smrg	    } else {
4081d522f475Smrg		SysError(ERROR_OPDEVTTY);
4082d522f475Smrg	    }
4083d522f475Smrg	} else {
4084d522f475Smrg
4085d522f475Smrg	    /* Get a copy of the current terminal's state,
4086d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
4087d522f475Smrg	     * may not have a controlling terminal at this point
4088d522f475Smrg	     * if started directly from xdm or xinit,
4089d522f475Smrg	     * in which case we just use the defaults as above.
4090d522f475Smrg	     */
4091d522f475Smrg#ifdef HAS_LTCHARS
4092d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
4093d522f475Smrg		ltc = d_ltc;
4094d522f475Smrg#endif /* HAS_LTCHARS */
4095d522f475Smrg#ifdef TIOCLSET
4096d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
4097d522f475Smrg		lmode = d_lmode;
4098d522f475Smrg#endif /* TIOCLSET */
4099d522f475Smrg#ifdef TERMIO_STRUCT
410020d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
410120d2c4d2Smrg	    if (rc == -1)
4102d522f475Smrg		tio = d_tio;
4103d522f475Smrg#else /* !TERMIO_STRUCT */
410420d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
410520d2c4d2Smrg	    if (rc == -1)
4106d522f475Smrg		sg = d_sg;
4107d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
4108d522f475Smrg		tc = d_tc;
4109d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
4110d522f475Smrg		discipline = d_disipline;
4111d522f475Smrg#ifdef sony
4112d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
4113d522f475Smrg		jmode = d_jmode;
4114d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
4115d522f475Smrg		jtc = d_jtc;
4116d522f475Smrg#endif /* sony */
4117d522f475Smrg#endif /* TERMIO_STRUCT */
4118d522f475Smrg
4119d522f475Smrg	    /*
4120d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
4121d522f475Smrg	     * erase value.  Just in case that will fail, first get
4122d522f475Smrg	     * the value from /dev/tty, so we will have something
4123d522f475Smrg	     * at least.
4124d522f475Smrg	     */
4125d522f475Smrg#if OPT_INITIAL_ERASE
4126d522f475Smrg	    if (resource.ptyInitialErase) {
4127d522f475Smrg#ifdef TERMIO_STRUCT
4128d522f475Smrg		initial_erase = tio.c_cc[VERASE];
4129d522f475Smrg#else /* !TERMIO_STRUCT */
4130d522f475Smrg		initial_erase = sg.sg_erase;
4131d522f475Smrg#endif /* TERMIO_STRUCT */
4132d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
4133d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
4134d522f475Smrg		       initial_erase));
4135d522f475Smrg	    }
4136d522f475Smrg#endif
4137d522f475Smrg	    close_fd(ttyfd);
4138d522f475Smrg	}
4139d522f475Smrg
4140d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
4141d522f475Smrg	    SysError(ERROR_PTYS);
4142d522f475Smrg	}
4143913cc679Smrg	TRACE_GET_TTYSIZE(screen->respond, "after get_pty");
4144d522f475Smrg#if OPT_INITIAL_ERASE
4145d522f475Smrg	if (resource.ptyInitialErase) {
41465307cd1aSmrg	    initial_erase = get_tty_erase(screen->respond,
41475307cd1aSmrg					  initial_erase,
41485307cd1aSmrg					  "pty");
4149d522f475Smrg	}
4150d522f475Smrg#endif /* OPT_INITIAL_ERASE */
4151d522f475Smrg    }
4152d522f475Smrg
4153d522f475Smrg    /* avoid double MapWindow requests */
4154d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
4155d522f475Smrg
415604b94745Smrg    wm_delete_window = CachedInternAtom(XtDisplay(toplevel),
415704b94745Smrg					"WM_DELETE_WINDOW");
4158d522f475Smrg
4159d522f475Smrg    if (!TEK4014_ACTIVE(xw))
4160956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
4161d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4162d522f475Smrg    if (Console) {
4163d522f475Smrg	/*
4164d522f475Smrg	 * Inform any running xconsole program
4165d522f475Smrg	 * that we are going to steal the console.
4166d522f475Smrg	 */
4167d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
416804b94745Smrg	TRACE(("getting for console name property \"%s\"\n", mit_console_name));
416904b94745Smrg	mit_console = CachedInternAtom(screen->display, mit_console_name);
4170d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
4171d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
4172d522f475Smrg		       mit_console, CurrentTime,
4173d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
4174d522f475Smrg    }
4175d522f475Smrg#endif
4176d522f475Smrg#if OPT_TEK4014
4177d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
4178d522f475Smrg	envnew = tekterm;
4179d522f475Smrg    } else
4180d522f475Smrg#endif
4181d522f475Smrg    {
4182d522f475Smrg	envnew = vtterm;
4183d522f475Smrg    }
4184d522f475Smrg
4185d522f475Smrg    /*
4186d522f475Smrg     * This used to exit if no termcap entry was found for the specified
4187d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
4188d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
4189d522f475Smrg     * entry is not found.
4190d522f475Smrg     */
4191d522f475Smrg    ok_termcap = True;
419220d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
419320d2c4d2Smrg	const char *last = NULL;
419420d2c4d2Smrg	char *next;
419520d2c4d2Smrg
419620d2c4d2Smrg	TermName = x_strdup(*envnew);
4197d522f475Smrg	ok_termcap = False;
4198d522f475Smrg	while (*envnew != NULL) {
419920d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
420020d2c4d2Smrg		next = x_strdup(*envnew);
420120d2c4d2Smrg		if (get_termcap(xw, next)) {
420220d2c4d2Smrg		    free(TermName);
420320d2c4d2Smrg		    TermName = next;
42040bd37d32Smrg		    ok_termcap = True + 1;
420520d2c4d2Smrg		    break;
420620d2c4d2Smrg		} else {
420720d2c4d2Smrg		    free(next);
420820d2c4d2Smrg		}
4209d522f475Smrg	    }
4210d522f475Smrg	    last = *envnew;
4211d522f475Smrg	    envnew++;
4212d522f475Smrg	}
4213d522f475Smrg    }
4214d522f475Smrg    if (ok_termcap) {
4215f2e35a3aSmrg	resource.term_name = x_strdup(TermName);
421620d2c4d2Smrg	resize_termcap(xw);
4217d522f475Smrg    }
4218d522f475Smrg
4219d522f475Smrg    /*
4220d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
4221d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
4222d522f475Smrg     */
4223d522f475Smrg#if OPT_INITIAL_ERASE
4224d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
4225d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
4226d522f475Smrg    setInitialErase = False;
4227f2e35a3aSmrg    if (override_tty_modes && ttyModes[XTTYMODE_erase].set) {
4228f2e35a3aSmrg	initial_erase = ttyModes[XTTYMODE_erase].value;
4229d522f475Smrg	setInitialErase = True;
4230d522f475Smrg    } else if (resource.ptyInitialErase) {
4231a1f3da82Smrg	/* EMPTY */ ;
4232d522f475Smrg    } else if (ok_termcap) {
423320d2c4d2Smrg	char *s = get_tcap_erase(xw);
4234d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
42355104ee6eSmrg	if (s != NULL) {
423620d2c4d2Smrg	    char *save = s;
4237d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
4238d522f475Smrg	    setInitialErase = True;
423920d2c4d2Smrg	    free(save);
4240d522f475Smrg	}
4241d522f475Smrg    }
4242d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
4243d522f475Smrg
4244d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
4245d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
4246d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
4247d522f475Smrg	if (initial_erase == ANSI_DEL) {
424820d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
4249d522f475Smrg	} else {
4250d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
4251d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
4252d522f475Smrg	}
4253d522f475Smrg	TRACE(("...sets DECBKM %s\n",
4254d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
4255d522f475Smrg    } else {
4256d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
4257d522f475Smrg    }
4258d522f475Smrg#endif /* OPT_INITIAL_ERASE */
4259d522f475Smrg
4260d522f475Smrg#ifdef TTYSIZE_STRUCT
4261d522f475Smrg    /* tell tty how big window is */
4262d522f475Smrg#if OPT_TEK4014
4263d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
4264913cc679Smrg	setup_winsize(ts, TDefaultRows, TDefaultCols,
4265913cc679Smrg		      TFullHeight(TekScreenOf(tekWidget)),
4266913cc679Smrg		      TFullWidth(TekScreenOf(tekWidget)));
4267d522f475Smrg    } else
4268d522f475Smrg#endif
4269d522f475Smrg    {
4270913cc679Smrg	setup_winsize(ts, MaxRows(screen), MaxCols(screen),
4271913cc679Smrg		      FullHeight(screen), FullWidth(screen));
4272d522f475Smrg    }
427320d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
4274d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
4275d522f475Smrg	   TTYSIZE_ROWS(ts),
4276d522f475Smrg	   TTYSIZE_COLS(ts), i));
4277d522f475Smrg#endif /* TTYSIZE_STRUCT */
4278d522f475Smrg
42790bd37d32Smrg#if !defined(USE_OPENPTY)
42800bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
42810bd37d32Smrg    /*
42820bd37d32Smrg     * utempter checks the ownership of the device; some implementations
42830bd37d32Smrg     * set ownership in grantpt - do this first.
42840bd37d32Smrg     */
42850bd37d32Smrg    grantpt(screen->respond);
42860bd37d32Smrg#endif
42870bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
42880bd37d32Smrg    unlockpt(screen->respond);
4289913cc679Smrg    TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
42900bd37d32Smrg#endif
42910bd37d32Smrg#endif /* !USE_OPENPTY */
42920bd37d32Smrg
4293d522f475Smrg    added_utmp_entry = False;
4294d522f475Smrg#if defined(USE_UTEMPTER)
4295d522f475Smrg#undef UTMP
42962e4f8982Smrg    if ((xw->misc.login_shell || !command_to_exec) && !resource.utmpInhibit) {
4297d522f475Smrg	struct UTMP_STR dummy;
4298d522f475Smrg
4299d522f475Smrg	/* Note: utempter may trim it anyway */
4300d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
43010bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
43020bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
4303f2e35a3aSmrg	UTEMPTER_ADD(ttydev, dummy.ut_host, screen->respond);
4304d522f475Smrg	added_utmp_entry = True;
4305d522f475Smrg    }
4306d522f475Smrg#endif
4307d522f475Smrg
4308d522f475Smrg    if (am_slave < 0) {
4309d522f475Smrg#if OPT_PTY_HANDSHAKE
4310d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
4311d522f475Smrg	    SysError(ERROR_FORK);
4312d522f475Smrg#endif
4313d522f475Smrg	TRACE(("Forking...\n"));
4314d522f475Smrg	if ((screen->pid = fork()) == -1)
4315d522f475Smrg	    SysError(ERROR_FORK);
4316d522f475Smrg
4317d522f475Smrg	if (screen->pid == 0) {
4318d522f475Smrg#ifdef USE_USG_PTYS
431920d2c4d2Smrg	    int ptyfd = -1;
4320d522f475Smrg	    char *pty_name;
4321d522f475Smrg#endif
4322d522f475Smrg	    /*
4323d522f475Smrg	     * now in child process
4324d522f475Smrg	     */
432504b94745Smrg#ifdef HAVE_SETSID
4326d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
4327d522f475Smrg#else
4328d522f475Smrg	    int pgrp = getpid();
4329d522f475Smrg#endif
433004b94745Smrg	    TRACE_CHILD;
4331d522f475Smrg
4332d522f475Smrg#ifdef USE_USG_PTYS
43330bd37d32Smrg#ifdef HAVE_SETPGID
433404b94745Smrg	    setpgid(0, 0);
43350bd37d32Smrg#else
433604b94745Smrg	    setpgrp();
43370bd37d32Smrg#endif
43380bd37d32Smrg	    unlockpt(screen->respond);
4339913cc679Smrg	    TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
43400bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
43410bd37d32Smrg		SysError(ERROR_PTSNAME);
43420bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
43430bd37d32Smrg		SysError(ERROR_OPPTSNAME);
43440bd37d32Smrg	    }
4345d522f475Smrg#ifdef I_PUSH
43462e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ptem")) {
43470bd37d32Smrg		SysError(ERROR_PTEM);
43480bd37d32Smrg	    }
4349d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
43500bd37d32Smrg	    else if (!x_getenv("CONSEM")
43512e4f8982Smrg		     && PUSH_FAILS(ptyfd, "consem")) {
43520bd37d32Smrg		SysError(ERROR_CONSEM);
43530bd37d32Smrg	    }
4354d522f475Smrg#endif /* !SVR4 */
43552e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ldterm")) {
43560bd37d32Smrg		SysError(ERROR_LDTERM);
43570bd37d32Smrg	    }
4358d522f475Smrg#ifdef SVR4			/* from Sony */
43592e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ttcompat")) {
43600bd37d32Smrg		SysError(ERROR_TTCOMPAT);
43610bd37d32Smrg	    }
4362d522f475Smrg#endif /* SVR4 */
4363d522f475Smrg#endif /* I_PUSH */
43640bd37d32Smrg	    ttyfd = ptyfd;
43650bd37d32Smrg	    close_fd(screen->respond);
4366d522f475Smrg
4367d522f475Smrg#ifdef TTYSIZE_STRUCT
43680bd37d32Smrg	    /* tell tty how big window is */
4369d522f475Smrg#if OPT_TEK4014
43700bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
4371913cc679Smrg		setup_winsize(ts, TDefaultRows, TDefaultCols,
4372913cc679Smrg			      TFullHeight(TekScreenOf(tekWidget)),
4373913cc679Smrg			      TFullWidth(TekScreenOf(tekWidget)));
43740bd37d32Smrg	    } else
4375d522f475Smrg#endif /* OPT_TEK4014 */
43760bd37d32Smrg	    {
4377913cc679Smrg		setup_winsize(ts, MaxRows(screen), MaxCols(screen),
4378913cc679Smrg			      FullHeight(screen), FullWidth(screen));
43790bd37d32Smrg	    }
4380913cc679Smrg	    trace_winsize(ts, "initial tty size");
4381d522f475Smrg#endif /* TTYSIZE_STRUCT */
4382d522f475Smrg
4383d522f475Smrg#endif /* USE_USG_PTYS */
4384d522f475Smrg
43850bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
4386d522f475Smrg
4387d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
43880bd37d32Smrg	    if (resource.ptyHandshake) {
43890bd37d32Smrg		char *ptr;
4390d522f475Smrg
43910bd37d32Smrg		/* close parent's sides of the pipes */
43920bd37d32Smrg		close(cp_pipe[0]);
43930bd37d32Smrg		close(pc_pipe[1]);
43940bd37d32Smrg
43950bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
43960bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
43970bd37d32Smrg		 * or err.
43980bd37d32Smrg		 */
43990bd37d32Smrg		if (cp_pipe[1] <= 2) {
44000bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
44010bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
44020bd37d32Smrg			cp_pipe[1] = i;
4403d522f475Smrg		    }
44040bd37d32Smrg		}
44050bd37d32Smrg		if (pc_pipe[0] <= 2) {
44060bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
44070bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
44080bd37d32Smrg			pc_pipe[0] = i;
4409d522f475Smrg		    }
44100bd37d32Smrg		}
4411d522f475Smrg
44120bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
44130bd37d32Smrg		close(ConnectionNumber(screen->display));
4414894e0ac8Smrg		if (screen->respond >= 0)
4415894e0ac8Smrg		    close(screen->respond);
4416d522f475Smrg
44170bd37d32Smrg		/* Now is the time to set up our process group and
44180bd37d32Smrg		 * open up the pty slave.
44190bd37d32Smrg		 */
4420d522f475Smrg#ifdef USE_SYSV_PGRP
4421d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
44220bd37d32Smrg		IGNORE_RC(setsid());
4423d522f475Smrg#else
44240bd37d32Smrg		IGNORE_RC(setpgrp());
4425d522f475Smrg#endif
4426d522f475Smrg#endif /* USE_SYSV_PGRP */
4427d522f475Smrg
4428d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
44290bd37d32Smrg		qsetlogin(getlogin(), ttydev);
4430d522f475Smrg#endif
44310bd37d32Smrg		if (ttyfd >= 0) {
44320bd37d32Smrg		    close_fd(ttyfd);
44330bd37d32Smrg		}
4434d522f475Smrg
44350bd37d32Smrg		for (;;) {
443620d2c4d2Smrg#if USE_NO_DEV_TTY
44370bd37d32Smrg		    if (!no_dev_tty
44380bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
44390bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
44400bd37d32Smrg			close_fd(ttyfd);
44410bd37d32Smrg		    }
444220d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
4443d522f475Smrg#ifdef CSRG_BASED
44440bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
4445d522f475Smrg#endif
44460bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
4447913cc679Smrg			TRACE_GET_TTYSIZE(ttyfd, "after open");
44480bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
4449913cc679Smrg			TRACE_GET_TTYSIZE(ttyfd, "after SET_TTYSIZE fixup");
4450d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
44510bd37d32Smrg			/* make /dev/tty work */
44520bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
4453d522f475Smrg#endif
4454d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
44550bd37d32Smrg			/* make /dev/tty work */
44560bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
4457d522f475Smrg#endif
4458d522f475Smrg#ifdef USE_SYSV_PGRP
44590bd37d32Smrg			/* We need to make sure that we are actually
44600bd37d32Smrg			 * the process group leader for the pty.  If
44610bd37d32Smrg			 * we are, then we should now be able to open
44620bd37d32Smrg			 * /dev/tty.
44630bd37d32Smrg			 */
44640bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
44650bd37d32Smrg			    /* success! */
44660bd37d32Smrg			    close(i);
4467d522f475Smrg			    break;
4468d522f475Smrg			}
44690bd37d32Smrg#else /* USE_SYSV_PGRP */
44700bd37d32Smrg			break;
44710bd37d32Smrg#endif /* USE_SYSV_PGRP */
44720bd37d32Smrg		    }
44730bd37d32Smrg		    perror("open ttydev");
4474d522f475Smrg#ifdef TIOCSCTTY
44750bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
4476d522f475Smrg#endif
44770bd37d32Smrg		    /* let our master know that the open failed */
44780bd37d32Smrg		    handshake.status = PTY_BAD;
44790bd37d32Smrg		    handshake.error = errno;
4480f2e35a3aSmrg		    copy_handshake(handshake, ttydev);
44810bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
44820bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
44830bd37d32Smrg				    (const char *) &handshake,
44840bd37d32Smrg				    sizeof(handshake)));
4485d522f475Smrg
44860bd37d32Smrg		    /* get reply from parent */
44870bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
44880bd37d32Smrg				   sizeof(handshake));
44890bd37d32Smrg		    if (i <= 0) {
44900bd37d32Smrg			/* parent terminated */
449104b94745Smrg			exit(ERROR_MISC);
4492d522f475Smrg		    }
4493d522f475Smrg
44940bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
44950bd37d32Smrg			/* No more ptys, let's shutdown. */
449604b94745Smrg			exit(ERROR_MISC);
4497d522f475Smrg		    }
44980bd37d32Smrg
44990bd37d32Smrg		    /* We have a new pty to try */
45000bd37d32Smrg		    if (ttyfd >= 0)
45010bd37d32Smrg			close(ttyfd);
45020bd37d32Smrg		    free(ttydev);
4503f2e35a3aSmrg		    handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
45040bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
4505d522f475Smrg		}
4506d522f475Smrg
45070bd37d32Smrg		/* use the same tty name that everyone else will use
45080bd37d32Smrg		 * (from ttyname)
45090bd37d32Smrg		 */
45105104ee6eSmrg		if ((ptr = ttyname(ttyfd)) != NULL) {
45110bd37d32Smrg		    free(ttydev);
45120bd37d32Smrg		    ttydev = x_strdup(ptr);
45130bd37d32Smrg		}
45140bd37d32Smrg	    }
45150bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
4516d522f475Smrg
4517d522f475Smrg	    set_pty_permissions(screen->uid,
4518913cc679Smrg				(unsigned) screen->gid,
4519d522f475Smrg				(resource.messages
4520d522f475Smrg				 ? 0622U
4521d522f475Smrg				 : 0600U));
4522d522f475Smrg
4523d522f475Smrg	    /*
4524d522f475Smrg	     * set up the tty modes
4525d522f475Smrg	     */
4526d522f475Smrg	    {
4527d522f475Smrg#ifdef TERMIO_STRUCT
452804b94745Smrg#if defined(umips) || defined(CRAY) || defined(__linux__)
4529d522f475Smrg		/* If the control tty had its modes screwed around with,
4530d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
4531d522f475Smrg		   will have bad values.  Let's just get termio from the
4532d522f475Smrg		   new tty and tailor it.  */
4533d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4534d522f475Smrg		    SysError(ERROR_TIOCGETP);
4535d522f475Smrg		tio.c_lflag |= ECHOE;
4536d522f475Smrg#endif /* umips */
4537d522f475Smrg		/* Now is also the time to change the modes of the
4538d522f475Smrg		 * child pty.
4539d522f475Smrg		 */
4540d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
454120d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
4542d522f475Smrg		tio.c_iflag |= ICRNL;
45430bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
4544d522f475Smrg#if OPT_LUIT_PROG
45455104ee6eSmrg		if (command_to_exec_with_luit == NULL)
4546d522f475Smrg#endif
4547d522f475Smrg		    if (screen->utf8_mode)
4548d522f475Smrg			tio.c_iflag |= IUTF8;
4549d522f475Smrg#endif
4550f2e35a3aSmrg		/* output: cr->cr, nl is not return, no delays, ln->cr/nl */
4551d522f475Smrg#ifndef USE_POSIX_TERMIOS
455220d2c4d2Smrg		UIntClr(tio.c_oflag,
455320d2c4d2Smrg			(OCRNL
455420d2c4d2Smrg			 | ONLRET
455520d2c4d2Smrg			 | NLDLY
455620d2c4d2Smrg			 | CRDLY
455720d2c4d2Smrg			 | TABDLY
455820d2c4d2Smrg			 | BSDLY
455920d2c4d2Smrg			 | VTDLY
456020d2c4d2Smrg			 | FFDLY));
4561d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4562f2e35a3aSmrg		tio.c_oflag |= D_TIO_FLAGS;
4563d522f475Smrg#ifndef USE_POSIX_TERMIOS
4564d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
4565d522f475Smrg#  define CBAUD V_CBAUD
4566d522f475Smrg# endif
456720d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
4568d522f475Smrg#ifdef BAUD_0
4569d522f475Smrg		/* baud rate is 0 (don't care) */
4570d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
45712e4f8982Smrg		tio.c_ispeed = tio.c_ospeed = line_speed;
4572d522f475Smrg#else /* !BAUD_0 */
45732e4f8982Smrg		tio.c_cflag |= line_speed;
4574d522f475Smrg#endif /* !BAUD_0 */
4575d522f475Smrg#else /* USE_POSIX_TERMIOS */
45762e4f8982Smrg		cfsetispeed(&tio, line_speed);
45772e4f8982Smrg		cfsetospeed(&tio, line_speed);
4578d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
4579d522f475Smrg		   when the xterm ends */
45802e4f8982Smrg		tio.c_cflag &= (unsigned) ~CLOCAL;
4581d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4582d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
4583d522f475Smrg		 * echo
4584d522f475Smrg		 */
4585d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
4586d522f475Smrg#ifdef ECHOKE
4587d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
4588d522f475Smrg#endif
4589d522f475Smrg#ifdef ECHOCTL
4590d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
4591d522f475Smrg#endif
4592f2e35a3aSmrg		for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
4593d522f475Smrg		    if (validTtyChar(tio, nn)) {
4594f2e35a3aSmrg			int sysMode = ttyChars[nn].sysMode;
4595f2e35a3aSmrg			tio.c_cc[sysMode] = (cc_t) ttyChars[nn].myDefault;
4596d522f475Smrg		    }
4597d522f475Smrg		}
4598d522f475Smrg
4599d522f475Smrg		if (override_tty_modes) {
4600f2e35a3aSmrg		    TRACE(("applying termios ttyModes\n"));
4601f2e35a3aSmrg		    for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
4602d522f475Smrg			if (validTtyChar(tio, nn)) {
4603f2e35a3aSmrg			    TMODE(ttyChars[nn].myMode,
4604f2e35a3aSmrg				  tio.c_cc[ttyChars[nn].sysMode]);
4605f2e35a3aSmrg			} else if (isTabMode(nn)) {
4606f2e35a3aSmrg			    unsigned tmp = (unsigned) tio.c_oflag;
4607f2e35a3aSmrg			    tmp = tmp & (unsigned) ~TABDLY;
4608f2e35a3aSmrg			    tmp |= (unsigned) ttyModes[ttyChars[nn].myMode].value;
4609f2e35a3aSmrg			    tio.c_oflag = tmp;
4610d522f475Smrg			}
4611d522f475Smrg		    }
4612d522f475Smrg#ifdef HAS_LTCHARS
4613d522f475Smrg		    /* both SYSV and BSD have ltchars */
4614d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4615d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4616d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4617d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4618d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4619d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4620d522f475Smrg#endif
4621d522f475Smrg		}
4622d522f475Smrg#ifdef HAS_LTCHARS
4623d522f475Smrg#ifdef __hpux
4624d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
4625d522f475Smrg		 * are not set to _POSIX_VDISABLE */
4626913cc679Smrg		ltc.t_rprntc = _POSIX_VDISABLE;
4627913cc679Smrg		ltc.t_rprntc = _POSIX_VDISABLE;
4628913cc679Smrg		ltc.t_flushc = _POSIX_VDISABLE;
4629913cc679Smrg		ltc.t_werasc = _POSIX_VDISABLE;
4630913cc679Smrg		ltc.t_lnextc = _POSIX_VDISABLE;
4631d522f475Smrg#endif /* __hpux */
4632d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
4633d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4634d522f475Smrg#endif /* HAS_LTCHARS */
4635d522f475Smrg#ifdef TIOCLSET
4636d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4637d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4638d522f475Smrg#endif /* TIOCLSET */
4639d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
4640d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4641d522f475Smrg
4642d522f475Smrg		/* ignore errors here - some platforms don't work */
464320d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
4644d522f475Smrg		if (screen->input_eight_bits)
4645d522f475Smrg		    tio.c_cflag |= CS8;
4646d522f475Smrg		else
4647d522f475Smrg		    tio.c_cflag |= CS7;
4648d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
4649d522f475Smrg
4650d522f475Smrg#else /* !TERMIO_STRUCT */
4651d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
4652d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
4653d522f475Smrg		/* make sure speed is set on pty so that editors work right */
46542e4f8982Smrg		sg.sg_ispeed = line_speed;
46552e4f8982Smrg		sg.sg_ospeed = line_speed;
4656d522f475Smrg		/* reset t_brkc to default value */
4657d522f475Smrg		tc.t_brkc = -1;
4658d522f475Smrg#ifdef LPASS8
4659d522f475Smrg		if (screen->input_eight_bits)
4660d522f475Smrg		    lmode |= LPASS8;
4661d522f475Smrg		else
4662d522f475Smrg		    lmode &= ~(LPASS8);
4663d522f475Smrg#endif
4664d522f475Smrg#ifdef sony
4665d522f475Smrg		jmode &= ~KM_KANJI;
4666d522f475Smrg#endif /* sony */
4667d522f475Smrg
4668d522f475Smrg		ltc = d_ltc;
4669d522f475Smrg
4670d522f475Smrg		if (override_tty_modes) {
4671f2e35a3aSmrg		    TRACE(("applying sgtty ttyModes\n"));
4672d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
4673d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
4674d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
4675d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
4676d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
4677d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
4678d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
4679d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
4680d522f475Smrg		    /* both SYSV and BSD have ltchars */
4681d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4682d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4683d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4684d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4685d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4686d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4687f2e35a3aSmrg		    if (ttyModes[XTTYMODE_tabs].set
4688f2e35a3aSmrg			|| ttyModes[XTTYMODE__tabs].set) {
4689f2e35a3aSmrg			sg.sg_flags &= ~XTABS;
4690f2e35a3aSmrg			if (ttyModes[XTTYMODE__tabs].set.set)
4691f2e35a3aSmrg			    sg.sg_flags |= XTABS;
4692f2e35a3aSmrg		    }
4693d522f475Smrg		}
4694d522f475Smrg
4695d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
4696d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4697d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
4698d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4699d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
4700d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
4701d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
4702d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
4703d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4704d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4705d522f475Smrg#ifdef sony
4706d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
4707d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
4708d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
4709d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
4710d522f475Smrg#endif /* sony */
4711d522f475Smrg#endif /* TERMIO_STRUCT */
4712d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4713d522f475Smrg		if (Console) {
4714d522f475Smrg#ifdef TIOCCONS
4715d522f475Smrg		    int on = 1;
4716d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
47170bd37d32Smrg			xtermPerror("cannot open console");
4718d522f475Smrg#endif
4719d522f475Smrg#ifdef SRIOCSREDIR
4720d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4721d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
47220bd37d32Smrg			xtermPerror("cannot open console");
472320d2c4d2Smrg		    IGNORE_RC(close(fd));
4724d522f475Smrg#endif
4725d522f475Smrg		}
4726d522f475Smrg#endif /* TIOCCONS */
4727d522f475Smrg	    }
4728d522f475Smrg
4729d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4730d522f475Smrg#ifdef USE_SYSV_SIGHUP
4731d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4732d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4733d522f475Smrg#else
4734d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4735d522f475Smrg#endif
4736d522f475Smrg	    /* restore various signals to their defaults */
4737d522f475Smrg	    signal(SIGINT, SIG_DFL);
4738d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4739d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4740d522f475Smrg
4741d522f475Smrg	    /*
4742d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4743d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4744d522f475Smrg	     * the terminal's erase mode from our best guess.
4745d522f475Smrg	     */
4746d522f475Smrg#if OPT_INITIAL_ERASE
4747d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4748d522f475Smrg		   initial_erase,
4749d522f475Smrg		   setInitialErase ? "YES" : "NO",
4750d522f475Smrg		   resource.ptyInitialErase,
4751d522f475Smrg		   override_tty_modes,
4752f2e35a3aSmrg		   ttyModes[XTTYMODE_erase].set));
4753d522f475Smrg	    if (setInitialErase) {
4754d522f475Smrg#if OPT_TRACE
4755d522f475Smrg		int old_erase;
4756d522f475Smrg#endif
4757d522f475Smrg#ifdef TERMIO_STRUCT
4758d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4759d522f475Smrg		    tio = d_tio;
4760d522f475Smrg#if OPT_TRACE
4761d522f475Smrg		old_erase = tio.c_cc[VERASE];
4762d522f475Smrg#endif
47630bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
476420d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4765d522f475Smrg#else /* !TERMIO_STRUCT */
4766d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4767d522f475Smrg		    sg = d_sg;
4768d522f475Smrg#if OPT_TRACE
4769d522f475Smrg		old_erase = sg.sg_erase;
4770d522f475Smrg#endif
4771d522f475Smrg		sg.sg_erase = initial_erase;
4772d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4773d522f475Smrg#endif /* TERMIO_STRUCT */
4774d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4775d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4776d522f475Smrg	    }
4777d522f475Smrg#endif
4778d522f475Smrg
4779d522f475Smrg	    xtermCopyEnv(environ);
47804419d26bSmrg	    xtermTrimEnv();
47810bd37d32Smrg
4782a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4783a1f3da82Smrg	    if (!resource.term_name)
478420d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4785d522f475Smrg
4786d522f475Smrg	    sprintf(buf, "%lu",
4787d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4788d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4789d522f475Smrg
4790d522f475Smrg	    /* put the display into the environment of the shell */
4791d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4792d522f475Smrg
4793d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4794d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4795d522f475Smrg
4796e39b573cSmrg	    /*
4797e39b573cSmrg	     * For debugging only, add environment variables that can be used
4798e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4799e39b573cSmrg	     * processes.
4800e39b573cSmrg	     */
4801e39b573cSmrg#if OPT_TRACE
4802e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4803e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4804e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4805e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4806e39b573cSmrg#endif
4807e39b573cSmrg
4808d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4809d522f475Smrg
4810d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4811d522f475Smrg	     */
4812d522f475Smrg	    {
4813d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4814d522f475Smrg		close_fd(ttyfd);
4815d522f475Smrg
481620d2c4d2Smrg		IGNORE_RC(close(0));
4817d522f475Smrg
4818d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4819d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4820d522f475Smrg		}
482120d2c4d2Smrg		IGNORE_RC(close(1));
482220d2c4d2Smrg		IGNORE_RC(close(2));
4823d522f475Smrg		dup(0);
4824d522f475Smrg		dup(0);
4825d522f475Smrg#else
4826d522f475Smrg		/* dup the tty */
4827d522f475Smrg		for (i = 0; i <= 2; i++)
4828d522f475Smrg		    if (i != ttyfd) {
482920d2c4d2Smrg			IGNORE_RC(close(i));
483020d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4831d522f475Smrg		    }
4832d522f475Smrg#ifndef ATT
4833d522f475Smrg		/* and close the tty */
4834d522f475Smrg		if (ttyfd > 2)
4835d522f475Smrg		    close_fd(ttyfd);
4836d522f475Smrg#endif
4837d522f475Smrg#endif /* CRAY */
4838d522f475Smrg	    }
4839d522f475Smrg
4840d522f475Smrg#if !defined(USE_SYSV_PGRP)
4841d522f475Smrg#ifdef TIOCSCTTY
4842d522f475Smrg	    setsid();
4843d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4844d522f475Smrg#endif
4845d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4846d522f475Smrg	    setpgrp(0, 0);
4847d522f475Smrg	    close(open(ttydev, O_WRONLY));
4848d522f475Smrg	    setpgrp(0, pgrp);
4849d522f475Smrg#if defined(__QNX__)
4850d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4851d522f475Smrg#endif
4852d522f475Smrg#endif /* !USE_SYSV_PGRP */
4853d522f475Smrg
4854d522f475Smrg#ifdef Lynx
4855d522f475Smrg	    {
4856d522f475Smrg		TERMIO_STRUCT t;
4857d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4858d522f475Smrg		    /* this gets lost somewhere on our way... */
4859d522f475Smrg		    t.c_oflag |= OPOST;
4860d522f475Smrg		    ttySetAttr(0, &t);
4861d522f475Smrg		}
4862d522f475Smrg	    }
4863d522f475Smrg#endif
4864d522f475Smrg
4865d522f475Smrg#ifdef HAVE_UTMP
4866d522f475Smrg	    login_name = NULL;
48670bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
48680bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4869d522f475Smrg	    }
4870d522f475Smrg	    if (login_name != NULL) {
4871d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4872d522f475Smrg	    }
4873d522f475Smrg#ifndef USE_UTEMPTER
4874d522f475Smrg#ifdef USE_UTMP_SETGID
4875d522f475Smrg	    setEffectiveGroup(save_egid);
4876d522f475Smrg	    TRACE_IDS;
4877d522f475Smrg#endif
4878d522f475Smrg#ifdef USE_SYSV_UTMP
4879d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4880d522f475Smrg	     * for the following reasons:
4881d522f475Smrg	     *   - It needs to have our correct process id (for
4882d522f475Smrg	     *     login).
4883d522f475Smrg	     *   - If our parent was to set it after the fork(),
4884d522f475Smrg	     *     it might make it out before we need it.
4885d522f475Smrg	     *   - We need to do it before we go and change our
4886d522f475Smrg	     *     user and group id's.
4887d522f475Smrg	     */
4888d522f475Smrg	    (void) call_setutent();
4889d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4890d522f475Smrg
4891d522f475Smrg	    /* position to entry in utmp file */
4892d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
489320d2c4d2Smrg	    utret = find_utmp(&utmp);
48945104ee6eSmrg	    if (utret == NULL) {
4895d522f475Smrg		(void) call_setutent();
4896d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
489720d2c4d2Smrg		utret = find_utmp(&utmp);
48985104ee6eSmrg		if (utret == NULL) {
4899d522f475Smrg		    (void) call_setutent();
4900d522f475Smrg		}
4901d522f475Smrg	    }
4902d522f475Smrg#if OPT_TRACE
4903d522f475Smrg	    if (!utret)
4904d522f475Smrg		TRACE(("getutid: NULL\n"));
4905d522f475Smrg	    else
49060bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
490720d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
49080bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
49090bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4910d522f475Smrg#endif
4911d522f475Smrg
4912d522f475Smrg	    /* set up the new entry */
4913d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4914d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4915d522f475Smrg	    utmp.ut_xstatus = 2;
4916d522f475Smrg#endif
4917894e0ac8Smrg	    copy_filled(utmp.ut_user,
4918894e0ac8Smrg			(login_name != NULL) ? login_name : "????",
4919894e0ac8Smrg			sizeof(utmp.ut_user));
4920d522f475Smrg	    /* why are we copying this string again?  (see above) */
4921894e0ac8Smrg	    copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4922894e0ac8Smrg	    copy_filled(utmp.ut_line,
4923894e0ac8Smrg			my_pty_name(ttydev), sizeof(utmp.ut_line));
4924d522f475Smrg
4925d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4926d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4927d522f475Smrg#endif
4928d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4929d522f475Smrg	    SetUtmpSysLen(utmp);
4930d522f475Smrg#endif
4931d522f475Smrg
4932894e0ac8Smrg	    copy_filled(utmp.ut_name,
4933894e0ac8Smrg			(login_name) ? login_name : "????",
4934894e0ac8Smrg			sizeof(utmp.ut_name));
4935d522f475Smrg
4936d522f475Smrg	    utmp.ut_pid = getpid();
4937d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4938d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4939d522f475Smrg	    utmp.ut_session = getsid(0);
4940d522f475Smrg#endif
4941d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
4942d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
4943d522f475Smrg#else
4944d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
4945d522f475Smrg#endif
4946d522f475Smrg
4947d522f475Smrg	    /* write out the entry */
4948d522f475Smrg	    if (!resource.utmpInhibit) {
4949d522f475Smrg		errno = 0;
4950d522f475Smrg		call_pututline(&utmp);
49510bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
49520bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
49530bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
4954d522f475Smrg		       (long) utmp.ut_pid,
4955d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
4956d522f475Smrg	    }
4957d522f475Smrg#ifdef WTMP
4958d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
4959d522f475Smrg	    if (xw->misc.login_shell)
4960d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
496104b94745Smrg#elif defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4962d522f475Smrg	    if (xw->misc.login_shell)
4963d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
4964d522f475Smrg#else
4965d522f475Smrg	    if (xw->misc.login_shell &&
4966d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
49670bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4968d522f475Smrg		close(i);
4969d522f475Smrg	    }
4970d522f475Smrg#endif
4971d522f475Smrg#endif
4972d522f475Smrg	    /* close the file */
4973d522f475Smrg	    (void) call_endutent();
4974d522f475Smrg
4975d522f475Smrg#else /* USE_SYSV_UTMP */
4976d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
4977d522f475Smrg	     * utmp entry.
4978d522f475Smrg	     */
4979d522f475Smrg	    tslot = ttyslot();
4980d522f475Smrg	    added_utmp_entry = False;
4981d522f475Smrg	    {
49820bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
4983d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
4984956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
4985894e0ac8Smrg		    copy_filled(utmp.ut_line,
4986894e0ac8Smrg				my_pty_name(ttydev),
4987894e0ac8Smrg				sizeof(utmp.ut_line));
4988894e0ac8Smrg		    copy_filled(utmp.ut_name, login_name,
4989894e0ac8Smrg				sizeof(utmp.ut_name));
4990d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4991d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
4992d522f475Smrg#endif
4993d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4994d522f475Smrg		    SetUtmpSysLen(utmp);
4995d522f475Smrg#endif
4996d522f475Smrg
4997d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
4998d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
49990bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
5000d522f475Smrg		    close(i);
5001d522f475Smrg		    added_utmp_entry = True;
5002d522f475Smrg#if defined(WTMP)
5003d522f475Smrg		    if (xw->misc.login_shell &&
5004d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
5005d522f475Smrg			int status;
5006d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
5007d522f475Smrg			status = close(i);
5008d522f475Smrg		    }
5009d522f475Smrg#elif defined(MNX_LASTLOG)
5010d522f475Smrg		    if (xw->misc.login_shell &&
5011d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
5012d522f475Smrg			lseek(i, (long) (screen->uid *
5013d522f475Smrg					 sizeof(utmp)), 0);
50140bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
5015d522f475Smrg			close(i);
5016d522f475Smrg		    }
5017d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
5018d522f475Smrg		} else
5019d522f475Smrg		    tslot = -tslot;
5020d522f475Smrg	    }
5021d522f475Smrg
5022d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
5023d522f475Smrg	     * clean up after us.
5024d522f475Smrg	     */
5025d522f475Smrg#if OPT_PTY_HANDSHAKE
5026d522f475Smrg	    if (resource.ptyHandshake) {
5027d522f475Smrg		handshake.tty_slot = tslot;
5028d522f475Smrg	    }
5029d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5030d522f475Smrg#endif /* USE_SYSV_UTMP */
5031d522f475Smrg
5032d522f475Smrg#ifdef USE_LASTLOGX
5033d522f475Smrg	    if (xw->misc.login_shell) {
5034956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
5035f2e35a3aSmrg		copy_filled(lastlogx.ll_line,
5036f2e35a3aSmrg			    my_pty_name(ttydev),
5037f2e35a3aSmrg			    sizeof(lastlogx.ll_line));
5038d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
5039d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
5040d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
5041d522f475Smrg	    }
5042d522f475Smrg#endif
5043d522f475Smrg
5044d522f475Smrg#ifdef USE_LASTLOG
5045d522f475Smrg	    if (xw->misc.login_shell &&
5046d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
5047d522f475Smrg		size_t size = sizeof(struct lastlog);
5048913cc679Smrg		off_t offset = (off_t) ((size_t) screen->uid * size);
5049d522f475Smrg
5050956cc18dSsnj		memset(&lastlog, 0, size);
5051f2e35a3aSmrg		copy_filled(lastlog.ll_line,
5052f2e35a3aSmrg			    my_pty_name(ttydev),
5053f2e35a3aSmrg			    sizeof(lastlog.ll_line));
5054d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
5055d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
5056d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
50570bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
5058d522f475Smrg		}
5059d522f475Smrg		close(i);
5060d522f475Smrg	    }
5061d522f475Smrg#endif /* USE_LASTLOG */
5062d522f475Smrg
5063d522f475Smrg#if defined(USE_UTMP_SETGID)
5064d522f475Smrg	    disableSetGid();
5065d522f475Smrg	    TRACE_IDS;
5066d522f475Smrg#endif
5067d522f475Smrg
5068d522f475Smrg#if OPT_PTY_HANDSHAKE
5069d522f475Smrg	    /* Let our parent know that we set up our utmp entry
5070d522f475Smrg	     * so that it can clean up after us.
5071d522f475Smrg	     */
5072d522f475Smrg	    if (resource.ptyHandshake) {
5073d522f475Smrg		handshake.status = UTMP_ADDED;
5074d522f475Smrg		handshake.error = 0;
5075f2e35a3aSmrg		copy_handshake(handshake, ttydev);
5076d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
507720d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
5078d522f475Smrg	    }
5079d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5080d522f475Smrg#endif /* USE_UTEMPTER */
5081d522f475Smrg#endif /* HAVE_UTMP */
5082d522f475Smrg
508320d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
5084d522f475Smrg	    TRACE_IDS;
5085e0a2b6dfSmrg#ifdef HAVE_INITGROUPS
50860bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
50870bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
5088d522f475Smrg		    perror("initgroups failed");
5089d522f475Smrg		    SysError(ERROR_INIGROUPS);
5090d522f475Smrg		}
5091d522f475Smrg	    }
5092d522f475Smrg#endif
5093d522f475Smrg	    if (setuid(screen->uid)) {
5094d522f475Smrg		SysError(ERROR_SETUID);
5095d522f475Smrg	    }
5096d522f475Smrg	    TRACE_IDS;
5097d522f475Smrg#if OPT_PTY_HANDSHAKE
5098d522f475Smrg	    if (resource.ptyHandshake) {
5099d522f475Smrg		/* mark the pipes as close on exec */
51000bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
51010bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
5102d522f475Smrg
5103d522f475Smrg		/* We are at the point where we are going to
5104d522f475Smrg		 * exec our shell (or whatever).  Let our parent
5105d522f475Smrg		 * know we arrived safely.
5106d522f475Smrg		 */
5107d522f475Smrg		handshake.status = PTY_GOOD;
5108d522f475Smrg		handshake.error = 0;
5109f2e35a3aSmrg		copy_handshake(handshake, ttydev);
5110d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
511120d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
511220d2c4d2Smrg				(const char *) &handshake,
511320d2c4d2Smrg				sizeof(handshake)));
5114d522f475Smrg
5115d522f475Smrg		if (resource.wait_for_map) {
511620d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
511720d2c4d2Smrg				   sizeof(handshake));
5118d522f475Smrg		    if (i != sizeof(handshake) ||
5119d522f475Smrg			handshake.status != PTY_EXEC) {
5120d522f475Smrg			/* some very bad problem occurred */
5121d522f475Smrg			exit(ERROR_PTY_EXEC);
5122d522f475Smrg		    }
5123d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
5124913cc679Smrg			TRACE(("handshake read ttysize: %dx%d\n",
5125d522f475Smrg			       handshake.rows, handshake.cols));
5126d522f475Smrg			set_max_row(screen, handshake.rows);
5127d522f475Smrg			set_max_col(screen, handshake.cols);
5128d522f475Smrg#ifdef TTYSIZE_STRUCT
5129d522f475Smrg			got_handshake_size = True;
5130913cc679Smrg			setup_winsize(ts, MaxRows(screen), MaxCols(screen),
5131913cc679Smrg				      FullHeight(screen), FullWidth(screen));
5132913cc679Smrg			trace_winsize(ts, "got handshake");
5133d522f475Smrg#endif /* TTYSIZE_STRUCT */
5134d522f475Smrg		    }
5135d522f475Smrg		}
5136d522f475Smrg	    }
5137d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5138d522f475Smrg
5139d522f475Smrg#ifdef USE_SYSV_ENVVARS
5140d522f475Smrg	    {
5141d522f475Smrg		char numbuf[12];
5142d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
5143d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
5144d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
5145d522f475Smrg		xtermSetenv("LINES", numbuf);
5146d522f475Smrg	    }
5147d522f475Smrg#ifdef HAVE_UTMP
51480bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
5149d522f475Smrg		if (!x_getenv("HOME"))
51500bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
5151d522f475Smrg		if (!x_getenv("SHELL"))
51520bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
5153d522f475Smrg	    }
5154d522f475Smrg#endif /* HAVE_UTMP */
5155d522f475Smrg#else /* USE_SYSV_ENVVARS */
515620d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
515720d2c4d2Smrg		resize_termcap(xw);
515820d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
515920d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
516020d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
516120d2c4d2Smrg		}
516220d2c4d2Smrg		/*
516320d2c4d2Smrg		 * work around broken termcap entries */
516420d2c4d2Smrg		if (resource.useInsertMode) {
516520d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
516620d2c4d2Smrg		    /* don't get duplicates */
516720d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
516820d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
516920d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
517020d2c4d2Smrg		    if (*newtc)
517120d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
517220d2c4d2Smrg		}
517320d2c4d2Smrg		if (*newtc) {
5174d522f475Smrg#if OPT_INITIAL_ERASE
51755307cd1aSmrg#define TERMCAP_ERASE "kb"
517620d2c4d2Smrg		    unsigned len;
517720d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
517820d2c4d2Smrg		    len = (unsigned) strlen(newtc);
517920d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
518020d2c4d2Smrg			len--;
518120d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
518220d2c4d2Smrg			    TERMCAP_ERASE,
518320d2c4d2Smrg			    CharOf(initial_erase));
518420d2c4d2Smrg#endif
518520d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
518620d2c4d2Smrg		}
5187d522f475Smrg	    }
5188d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5189913cc679Smrg#ifdef OWN_TERMINFO_ENV
5190913cc679Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
5191913cc679Smrg#endif
5192d522f475Smrg
5193d522f475Smrg#if OPT_PTY_HANDSHAKE
5194d522f475Smrg	    /*
5195d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
5196d522f475Smrg	     *
5197d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
5198d522f475Smrg	     * use that to prevent races.
5199d522f475Smrg	     */
5200913cc679Smrg	    TRACE(("should we reset screensize after pty-handshake?\n"));
5201913cc679Smrg	    TRACE(("... ptyHandshake      :%d\n", resource.ptyHandshake));
5202913cc679Smrg	    TRACE(("... ptySttySize       :%d\n", resource.ptySttySize));
5203913cc679Smrg	    TRACE(("... got_handshake_size:%d\n", got_handshake_size));
5204913cc679Smrg	    TRACE(("... wait_for_map0     :%d\n", resource.wait_for_map0));
5205d522f475Smrg	    if (resource.ptyHandshake
5206d522f475Smrg		&& resource.ptySttySize
5207d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
5208d522f475Smrg#ifdef TTYSIZE_STRUCT
520920d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
5210913cc679Smrg		trace_winsize(ts, "ptyHandshake SET_TTYSIZE");
5211d522f475Smrg#endif /* TTYSIZE_STRUCT */
5212d522f475Smrg	    }
5213d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5214d522f475Smrg	    signal(SIGHUP, SIG_DFL);
5215d522f475Smrg
52160bd37d32Smrg	    /*
5217e0a2b6dfSmrg	     * If we have an explicit shell to run, make that set $SHELL.
5218e0a2b6dfSmrg	     * Next, allow an existing setting of $SHELL, for absolute paths.
52190bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
52200bd37d32Smrg	     * password information, if possible.
52210bd37d32Smrg	     *
52220bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
52230bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
52240bd37d32Smrg	     */
5225e0a2b6dfSmrg	    if (validShell(explicit_shname)) {
5226e0a2b6dfSmrg		xtermSetenv("SHELL", explicit_shname);
5227e0a2b6dfSmrg	    } else if (validProgram(shell_path = x_getenv("SHELL"))) {
5228e0a2b6dfSmrg		if (!validShell(shell_path)) {
5229e0a2b6dfSmrg		    xtermUnsetenv("SHELL");
5230d522f475Smrg		}
5231e0a2b6dfSmrg	    } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
5232e0a2b6dfSmrg		       || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
5233e0a2b6dfSmrg		shell_path = resetShell(shell_path);
5234e0a2b6dfSmrg	    } else if (validShell(shell_path)) {
5235e0a2b6dfSmrg		xtermSetenv("SHELL", shell_path);
5236d522f475Smrg	    } else {
5237e0a2b6dfSmrg		shell_path = resetShell(shell_path);
5238d522f475Smrg	    }
5239e0a2b6dfSmrg
5240e0a2b6dfSmrg	    /*
5241e0a2b6dfSmrg	     * Set $XTERM_SHELL, which is not necessarily a valid shell, but
5242e0a2b6dfSmrg	     * is executable.
5243e0a2b6dfSmrg	     */
5244e0a2b6dfSmrg	    if (validProgram(explicit_shname)) {
5245e0a2b6dfSmrg		shell_path = explicit_shname;
52465104ee6eSmrg	    } else if (shell_path == NULL) {
5247e0a2b6dfSmrg		/* this could happen if the explicit shname lost a race */
5248e0a2b6dfSmrg		shell_path = resetShell(shell_path);
52490bd37d32Smrg	    }
52500bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
5251d522f475Smrg
52520bd37d32Smrg	    shname = x_basename(shell_path);
52530bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
5254d522f475Smrg
5255d522f475Smrg#if OPT_LUIT_PROG
5256d522f475Smrg	    /*
5257d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
5258d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
5259d522f475Smrg	     * to command that the user gave anyway.
5260d522f475Smrg	     */
52612eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
52620bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
52630bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
52640bd37d32Smrg		free(myShell);
52650bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
5266d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
52670bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
52680bd37d32Smrg		xtermWarning("cannot support your locale.\n");
5269d522f475Smrg	    }
5270d522f475Smrg#endif
5271d522f475Smrg	    if (command_to_exec) {
52720bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
52730bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
52740bd37d32Smrg		free(myShell);
52750bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
5276d522f475Smrg		execvp(*command_to_exec, command_to_exec);
52775104ee6eSmrg		if (command_to_exec[1] == NULL)
52780bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
52790bd37d32Smrg			   (void *) 0);
52800bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
5281d522f475Smrg	    }
5282d522f475Smrg#ifdef USE_SYSV_SIGHUP
5283d522f475Smrg	    /* fix pts sh hanging around */
5284d522f475Smrg	    signal(SIGHUP, SIG_DFL);
5285d522f475Smrg#endif
5286d522f475Smrg
52875104ee6eSmrg	    if ((shname_minus = (char *) malloc(strlen(shname) + 2)) != NULL) {
528801037d57Smrg		(void) strcpy(shname_minus, "-");
528901037d57Smrg		(void) strcat(shname_minus, shname);
529001037d57Smrg	    } else {
529101037d57Smrg		static char default_minus[] = "-sh";
529201037d57Smrg		shname_minus = default_minus;
529301037d57Smrg	    }
5294d522f475Smrg#ifndef TERMIO_STRUCT
52950bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
52960bd37d32Smrg		     ? NTTYDISC
52970bd37d32Smrg		     : 0);
5298d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
5299d522f475Smrg#endif /* !TERMIO_STRUCT */
5300d522f475Smrg
5301d522f475Smrg#ifdef USE_LOGIN_DASH_P
53020bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
5303d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
5304d522f475Smrg#endif
53052eaa94a1Schristos
53062eaa94a1Schristos#if OPT_LUIT_PROG
53072eaa94a1Schristos	    if (command_to_exec_with_luit) {
53082eaa94a1Schristos		if (xw->misc.login_shell) {
53090bd37d32Smrg		    char *params[4];
53100bd37d32Smrg		    params[0] = x_strdup("-argv0");
53110bd37d32Smrg		    params[1] = shname_minus;
53120bd37d32Smrg		    params[2] = NULL;
53130bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
53140bd37d32Smrg				 + command_length_with_luit,
53150bd37d32Smrg				 params);
53162eaa94a1Schristos		}
53170bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
53182eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
53192eaa94a1Schristos		/* Exec failed. */
53200bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
53212eaa94a1Schristos	    }
53222eaa94a1Schristos#endif
53230bd37d32Smrg	    execlp(shell_path,
5324d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
5325d522f475Smrg		   (void *) 0);
5326d522f475Smrg
5327d522f475Smrg	    /* Exec failed. */
53280bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
532920d2c4d2Smrg	    IGNORE_RC(sleep(5));
53300bd37d32Smrg	    free(shell_path);
5331d522f475Smrg	    exit(ERROR_EXEC);
5332d522f475Smrg	}
5333d522f475Smrg	/* end if in child after fork */
5334d522f475Smrg#if OPT_PTY_HANDSHAKE
5335d522f475Smrg	if (resource.ptyHandshake) {
5336d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
5337d522f475Smrg	     * child process.
5338d522f475Smrg	     */
5339d522f475Smrg
5340d522f475Smrg	    /* close childs's sides of the pipes */
5341d522f475Smrg	    close(cp_pipe[1]);
5342d522f475Smrg	    close(pc_pipe[0]);
5343d522f475Smrg
5344d522f475Smrg	    for (done = 0; !done;) {
5345d522f475Smrg		if (read(cp_pipe[0],
5346d522f475Smrg			 (char *) &handshake,
5347d522f475Smrg			 sizeof(handshake)) <= 0) {
5348d522f475Smrg		    /* Our child is done talking to us.  If it terminated
5349d522f475Smrg		     * due to an error, we will catch the death of child
5350d522f475Smrg		     * and clean up.
5351d522f475Smrg		     */
5352d522f475Smrg		    break;
5353d522f475Smrg		}
5354d522f475Smrg
5355d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
5356d522f475Smrg		switch (handshake.status) {
5357d522f475Smrg		case PTY_GOOD:
5358d522f475Smrg		    /* Success!  Let's free up resources and
5359d522f475Smrg		     * continue.
5360d522f475Smrg		     */
5361d522f475Smrg		    done = 1;
5362d522f475Smrg		    break;
5363d522f475Smrg
5364d522f475Smrg		case PTY_BAD:
5365d522f475Smrg		    /* The open of the pty failed!  Let's get
5366d522f475Smrg		     * another one.
5367d522f475Smrg		     */
536820d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
5369d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
5370d522f475Smrg			/* no more ptys! */
53710bd37d32Smrg			xtermPerror("child process can find no available ptys");
5372d522f475Smrg			handshake.status = PTY_NOMORE;
5373d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
537420d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
537520d2c4d2Smrg					(const char *) &handshake,
537620d2c4d2Smrg					sizeof(handshake)));
5377d522f475Smrg			exit(ERROR_PTYS);
5378d522f475Smrg		    }
5379d522f475Smrg		    handshake.status = PTY_NEW;
5380f2e35a3aSmrg		    copy_handshake(handshake, ttydev);
5381d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
538220d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
538320d2c4d2Smrg				    (const char *) &handshake,
538420d2c4d2Smrg				    sizeof(handshake)));
5385d522f475Smrg		    break;
5386d522f475Smrg
5387d522f475Smrg		case PTY_FATALERROR:
5388d522f475Smrg		    errno = handshake.error;
5389d522f475Smrg		    close(cp_pipe[0]);
5390d522f475Smrg		    close(pc_pipe[1]);
5391d522f475Smrg		    SysError(handshake.fatal_error);
5392d522f475Smrg		    /*NOTREACHED */
5393d522f475Smrg
5394d522f475Smrg		case UTMP_ADDED:
5395d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
5396d522f475Smrg		     * this so that we can reset it later.
5397d522f475Smrg		     */
5398d522f475Smrg		    added_utmp_entry = True;
5399d522f475Smrg#ifndef	USE_SYSV_UTMP
5400d522f475Smrg		    tslot = handshake.tty_slot;
5401d522f475Smrg#endif /* USE_SYSV_UTMP */
5402d522f475Smrg		    free(ttydev);
5403f2e35a3aSmrg		    handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
5404d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
5405d522f475Smrg		    break;
5406d522f475Smrg		case PTY_NEW:
5407d522f475Smrg		case PTY_NOMORE:
5408d522f475Smrg		case UTMP_TTYSLOT:
5409d522f475Smrg		case PTY_EXEC:
5410d522f475Smrg		default:
54110bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
54120bd37d32Smrg				 (int) handshake.status);
5413d522f475Smrg		}
5414d522f475Smrg	    }
5415d522f475Smrg	    /* close our sides of the pipes */
5416d522f475Smrg	    if (!resource.wait_for_map) {
5417d522f475Smrg		close(cp_pipe[0]);
5418d522f475Smrg		close(pc_pipe[1]);
5419d522f475Smrg	    }
5420d522f475Smrg	}
5421d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5422d522f475Smrg    }
5423d522f475Smrg
5424d522f475Smrg    /* end if no slave */
5425d522f475Smrg    /*
5426d522f475Smrg     * still in parent (xterm process)
5427d522f475Smrg     */
5428d522f475Smrg#ifdef USE_SYSV_SIGHUP
5429d522f475Smrg    /* hung sh problem? */
5430d522f475Smrg    signal(SIGHUP, SIG_DFL);
5431d522f475Smrg#else
5432d522f475Smrg    signal(SIGHUP, SIG_IGN);
5433d522f475Smrg#endif
5434d522f475Smrg
5435d522f475Smrg/*
5436d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
5437d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
5438d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
5439d522f475Smrg * don't ignore the signals.  This is annoying.
5440d522f475Smrg */
5441d522f475Smrg
5442d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
5443d522f475Smrg    signal(SIGINT, SIG_IGN);
5444d522f475Smrg
5445d522f475Smrg#ifndef SYSV
5446d522f475Smrg    /* hung shell problem */
5447d522f475Smrg    signal(SIGQUIT, SIG_IGN);
5448d522f475Smrg#endif
5449d522f475Smrg    signal(SIGTERM, SIG_IGN);
5450d522f475Smrg#elif defined(SYSV) || defined(__osf__)
5451d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
5452d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
5453d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
5454d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
5455d522f475Smrg     * tank on everything.
5456d522f475Smrg     */
5457d522f475Smrg    if (getpid() == getpgrp()) {
5458d522f475Smrg	(void) signal(SIGINT, Exit);
5459d522f475Smrg	(void) signal(SIGQUIT, Exit);
5460d522f475Smrg	(void) signal(SIGTERM, Exit);
5461d522f475Smrg    } else {
5462d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
5463d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
5464d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
5465d522f475Smrg    }
5466d522f475Smrg    (void) signal(SIGPIPE, Exit);
5467d522f475Smrg#else /* SYSV */
5468d522f475Smrg    signal(SIGINT, Exit);
5469d522f475Smrg    signal(SIGQUIT, Exit);
5470d522f475Smrg    signal(SIGTERM, Exit);
5471d522f475Smrg    signal(SIGPIPE, Exit);
5472d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
54730bd37d32Smrg#ifdef NO_LEAKS
54740bd37d32Smrg    if (ok_termcap != True)
54750bd37d32Smrg	free(TermName);
54760bd37d32Smrg#endif
5477d522f475Smrg
5478d522f475Smrg    return 0;
5479d522f475Smrg}				/* end spawnXTerm */
5480d522f475Smrg
54810bd37d32Smrgvoid
5482d522f475SmrgExit(int n)
5483d522f475Smrg{
548420d2c4d2Smrg    XtermWidget xw = term;
548520d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
5486d522f475Smrg
5487d522f475Smrg#ifdef USE_UTEMPTER
54880bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
54890bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
54900bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
5491f2e35a3aSmrg	UTEMPTER_DEL();
54920bd37d32Smrg    }
5493d522f475Smrg#elif defined(HAVE_UTMP)
5494d522f475Smrg#ifdef USE_SYSV_UTMP
5495d522f475Smrg    struct UTMP_STR utmp;
5496d522f475Smrg    struct UTMP_STR *utptr;
5497d522f475Smrg
54980bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
5499d522f475Smrg    /* don't do this more than once */
55000bd37d32Smrg    if (xterm_exiting) {
55010bd37d32Smrg	exit(n);
55020bd37d32Smrg    }
5503d522f475Smrg    xterm_exiting = True;
5504d522f475Smrg
5505d522f475Smrg#ifdef PUCC_PTYD
5506d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
5507d522f475Smrg#endif /* PUCC_PTYD */
5508d522f475Smrg
5509d522f475Smrg    /* cleanup the utmp entry we forged earlier */
5510d522f475Smrg    if (!resource.utmpInhibit
5511d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
5512d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
5513d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5514d522f475Smrg	) {
5515d522f475Smrg#if defined(USE_UTMP_SETGID)
5516d522f475Smrg	setEffectiveGroup(save_egid);
5517d522f475Smrg	TRACE_IDS;
5518d522f475Smrg#endif
5519d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
5520d522f475Smrg	(void) call_setutent();
5521d522f475Smrg
5522d522f475Smrg	/*
5523d522f475Smrg	 * We could use getutline() if we didn't support old systems.
5524d522f475Smrg	 */
55255104ee6eSmrg	while ((utptr = find_utmp(&utmp)) != NULL) {
5526d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
5527d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
5528d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
5529d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
5530d522f475Smrg		utptr->ut_session = getsid(0);
5531d522f475Smrg#endif
5532d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
5533d522f475Smrg		utptr->ut_tv.tv_usec = 0;
5534d522f475Smrg#else
5535d522f475Smrg		*utptr->ut_user = 0;
5536d522f475Smrg		utptr->ut_time = time((time_t *) 0);
5537d522f475Smrg#endif
5538d522f475Smrg		(void) call_pututline(utptr);
5539d522f475Smrg#ifdef WTMP
5540d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
554120d2c4d2Smrg		if (xw->misc.login_shell)
5542d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
554304b94745Smrg#elif defined(__linux__) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
5544894e0ac8Smrg		copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
554520d2c4d2Smrg		if (xw->misc.login_shell)
5546d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
5547d522f475Smrg#else
5548d522f475Smrg		/* set wtmp entry if wtmp file exists */
554920d2c4d2Smrg		if (xw->misc.login_shell) {
5550d522f475Smrg		    int fd;
5551d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
55520bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
5553d522f475Smrg			close(fd);
5554d522f475Smrg		    }
5555d522f475Smrg		}
5556d522f475Smrg#endif
5557d522f475Smrg#endif
5558d522f475Smrg		break;
5559d522f475Smrg	    }
5560d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
5561d522f475Smrg	}
5562d522f475Smrg	(void) call_endutent();
5563d522f475Smrg#ifdef USE_UTMP_SETGID
5564d522f475Smrg	disableSetGid();
5565d522f475Smrg	TRACE_IDS;
5566d522f475Smrg#endif
5567d522f475Smrg    }
5568d522f475Smrg#else /* not USE_SYSV_UTMP */
5569d522f475Smrg    int wfd;
5570d522f475Smrg    struct utmp utmp;
5571d522f475Smrg
55720bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
5573d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
5574d522f475Smrg	(am_slave < 0 && tslot > 0)) {
5575d522f475Smrg#if defined(USE_UTMP_SETGID)
5576d522f475Smrg	setEffectiveGroup(save_egid);
5577d522f475Smrg	TRACE_IDS;
5578d522f475Smrg#endif
5579d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
5580956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
5581d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
55820bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5583d522f475Smrg	    close(wfd);
5584d522f475Smrg	}
5585d522f475Smrg#ifdef WTMP
558620d2c4d2Smrg	if (xw->misc.login_shell &&
5587d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
5588894e0ac8Smrg	    copy_filled(utmp.ut_line,
5589894e0ac8Smrg			my_pty_name(ttydev),
5590894e0ac8Smrg			sizeof(utmp.ut_line));
5591d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
55920bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5593d522f475Smrg	    close(wfd);
5594d522f475Smrg	}
5595d522f475Smrg#endif /* WTMP */
5596d522f475Smrg#ifdef USE_UTMP_SETGID
5597d522f475Smrg	disableSetGid();
5598d522f475Smrg	TRACE_IDS;
5599d522f475Smrg#endif
5600d522f475Smrg    }
5601d522f475Smrg#endif /* USE_SYSV_UTMP */
5602d522f475Smrg#endif /* HAVE_UTMP */
5603d522f475Smrg
5604e0a2b6dfSmrg    cleanup_colored_cursor();
5605e0a2b6dfSmrg
5606d522f475Smrg    /*
5607d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
5608d522f475Smrg     * in the middle of the data.
5609d522f475Smrg     */
5610d522f475Smrg    ttyFlush(screen->respond);
5611d522f475Smrg
5612e39b573cSmrg#ifdef USE_PTY_SEARCH
5613d522f475Smrg    if (am_slave < 0) {
5614d522f475Smrg	TRACE_IDS;
5615d522f475Smrg	/* restore ownership of tty and pty */
5616d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
5617d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
5618d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
5619d522f475Smrg#endif
5620d522f475Smrg    }
5621e39b573cSmrg#endif
5622d522f475Smrg
5623d522f475Smrg    /*
56240bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
5625d522f475Smrg     * grabbing it, and *then* having us release ownership....
5626d522f475Smrg     */
5627d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
5628d522f475Smrg#ifdef ALLOWLOGGING
5629d522f475Smrg    if (screen->logging)
563020d2c4d2Smrg	CloseLog(xw);
5631d522f475Smrg#endif
5632d522f475Smrg
5633e39b573cSmrg    xtermPrintOnXError(xw, n);
5634e39b573cSmrg
5635d522f475Smrg#ifdef NO_LEAKS
5636d522f475Smrg    if (n == 0) {
56370bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
56380bd37d32Smrg
5639d522f475Smrg	TRACE(("Freeing memory leaks\n"));
5640d522f475Smrg
56410bd37d32Smrg	if (toplevel) {
56420bd37d32Smrg	    XtDestroyWidget(toplevel);
56430bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
56440bd37d32Smrg	}
56455104ee6eSmrg	sortedOpts(NULL, NULL, 0);
56460bd37d32Smrg	noleaks_charproc();
56470bd37d32Smrg	noleaks_ptydata();
5648894e0ac8Smrg#if OPT_GRAPHICS
56494419d26bSmrg	noleaks_graphics(dpy);
5650894e0ac8Smrg#endif
5651d522f475Smrg#if OPT_WIDE_CHARS
56520bd37d32Smrg	noleaks_CharacterClass();
5653d522f475Smrg#endif
56540bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
56550bd37d32Smrg	XtCloseDisplay(dpy);
56560bd37d32Smrg	XtDestroyApplicationContext(app_con);
56570bd37d32Smrg	xtermCloseSession();
56580bd37d32Smrg	TRACE(("closed display\n"));
56590bd37d32Smrg
566020d2c4d2Smrg	TRACE_CLOSE();
5661d522f475Smrg    }
5662d522f475Smrg#endif
5663d522f475Smrg
5664d522f475Smrg    exit(n);
5665d522f475Smrg}
5666d522f475Smrg
5667d522f475Smrg/* ARGSUSED */
5668d522f475Smrgstatic void
566920d2c4d2Smrgresize_termcap(XtermWidget xw)
5670d522f475Smrg{
567120d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
567220d2c4d2Smrg
5673d522f475Smrg#ifndef USE_SYSV_ENVVARS
567404b94745Smrg    if (!TEK4014_ACTIVE(xw) && newtc != NULL && *newtc) {
5675d522f475Smrg	TScreen *screen = TScreenOf(xw);
5676d522f475Smrg	char *ptr1, *ptr2;
5677d522f475Smrg	size_t i;
5678d522f475Smrg	int li_first = 0;
5679d522f475Smrg	char *temp;
5680d522f475Smrg	char oldtc[TERMCAP_SIZE];
5681d522f475Smrg
5682d522f475Smrg	strcpy(oldtc, newtc);
5683d522f475Smrg	TRACE(("resize %s\n", oldtc));
5684d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
5685d522f475Smrg	    strcat(oldtc, "co#80:");
5686d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
5687d522f475Smrg	}
5688d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
5689d522f475Smrg	    strcat(oldtc, "li#24:");
5690d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
5691d522f475Smrg	}
5692d522f475Smrg	if (ptr1 > ptr2) {
5693d522f475Smrg	    li_first++;
5694d522f475Smrg	    temp = ptr1;
5695d522f475Smrg	    ptr1 = ptr2;
5696d522f475Smrg	    ptr2 = temp;
5697d522f475Smrg	}
5698d522f475Smrg	ptr1 += 3;
5699d522f475Smrg	ptr2 += 3;
5700956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
570104b94745Smrg	if (i >= TERMCAP_SIZE - 10) {
570204b94745Smrg	    TRACE(("...insufficient space: %lu\n", (unsigned long) i));
570304b94745Smrg	    return;
570404b94745Smrg	}
5705d522f475Smrg	temp = newtc + i;
5706d522f475Smrg	sprintf(temp, "%d", (li_first
5707d522f475Smrg			     ? MaxRows(screen)
5708d522f475Smrg			     : MaxCols(screen)));
5709d522f475Smrg	temp += strlen(temp);
57105104ee6eSmrg	if ((ptr1 = strchr(ptr1, ':')) != NULL && (ptr1 < ptr2)) {
57110bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
57120bd37d32Smrg	    temp += i;
57130bd37d32Smrg	    sprintf(temp, "%d", (li_first
57140bd37d32Smrg				 ? MaxCols(screen)
57150bd37d32Smrg				 : MaxRows(screen)));
57165104ee6eSmrg	    if ((ptr2 = strchr(ptr2, ':')) != NULL) {
57170bd37d32Smrg		strcat(temp, ptr2);
57180bd37d32Smrg	    }
57190bd37d32Smrg	}
5720d522f475Smrg	TRACE(("   ==> %s\n", newtc));
5721d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
5722d522f475Smrg    }
5723d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5724d522f475Smrg}
5725d522f475Smrg
5726d522f475Smrg/*
5727d522f475Smrg * Does a non-blocking wait for a child process.  If the system
5728d522f475Smrg * doesn't support non-blocking wait, do nothing.
5729d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
5730d522f475Smrg */
5731d522f475Smrgint
5732d522f475Smrgnonblocking_wait(void)
5733d522f475Smrg{
5734d522f475Smrg#ifdef USE_POSIX_WAIT
5735d522f475Smrg    pid_t pid;
5736d522f475Smrg
5737d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5738d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5739d522f475Smrg    /* cannot do non-blocking wait */
5740d522f475Smrg    int pid = 0;
5741d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5742d522f475Smrg#if defined(Lynx)
5743d522f475Smrg    int status;
5744d522f475Smrg#else
5745d522f475Smrg    union wait status;
5746d522f475Smrg#endif
5747d522f475Smrg    int pid;
5748d522f475Smrg
5749d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5750d522f475Smrg#endif /* USE_POSIX_WAIT else */
5751d522f475Smrg    return pid;
5752d522f475Smrg}
5753d522f475Smrg
5754d522f475Smrg/* ARGSUSED */
57550bd37d32Smrgstatic void
5756d522f475Smrgreapchild(int n GCC_UNUSED)
5757d522f475Smrg{
5758d522f475Smrg    int olderrno = errno;
5759d522f475Smrg    int pid;
5760d522f475Smrg
57610bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
57620bd37d32Smrg
5763d522f475Smrg    pid = wait(NULL);
5764d522f475Smrg
5765d522f475Smrg#ifdef USE_SYSV_SIGNALS
5766d522f475Smrg    /* cannot re-enable signal before waiting for child
5767d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5768d522f475Smrg     */
5769d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5770d522f475Smrg#endif
5771d522f475Smrg
5772d522f475Smrg    do {
577320d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
57740bd37d32Smrg	    DEBUG_MSG("Exiting\n");
57752e4f8982Smrg	    if (hold_screen)
57762e4f8982Smrg		caught_intr = True;
57772e4f8982Smrg	    else
5778d522f475Smrg		need_cleanup = True;
5779d522f475Smrg	}
5780d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5781d522f475Smrg
5782d522f475Smrg    errno = olderrno;
5783d522f475Smrg}
5784d522f475Smrg
5785d522f475Smrgstatic void
578620d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5787d522f475Smrg{
5788d522f475Smrg    char *base = buf;
5789d522f475Smrg    char *first = base;
5790d522f475Smrg    int count = 0;
5791d522f475Smrg    size_t len = strlen(str);
5792d522f475Smrg
5793d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5794d522f475Smrg
5795d522f475Smrg    while (*buf != 0) {
5796d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5797d522f475Smrg	    while (*buf != 0) {
5798d522f475Smrg		if (*buf == '\\')
5799d522f475Smrg		    buf++;
5800d522f475Smrg		else if (*buf == ':')
5801d522f475Smrg		    break;
5802d522f475Smrg		if (*buf != 0)
5803d522f475Smrg		    buf++;
5804d522f475Smrg	    }
58050bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
58060bd37d32Smrg		;
58070bd37d32Smrg	    }
5808d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5809d522f475Smrg	    return;
5810d522f475Smrg	} else if (*buf == '\\') {
5811d522f475Smrg	    buf++;
5812d522f475Smrg	} else if (*buf == ':') {
5813d522f475Smrg	    first = buf;
5814d522f475Smrg	    count = 0;
5815d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5816d522f475Smrg	    count++;
5817d522f475Smrg	}
5818d522f475Smrg	if (*buf != 0)
5819d522f475Smrg	    buf++;
5820d522f475Smrg    }
5821d522f475Smrg    TRACE(("...cannot remove\n"));
5822d522f475Smrg}
5823d522f475Smrg
5824d522f475Smrg/*
5825d522f475Smrg * parse_tty_modes accepts lines of the following form:
5826d522f475Smrg *
5827d522f475Smrg *         [SETTING] ...
5828d522f475Smrg *
5829f2e35a3aSmrg * where setting consists of the words in the ttyModes[] array followed by a
5830f2e35a3aSmrg * character or ^char.
5831d522f475Smrg */
5832d522f475Smrgstatic int
5833f2e35a3aSmrgparse_tty_modes(char *s)
5834d522f475Smrg{
5835d522f475Smrg    int c;
5836f2e35a3aSmrg    Cardinal j, k;
5837d522f475Smrg    int count = 0;
5838f2e35a3aSmrg    Boolean found;
5839d522f475Smrg
5840d522f475Smrg    TRACE(("parse_tty_modes\n"));
5841a1f3da82Smrg    for (;;) {
5842d522f475Smrg	size_t len;
5843d522f475Smrg
5844f2e35a3aSmrg	while (*s && isspace(CharOf(*s))) {
5845d522f475Smrg	    s++;
5846f2e35a3aSmrg	}
5847f2e35a3aSmrg	if (!*s) {
5848d522f475Smrg	    return count;
5849f2e35a3aSmrg	}
5850d522f475Smrg
5851f2e35a3aSmrg	for (len = 0; s[len] && !isspace(CharOf(s[len])); ++len) {
5852f2e35a3aSmrg	    ;
5853f2e35a3aSmrg	}
5854f2e35a3aSmrg	found = False;
5855f2e35a3aSmrg	for (j = 0; j < XtNumber(ttyModes); ++j) {
5856f2e35a3aSmrg	    if (len == ttyModes[j].len
5857f2e35a3aSmrg		&& strncmp(s,
5858f2e35a3aSmrg			   ttyModes[j].name,
5859f2e35a3aSmrg			   ttyModes[j].len) == 0) {
5860f2e35a3aSmrg		found = True;
5861d522f475Smrg		break;
5862f2e35a3aSmrg	    }
5863d522f475Smrg	}
5864f2e35a3aSmrg	if (!found) {
5865d522f475Smrg	    return -1;
5866f2e35a3aSmrg	}
5867d522f475Smrg
5868f2e35a3aSmrg	s += ttyModes[j].len;
5869f2e35a3aSmrg	while (*s && isspace(CharOf(*s))) {
5870d522f475Smrg	    s++;
5871f2e35a3aSmrg	}
5872d522f475Smrg
5873f2e35a3aSmrg	/* check if this needs a parameter */
5874f2e35a3aSmrg	found = False;
5875f2e35a3aSmrg	for (k = 0, c = 0; k < XtNumber(ttyChars); ++k) {
5876f2e35a3aSmrg	    if ((int) j == ttyChars[k].myMode) {
5877f2e35a3aSmrg		if (ttyChars[k].sysMode < 0) {
5878f2e35a3aSmrg		    found = True;
5879f2e35a3aSmrg		    c = ttyChars[k].myDefault;
5880f2e35a3aSmrg		}
5881f2e35a3aSmrg		break;
5882f2e35a3aSmrg	    }
5883f2e35a3aSmrg	}
5884f2e35a3aSmrg
5885f2e35a3aSmrg	if (!found) {
5886f2e35a3aSmrg	    if (!*s
5887f2e35a3aSmrg		|| (c = decode_keyvalue(&s, False)) == -1) {
5888f2e35a3aSmrg		return -1;
5889f2e35a3aSmrg	    }
5890d522f475Smrg	}
5891f2e35a3aSmrg	ttyModes[j].value = c;
5892f2e35a3aSmrg	ttyModes[j].set = 1;
5893f2e35a3aSmrg	count++;
5894f2e35a3aSmrg	TRACE(("...parsed #%d: %s=%#x\n", count, ttyModes[j].name, c));
5895d522f475Smrg    }
5896d522f475Smrg}
5897d522f475Smrg
589804b94745Smrg#ifndef GetBytesAvailable
5899d522f475Smrgint
590004b94745SmrgGetBytesAvailable(Display *dpy)
5901d522f475Smrg{
590204b94745Smrg    int fd = ConnectionNumber(dpy);
590304b94745Smrg    int result;
5904d522f475Smrg#if defined(FIONREAD)
590504b94745Smrg    ioctl(fd, FIONREAD, (char *) &result);
5906d522f475Smrg#elif defined(__CYGWIN__)
5907d522f475Smrg    fd_set set;
590820d2c4d2Smrg    struct timeval select_timeout =
5909d522f475Smrg    {0, 0};
5910d522f475Smrg
5911d522f475Smrg    FD_ZERO(&set);
5912d522f475Smrg    FD_SET(fd, &set);
591304b94745Smrg    result = (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0) ? 1 : 0;
591404b94745Smrg#else
5915d522f475Smrg    struct pollfd pollfds[1];
5916d522f475Smrg
5917d522f475Smrg    pollfds[0].fd = fd;
5918d522f475Smrg    pollfds[0].events = POLLIN;
591904b94745Smrg    result = poll(pollfds, 1, 0);
5920d522f475Smrg#endif
592104b94745Smrg    return result;
5922d522f475Smrg}
59235104ee6eSmrg#endif /* !GetBytesAvailable */
5924d522f475Smrg
5925d522f475Smrg/* Utility function to try to hide system differences from
5926d522f475Smrg   everybody who used to call killpg() */
5927d522f475Smrg
5928d522f475Smrgint
5929d522f475Smrgkill_process_group(int pid, int sig)
5930d522f475Smrg{
5931d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5932d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5933d522f475Smrg    return kill(-pid, sig);
5934d522f475Smrg#else
5935d522f475Smrg    return killpg(pid, sig);
5936d522f475Smrg#endif
5937d522f475Smrg}
5938d522f475Smrg
5939d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
5940d522f475Smrg#include <sys/types.h>
5941d522f475Smrg#include <sys/proc_msg.h>
5942d522f475Smrg#include <sys/kernel.h>
5943d522f475Smrg#include <string.h>
5944d522f475Smrg#include <errno.h>
5945d522f475Smrg
5946d522f475Smrgstruct _proc_session ps;
5947d522f475Smrgstruct _proc_session_reply rps;
5948d522f475Smrg
5949d522f475Smrgint
5950d522f475Smrgqsetlogin(char *login, char *ttyname)
5951d522f475Smrg{
5952d522f475Smrg    int v = getsid(getpid());
5953d522f475Smrg
5954d522f475Smrg    memset(&ps, 0, sizeof(ps));
5955d522f475Smrg    memset(&rps, 0, sizeof(rps));
5956d522f475Smrg
5957d522f475Smrg    ps.type = _PROC_SESSION;
5958d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
5959d522f475Smrg    ps.sid = v;
5960d522f475Smrg    strcpy(ps.name, login);
5961d522f475Smrg
5962d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5963d522f475Smrg
5964d522f475Smrg    if (rps.status < 0)
5965d522f475Smrg	return (rps.status);
5966d522f475Smrg
5967d522f475Smrg    ps.type = _PROC_SESSION;
5968d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
5969d522f475Smrg    ps.sid = v;
5970d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
5971d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5972d522f475Smrg
5973d522f475Smrg    return (rps.status);
5974d522f475Smrg}
5975d522f475Smrg#endif
597601037d57Smrg
597701037d57Smrg#ifdef __minix
597801037d57Smrgint
597901037d57Smrgsetpgrp(void)
598001037d57Smrg{
598101037d57Smrg    return 0;
598201037d57Smrg}
598301037d57Smrg
598401037d57Smrgvoid
598501037d57Smrg_longjmp(jmp_buf _env, int _val)
598601037d57Smrg{
598701037d57Smrg    longjmp(_env, _val);
598801037d57Smrg}
598901037d57Smrg#endif
5990