main.c revision 01037d57
101037d57Smrg/* $XTermId: main.c,v 1.769 2015/04/10 00:33:25 tom Exp $ */
20bd37d32Smrg
30bd37d32Smrg/*
401037d57Smrg * Copyright 2002-2014,2015 by Thomas E. Dickey
50bd37d32Smrg *
60bd37d32Smrg *                         All Rights Reserved
70bd37d32Smrg *
80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90bd37d32Smrg * copy of this software and associated documentation files (the
100bd37d32Smrg * "Software"), to deal in the Software without restriction, including
110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish,
120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to
130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to
140bd37d32Smrg * the following conditions:
150bd37d32Smrg *
160bd37d32Smrg * The above copyright notice and this permission notice shall be included
170bd37d32Smrg * in all copies or substantial portions of the Software.
180bd37d32Smrg *
190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
260bd37d32Smrg *
270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright
280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the
290bd37d32Smrg * sale, use or other dealings in this Software without prior written
300bd37d32Smrg * authorization.
310bd37d32Smrg *
320bd37d32Smrg * Copyright 1987, 1988  The Open Group
330bd37d32Smrg *
340bd37d32Smrg * Permission to use, copy, modify, distribute, and sell this software and its
350bd37d32Smrg * documentation for any purpose is hereby granted without fee, provided that
360bd37d32Smrg * the above copyright notice appear in all copies and that both that
370bd37d32Smrg * copyright notice and this permission notice appear in supporting
380bd37d32Smrg * documentation.
390bd37d32Smrg *
400bd37d32Smrg * The above copyright notice and this permission notice shall be included in
410bd37d32Smrg * all copies or substantial portions of the Software.
420bd37d32Smrg *
430bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
440bd37d32Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
450bd37d32Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
460bd37d32Smrg * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
470bd37d32Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
480bd37d32Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
490bd37d32Smrg *
500bd37d32Smrg * Except as contained in this notice, the name of The Open Group shall not be
510bd37d32Smrg * used in advertising or otherwise to promote the sale, use or other dealings
520bd37d32Smrg * in this Software without prior written authorization from The Open Group.
530bd37d32Smrg *
540bd37d32Smrg * Copyright 1987, 1988 by Digital Equipment Corporation, Maynard.
550bd37d32Smrg *
560bd37d32Smrg *                         All Rights Reserved
570bd37d32Smrg *
580bd37d32Smrg * Permission to use, copy, modify, and distribute this software and its
590bd37d32Smrg * documentation for any purpose and without fee is hereby granted,
600bd37d32Smrg * provided that the above copyright notice appear in all copies and that
610bd37d32Smrg * both that copyright notice and this permission notice appear in
620bd37d32Smrg * supporting documentation, and that the name of Digital not be used in
630bd37d32Smrg * advertising or publicity pertaining to distribution of the software
640bd37d32Smrg * without specific, written prior permission.
650bd37d32Smrg *
660bd37d32Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
670bd37d32Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
680bd37d32Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
690bd37d32Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
700bd37d32Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
710bd37d32Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
720bd37d32Smrg * SOFTWARE.
730bd37d32Smrg */
74d522f475Smrg
75d522f475Smrg/*
76d522f475Smrg *				 W A R N I N G
77d522f475Smrg *
78d522f475Smrg * If you think you know what all of this code is doing, you are
79d522f475Smrg * probably very mistaken.  There be serious and nasty dragons here.
80d522f475Smrg *
81d522f475Smrg * This client is *not* to be taken as an example of how to write X
82d522f475Smrg * Toolkit applications.  It is in need of a substantial rewrite,
83d522f475Smrg * ideally to create a generic tty widget with several different parsing
84d522f475Smrg * widgets so that you can plug 'em together any way you want.  Don't
85d522f475Smrg * hold your breath, though....
86d522f475Smrg */
87d522f475Smrg
88d522f475Smrg/* main.c */
89d522f475Smrg
90d522f475Smrg#define RES_OFFSET(field)	XtOffsetOf(XTERM_RESOURCE, field)
91d522f475Smrg
92d522f475Smrg#include <xterm.h>
930bd37d32Smrg#include <version.h>
94894e0ac8Smrg#include <graphics.h>
95d522f475Smrg
96d522f475Smrg#include <X11/cursorfont.h>
97d522f475Smrg#include <X11/Xlocale.h>
98d522f475Smrg
99d522f475Smrg#if OPT_TOOLBAR
100d522f475Smrg
101d522f475Smrg#if defined(HAVE_LIB_XAW)
102d522f475Smrg#include <X11/Xaw/Form.h>
103d522f475Smrg#elif defined(HAVE_LIB_XAW3D)
104d522f475Smrg#include <X11/Xaw3d/Form.h>
10501037d57Smrg#elif defined(HAVE_LIB_XAW3DXFT)
10601037d57Smrg#include <X11/Xaw3dxft/Form.h>
107d522f475Smrg#elif defined(HAVE_LIB_NEXTAW)
108d522f475Smrg#include <X11/neXtaw/Form.h>
109d522f475Smrg#elif defined(HAVE_LIB_XAWPLUS)
110d522f475Smrg#include <X11/XawPlus/Form.h>
111d522f475Smrg#endif
112d522f475Smrg
113d522f475Smrg#endif /* OPT_TOOLBAR */
114d522f475Smrg
115d522f475Smrg#include <pwd.h>
116d522f475Smrg#include <ctype.h>
117d522f475Smrg
118d522f475Smrg#include <data.h>
119d522f475Smrg#include <error.h>
120d522f475Smrg#include <menu.h>
121d522f475Smrg#include <main.h>
122d522f475Smrg#include <xstrings.h>
123d522f475Smrg#include <xtermcap.h>
124d522f475Smrg#include <xterm_io.h>
125d522f475Smrg
126d522f475Smrg#if OPT_WIDE_CHARS
127d522f475Smrg#include <charclass.h>
128d522f475Smrg#endif
129d522f475Smrg
130d522f475Smrg#ifdef __osf__
131d522f475Smrg#define USE_SYSV_SIGNALS
132d522f475Smrg#define WTMP
133d522f475Smrg#include <pty.h>		/* openpty() */
134d522f475Smrg#endif
135d522f475Smrg
136d522f475Smrg#ifdef __sgi
137d522f475Smrg#include <grp.h>		/* initgroups() */
138d522f475Smrg#endif
139d522f475Smrg
1400bd37d32Smrgstatic void Syntax(char *) GCC_NORETURN;
1410bd37d32Smrgstatic void HsSysError(int) GCC_NORETURN;
142d522f475Smrg
143d522f475Smrg#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE)
144d522f475Smrg#define USE_POSIX_SIGNALS
145d522f475Smrg#endif
146d522f475Smrg
147d522f475Smrg#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
148d522f475Smrg/* older SYSV systems cannot ignore SIGHUP.
149d522f475Smrg   Shell hangs, or you get extra shells, or something like that */
150d522f475Smrg#define USE_SYSV_SIGHUP
151d522f475Smrg#endif
152d522f475Smrg
153d522f475Smrg#if defined(sony) && defined(bsd43) && !defined(KANJI)
154d522f475Smrg#define KANJI
155d522f475Smrg#endif
156d522f475Smrg
157d522f475Smrg#ifdef linux
158d522f475Smrg#define USE_SYSV_PGRP
159d522f475Smrg#define USE_SYSV_SIGNALS
160d522f475Smrg#define WTMP
161d522f475Smrg#ifdef __GLIBC__
162d522f475Smrg#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
163d522f475Smrg#include <pty.h>
164d522f475Smrg#endif
165d522f475Smrg#endif
166d522f475Smrg#endif
167d522f475Smrg
168d522f475Smrg#ifdef __MVS__
169d522f475Smrg#define USE_SYSV_PGRP
170d522f475Smrg#define USE_SYSV_SIGNALS
171d522f475Smrg#endif
172d522f475Smrg
173d522f475Smrg#ifdef __CYGWIN__
174d522f475Smrg#define WTMP
175d522f475Smrg#endif
176d522f475Smrg
177d522f475Smrg#ifdef __SCO__
178d522f475Smrg#ifndef _SVID3
179d522f475Smrg#define _SVID3
180d522f475Smrg#endif
181d522f475Smrg#endif
182d522f475Smrg
183d522f475Smrg#if defined(__GLIBC__) && !defined(linux)
184d522f475Smrg#define USE_SYSV_PGRP
185d522f475Smrg#define WTMP
186d522f475Smrg#endif
187d522f475Smrg
188d522f475Smrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID)
189d522f475Smrg#include <grp.h>
190d522f475Smrg#endif
191d522f475Smrg
192d522f475Smrg#ifndef TTY_GROUP_NAME
193d522f475Smrg#define TTY_GROUP_NAME "tty"
194d522f475Smrg#endif
195d522f475Smrg
196d522f475Smrg#include <sys/stat.h>
197d522f475Smrg
198d522f475Smrg#ifdef Lynx
199d522f475Smrg#ifndef BSDLY
200d522f475Smrg#define BSDLY	0
201d522f475Smrg#endif
202d522f475Smrg#ifndef VTDLY
203d522f475Smrg#define VTDLY	0
204d522f475Smrg#endif
205d522f475Smrg#ifndef FFDLY
206d522f475Smrg#define FFDLY	0
207d522f475Smrg#endif
208d522f475Smrg#endif
209d522f475Smrg
210d522f475Smrg#ifdef SYSV			/* { */
211d522f475Smrg
212d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
213d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
214d522f475Smrg#include <poll.h>		/* for POLLIN */
215d522f475Smrg#endif /* USE_USG_PTYS */
216d522f475Smrg
217d522f475Smrg#define USE_SYSV_SIGNALS
218d522f475Smrg#define	USE_SYSV_PGRP
219d522f475Smrg
220d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
221d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
222d522f475Smrg#endif
223d522f475Smrg
224d522f475Smrg/*
225d522f475Smrg * now get system-specific includes
226d522f475Smrg */
227d522f475Smrg#ifdef macII
228d522f475Smrg#include <sys/ttychars.h>
229d522f475Smrg#undef USE_SYSV_ENVVARS
230d522f475Smrg#undef FIOCLEX
231d522f475Smrg#undef FIONCLEX
232d522f475Smrg#define setpgrp2 setpgrp
233d522f475Smrg#include <sgtty.h>
234d522f475Smrg#include <sys/resource.h>
235d522f475Smrg#endif
236d522f475Smrg
237d522f475Smrg#ifdef __hpux
238d522f475Smrg#include <sys/ptyio.h>
239d522f475Smrg#endif /* __hpux */
240d522f475Smrg
241d522f475Smrg#ifdef __osf__
242d522f475Smrg#undef  USE_SYSV_PGRP
243d522f475Smrg#define setpgrp setpgid
244d522f475Smrg#endif
245d522f475Smrg
246d522f475Smrg#ifdef __sgi
247d522f475Smrg#include <sys/sysmacros.h>
248d522f475Smrg#endif /* __sgi */
249d522f475Smrg
250d522f475Smrg#ifdef sun
251d522f475Smrg#include <sys/strredir.h>
252d522f475Smrg#endif
253d522f475Smrg
254e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
255d522f475Smrg
256d522f475Smrg#ifdef __QNX__
257d522f475Smrg
258d522f475Smrg#ifndef __QNXNTO__
259d522f475Smrg#define ttyslot() 1
260d522f475Smrg#else
261d522f475Smrg#define USE_SYSV_PGRP
262d522f475Smrgextern __inline__
263d522f475Smrgint
264d522f475Smrgttyslot(void)
265d522f475Smrg{
266d522f475Smrg    return 1;			/* yuk */
267d522f475Smrg}
268d522f475Smrg#endif
269d522f475Smrg
270d522f475Smrg#else
271d522f475Smrg
272d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
273d522f475Smrg#define setpgrp setpgid
274d522f475Smrg#endif
275d522f475Smrg
276d522f475Smrg#ifndef linux
277d522f475Smrg#ifndef VMS
278d522f475Smrg#ifndef USE_POSIX_TERMIOS
279d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
280d522f475Smrg#include <sgtty.h>
281d522f475Smrg#endif
282d522f475Smrg#endif /* USE_POSIX_TERMIOS */
283d522f475Smrg#ifdef Lynx
284d522f475Smrg#include <resource.h>
285d522f475Smrg#else
286d522f475Smrg#include <sys/resource.h>
287d522f475Smrg#endif
288d522f475Smrg#endif /* !VMS */
289d522f475Smrg#endif /* !linux */
290d522f475Smrg
291d522f475Smrg#endif /* __QNX__ */
292d522f475Smrg
293d522f475Smrg#endif /* } !SYSV */
294d522f475Smrg
295d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
296d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
297d522f475Smrg#ifndef NOFILE
298d522f475Smrg#define NOFILE OPEN_MAX
299d522f475Smrg#endif
300d522f475Smrg#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
301d522f475Smrg#include <sys/param.h>		/* for NOFILE */
302d522f475Smrg#endif
303d522f475Smrg
304d522f475Smrg#if defined(BSD) && (BSD >= 199103)
305d522f475Smrg#define WTMP
306d522f475Smrg#endif
307d522f475Smrg
308d522f475Smrg#include <stdio.h>
309d522f475Smrg
310d522f475Smrg#ifdef __hpux
311d522f475Smrg#include <sys/utsname.h>
312d522f475Smrg#endif /* __hpux */
313d522f475Smrg
314d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
315d522f475Smrg#define ttyslot() 1
316d522f475Smrg#endif /* apollo */
317d522f475Smrg
318d522f475Smrg#if defined(UTMPX_FOR_UTMP)
319d522f475Smrg#define UTMP_STR utmpx
320d522f475Smrg#else
321d522f475Smrg#define UTMP_STR utmp
322d522f475Smrg#endif
323d522f475Smrg
324d522f475Smrg#if defined(USE_UTEMPTER)
325d522f475Smrg#include <utempter.h>
326d522f475Smrg#endif
327d522f475Smrg
328d522f475Smrg#if defined(UTMPX_FOR_UTMP)
329d522f475Smrg
330d522f475Smrg#include <utmpx.h>
331d522f475Smrg
332d522f475Smrg#define call_endutent  endutxent
333d522f475Smrg#define call_getutid   getutxid
334d522f475Smrg#define call_pututline pututxline
335d522f475Smrg#define call_setutent  setutxent
336d522f475Smrg#define call_updwtmp   updwtmpx
337d522f475Smrg
338d522f475Smrg#elif defined(HAVE_UTMP)
339d522f475Smrg
340d522f475Smrg#include <utmp.h>
341d522f475Smrg
342d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
343d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
344d522f475Smrg#endif
345d522f475Smrg
346d522f475Smrg#define call_endutent  endutent
347d522f475Smrg#define call_getutid   getutid
348d522f475Smrg#define call_pututline pututline
349d522f475Smrg#define call_setutent  setutent
350d522f475Smrg#define call_updwtmp   updwtmp
351d522f475Smrg
352d522f475Smrg#endif
353d522f475Smrg
354d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
355d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
356d522f475Smrg#endif
357d522f475Smrg
358d522f475Smrg#ifndef USE_LASTLOGX
359d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
360d522f475Smrg#define USE_LASTLOGX 1
361d522f475Smrg#endif
362d522f475Smrg#endif
363d522f475Smrg
364d522f475Smrg#ifdef  PUCC_PTYD
365d522f475Smrg#include <local/openpty.h>
366d522f475Smrg#endif /* PUCC_PTYD */
367d522f475Smrg
368d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
369d522f475Smrg#include <util.h>		/* openpty() */
370d522f475Smrg#endif
371d522f475Smrg
372956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
373d522f475Smrg#include <libutil.h>		/* openpty() */
374d522f475Smrg#endif
375d522f475Smrg
376d522f475Smrg#if !defined(UTMP_FILENAME)
377d522f475Smrg#if defined(UTMP_FILE)
378d522f475Smrg#define UTMP_FILENAME UTMP_FILE
379d522f475Smrg#elif defined(_PATH_UTMP)
380d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
381d522f475Smrg#else
382d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
383d522f475Smrg#endif
384d522f475Smrg#endif
385d522f475Smrg
386d522f475Smrg#ifndef LASTLOG_FILENAME
387d522f475Smrg#ifdef _PATH_LASTLOG
388d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
389d522f475Smrg#else
390d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
391d522f475Smrg#endif
392d522f475Smrg#endif
393d522f475Smrg
394d522f475Smrg#if !defined(WTMP_FILENAME)
395d522f475Smrg#if defined(WTMP_FILE)
396d522f475Smrg#define WTMP_FILENAME WTMP_FILE
397d522f475Smrg#elif defined(_PATH_WTMP)
398d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
399d522f475Smrg#elif defined(SYSV)
400d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
401d522f475Smrg#else
402d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
403d522f475Smrg#endif
404d522f475Smrg#endif
405d522f475Smrg
406d522f475Smrg#include <signal.h>
407d522f475Smrg
408d522f475Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
409d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
410d522f475Smrg#endif
411d522f475Smrg
412d522f475Smrg#ifdef SIGTSTP
413d522f475Smrg#include <sys/wait.h>
414d522f475Smrg#endif
415d522f475Smrg
416d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
417d522f475Smrg#undef ECHOKE
418d522f475Smrg#undef ECHOCTL
419d522f475Smrg#endif
420d522f475Smrg
421d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
422d522f475Smrg#include <sys/ttydefaults.h>
423d522f475Smrg#endif
424d522f475Smrg
425d522f475Smrg#ifdef X_NOT_POSIX
426d522f475Smrgextern long lseek();
427d522f475Smrg#if defined(USG) || defined(SVR4)
428d522f475Smrgextern unsigned sleep();
429d522f475Smrg#else
430d522f475Smrgextern void sleep();
431d522f475Smrg#endif
432d522f475Smrgextern char *ttyname();
433d522f475Smrg#endif
434d522f475Smrg
435d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
436d522f475Smrgextern char *ptsname(int);
437d522f475Smrg#endif
438d522f475Smrg
439d522f475Smrg#ifndef VMS
4400bd37d32Smrgstatic void reapchild(int /* n */ );
441d522f475Smrgstatic int spawnXTerm(XtermWidget /* xw */ );
44220d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
443d522f475Smrg#ifdef USE_PTY_SEARCH
44420d2c4d2Smrgstatic int pty_search(int * /* pty */ );
445d522f475Smrg#endif
446d522f475Smrg#endif /* ! VMS */
447d522f475Smrg
448d522f475Smrgstatic int get_pty(int *pty, char *from);
44920d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
450e0a2b6dfSmrgstatic void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
451d522f475Smrg
452d522f475Smrgstatic Bool added_utmp_entry = False;
453d522f475Smrg
454d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
455d522f475Smrgstatic uid_t save_euid;
456d522f475Smrgstatic gid_t save_egid;
457d522f475Smrg#endif
458d522f475Smrg
459d522f475Smrgstatic uid_t save_ruid;
460d522f475Smrgstatic gid_t save_rgid;
461d522f475Smrg
462d522f475Smrg#if defined(USE_UTMP_SETGID)
463d522f475Smrgstatic int really_get_pty(int *pty, char *from);
464d522f475Smrg#endif
465d522f475Smrg
466d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
467d522f475Smrgstatic Bool xterm_exiting = False;
468d522f475Smrg#endif
469d522f475Smrg
470d522f475Smrgstatic char *explicit_shname = NULL;
471d522f475Smrg
472d522f475Smrg/*
473d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
474d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
475d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
476d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
477d522f475Smrg** SEGV.
478d522f475Smrg*/
479d522f475Smrgstatic char **command_to_exec = NULL;
480d522f475Smrg
481d522f475Smrg#if OPT_LUIT_PROG
482d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
4830bd37d32Smrgstatic unsigned command_length_with_luit = 0;
484d522f475Smrg#endif
485d522f475Smrg
486d522f475Smrg#define TERMCAP_ERASE "kb"
487d522f475Smrg#define VAL_INITIAL_ERASE A2E(8)
488d522f475Smrg
489d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
490d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
491d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
492d522f475Smrg * about padding generally store the code in a short, which does not have
493d522f475Smrg * enough bits for the extended values.
494d522f475Smrg */
495d522f475Smrg#ifdef B38400			/* everyone should define this */
496d522f475Smrg#define VAL_LINE_SPEED B38400
497d522f475Smrg#else /* ...but xterm's used this for a long time */
498d522f475Smrg#define VAL_LINE_SPEED B9600
499d522f475Smrg#endif
500d522f475Smrg
501d522f475Smrg/*
502d522f475Smrg * Allow use of system default characters if defined and reasonable.
503d522f475Smrg * These are based on the BSD ttydefaults.h
504d522f475Smrg */
505d522f475Smrg#ifndef CBRK
506d522f475Smrg#define CBRK     0xff		/* was 0 */
507d522f475Smrg#endif
508d522f475Smrg#ifndef CDISCARD
509d522f475Smrg#define CDISCARD CONTROL('O')
510d522f475Smrg#endif
511d522f475Smrg#ifndef CDSUSP
512d522f475Smrg#define CDSUSP   CONTROL('Y')
513d522f475Smrg#endif
514d522f475Smrg#ifndef CEOF
515d522f475Smrg#define CEOF     CONTROL('D')
516d522f475Smrg#endif
517d522f475Smrg#ifndef CEOL
518d522f475Smrg#define CEOL	 0xff		/* was 0 */
519d522f475Smrg#endif
520d522f475Smrg#ifndef CERASE
521d522f475Smrg#define CERASE   0177
522d522f475Smrg#endif
523d522f475Smrg#ifndef CERASE2
524d522f475Smrg#define	CERASE2  CONTROL('H')
525d522f475Smrg#endif
526d522f475Smrg#ifndef CFLUSH
527d522f475Smrg#define CFLUSH   CONTROL('O')
528d522f475Smrg#endif
529d522f475Smrg#ifndef CINTR
530d522f475Smrg#define CINTR    CONTROL('C')
531d522f475Smrg#endif
532d522f475Smrg#ifndef CKILL
533d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
534d522f475Smrg#endif
535d522f475Smrg#ifndef CLNEXT
536d522f475Smrg#define CLNEXT   CONTROL('V')
537d522f475Smrg#endif
538d522f475Smrg#ifndef CNUL
539d522f475Smrg#define CNUL     0
540d522f475Smrg#endif
541d522f475Smrg#ifndef CQUIT
542d522f475Smrg#define CQUIT    CONTROL('\\')
543d522f475Smrg#endif
544d522f475Smrg#ifndef CRPRNT
545d522f475Smrg#define CRPRNT   CONTROL('R')
546d522f475Smrg#endif
547d522f475Smrg#ifndef CREPRINT
548d522f475Smrg#define CREPRINT CRPRNT
549d522f475Smrg#endif
550d522f475Smrg#ifndef CSTART
551d522f475Smrg#define CSTART   CONTROL('Q')
552d522f475Smrg#endif
553d522f475Smrg#ifndef CSTATUS
554d522f475Smrg#define	CSTATUS  CONTROL('T')
555d522f475Smrg#endif
556d522f475Smrg#ifndef CSTOP
557d522f475Smrg#define CSTOP    CONTROL('S')
558d522f475Smrg#endif
559d522f475Smrg#ifndef CSUSP
560d522f475Smrg#define CSUSP    CONTROL('Z')
561d522f475Smrg#endif
562d522f475Smrg#ifndef CSWTCH
563d522f475Smrg#define CSWTCH   0
564d522f475Smrg#endif
565d522f475Smrg#ifndef CWERASE
566d522f475Smrg#define CWERASE  CONTROL('W')
567d522f475Smrg#endif
568d522f475Smrg
569d522f475Smrg#ifdef USE_ANY_SYSV_TERMIO
570d522f475Smrg#define TERMIO_STRUCT struct termio
571d522f475Smrg#define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
572d522f475Smrg#define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
573d522f475Smrg#define ttyFlush(fd)          ioctl(fd, TCFLSH, 1)
574d522f475Smrg#elif defined(USE_POSIX_TERMIOS)
575d522f475Smrg#define TERMIO_STRUCT struct termios
576d522f475Smrg#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
577d522f475Smrg#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
578d522f475Smrg#define ttyFlush(fd)          tcflush(fd, TCOFLUSH)
579d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO */
580d522f475Smrg
581d522f475Smrg#ifndef VMS
582d522f475Smrg#ifdef TERMIO_STRUCT
583d522f475Smrg/* The following structures are initialized in main() in order
584d522f475Smrg** to eliminate any assumptions about the internal order of their
585d522f475Smrg** contents.
586d522f475Smrg*/
587d522f475Smrgstatic TERMIO_STRUCT d_tio;
588d522f475Smrg
589d522f475Smrg#ifdef HAS_LTCHARS
590d522f475Smrgstatic struct ltchars d_ltc;
591d522f475Smrg#endif /* HAS_LTCHARS */
592d522f475Smrg
593d522f475Smrg#ifdef TIOCLSET
594d522f475Smrgstatic unsigned int d_lmode;
595d522f475Smrg#endif /* TIOCLSET */
596d522f475Smrg
597d522f475Smrg#else /* !TERMIO_STRUCT */
598d522f475Smrgstatic struct sgttyb d_sg =
599d522f475Smrg{
600d522f475Smrg    0, 0, 0177, CKILL, (EVENP | ODDP | ECHO | XTABS | CRMOD)
601d522f475Smrg};
602d522f475Smrgstatic struct tchars d_tc =
603d522f475Smrg{
604d522f475Smrg    CINTR, CQUIT, CSTART,
605d522f475Smrg    CSTOP, CEOF, CBRK
606d522f475Smrg};
607d522f475Smrgstatic struct ltchars d_ltc =
608d522f475Smrg{
609d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
610d522f475Smrg    CFLUSH, CWERASE, CLNEXT
611d522f475Smrg};
612d522f475Smrgstatic int d_disipline = NTTYDISC;
613d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
614d522f475Smrg#ifdef sony
615d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
616d522f475Smrgstatic struct jtchars d_jtc =
617d522f475Smrg{
618d522f475Smrg    'J', 'B'
619d522f475Smrg};
620d522f475Smrg#endif /* sony */
621d522f475Smrg#endif /* TERMIO_STRUCT */
622d522f475Smrg#endif /* ! VMS */
623d522f475Smrg
624d522f475Smrg/*
625d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
626d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
627d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
628d522f475Smrg */
629d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
630d522f475Smrgstatic Boolean override_tty_modes = False;
631d522f475Smrg/* *INDENT-OFF* */
632d522f475Smrgstatic struct _xttymodes {
63320d2c4d2Smrg    const char *name;
634d522f475Smrg    size_t len;
635d522f475Smrg    int set;
636d522f475Smrg    int value;
637d522f475Smrg} ttymodelist[] = {
638d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
639d522f475Smrg#define XTTYMODE_intr	0
640d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
641d522f475Smrg#define XTTYMODE_quit	1
642d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
643d522f475Smrg#define XTTYMODE_erase	2
644d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
645d522f475Smrg#define XTTYMODE_kill	3
646d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
647d522f475Smrg#define XTTYMODE_eof	4
648d522f475Smrg    TTYMODE("eol"),		/* VEOL */
649d522f475Smrg#define XTTYMODE_eol	5
650d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
651d522f475Smrg#define XTTYMODE_swtch	6
652d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
653d522f475Smrg#define XTTYMODE_start	7
654d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
655d522f475Smrg#define XTTYMODE_stop	8
656d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
657d522f475Smrg#define XTTYMODE_brk	9
658d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
659d522f475Smrg#define XTTYMODE_susp	10
660d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
661d522f475Smrg#define XTTYMODE_dsusp	11
662d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
663d522f475Smrg#define XTTYMODE_rprnt	12
664d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
665d522f475Smrg#define XTTYMODE_flush	13
666d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
667d522f475Smrg#define XTTYMODE_weras	14
668d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
669d522f475Smrg#define XTTYMODE_lnext	15
670d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
671d522f475Smrg#define XTTYMODE_status	16
672d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
673d522f475Smrg#define XTTYMODE_erase2	17
674d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
675d522f475Smrg#define XTTYMODE_eol2	18
676d522f475Smrg    { NULL,	0, 0, '\0' },	/* end of data */
677d522f475Smrg};
678d522f475Smrg
679d522f475Smrg#define validTtyChar(data, n) \
680d522f475Smrg	    (known_ttyChars[n].sysMode >= 0 && \
681d522f475Smrg	     known_ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
682d522f475Smrg
683d522f475Smrgstatic const struct {
684d522f475Smrg    int sysMode;
685d522f475Smrg    int myMode;
686d522f475Smrg    int myDefault;
687d522f475Smrg} known_ttyChars[] = {
688d522f475Smrg#ifdef VINTR
689d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
690d522f475Smrg#endif
691d522f475Smrg#ifdef VQUIT
692d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
693d522f475Smrg#endif
694d522f475Smrg#ifdef VERASE
695d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
696d522f475Smrg#endif
697d522f475Smrg#ifdef VKILL
698d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
699d522f475Smrg#endif
700d522f475Smrg#ifdef VEOF
701d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
702d522f475Smrg#endif
703d522f475Smrg#ifdef VEOL
704d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
705d522f475Smrg#endif
706d522f475Smrg#ifdef VSWTCH
707d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
708d522f475Smrg#endif
709d522f475Smrg#ifdef VSTART
710d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
711d522f475Smrg#endif
712d522f475Smrg#ifdef VSTOP
713d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
714d522f475Smrg#endif
715d522f475Smrg#ifdef VSUSP
716d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
717d522f475Smrg#endif
718d522f475Smrg#ifdef VDSUSP
719d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
720d522f475Smrg#endif
721d522f475Smrg#ifdef VREPRINT
722d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
723d522f475Smrg#endif
724d522f475Smrg#ifdef VDISCARD
725d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
726d522f475Smrg#endif
727d522f475Smrg#ifdef VWERASE
728d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
729d522f475Smrg#endif
730d522f475Smrg#ifdef VLNEXT
731d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
732d522f475Smrg#endif
733d522f475Smrg#ifdef VSTATUS
734d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
735d522f475Smrg#endif
736d522f475Smrg#ifdef VERASE2
737d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
738d522f475Smrg#endif
739d522f475Smrg#ifdef VEOL2
740d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
741d522f475Smrg#endif
742d522f475Smrg};
743d522f475Smrg/* *INDENT-ON* */
744d522f475Smrg
7450bd37d32Smrg#define TMODE(ind,var) if (ttymodelist[ind].set) var = (cc_t) ttymodelist[ind].value
746d522f475Smrg
747d522f475Smrgstatic int parse_tty_modes(char *s, struct _xttymodes *modelist);
748d522f475Smrg
749d522f475Smrg#ifndef USE_UTEMPTER
750d522f475Smrg#ifdef USE_SYSV_UTMP
751d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
752d522f475Smrgextern struct utmp *getutid();
753d522f475Smrg#endif /* AIXV3 */
754d522f475Smrg
755d522f475Smrg#else /* not USE_SYSV_UTMP */
756d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
757d522f475Smrg#endif /* USE_SYSV_UTMP */
758d522f475Smrg
759d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
760d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
761d522f475Smrg#else
762d522f475Smrg#undef USE_LASTLOG
763d522f475Smrg#endif
764d522f475Smrg
765d522f475Smrg#ifdef WTMP
766d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
767d522f475Smrg#endif
768d522f475Smrg#endif /* !USE_UTEMPTER */
769d522f475Smrg
770d522f475Smrg/*
771d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
772d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
773d522f475Smrg * WTMP and USE_LASTLOG.
774d522f475Smrg */
775d522f475Smrg#ifdef USE_LOGIN_DASH_P
776d522f475Smrg#ifndef LOGIN_FILENAME
777d522f475Smrg#define LOGIN_FILENAME "/bin/login"
778d522f475Smrg#endif
779d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
780d522f475Smrg#endif
781d522f475Smrg
78201037d57Smrgstatic char noPassedPty[2];
78301037d57Smrgstatic char *passedPty = noPassedPty;	/* name if pty if slave */
784d522f475Smrg
785d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
786d522f475Smrgstatic int Console;
787d522f475Smrg#include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
788d522f475Smrg#define MIT_CONSOLE_LEN	12
789d522f475Smrg#define MIT_CONSOLE "MIT_CONSOLE_"
790d522f475Smrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
791d522f475Smrgstatic Atom mit_console;
792d522f475Smrg#endif /* TIOCCONS */
793d522f475Smrg
794d522f475Smrg#ifndef USE_SYSV_UTMP
795d522f475Smrgstatic int tslot;
796d522f475Smrg#endif /* USE_SYSV_UTMP */
797d522f475Smrgstatic sigjmp_buf env;
798d522f475Smrg
799d522f475Smrg#define SetUtmpHost(dst, screen) \
800d522f475Smrg	{ \
801d522f475Smrg	    char host[sizeof(dst) + 1]; \
802d522f475Smrg	    strncpy(host, DisplayString(screen->display), sizeof(host)); \
803d522f475Smrg	    TRACE(("DisplayString(%s)\n", host)); \
804d522f475Smrg	    if (!resource.utmpDisplayId) { \
805d522f475Smrg		char *endptr = strrchr(host, ':'); \
806d522f475Smrg		if (endptr) { \
807d522f475Smrg		    TRACE(("trimming display-id '%s'\n", host)); \
808d522f475Smrg		    *endptr = '\0'; \
809d522f475Smrg		} \
810d522f475Smrg	    } \
811894e0ac8Smrg	    copy_filled(dst, host, sizeof(dst)); \
812d522f475Smrg	}
813d522f475Smrg
814d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
815d522f475Smrg#  define SetUtmpSysLen(utmp) 			   \
816d522f475Smrg	{ \
817d522f475Smrg	    utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
818d522f475Smrg	    utmp.ut_syslen = strlen(utmp.ut_host) + 1; \
819d522f475Smrg	}
820d522f475Smrg#endif
821d522f475Smrg
822d522f475Smrg/* used by VT (charproc.c) */
823d522f475Smrg
824d522f475Smrgstatic XtResource application_resources[] =
825d522f475Smrg{
826d522f475Smrg    Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
827d522f475Smrg    Sres(XtNtitle, XtCTitle, title, NULL),
8280bd37d32Smrg    Sres(XtNiconHint, XtCIconHint, icon_hint, NULL),
829d522f475Smrg    Sres(XtNiconName, XtCIconName, icon_name, NULL),
830d522f475Smrg    Sres("termName", "TermName", term_name, NULL),
831d522f475Smrg    Sres("ttyModes", "TtyModes", tty_modes, NULL),
832d522f475Smrg    Bres("hold", "Hold", hold_screen, False),
833d522f475Smrg    Bres("utmpInhibit", "UtmpInhibit", utmpInhibit, False),
834d522f475Smrg    Bres("utmpDisplayId", "UtmpDisplayId", utmpDisplayId, True),
835d522f475Smrg    Bres("messages", "Messages", messages, True),
836d522f475Smrg    Ires("minBufSize", "MinBufSize", minBufSize, 4096),
837d522f475Smrg    Ires("maxBufSize", "MaxBufSize", maxBufSize, 32768),
83820d2c4d2Smrg    Sres("menuLocale", "MenuLocale", menuLocale, DEF_MENU_LOCALE),
839a1f3da82Smrg    Sres("omitTranslation", "OmitTranslation", omitTranslation, NULL),
840d522f475Smrg    Sres("keyboardType", "KeyboardType", keyboardType, "unknown"),
841e39b573cSmrg#if OPT_PRINT_ON_EXIT
842e39b573cSmrg    Ires("printModeImmediate", "PrintModeImmediate", printModeNow, 0),
843e39b573cSmrg    Ires("printOptsImmediate", "PrintOptsImmediate", printOptsNow, 9),
844e39b573cSmrg    Sres("printFileImmediate", "PrintFileImmediate", printFileNow, NULL),
845e39b573cSmrg    Ires("printModeOnXError", "PrintModeOnXError", printModeOnXError, 0),
846e39b573cSmrg    Ires("printOptsOnXError", "PrintOptsOnXError", printOptsOnXError, 9),
847e39b573cSmrg    Sres("printFileOnXError", "PrintFileOnXError", printFileOnXError, NULL),
848e39b573cSmrg#endif
849d522f475Smrg#if OPT_SUNPC_KBD
850d522f475Smrg    Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
851d522f475Smrg#endif
852d522f475Smrg#if OPT_HP_FUNC_KEYS
853d522f475Smrg    Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
854d522f475Smrg#endif
855d522f475Smrg#if OPT_SCO_FUNC_KEYS
856d522f475Smrg    Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
857d522f475Smrg#endif
858d522f475Smrg#if OPT_SUN_FUNC_KEYS
859d522f475Smrg    Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
860d522f475Smrg#endif
861d522f475Smrg#if OPT_TCAP_FKEYS
862d522f475Smrg    Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
863d522f475Smrg#endif
864d522f475Smrg#if OPT_INITIAL_ERASE
865d522f475Smrg    Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
866d522f475Smrg    Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
867d522f475Smrg#endif
868d522f475Smrg    Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
869d522f475Smrg#if OPT_ZICONBEEP
870d522f475Smrg    Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
8710bd37d32Smrg    Sres("zIconTitleFormat", "ZIconTitleFormat", zIconFormat, "*** %s"),
872d522f475Smrg#endif
873d522f475Smrg#if OPT_PTY_HANDSHAKE
874d522f475Smrg    Bres("waitForMap", "WaitForMap", wait_for_map, False),
875d522f475Smrg    Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
876d522f475Smrg    Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
877d522f475Smrg#endif
878e0a2b6dfSmrg#if OPT_REPORT_COLORS
879e0a2b6dfSmrg    Bres("reportColors", "ReportColors", reportColors, False),
880e0a2b6dfSmrg#endif
881e0a2b6dfSmrg#if OPT_REPORT_FONTS
882e0a2b6dfSmrg    Bres("reportFonts", "ReportFonts", reportFonts, False),
883e0a2b6dfSmrg#endif
884d522f475Smrg#if OPT_SAME_NAME
885d522f475Smrg    Bres("sameName", "SameName", sameName, True),
886d522f475Smrg#endif
887d522f475Smrg#if OPT_SESSION_MGT
888d522f475Smrg    Bres("sessionMgt", "SessionMgt", sessionMgt, True),
889d522f475Smrg#endif
890d522f475Smrg#if OPT_TOOLBAR
891d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
892d522f475Smrg#endif
893956cc18dSsnj#if OPT_MAXIMIZE
894956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
895a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
896956cc18dSsnj#endif
897d522f475Smrg};
898d522f475Smrg
89920d2c4d2Smrgstatic String fallback_resources[] =
900d522f475Smrg{
901e39b573cSmrg#if OPT_TOOLBAR
902e39b573cSmrg    "*toolBar: false",
903e39b573cSmrg#endif
904d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
905d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
906d522f475Smrg    "*SimpleMenu*Sme.height: 16",
907d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
908d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
909d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
910d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
911d522f475Smrg#if OPT_TEK4014
912d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
913d522f475Smrg#endif
914d522f475Smrg    NULL
915d522f475Smrg};
916d522f475Smrg
917d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
918d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
919d522f475Smrg/* *INDENT-OFF* */
920d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
92120d2c4d2Smrg{"-geometry",	"*vt100.geometry",XrmoptionSepArg,	(XPointer) NULL},
92220d2c4d2Smrg{"-132",	"*c132",	XrmoptionNoArg,		(XPointer) "on"},
92320d2c4d2Smrg{"+132",	"*c132",	XrmoptionNoArg,		(XPointer) "off"},
92420d2c4d2Smrg{"-ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "on"},
92520d2c4d2Smrg{"+ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "off"},
92620d2c4d2Smrg{"-aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "on"},
92720d2c4d2Smrg{"+aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "off"},
928d522f475Smrg#ifndef NO_ACTIVE_ICON
92920d2c4d2Smrg{"-ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "off"},
93020d2c4d2Smrg{"+ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "on"},
931d522f475Smrg#endif /* NO_ACTIVE_ICON */
93220d2c4d2Smrg{"-b",		"*internalBorder",XrmoptionSepArg,	(XPointer) NULL},
93320d2c4d2Smrg{"-bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "on"},
93420d2c4d2Smrg{"+bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "off"},
93520d2c4d2Smrg{"-bcf",	"*cursorOffTime",XrmoptionSepArg,	(XPointer) NULL},
93620d2c4d2Smrg{"-bcn",	"*cursorOnTime",XrmoptionSepArg,	(XPointer) NULL},
93720d2c4d2Smrg{"-bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "off"},
93820d2c4d2Smrg{"+bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "on"},
93920d2c4d2Smrg{"-cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "off"},
94020d2c4d2Smrg{"+cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "on"},
94120d2c4d2Smrg{"-cc",		"*charClass",	XrmoptionSepArg,	(XPointer) NULL},
94220d2c4d2Smrg{"-cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "off"},
94320d2c4d2Smrg{"+cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "on"},
94420d2c4d2Smrg{"-cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "off"},
94520d2c4d2Smrg{"+cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "on"},
94620d2c4d2Smrg{"-cr",		"*cursorColor",	XrmoptionSepArg,	(XPointer) NULL},
94720d2c4d2Smrg{"-cu",		"*curses",	XrmoptionNoArg,		(XPointer) "on"},
94820d2c4d2Smrg{"+cu",		"*curses",	XrmoptionNoArg,		(XPointer) "off"},
94920d2c4d2Smrg{"-dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "off"},
95020d2c4d2Smrg{"+dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "on"},
95120d2c4d2Smrg{"-fb",		"*boldFont",	XrmoptionSepArg,	(XPointer) NULL},
95220d2c4d2Smrg{"-fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"off"},
95320d2c4d2Smrg{"+fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"on"},
95420d2c4d2Smrg{"-fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"off"},
95520d2c4d2Smrg{"+fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"on"},
956d522f475Smrg#ifndef NO_ACTIVE_ICON
95720d2c4d2Smrg{"-fi",		"*iconFont",	XrmoptionSepArg,	(XPointer) NULL},
958d522f475Smrg#endif /* NO_ACTIVE_ICON */
959d522f475Smrg#if OPT_RENDERFONT
96020d2c4d2Smrg{"-fa",		"*faceName",	XrmoptionSepArg,	(XPointer) NULL},
96120d2c4d2Smrg{"-fd",		"*faceNameDoublesize", XrmoptionSepArg,	(XPointer) NULL},
96220d2c4d2Smrg{"-fs",		"*faceSize",	XrmoptionSepArg,	(XPointer) NULL},
963d522f475Smrg#endif
96401037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
96501037d57Smrg{"-itc",	"*colorITMode",	XrmoptionNoArg,		(XPointer) "off"},
96601037d57Smrg{"+itc",	"*colorITMode",	XrmoptionNoArg,		(XPointer) "on"},
96701037d57Smrg#endif
968d522f475Smrg#if OPT_WIDE_CHARS
96920d2c4d2Smrg{"-fw",		"*wideFont",	XrmoptionSepArg,	(XPointer) NULL},
97020d2c4d2Smrg{"-fwb",	"*wideBoldFont", XrmoptionSepArg,	(XPointer) NULL},
971d522f475Smrg#endif
972d522f475Smrg#if OPT_INPUT_METHOD
97320d2c4d2Smrg{"-fx",		"*ximFont",	XrmoptionSepArg,	(XPointer) NULL},
974d522f475Smrg#endif
975d522f475Smrg#if OPT_HIGHLIGHT_COLOR
97620d2c4d2Smrg{"-hc",		"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
97720d2c4d2Smrg{"-hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "on"},
97820d2c4d2Smrg{"+hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "off"},
97920d2c4d2Smrg{"-selfg",	"*highlightTextColor", XrmoptionSepArg,	(XPointer) NULL},
98020d2c4d2Smrg{"-selbg",	"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
981d522f475Smrg#endif
982d522f475Smrg#if OPT_HP_FUNC_KEYS
98320d2c4d2Smrg{"-hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "on"},
98420d2c4d2Smrg{"+hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "off"},
985d522f475Smrg#endif
98620d2c4d2Smrg{"-hold",	"*hold",	XrmoptionNoArg,		(XPointer) "on"},
98720d2c4d2Smrg{"+hold",	"*hold",	XrmoptionNoArg,		(XPointer) "off"},
988d522f475Smrg#if OPT_INITIAL_ERASE
98920d2c4d2Smrg{"-ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "on"},
99020d2c4d2Smrg{"+ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "off"},
991d522f475Smrg#endif
99220d2c4d2Smrg{"-j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "on"},
99320d2c4d2Smrg{"+j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "off"},
994d522f475Smrg#if OPT_C1_PRINT
99520d2c4d2Smrg{"-k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "on"},
99620d2c4d2Smrg{"+k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "off"},
997d522f475Smrg#endif
99820d2c4d2Smrg{"-kt",		"*keyboardType", XrmoptionSepArg,	(XPointer) NULL},
999d522f475Smrg/* parse logging options anyway for compatibility */
100020d2c4d2Smrg{"-l",		"*logging",	XrmoptionNoArg,		(XPointer) "on"},
100120d2c4d2Smrg{"+l",		"*logging",	XrmoptionNoArg,		(XPointer) "off"},
100220d2c4d2Smrg{"-lf",		"*logFile",	XrmoptionSepArg,	(XPointer) NULL},
100320d2c4d2Smrg{"-ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "on"},
100420d2c4d2Smrg{"+ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "off"},
100520d2c4d2Smrg{"-mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "on"},
100620d2c4d2Smrg{"+mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "off"},
100720d2c4d2Smrg{"-mc",		"*multiClickTime", XrmoptionSepArg,	(XPointer) NULL},
100820d2c4d2Smrg{"-mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "off"},
100920d2c4d2Smrg{"+mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "on"},
101020d2c4d2Smrg{"-ms",		"*pointerColor",XrmoptionSepArg,	(XPointer) NULL},
101120d2c4d2Smrg{"-nb",		"*nMarginBell",	XrmoptionSepArg,	(XPointer) NULL},
101220d2c4d2Smrg{"-nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "off"},
101320d2c4d2Smrg{"+nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "on"},
101420d2c4d2Smrg{"-pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "on"},
101520d2c4d2Smrg{"+pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "off"},
101620d2c4d2Smrg{"-rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "on"},
101720d2c4d2Smrg{"+rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "off"},
101820d2c4d2Smrg{"-s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "on"},
101920d2c4d2Smrg{"+s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "off"},
102020d2c4d2Smrg{"-sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "on"},
102120d2c4d2Smrg{"+sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "off"},
1022e0a2b6dfSmrg#if OPT_REPORT_COLORS
1023e0a2b6dfSmrg{"-report-colors","*reportColors", XrmoptionNoArg,	(XPointer) "on"},
1024e0a2b6dfSmrg#endif
1025e0a2b6dfSmrg#if OPT_REPORT_FONTS
1026e0a2b6dfSmrg{"-report-fonts","*reportFonts", XrmoptionNoArg,	(XPointer) "on"},
1027e0a2b6dfSmrg#endif
1028d522f475Smrg#ifdef SCROLLBAR_RIGHT
102920d2c4d2Smrg{"-leftbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "off"},
103020d2c4d2Smrg{"-rightbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "on"},
103120d2c4d2Smrg#endif
103220d2c4d2Smrg{"-rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "off"},
103320d2c4d2Smrg{"+rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "on"},
103420d2c4d2Smrg{"-sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "on"},
103520d2c4d2Smrg{"+sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "off"},
10360bd37d32Smrg{"-sh",		"*scaleHeight", XrmoptionSepArg,	(XPointer) NULL},
103720d2c4d2Smrg{"-si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "off"},
103820d2c4d2Smrg{"+si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "on"},
103920d2c4d2Smrg{"-sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "on"},
104020d2c4d2Smrg{"+sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "off"},
104120d2c4d2Smrg{"-sl",		"*saveLines",	XrmoptionSepArg,	(XPointer) NULL},
1042d522f475Smrg#if OPT_SUNPC_KBD
104320d2c4d2Smrg{"-sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "on"},
104420d2c4d2Smrg{"+sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "off"},
1045d522f475Smrg#endif
1046d522f475Smrg#if OPT_TEK4014
104720d2c4d2Smrg{"-t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "on"},
104820d2c4d2Smrg{"+t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "off"},
1049d522f475Smrg#endif
105020d2c4d2Smrg{"-ti",		"*decTerminalID",XrmoptionSepArg,	(XPointer) NULL},
105120d2c4d2Smrg{"-tm",		"*ttyModes",	XrmoptionSepArg,	(XPointer) NULL},
105220d2c4d2Smrg{"-tn",		"*termName",	XrmoptionSepArg,	(XPointer) NULL},
1053d522f475Smrg#if OPT_WIDE_CHARS
105420d2c4d2Smrg{"-u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "2"},
105520d2c4d2Smrg{"+u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "0"},
1056d522f475Smrg#endif
1057d522f475Smrg#if OPT_LUIT_PROG
105820d2c4d2Smrg{"-lc",		"*locale",	XrmoptionNoArg,		(XPointer) "on"},
105920d2c4d2Smrg{"+lc",		"*locale",	XrmoptionNoArg,		(XPointer) "off"},
106020d2c4d2Smrg{"-lcc",	"*localeFilter",XrmoptionSepArg,	(XPointer) NULL},
106120d2c4d2Smrg{"-en",		"*locale",	XrmoptionSepArg,	(XPointer) NULL},
106220d2c4d2Smrg#endif
106320d2c4d2Smrg{"-uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "on"},
106420d2c4d2Smrg{"+uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "off"},
106520d2c4d2Smrg{"-ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "off"},
106620d2c4d2Smrg{"+ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "on"},
106720d2c4d2Smrg{"-ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "off"},
106820d2c4d2Smrg{"+ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "on"},
106920d2c4d2Smrg{"-ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "on"},
107020d2c4d2Smrg{"+ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "off"},
107120d2c4d2Smrg{"-im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "on"},
107220d2c4d2Smrg{"+im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "off"},
107320d2c4d2Smrg{"-vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "on"},
107420d2c4d2Smrg{"+vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "off"},
107520d2c4d2Smrg{"-pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "on"},
107620d2c4d2Smrg{"+pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "off"},
1077d522f475Smrg#if OPT_WIDE_CHARS
107820d2c4d2Smrg{"-wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "on"},
107920d2c4d2Smrg{"+wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "off"},
108020d2c4d2Smrg{"-mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "on"},
108120d2c4d2Smrg{"+mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "off"},
108220d2c4d2Smrg{"-cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "on"},
108320d2c4d2Smrg{"+cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "off"},
108420d2c4d2Smrg#endif
108520d2c4d2Smrg{"-wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "on"},
108620d2c4d2Smrg{"+wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "off"},
1087d522f475Smrg#if OPT_ZICONBEEP
108820d2c4d2Smrg{"-ziconbeep",	"*zIconBeep",	XrmoptionSepArg,	(XPointer) NULL},
1089d522f475Smrg#endif
1090d522f475Smrg#if OPT_SAME_NAME
109120d2c4d2Smrg{"-samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "on"},
109220d2c4d2Smrg{"+samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "off"},
1093d522f475Smrg#endif
1094d522f475Smrg#if OPT_SESSION_MGT
109520d2c4d2Smrg{"-sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "on"},
109620d2c4d2Smrg{"+sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "off"},
1097d522f475Smrg#endif
1098d522f475Smrg#if OPT_TOOLBAR
109920d2c4d2Smrg{"-tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "on"},
110020d2c4d2Smrg{"+tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "off"},
1101d522f475Smrg#endif
1102956cc18dSsnj#if OPT_MAXIMIZE
110320d2c4d2Smrg{"-maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "on"},
110420d2c4d2Smrg{"+maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "off"},
1105a1f3da82Smrg{"-fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "on"},
1106a1f3da82Smrg{"+fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "off"},
1107956cc18dSsnj#endif
1108d522f475Smrg/* options that we process ourselves */
110920d2c4d2Smrg{"-help",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
111020d2c4d2Smrg{"-version",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
111120d2c4d2Smrg{"-class",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
111220d2c4d2Smrg{"-e",		NULL,		XrmoptionSkipLine,	(XPointer) NULL},
111320d2c4d2Smrg{"-into",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
1114d522f475Smrg/* bogus old compatibility stuff for which there are
1115d522f475Smrg   standard XtOpenApplication options now */
111620d2c4d2Smrg{"%",		"*tekGeometry",	XrmoptionStickyArg,	(XPointer) NULL},
111720d2c4d2Smrg{"#",		".iconGeometry",XrmoptionStickyArg,	(XPointer) NULL},
111820d2c4d2Smrg{"-T",		".title",	XrmoptionSepArg,	(XPointer) NULL},
111920d2c4d2Smrg{"-n",		"*iconName",	XrmoptionSepArg,	(XPointer) NULL},
112020d2c4d2Smrg{"-r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
112120d2c4d2Smrg{"+r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
112220d2c4d2Smrg{"-rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
112320d2c4d2Smrg{"+rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
112420d2c4d2Smrg{"-w",		".borderWidth", XrmoptionSepArg,	(XPointer) NULL},
1125d522f475Smrg};
1126d522f475Smrg
1127d522f475Smrgstatic OptionHelp xtermOptions[] = {
1128d522f475Smrg{ "-version",              "print the version number" },
1129d522f475Smrg{ "-help",                 "print out this message" },
1130d522f475Smrg{ "-display displayname",  "X server to contact" },
1131d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1132d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1133d522f475Smrg{ "-bg color",             "background color" },
1134d522f475Smrg{ "-fg color",             "foreground color" },
1135d522f475Smrg{ "-bd color",             "border color" },
1136d522f475Smrg{ "-bw number",            "border width in pixels" },
1137d522f475Smrg{ "-fn fontname",          "normal text font" },
1138d522f475Smrg{ "-fb fontname",          "bold text font" },
1139d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1140d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1141d522f475Smrg#if OPT_RENDERFONT
1142d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1143d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1144d522f475Smrg{ "-fs size",              "FreeType font-size" },
1145d522f475Smrg#endif
1146d522f475Smrg#if OPT_WIDE_CHARS
1147d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1148d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1149d522f475Smrg#endif
1150d522f475Smrg#if OPT_INPUT_METHOD
1151d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1152d522f475Smrg#endif
1153d522f475Smrg{ "-iconic",               "start iconic" },
1154d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
1155d522f475Smrg{ "-class string",         "class string (XTerm)" },
1156d522f475Smrg{ "-title string",         "title string" },
1157d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1158d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1159d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1160d522f475Smrg#ifndef NO_ACTIVE_ICON
1161d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1162d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1163d522f475Smrg#endif /* NO_ACTIVE_ICON */
1164d522f475Smrg{ "-b number",             "internal border in pixels" },
1165d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1166d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1167d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1168d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1169d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1170d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1171d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1172d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1173d522f475Smrg{ "-cr color",             "text cursor color" },
1174d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1175d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1176d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1177d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1178d522f475Smrg{ "-selbg color",          "selection background color" },
1179d522f475Smrg{ "-selfg color",          "selection foreground color" },
11800bd37d32Smrg/* -hc is deprecated, not shown in help message */
1181d522f475Smrg#endif
1182d522f475Smrg#if OPT_HP_FUNC_KEYS
1183d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1184d522f475Smrg#endif
1185d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1186d522f475Smrg#if OPT_INITIAL_ERASE
1187d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1188d522f475Smrg#endif
1189d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1190d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1191d522f475Smrg#if OPT_C1_PRINT
1192d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1193d522f475Smrg#endif
1194d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1195d522f475Smrg#ifdef ALLOWLOGGING
1196d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1197d522f475Smrg{ "-lf filename",          "logging filename" },
1198d522f475Smrg#else
1199d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1200d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1201d522f475Smrg#endif
1202d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1203d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1204d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1205d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1206d522f475Smrg{ "-ms color",             "pointer color" },
1207d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
1208d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1209d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1210d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1211d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1212d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1213d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1214e0a2b6dfSmrg#if OPT_REPORT_COLORS
1215e0a2b6dfSmrg{ "-report-colors",        "report colors as they are allocated" },
1216e0a2b6dfSmrg#endif
1217e0a2b6dfSmrg#if OPT_REPORT_FONTS
1218e0a2b6dfSmrg{ "-report-fonts",         "report fonts as loaded to stdout" },
1219e0a2b6dfSmrg#endif
1220d522f475Smrg#ifdef SCROLLBAR_RIGHT
1221d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1222d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1223d522f475Smrg#endif
1224d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1225d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1226894e0ac8Smrg{ "-sh number",            "scale line-height values by the given number" },
1227d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1228d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1229d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1230d522f475Smrg#if OPT_SUNPC_KBD
1231d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1232d522f475Smrg#endif
1233d522f475Smrg#if OPT_TEK4014
1234d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1235d522f475Smrg#endif
1236d522f475Smrg#if OPT_TOOLBAR
1237d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1238d522f475Smrg#endif
1239d522f475Smrg{ "-ti termid",            "terminal identifier" },
1240d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1241d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1242d522f475Smrg#if OPT_WIDE_CHARS
1243d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1244d522f475Smrg#endif
1245d522f475Smrg#if OPT_LUIT_PROG
1246d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1247d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
12480bd37d32Smrg/* -en is deprecated, not shown in help message */
1249d522f475Smrg#endif
12502eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1251d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1252d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1253d522f475Smrg#ifdef HAVE_UTMP
1254d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1255d522f475Smrg#else
1256d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1257d522f475Smrg#endif
1258d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1259d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
126001037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
126101037d57Smrg{ "-/+itc",                "turn off/on display of italic as color"},
126201037d57Smrg#endif
1263d522f475Smrg#if OPT_WIDE_CHARS
1264d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1265d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1266d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1267d522f475Smrg#endif
1268d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1269d522f475Smrg{ "-e command args ...",   "command to execute" },
1270d522f475Smrg#if OPT_TEK4014
1271d522f475Smrg{ "%geom",                 "Tek window geometry" },
1272d522f475Smrg#endif
1273d522f475Smrg{ "#geom",                 "icon window geometry" },
1274d522f475Smrg{ "-T string",             "title name for window" },
1275d522f475Smrg{ "-n string",             "icon name for window" },
1276d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1277d522f475Smrg{ "-C",                    "intercept console messages" },
1278d522f475Smrg#else
1279d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1280d522f475Smrg#endif
1281d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1282d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1283d522f475Smrg#if OPT_ZICONBEEP
1284d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1285d522f475Smrg#endif
1286d522f475Smrg#if OPT_SAME_NAME
1287d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1288d522f475Smrg#endif
1289d522f475Smrg#if OPT_SESSION_MGT
1290d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1291d522f475Smrg#endif
1292956cc18dSsnj#if OPT_MAXIMIZE
1293956cc18dSsnj{"-/+maximized",           "turn on/off maxmize on startup" },
1294a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1295956cc18dSsnj#endif
1296d522f475Smrg{ NULL, NULL }};
1297d522f475Smrg/* *INDENT-ON* */
1298d522f475Smrg
129901037d57Smrgstatic const char *const message[] =
1300d522f475Smrg{
1301d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1302d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1303d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1304d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1305d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
1306d522f475Smrg    NULL};
1307d522f475Smrg
1308d522f475Smrg/*
1309d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1310d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1311d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1312d522f475Smrg */
1313d522f475Smrgstatic int
1314d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1315d522f475Smrg{
1316d522f475Smrg    char *string = *ptr;
1317d522f475Smrg    int value = -1;
1318d522f475Smrg
131920d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1320d522f475Smrg    if (*string == '^') {
1321d522f475Smrg	switch (*++string) {
1322d522f475Smrg	case '?':
1323d522f475Smrg	    value = A2E(ANSI_DEL);
1324d522f475Smrg	    break;
1325d522f475Smrg	case '-':
1326d522f475Smrg	    if (!termcap) {
1327d522f475Smrg		errno = 0;
1328d522f475Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
1329d522f475Smrg		value = _POSIX_VDISABLE;
1330d522f475Smrg#endif
1331d522f475Smrg#if defined(_PC_VDISABLE)
1332d522f475Smrg		if (value == -1) {
133320d2c4d2Smrg		    value = (int) fpathconf(0, _PC_VDISABLE);
1334d522f475Smrg		    if (value == -1) {
1335d522f475Smrg			if (errno != 0)
1336d522f475Smrg			    break;	/* skip this (error) */
1337d522f475Smrg			value = 0377;
1338d522f475Smrg		    }
1339d522f475Smrg		}
1340d522f475Smrg#elif defined(VDISABLE)
1341d522f475Smrg		if (value == -1)
1342d522f475Smrg		    value = VDISABLE;
1343d522f475Smrg#endif
1344d522f475Smrg		break;
1345d522f475Smrg	    }
1346d522f475Smrg	    /* FALLTHRU */
1347d522f475Smrg	default:
1348d522f475Smrg	    value = CONTROL(*string);
1349d522f475Smrg	    break;
1350d522f475Smrg	}
1351d522f475Smrg	++string;
1352d522f475Smrg    } else if (termcap && (*string == '\\')) {
1353d522f475Smrg	char *d;
135420d2c4d2Smrg	int temp = (int) strtol(string + 1, &d, 8);
1355d522f475Smrg	if (temp > 0 && d != string) {
1356d522f475Smrg	    value = temp;
1357d522f475Smrg	    string = d;
1358d522f475Smrg	}
1359d522f475Smrg    } else {
1360d522f475Smrg	value = CharOf(*string);
1361d522f475Smrg	++string;
1362d522f475Smrg    }
1363d522f475Smrg    *ptr = string;
136420d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1365d522f475Smrg    return value;
1366d522f475Smrg}
1367d522f475Smrg
1368d522f475Smrgstatic int
13690bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
13700bd37d32Smrg{
13710bd37d32Smrg    int result = -1;
13720bd37d32Smrg    int n;
13730bd37d32Smrg    int ch;
13740bd37d32Smrg
13750bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
13760bd37d32Smrg	if (param[n] == ch) {
13770bd37d32Smrg	    result = n;
13780bd37d32Smrg	} else {
13790bd37d32Smrg	    if (param[n] != '\0')
13800bd37d32Smrg		result = -1;
13810bd37d32Smrg	    break;
13820bd37d32Smrg	}
13830bd37d32Smrg    }
13840bd37d32Smrg
13850bd37d32Smrg    return result;
13860bd37d32Smrg}
13870bd37d32Smrg
13880bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
13890bd37d32Smrgstatic int
13900bd37d32SmrgcountArg(XrmOptionDescRec * item)
1391d522f475Smrg{
13920bd37d32Smrg    int result = 0;
13930bd37d32Smrg
13940bd37d32Smrg    switch (item->argKind) {
13950bd37d32Smrg    case XrmoptionNoArg:
13960bd37d32Smrg	/* FALLTHRU */
13970bd37d32Smrg    case XrmoptionIsArg:
13980bd37d32Smrg	/* FALLTHRU */
13990bd37d32Smrg    case XrmoptionStickyArg:
14000bd37d32Smrg	break;
14010bd37d32Smrg    case XrmoptionSepArg:
14020bd37d32Smrg	/* FALLTHRU */
14030bd37d32Smrg    case XrmoptionResArg:
14040bd37d32Smrg	/* FALLTHRU */
14050bd37d32Smrg    case XrmoptionSkipArg:
14060bd37d32Smrg	result = 1;
14070bd37d32Smrg	break;
14080bd37d32Smrg    case XrmoptionSkipLine:
14090bd37d32Smrg	break;
14100bd37d32Smrg    case XrmoptionSkipNArgs:
14110bd37d32Smrg	result = (int) (long) (item->value);
14120bd37d32Smrg	break;
14130bd37d32Smrg    }
14140bd37d32Smrg    return result;
14150bd37d32Smrg}
14160bd37d32Smrg
14170bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
14180bd37d32Smrg
14190bd37d32Smrg/*
14200bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
14210bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
14220bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
14230bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
14240bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
14250bd37d32Smrg * standard table (something that the X libraries should do).
14260bd37d32Smrg */
14270bd37d32Smrgstatic XrmOptionDescRec *
14280bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
14290bd37d32Smrg{
14300bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
14310bd37d32Smrg    /* *INDENT-OFF* */
14320bd37d32Smrg#define DATA(option,kind) { option, NULL, kind, (XtPointer) NULL }
14330bd37d32Smrg    static XrmOptionDescRec opTable[] = {
14340bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
14350bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
14360bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
14370bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
14380bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
14390bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
14400bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
14410bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
14420bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
14430bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
14440bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
14450bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
14460bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
14470bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
14480bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
14490bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
14500bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
14510bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
14520bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
14530bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
14540bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
14550bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
14560bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
14570bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
14580bd37d32Smrg#endif /* TIOCCONS */
14590bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
14600bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
14610bd37d32Smrg    };
14620bd37d32Smrg#undef DATA
14630bd37d32Smrg    /* *INDENT-ON* */
14640bd37d32Smrg
14650bd37d32Smrg    XrmOptionDescRec *result = 0;
14660bd37d32Smrg    Cardinal inlist;
14670bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
14680bd37d32Smrg    int atbest = -1;
14690bd37d32Smrg    int best = -1;
14700bd37d32Smrg    int test;
14710bd37d32Smrg    Boolean exact = False;
14720bd37d32Smrg    int ambiguous1 = -1;
14730bd37d32Smrg    int ambiguous2 = -1;
14740bd37d32Smrg    char *option;
14750bd37d32Smrg    char *value;
14760bd37d32Smrg
14770bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
14780bd37d32Smrg		 ? &optionDescList[n] \
14790bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
14800bd37d32Smrg
14810bd37d32Smrg    if ((option = argv[*num]) != 0) {
14820bd37d32Smrg	Boolean need_value;
14830bd37d32Smrg	Boolean have_value = False;
14840bd37d32Smrg
14850bd37d32Smrg	TRACE(("parseArg %s\n", option));
14860bd37d32Smrg	if ((value = argv[(*num) + 1]) != 0) {
1487e0a2b6dfSmrg	    have_value = (Boolean) !isOption(value);
14880bd37d32Smrg	}
14890bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
14900bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
14910bd37d32Smrg
14920bd37d32Smrg	    test = matchArg(check, option);
14930bd37d32Smrg	    if (test < 0)
14940bd37d32Smrg		continue;
14950bd37d32Smrg
14960bd37d32Smrg	    /* check for exact match */
14970bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
14980bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
14990bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
15000bd37d32Smrg			exact = True;
15010bd37d32Smrg			atbest = (int) inlist;
15020bd37d32Smrg			break;
15030bd37d32Smrg		    }
15040bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
15050bd37d32Smrg		    exact = True;
15060bd37d32Smrg		    atbest = (int) inlist;
15070bd37d32Smrg		    break;
15080bd37d32Smrg		}
15090bd37d32Smrg	    }
15100bd37d32Smrg
15110bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
15120bd37d32Smrg
15130bd37d32Smrg	    if (need_value && value != 0) {
15140bd37d32Smrg		;
15150bd37d32Smrg	    } else if (need_value ^ have_value) {
15160bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
15170bd37d32Smrg		continue;
15180bd37d32Smrg	    }
15190bd37d32Smrg
15200bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
15210bd37d32Smrg	    if (test > 0
15220bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
15230bd37d32Smrg		atbest = (int) inlist;
1524e0a2b6dfSmrg		if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
1525e0a2b6dfSmrg		    /* in particular, silence a warning about ambiguity */
1526e0a2b6dfSmrg		    exact = 1;
1527e0a2b6dfSmrg		}
15280bd37d32Smrg		break;
15290bd37d32Smrg	    }
15300bd37d32Smrg	    if (test > best) {
15310bd37d32Smrg		best = test;
15320bd37d32Smrg		atbest = (int) inlist;
15330bd37d32Smrg	    } else if (test == best) {
15340bd37d32Smrg		if (atbest >= 0) {
15350bd37d32Smrg		    if (atbest > 0) {
15360bd37d32Smrg			ambiguous1 = (int) inlist;
15370bd37d32Smrg			ambiguous2 = (int) atbest;
15380bd37d32Smrg		    }
15390bd37d32Smrg		    atbest = -1;
15400bd37d32Smrg		}
15410bd37d32Smrg	    }
15420bd37d32Smrg	}
15430bd37d32Smrg    }
15440bd37d32Smrg
15450bd37d32Smrg    *valuep = 0;
15460bd37d32Smrg    if (atbest >= 0) {
15470bd37d32Smrg	result = ITEM(atbest);
15480bd37d32Smrg	if (!exact) {
15490bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
15500bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
15510bd37d32Smrg			     ITEM(ambiguous1)->option,
15520bd37d32Smrg			     ITEM(ambiguous2)->option);
15530bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
15540bd37d32Smrg		result = 0;
15550bd37d32Smrg	    }
15560bd37d32Smrg	}
15570bd37d32Smrg	if (result != 0) {
15580bd37d32Smrg	    TRACE(("...result %s\n", result->option));
15590bd37d32Smrg	    /* expand abbreviations */
15600bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
15610bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
15620bd37d32Smrg		    argv[*num] = x_strdup(result->option);
15630bd37d32Smrg		}
15640bd37d32Smrg	    }
15650bd37d32Smrg
15660bd37d32Smrg	    /* adjust (*num) to skip option value */
15670bd37d32Smrg	    (*num) += countArg(result);
15680bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
15690bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
15700bd37d32Smrg		*valuep = argv[*num];
15710bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
15720bd37d32Smrg	    }
15730bd37d32Smrg	}
15740bd37d32Smrg    }
15750bd37d32Smrg#undef ITEM
15760bd37d32Smrg    return result;
1577d522f475Smrg}
1578d522f475Smrg
1579d522f475Smrgstatic void
1580d522f475SmrgSyntax(char *badOption)
1581d522f475Smrg{
1582d522f475Smrg    OptionHelp *opt;
1583d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1584d522f475Smrg    int col;
1585d522f475Smrg
15860bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
15870bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1588d522f475Smrg
1589d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1590956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1591d522f475Smrg    for (opt = list; opt->opt; opt++) {
1592956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1593d522f475Smrg	if (col + len > 79) {
1594d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1595d522f475Smrg	    col = 3;
1596d522f475Smrg	}
1597d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1598d522f475Smrg	col += len;
1599d522f475Smrg    }
1600d522f475Smrg
1601d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1602d522f475Smrg	    ProgramName);
1603d522f475Smrg    exit(1);
1604d522f475Smrg}
1605d522f475Smrg
1606d522f475Smrgstatic void
1607d522f475SmrgVersion(void)
1608d522f475Smrg{
1609d522f475Smrg    printf("%s\n", xtermVersion());
1610d522f475Smrg    fflush(stdout);
1611d522f475Smrg}
1612d522f475Smrg
1613d522f475Smrgstatic void
1614d522f475SmrgHelp(void)
1615d522f475Smrg{
1616d522f475Smrg    OptionHelp *opt;
1617d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
161801037d57Smrg    const char *const *cpp;
1619d522f475Smrg
1620d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1621d522f475Smrg	   xtermVersion(), ProgramName);
1622d522f475Smrg    printf("where options include:\n");
1623d522f475Smrg    for (opt = list; opt->opt; opt++) {
1624d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1625d522f475Smrg    }
1626d522f475Smrg
1627d522f475Smrg    putchar('\n');
1628d522f475Smrg    for (cpp = message; *cpp; cpp++)
1629d522f475Smrg	puts(*cpp);
1630d522f475Smrg    putchar('\n');
1631d522f475Smrg    fflush(stdout);
1632d522f475Smrg}
1633d522f475Smrg
1634d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1635d522f475Smrg/* ARGSUSED */
1636d522f475Smrgstatic Boolean
1637d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1638894e0ac8Smrg			Atom *selection GCC_UNUSED,
1639894e0ac8Smrg			Atom *target GCC_UNUSED,
1640894e0ac8Smrg			Atom *type GCC_UNUSED,
1641d522f475Smrg			XtPointer *value GCC_UNUSED,
1642d522f475Smrg			unsigned long *length GCC_UNUSED,
1643d522f475Smrg			int *format GCC_UNUSED)
1644d522f475Smrg{
1645d522f475Smrg    /* we don't save console output, so can't offer it */
1646d522f475Smrg    return False;
1647d522f475Smrg}
1648d522f475Smrg#endif /* TIOCCONS */
1649d522f475Smrg
1650d522f475Smrg/*
1651d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1652d522f475Smrg */
1653d522f475Smrg/* ARGSUSED */
1654d522f475Smrgstatic void
1655d522f475SmrgDeleteWindow(Widget w,
1656894e0ac8Smrg	     XEvent *event GCC_UNUSED,
1657e0a2b6dfSmrg	     String *params GCC_UNUSED,
1658d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1659d522f475Smrg{
1660d522f475Smrg#if OPT_TEK4014
1661d522f475Smrg    if (w == toplevel) {
1662d522f475Smrg	if (TEK4014_SHOWN(term))
1663d522f475Smrg	    hide_vt_window();
1664d522f475Smrg	else
1665d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
166620d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1667d522f475Smrg	hide_tek_window();
1668d522f475Smrg    else
1669d522f475Smrg#endif
1670d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1671d522f475Smrg}
1672d522f475Smrg
1673d522f475Smrg/* ARGSUSED */
1674d522f475Smrgstatic void
1675d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1676894e0ac8Smrg		XEvent *event,
1677e0a2b6dfSmrg		String *params GCC_UNUSED,
1678d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1679d522f475Smrg{
1680d522f475Smrg    switch (event->type) {
1681d522f475Smrg    case MappingNotify:
1682d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1683d522f475Smrg	break;
1684d522f475Smrg    }
1685d522f475Smrg}
1686d522f475Smrg
1687d522f475Smrgstatic XtActionsRec actionProcs[] =
1688d522f475Smrg{
1689d522f475Smrg    {"DeleteWindow", DeleteWindow},
1690d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1691d522f475Smrg};
1692d522f475Smrg
1693d522f475Smrg/*
1694d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1695d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1696d522f475Smrg * utmp.
1697d522f475Smrg */
1698d522f475Smrgstatic char *
1699d522f475Smrgmy_pty_name(char *device)
1700d522f475Smrg{
1701d522f475Smrg    size_t len = strlen(device);
1702d522f475Smrg    Bool name = False;
1703d522f475Smrg
1704d522f475Smrg    while (len != 0) {
1705d522f475Smrg	int ch = device[len - 1];
1706d522f475Smrg	if (isdigit(ch)) {
1707d522f475Smrg	    len--;
1708d522f475Smrg	} else if (ch == '/') {
1709d522f475Smrg	    if (name)
1710d522f475Smrg		break;
1711d522f475Smrg	    len--;
1712d522f475Smrg	} else if (isalpha(ch)) {
1713d522f475Smrg	    name = True;
1714d522f475Smrg	    len--;
1715d522f475Smrg	} else {
1716d522f475Smrg	    break;
1717d522f475Smrg	}
1718d522f475Smrg    }
1719d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1720d522f475Smrg    return device + len;
1721d522f475Smrg}
1722d522f475Smrg
1723d522f475Smrg/*
1724d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1725d522f475Smrg * last few characters for a utmp identifier.
1726d522f475Smrg */
1727d522f475Smrgstatic char *
1728d522f475Smrgmy_pty_id(char *device)
1729d522f475Smrg{
1730d522f475Smrg    char *name = my_pty_name(device);
1731d522f475Smrg    char *leaf = x_basename(name);
1732d522f475Smrg
1733d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1734956cc18dSsnj	int len = (int) strlen(leaf);
1735d522f475Smrg	if (PTYCHARLEN < len)
1736d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1737d522f475Smrg    }
1738d522f475Smrg    TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
1739d522f475Smrg    return leaf;
1740d522f475Smrg}
1741d522f475Smrg
1742d522f475Smrg/*
1743d522f475Smrg * Set the tty/pty identifier
1744d522f475Smrg */
1745d522f475Smrgstatic void
1746d522f475Smrgset_pty_id(char *device, char *id)
1747d522f475Smrg{
1748d522f475Smrg    char *name = my_pty_name(device);
1749d522f475Smrg    char *leaf = x_basename(name);
1750d522f475Smrg
1751d522f475Smrg    if (name == leaf) {
1752d522f475Smrg	strcpy(my_pty_id(device), id);
1753d522f475Smrg    } else {
1754d522f475Smrg	strcpy(leaf, id);
1755d522f475Smrg    }
1756d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
1757d522f475Smrg}
1758d522f475Smrg
1759d522f475Smrg/*
1760d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
1761d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
1762d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
1763d522f475Smrg * not, fall-thru to the original logic.
1764d522f475Smrg */
1765d522f475Smrgstatic Bool
1766d522f475SmrgParseSccn(char *option)
1767d522f475Smrg{
1768d522f475Smrg    char *leaf = x_basename(option);
1769d522f475Smrg    Bool code = False;
1770d522f475Smrg
177101037d57Smrg    passedPty = x_strdup(option);
1772d522f475Smrg    if (leaf != option) {
1773d522f475Smrg	if (leaf - option > 0
1774d522f475Smrg	    && isdigit(CharOf(*leaf))
1775d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
1776956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
1777d522f475Smrg	    /*
1778d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
1779d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
1780d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
1781d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
1782d522f475Smrg	     */
1783d522f475Smrg	    passedPty[len] = 0;
1784d522f475Smrg	    code = True;
1785d522f475Smrg	}
1786d522f475Smrg    } else {
1787d522f475Smrg	code = (sscanf(option, "%c%c%d",
1788d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
178901037d57Smrg	passedPty[2] = '\0';
1790d522f475Smrg    }
1791d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
1792d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
1793d522f475Smrg    return code;
1794d522f475Smrg}
1795d522f475Smrg
1796d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
1797d522f475Smrg/*
1798d522f475Smrg * From "man utmp":
1799d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
1800d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
1801d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
1802d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
1803d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
1804d522f475Smrg * ut_time, ut_user and ut_host as well.
1805d522f475Smrg *
1806d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
1807d522f475Smrg * pty implementation allows more than 3 digits.
1808d522f475Smrg */
1809d522f475Smrgstatic char *
1810d522f475Smrgmy_utmp_id(char *device)
1811d522f475Smrg{
1812d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
1813d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
1814d522f475Smrg    static char result[UTIDSIZE + 1];
1815d522f475Smrg
1816d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
1817d522f475Smrg    /*
1818d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
1819d522f475Smrg     * issues, and can use the available space in ut_id differently from the
1820d522f475Smrg     * default convention.
1821d522f475Smrg     *
1822d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
1823d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
1824d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
1825d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
1826d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
1827d522f475Smrg     * last three digits of the device name, regardless of the format of the
1828d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
1829d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
1830d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
1831d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
1832d522f475Smrg     */
1833d522f475Smrg    int len, n;
1834d522f475Smrg
1835d522f475Smrg    len = strlen(device);
1836d522f475Smrg    n = UTIDSIZE;
1837d522f475Smrg    result[n] = '\0';
1838d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
1839d522f475Smrg	result[--n] = device[--len];
1840d522f475Smrg    while (n > 0)
1841d522f475Smrg	result[--n] = '0';
1842d522f475Smrg    result[0] = 'x';
1843d522f475Smrg#else
1844d522f475Smrg    char *name = my_pty_name(device);
1845d522f475Smrg    char *leaf = x_basename(name);
1846d522f475Smrg    size_t len = strlen(leaf);
1847d522f475Smrg
1848d522f475Smrg    if ((UTIDSIZE - 1) < len)
1849d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
1850d522f475Smrg    sprintf(result, "p%s", leaf);
1851d522f475Smrg#endif
1852d522f475Smrg
1853d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
1854d522f475Smrg    return result;
1855d522f475Smrg}
1856d522f475Smrg#endif /* USE_SYSV_UTMP */
1857d522f475Smrg
1858d522f475Smrg#ifdef USE_POSIX_SIGNALS
1859d522f475Smrg
1860d522f475Smrgtypedef void (*sigfunc) (int);
1861d522f475Smrg
1862d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
1863d522f475Smrg   has just been stopped and not actually killed */
1864d522f475Smrg
1865d522f475Smrgstatic sigfunc
1866d522f475Smrgposix_signal(int signo, sigfunc func)
1867d522f475Smrg{
1868d522f475Smrg    struct sigaction act, oact;
1869d522f475Smrg
1870d522f475Smrg    act.sa_handler = func;
1871d522f475Smrg    sigemptyset(&act.sa_mask);
1872d522f475Smrg#ifdef SA_RESTART
1873d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
1874d522f475Smrg#else
1875d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
1876d522f475Smrg#endif
1877d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
1878d522f475Smrg	return (SIG_ERR);
1879d522f475Smrg    return (oact.sa_handler);
1880d522f475Smrg}
1881d522f475Smrg
18820bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
1883d522f475Smrg
1884d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
1885d522f475Smrgstatic void
1886d522f475SmrgdisableSetUid(void)
1887d522f475Smrg{
1888d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
1889d522f475Smrg    if (setuid(save_ruid) == -1) {
18900bd37d32Smrg	xtermWarning("unable to reset uid\n");
1891d522f475Smrg	exit(1);
1892d522f475Smrg    }
1893d522f475Smrg    TRACE_IDS;
1894d522f475Smrg}
1895d522f475Smrg#else
1896d522f475Smrg#define disableSetUid()		/* nothing */
1897d522f475Smrg#endif /* DISABLE_SETUID */
1898d522f475Smrg
1899d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
1900d522f475Smrgstatic void
1901d522f475SmrgdisableSetGid(void)
1902d522f475Smrg{
1903d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
1904d522f475Smrg    if (setegid(save_rgid) == -1) {
19050bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
1906d522f475Smrg	exit(1);
1907d522f475Smrg    }
1908d522f475Smrg    TRACE_IDS;
1909d522f475Smrg}
1910d522f475Smrg#else
1911d522f475Smrg#define disableSetGid()		/* nothing */
1912d522f475Smrg#endif /* DISABLE_SETGID */
1913d522f475Smrg
1914d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
1915d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
1916d522f475Smrgstatic void
1917d522f475SmrgsetEffectiveGroup(gid_t group)
1918d522f475Smrg{
1919d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
1920d522f475Smrg    if (setegid(group) == -1) {
1921d522f475Smrg#ifdef __MVS__
1922d522f475Smrg	if (!(errno == EMVSERR))	/* could happen if _BPX_SHAREAS=REUSE */
1923d522f475Smrg#endif
1924d522f475Smrg	{
19250bd37d32Smrg	    xtermPerror("setegid(%d)", (int) group);
1926d522f475Smrg	}
1927d522f475Smrg    }
1928d522f475Smrg    TRACE_IDS;
1929d522f475Smrg}
1930d522f475Smrg#endif
1931d522f475Smrg
1932d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
1933d522f475Smrgstatic void
1934d522f475SmrgsetEffectiveUser(uid_t user)
1935d522f475Smrg{
1936d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
1937d522f475Smrg    if (seteuid(user) == -1) {
1938d522f475Smrg#ifdef __MVS__
1939d522f475Smrg	if (!(errno == EMVSERR))
1940d522f475Smrg#endif
1941d522f475Smrg	{
19420bd37d32Smrg	    xtermPerror("seteuid(%d)", (int) user);
1943d522f475Smrg	}
1944d522f475Smrg    }
1945d522f475Smrg    TRACE_IDS;
1946d522f475Smrg}
1947d522f475Smrg#endif
1948d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
1949d522f475Smrg
1950d522f475Smrgint
1951d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
1952d522f475Smrg{
1953a1f3da82Smrg#if OPT_MAXIMIZE
1954a1f3da82Smrg#define DATA(name) { #name, es##name }
195501037d57Smrg    static const FlagList tblFullscreen[] =
1956a1f3da82Smrg    {
1957a1f3da82Smrg	DATA(Always),
1958a1f3da82Smrg	DATA(Never)
1959a1f3da82Smrg    };
1960a1f3da82Smrg#undef DATA
1961a1f3da82Smrg#endif
1962a1f3da82Smrg
1963d522f475Smrg    Widget form_top, menu_top;
1964d522f475Smrg    Dimension menu_high;
1965d522f475Smrg    TScreen *screen;
1966d522f475Smrg    int mode;
1967e0a2b6dfSmrg    char *my_class = x_strdup(DEFCLASS);
1968d522f475Smrg    Window winToEmbedInto = None;
1969d522f475Smrg
1970d522f475Smrg    ProgramName = argv[0];
1971d522f475Smrg
1972d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
1973d522f475Smrg    save_euid = geteuid();
1974d522f475Smrg    save_egid = getegid();
1975d522f475Smrg#endif
1976d522f475Smrg
1977d522f475Smrg    save_ruid = getuid();
1978d522f475Smrg    save_rgid = getgid();
1979d522f475Smrg
1980d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
1981d522f475Smrg#if defined(DISABLE_SETUID)
1982d522f475Smrg    disableSetUid();
1983d522f475Smrg#endif
1984d522f475Smrg#if defined(DISABLE_SETGID)
1985d522f475Smrg    disableSetGid();
1986d522f475Smrg#endif
1987d522f475Smrg    TRACE_IDS;
1988d522f475Smrg#endif
1989d522f475Smrg
1990d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
1991d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
1992d522f475Smrg#ifdef USE_PTY_DEVICE
1993d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
1994d522f475Smrg    if (!ttydev || !ptydev)
1995d522f475Smrg#else
1996d522f475Smrg    if (!ttydev)
1997d522f475Smrg#endif
1998d522f475Smrg    {
19990bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
2000d522f475Smrg	exit(1);
2001d522f475Smrg    }
2002d522f475Smrg    strcpy(ttydev, TTYDEV);
2003d522f475Smrg#ifdef USE_PTY_DEVICE
2004d522f475Smrg    strcpy(ptydev, PTYDEV);
2005d522f475Smrg#endif
2006d522f475Smrg
2007d522f475Smrg#if defined(USE_UTMP_SETGID)
2008d522f475Smrg    get_pty(NULL, NULL);
2009d522f475Smrg    disableSetUid();
2010d522f475Smrg    disableSetGid();
2011d522f475Smrg    TRACE_IDS;
2012d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
2013d522f475Smrg#endif
2014d522f475Smrg
2015d522f475Smrg    /* Do these first, since we may not be able to open the display */
2016d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
2017d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
2018d522f475Smrg    if (argc > 1) {
20190bd37d32Smrg	XrmOptionDescRec *option_ptr;
20200bd37d32Smrg	char *option_value;
2021d522f475Smrg	int n;
2022e39b573cSmrg	Bool quit = False;
2023d522f475Smrg
2024d522f475Smrg	for (n = 1; n < argc; n++) {
20250bd37d32Smrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
20260bd37d32Smrg		if (argv[n] == 0) {
20270bd37d32Smrg		    break;
20280bd37d32Smrg		} else if (isOption(argv[n])) {
20290bd37d32Smrg		    Syntax(argv[n]);
20300bd37d32Smrg		} else if (explicit_shname != 0) {
20310bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
20320bd37d32Smrg		    Syntax(argv[n]);
20330bd37d32Smrg		}
20340bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
20350bd37d32Smrg		if (explicit_shname == 0)
20360bd37d32Smrg		    exit(0);
20370bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
20380bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
20390bd37d32Smrg		command_to_exec = (argv + n + 1);
20400bd37d32Smrg		if (!command_to_exec[0])
20410bd37d32Smrg		    Syntax(argv[n]);
20420bd37d32Smrg		break;
20430bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2044d522f475Smrg		Version();
2045e39b573cSmrg		quit = True;
20460bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2047d522f475Smrg		Help();
2048e39b573cSmrg		quit = True;
20490bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
2050e0a2b6dfSmrg		free(my_class);
20510bd37d32Smrg		if ((my_class = x_strdup(option_value)) == 0) {
2052d522f475Smrg		    Help();
2053e39b573cSmrg		    quit = True;
2054d522f475Smrg		}
20550bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
20560bd37d32Smrg		char *endPtr;
20570bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
2058d522f475Smrg	    }
2059d522f475Smrg	}
2060d522f475Smrg	if (quit)
2061d522f475Smrg	    exit(0);
20620bd37d32Smrg	/*
20630bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
20640bd37d32Smrg	 * then give up.
20650bd37d32Smrg	 */
20660bd37d32Smrg	if (n < argc && !command_to_exec) {
20670bd37d32Smrg	    Syntax(argv[n]);
20680bd37d32Smrg	}
2069d522f475Smrg    }
2070d522f475Smrg
20710bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2072d522f475Smrg#if OPT_I18N_SUPPORT
2073d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2074d522f475Smrg#endif
2075d522f475Smrg
2076d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2077d522f475Smrg    /* Initialization is done here rather than above in order
2078d522f475Smrg     * to prevent any assumptions about the order of the contents
2079d522f475Smrg     * of the various terminal structures (which may change from
2080d522f475Smrg     * implementation to implementation).
2081d522f475Smrg     */
2082d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2083d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2084d522f475Smrg#ifdef TAB3
2085d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR | TAB3;
2086d522f475Smrg#else
2087d522f475Smrg#ifdef ONLCR
2088d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR;
2089d522f475Smrg#else
2090d522f475Smrg    d_tio.c_oflag = OPOST;
2091d522f475Smrg#endif
2092d522f475Smrg#endif
2093d522f475Smrg    {
2094d522f475Smrg	Cardinal nn;
2095d522f475Smrg
2096d522f475Smrg	/* fill in default-values */
2097d522f475Smrg	for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2098d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2099d522f475Smrg		d_tio.c_cc[known_ttyChars[nn].sysMode] =
21000bd37d32Smrg		    (cc_t) known_ttyChars[nn].myDefault;
2101d522f475Smrg	    }
2102d522f475Smrg	}
2103d522f475Smrg    }
2104d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
2105d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2106d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2107d522f475Smrg#ifdef ECHOKE
2108d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2109d522f475Smrg#endif
2110d522f475Smrg#ifdef ECHOCTL
2111d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2112d522f475Smrg#endif
2113d522f475Smrg#ifndef USE_TERMIOS		/* { */
2114d522f475Smrg    d_tio.c_line = 0;
2115d522f475Smrg#endif /* } */
2116d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2117d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2118d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2119d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2120d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2121d522f475Smrg    d_ltc.t_werasc = CWERASE;
2122d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2123d522f475Smrg#endif /* } HAS_LTCHARS */
2124d522f475Smrg#ifdef TIOCLSET			/* { */
2125d522f475Smrg    d_lmode = 0;
2126d522f475Smrg#endif /* } TIOCLSET */
2127d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2128d522f475Smrg#ifndef USE_POSIX_TERMIOS
2129d522f475Smrg#ifdef BAUD_0			/* { */
2130d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2131d522f475Smrg#else /* }{ !BAUD_0 */
2132d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2133d522f475Smrg#endif /* } !BAUD_0 */
2134d522f475Smrg#else /* USE_POSIX_TERMIOS */
2135d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2136d522f475Smrg    cfsetispeed(&d_tio, VAL_LINE_SPEED);
2137d522f475Smrg    cfsetospeed(&d_tio, VAL_LINE_SPEED);
2138d522f475Smrg#endif
2139d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2140d522f475Smrg#ifdef ECHOKE
2141d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2142d522f475Smrg#endif
2143d522f475Smrg#ifdef ECHOCTL
2144d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2145d522f475Smrg#endif
2146d522f475Smrg#ifndef USE_POSIX_TERMIOS
2147d522f475Smrg#ifdef NTTYDISC
2148d522f475Smrg    d_tio.c_line = NTTYDISC;
2149d522f475Smrg#else
2150d522f475Smrg    d_tio.c_line = 0;
2151d522f475Smrg#endif
2152d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2153d522f475Smrg#ifdef __sgi
2154d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2155d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2156d522f475Smrg#endif
2157d522f475Smrg#ifdef __MVS__
2158d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2159d522f475Smrg#endif
2160d522f475Smrg    {
2161d522f475Smrg	Cardinal nn;
2162d522f475Smrg	int i;
2163d522f475Smrg
2164d522f475Smrg	/* try to inherit tty settings */
2165d522f475Smrg	for (i = 0; i <= 2; i++) {
2166d522f475Smrg	    TERMIO_STRUCT deftio;
2167d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2168d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2169d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2170d522f475Smrg			d_tio.c_cc[known_ttyChars[nn].sysMode] =
2171d522f475Smrg			    deftio.c_cc[known_ttyChars[nn].sysMode];
2172d522f475Smrg		    }
2173d522f475Smrg		}
2174d522f475Smrg		break;
2175d522f475Smrg	    }
2176d522f475Smrg	}
2177d522f475Smrg    }
2178d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2179d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2180d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2181d522f475Smrg#endif /* } */
2182d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2183d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2184d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2185d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2186d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2187d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2188d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2189d522f475Smrg#endif /* } HAS_LTCHARS */
2190d522f475Smrg
2191d522f475Smrg#ifdef TIOCLSET			/* { */
2192d522f475Smrg    d_lmode = 0;
2193d522f475Smrg#endif /* } TIOCLSET */
2194d522f475Smrg#endif /* } macII, ATT, CRAY */
2195d522f475Smrg#endif /* } TERMIO_STRUCT */
2196d522f475Smrg
2197d522f475Smrg    /* Init the Toolkit. */
2198d522f475Smrg    {
2199d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2200d522f475Smrg	setEffectiveGroup(save_rgid);
2201d522f475Smrg	setEffectiveUser(save_ruid);
2202d522f475Smrg	TRACE_IDS;
2203d522f475Smrg#endif
2204e0a2b6dfSmrg	init_colored_cursor();
2205d522f475Smrg
22060bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
22070bd37d32Smrg					my_class,
22080bd37d32Smrg					optionDescList,
22090bd37d32Smrg					XtNumber(optionDescList),
22100bd37d32Smrg					&argc, (String *) argv,
22110bd37d32Smrg					fallback_resources,
22120bd37d32Smrg					sessionShellWidgetClass,
22130bd37d32Smrg					NULL, 0);
2214d522f475Smrg
2215d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2216d522f475Smrg				  application_resources,
2217d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2218d522f475Smrg	TRACE_XRES();
2219a1f3da82Smrg#if OPT_MAXIMIZE
2220a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2221a1f3da82Smrg					      tblFullscreen,
2222a1f3da82Smrg					      XtNumber(tblFullscreen));
2223a1f3da82Smrg#endif
2224e39b573cSmrg	VTInitTranslations();
2225d522f475Smrg#if OPT_PTY_HANDSHAKE
2226d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2227d522f475Smrg#endif
2228d522f475Smrg
2229d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2230d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2231d522f475Smrg#if !defined(DISABLE_SETUID)
2232d522f475Smrg	setEffectiveUser(save_euid);
2233d522f475Smrg#endif
2234d522f475Smrg#if !defined(DISABLE_SETGID)
2235d522f475Smrg	setEffectiveGroup(save_egid);
2236d522f475Smrg#endif
2237d522f475Smrg	TRACE_IDS;
2238d522f475Smrg#endif
2239d522f475Smrg#endif
2240d522f475Smrg    }
2241d522f475Smrg
2242d522f475Smrg    /*
2243d522f475Smrg     * ICCCM delete_window.
2244d522f475Smrg     */
2245d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2246d522f475Smrg
2247d522f475Smrg    /*
2248d522f475Smrg     * fill in terminal modes
2249d522f475Smrg     */
2250d522f475Smrg    if (resource.tty_modes) {
2251d522f475Smrg	int n = parse_tty_modes(resource.tty_modes, ttymodelist);
2252d522f475Smrg	if (n < 0) {
22530bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2254d522f475Smrg	} else if (n > 0) {
2255d522f475Smrg	    override_tty_modes = True;
2256d522f475Smrg	}
2257d522f475Smrg    }
22580bd37d32Smrg    initZIconBeep();
2259d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2260d522f475Smrg    if (resource.icon_geometry != NULL) {
2261d522f475Smrg	int scr, junk;
2262d522f475Smrg	int ix, iy;
2263d522f475Smrg	Arg args[2];
2264d522f475Smrg
2265d522f475Smrg	for (scr = 0;		/* yyuucchh */
2266d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2267d522f475Smrg	     scr++) ;
2268d522f475Smrg
2269d522f475Smrg	args[0].name = XtNiconX;
2270d522f475Smrg	args[1].name = XtNiconY;
2271d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2272d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2273d522f475Smrg	args[0].value = (XtArgVal) ix;
2274d522f475Smrg	args[1].value = (XtArgVal) iy;
2275d522f475Smrg	XtSetValues(toplevel, args, 2);
2276d522f475Smrg    }
2277d522f475Smrg
2278d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2279d522f475Smrg		number_ourTopLevelShellArgs);
2280d522f475Smrg
2281d522f475Smrg#if OPT_WIDE_CHARS
2282d522f475Smrg    /* seems as good a place as any */
2283d522f475Smrg    init_classtab();
2284d522f475Smrg#endif
2285d522f475Smrg
2286d522f475Smrg    /* Parse the rest of the command line */
2287d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2288d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
22890bd37d32Smrg	if (!isOption(*argv)) {
2290d522f475Smrg#ifdef VMS
2291d522f475Smrg	    Syntax(*argv);
2292d522f475Smrg#else
2293d522f475Smrg	    if (argc > 1)
2294d522f475Smrg		Syntax(*argv);
2295d522f475Smrg	    continue;
2296d522f475Smrg#endif
22970bd37d32Smrg	}
2298d522f475Smrg
2299d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2300d522f475Smrg	switch (argv[0][1]) {
2301d522f475Smrg	case 'C':
2302d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2303d522f475Smrg#ifndef __sgi
2304d522f475Smrg	    {
2305d522f475Smrg		struct stat sbuf;
2306d522f475Smrg
2307d522f475Smrg		/* Must be owner and have read/write permission.
2308d522f475Smrg		   xdm cooperates to give the console the right user. */
2309d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2310d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2311d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2312d522f475Smrg		    Console = True;
2313d522f475Smrg		} else
2314d522f475Smrg		    Console = False;
2315d522f475Smrg	    }
2316d522f475Smrg#else /* __sgi */
2317d522f475Smrg	    Console = True;
2318d522f475Smrg#endif /* __sgi */
2319d522f475Smrg#endif /* TIOCCONS */
2320d522f475Smrg	    continue;
2321d522f475Smrg	case 'S':
2322d522f475Smrg	    if (!ParseSccn(*argv + 2))
2323d522f475Smrg		Syntax(*argv);
2324d522f475Smrg	    continue;
2325d522f475Smrg#ifdef DEBUG
2326d522f475Smrg	case 'D':
2327d522f475Smrg	    debug = True;
2328d522f475Smrg	    continue;
2329d522f475Smrg#endif /* DEBUG */
23300bd37d32Smrg	case 'c':
23310bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2332d522f475Smrg		Syntax(*argv);
23330bd37d32Smrg	    argc--, argv++;
2334d522f475Smrg	    continue;
2335d522f475Smrg	case 'e':
23360bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2337d522f475Smrg		Syntax(*argv);
23380bd37d32Smrg	    command_to_exec = (argv + 1);
2339d522f475Smrg	    break;
2340d522f475Smrg	case 'i':
23410bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2342d522f475Smrg		Syntax(*argv);
23430bd37d32Smrg	    argc--, argv++;
2344d522f475Smrg	    continue;
2345d522f475Smrg
2346d522f475Smrg	default:
2347d522f475Smrg	    Syntax(*argv);
2348d522f475Smrg	}
2349d522f475Smrg	break;
2350d522f475Smrg    }
2351d522f475Smrg
2352d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2353d522f475Smrg
2354d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2355d522f475Smrg						 form_top,
2356d522f475Smrg#if OPT_TOOLBAR
2357d522f475Smrg						 XtNmenuBar, menu_top,
2358d522f475Smrg						 XtNresizable, True,
2359d522f475Smrg						 XtNfromVert, menu_top,
2360d522f475Smrg						 XtNleft, XawChainLeft,
2361d522f475Smrg						 XtNright, XawChainRight,
2362d522f475Smrg						 XtNtop, XawChainTop,
2363d522f475Smrg						 XtNbottom, XawChainBottom,
2364d522f475Smrg						 XtNmenuHeight, menu_high,
2365d522f475Smrg#endif
2366d522f475Smrg						 (XtPointer) 0);
2367d522f475Smrg    decode_keyboard_type(term, &resource);
2368d522f475Smrg
2369d522f475Smrg    screen = TScreenOf(term);
2370d522f475Smrg    screen->inhibit = 0;
2371d522f475Smrg
2372d522f475Smrg#ifdef ALLOWLOGGING
2373d522f475Smrg    if (term->misc.logInhibit)
2374d522f475Smrg	screen->inhibit |= I_LOG;
2375d522f475Smrg#endif
2376d522f475Smrg    if (term->misc.signalInhibit)
2377d522f475Smrg	screen->inhibit |= I_SIGNAL;
2378d522f475Smrg#if OPT_TEK4014
2379d522f475Smrg    if (term->misc.tekInhibit)
2380d522f475Smrg	screen->inhibit |= I_TEK;
2381d522f475Smrg#endif
2382d522f475Smrg
2383d522f475Smrg    /*
2384d522f475Smrg     * We might start by showing the tek4014 window.
2385d522f475Smrg     */
2386d522f475Smrg#if OPT_TEK4014
2387d522f475Smrg    if (screen->inhibit & I_TEK)
2388d522f475Smrg	TEK4014_ACTIVE(term) = False;
2389d522f475Smrg
2390d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2391d522f475Smrg	SysError(ERROR_INIT);
2392d522f475Smrg#endif
2393d522f475Smrg
2394d522f475Smrg    /*
2395d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2396d522f475Smrg     */
2397d522f475Smrg#if OPT_TOOLBAR
2398d522f475Smrg    ShowToolbar(resource.toolBar);
2399d522f475Smrg#endif
2400d522f475Smrg
24010bd37d32Smrg    xtermOpenSession();
2402d522f475Smrg
2403d522f475Smrg    /*
2404d522f475Smrg     * Set title and icon name if not specified
2405d522f475Smrg     */
2406d522f475Smrg    if (command_to_exec) {
2407d522f475Smrg	Arg args[2];
2408d522f475Smrg
2409d522f475Smrg	if (!resource.title) {
2410d522f475Smrg	    if (command_to_exec) {
2411d522f475Smrg		resource.title = x_basename(command_to_exec[0]);
2412d522f475Smrg	    }			/* else not reached */
2413d522f475Smrg	}
2414d522f475Smrg
2415d522f475Smrg	if (!resource.icon_name)
2416d522f475Smrg	    resource.icon_name = resource.title;
2417d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2418d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2419d522f475Smrg
24200bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2421d522f475Smrg	       resource.title,
2422d522f475Smrg	       resource.icon_name,
24230bd37d32Smrg	       NonNull(resource.icon_hint),
2424d522f475Smrg	       *command_to_exec));
2425d522f475Smrg
2426d522f475Smrg	XtSetValues(toplevel, args, 2);
2427d522f475Smrg    }
2428d522f475Smrg#if OPT_LUIT_PROG
2429d522f475Smrg    if (term->misc.callfilter) {
24300bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
24310bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
24320bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
24330bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
24340bd37d32Smrg
24350bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
24360bd37d32Smrg						  (count_split
24370bd37d32Smrg						   + count_exec
24380bd37d32Smrg						   + count_using
24390bd37d32Smrg						   + 8));
24400bd37d32Smrg	if (command_to_exec_with_luit == NULL)
24410bd37d32Smrg	    SysError(ERROR_LUMALLOC);
24420bd37d32Smrg
24430bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
24440bd37d32Smrg	if (count_using) {
24450bd37d32Smrg	    char *encoding_opt[4];
24460bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
24470bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
24480bd37d32Smrg	    encoding_opt[2] = 0;
24490bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
24500bd37d32Smrg	}
24510bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
24520bd37d32Smrg	if (count_exec) {
24530bd37d32Smrg	    char *delimiter[2];
24540bd37d32Smrg	    delimiter[0] = x_strdup("--");
24550bd37d32Smrg	    delimiter[1] = 0;
24560bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
24570bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2458d522f475Smrg	}
24590bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
24600bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2461d522f475Smrg    }
2462d522f475Smrg#endif
2463d522f475Smrg
24640bd37d32Smrg    if_DEBUG({
2465d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2466d522f475Smrg	   done securely by a privileged xterm process (although we try),
2467d522f475Smrg	   so the debug feature is disabled by default. */
2468e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2469d522f475Smrg	int i = -1;
24700bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
24710bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
24720bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2473d522f475Smrg	}
2474d522f475Smrg	if (i >= 0) {
2475d522f475Smrg	    dup2(i, 2);
2476d522f475Smrg
2477d522f475Smrg	    /* mark this file as close on exec */
2478d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2479d522f475Smrg	}
24800bd37d32Smrg    });
2481d522f475Smrg
2482d522f475Smrg    spawnXTerm(term);
2483d522f475Smrg
2484d522f475Smrg#ifndef VMS
2485d522f475Smrg    /* Child process is out there, let's catch its termination */
2486d522f475Smrg
2487d522f475Smrg#ifdef USE_POSIX_SIGNALS
2488d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2489d522f475Smrg#else
2490d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2491d522f475Smrg#endif
2492d522f475Smrg    /* Realize procs have now been executed */
2493d522f475Smrg
2494d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2495d522f475Smrg	char buf[80];
2496d522f475Smrg
2497d522f475Smrg	buf[0] = '\0';
2498d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
249920d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2500d522f475Smrg    }
2501d522f475Smrg#ifdef AIXV3
2502d522f475Smrg#if (OSMAJORVERSION < 4)
2503d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2504d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2505d522f475Smrg     * to the slave-pty process when xterm exits.
2506d522f475Smrg     */
2507d522f475Smrg
2508d522f475Smrg    {
2509d522f475Smrg	TERMIO_STRUCT tio;
2510d522f475Smrg
2511d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
2512d522f475Smrg	    SysError(ERROR_TIOCGETP);
2513d522f475Smrg
2514d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
2515d522f475Smrg
2516d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
2517d522f475Smrg	    SysError(ERROR_TIOCSETP);
2518d522f475Smrg    }
2519d522f475Smrg#endif
2520d522f475Smrg#endif
252101037d57Smrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__) || defined(__minix)
2522d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
2523d522f475Smrg	SysError(ERROR_F_GETFL);
2524d522f475Smrg#ifdef O_NDELAY
2525d522f475Smrg    mode |= O_NDELAY;
2526d522f475Smrg#else
2527d522f475Smrg    mode |= O_NONBLOCK;
2528d522f475Smrg#endif /* O_NDELAY */
2529d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
2530d522f475Smrg	SysError(ERROR_F_SETFL);
2531d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
2532d522f475Smrg    mode = 1;
2533d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
2534d522f475Smrg	SysError(ERROR_FIONBIO);
2535d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
2536d522f475Smrg
2537d522f475Smrg    /* The erase character is used to delete the current completion */
2538d522f475Smrg#if OPT_DABBREV
2539d522f475Smrg#ifdef TERMIO_STRUCT
2540d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
2541d522f475Smrg#else
2542d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
2543d522f475Smrg#endif
2544d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
2545d522f475Smrg#endif
2546d522f475Smrg
2547d522f475Smrg    FD_ZERO(&pty_mask);
2548d522f475Smrg    FD_ZERO(&X_mask);
2549d522f475Smrg    FD_ZERO(&Select_mask);
2550d522f475Smrg    FD_SET(screen->respond, &pty_mask);
2551d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
2552d522f475Smrg    FD_SET(screen->respond, &Select_mask);
2553d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
2554d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
2555d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
2556d522f475Smrg		 : (1 + screen->respond));
2557d522f475Smrg
2558d522f475Smrg#endif /* !VMS */
25590bd37d32Smrg    if_DEBUG({
25600bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
25610bd37d32Smrg    });
2562d522f475Smrg    XSetErrorHandler(xerror);
2563d522f475Smrg    XSetIOErrorHandler(xioerror);
256401037d57Smrg#if OPT_SESSION_MGT
2565e39b573cSmrg    IceSetIOErrorHandler(ice_error);
256601037d57Smrg#endif
2567d522f475Smrg
2568d522f475Smrg    initPtyData(&VTbuffer);
2569d522f475Smrg#ifdef ALLOWLOGGING
2570d522f475Smrg    if (term->misc.log_on) {
257120d2c4d2Smrg	StartLog(term);
2572d522f475Smrg    }
2573d522f475Smrg#endif
2574d522f475Smrg
25750bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
2576d522f475Smrg#if OPT_COLOR_RES
2577a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
2578a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
257920d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
258020d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2581d522f475Smrg
2582a1f3da82Smrg    if (term->misc.re_verse0) {
2583a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
2584a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
2585a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
2586a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
2587a1f3da82Smrg	} else {
2588a1f3da82Smrg	    ReverseVideo(term);
2589a1f3da82Smrg	}
2590a1f3da82Smrg	term->misc.re_verse = True;
2591a1f3da82Smrg	update_reversevideo();
2592a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
2593a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
2594a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
2595a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2596a1f3da82Smrg    }
2597d522f475Smrg#endif /* OPT_COLOR_RES */
2598d522f475Smrg
2599956cc18dSsnj#if OPT_MAXIMIZE
2600956cc18dSsnj    if (resource.maximized)
2601956cc18dSsnj	RequestMaximize(term, True);
2602956cc18dSsnj#endif
2603d522f475Smrg    for (;;) {
2604d522f475Smrg#if OPT_TEK4014
2605d522f475Smrg	if (TEK4014_ACTIVE(term))
2606d522f475Smrg	    TekRun();
2607d522f475Smrg	else
2608d522f475Smrg#endif
2609956cc18dSsnj	    VTRun(term);
2610d522f475Smrg    }
2611d522f475Smrg}
2612d522f475Smrg
2613956cc18dSsnj#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2614d522f475Smrg#define USE_OPENPTY 1
2615d522f475Smrgstatic int opened_tty = -1;
2616d522f475Smrg#endif
2617d522f475Smrg
2618d522f475Smrg/*
2619d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
2620d522f475Smrg *
2621d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
2622d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
2623d522f475Smrg * so that if a pty master is found and later, we find that the slave
2624d522f475Smrg * has problems, we can re-enter this function and get another one.
2625d522f475Smrg */
2626d522f475Smrgstatic int
2627d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
2628d522f475Smrg{
2629d522f475Smrg    int result = 1;
2630d522f475Smrg
26310bd37d32Smrg#if defined(USE_OPENPTY)
26320bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
26330bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
26340bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
26350bd37d32Smrg	char *name = ptsname(*pty);
26360bd37d32Smrg	if (name != 0) {
26370bd37d32Smrg	    strcpy(ttydev, name);
26380bd37d32Smrg	    result = 0;
26390bd37d32Smrg	}
26400bd37d32Smrg    }
26410bd37d32Smrg#ifdef USE_PTY_SEARCH
26420bd37d32Smrg    if (result) {
26430bd37d32Smrg	result = pty_search(pty);
26440bd37d32Smrg    }
26450bd37d32Smrg#endif
26460bd37d32Smrg#elif defined(PUCC_PTYD)
2647d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
2648d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
2649d522f475Smrg			       save_ruid, from)) < 0);
2650d522f475Smrg#elif defined(__QNXNTO__)
2651d522f475Smrg    result = pty_search(pty);
2652d522f475Smrg#else
2653d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
2654d522f475Smrg#ifdef __GLIBC__		/* if __GLIBC__ and USE_USG_PTYS, we know glibc >= 2.1 */
2655d522f475Smrg    /* GNU libc 2 allows us to abstract away from having to know the
2656d522f475Smrg       master pty device name. */
2657d522f475Smrg    if ((*pty = getpt()) >= 0) {
2658d522f475Smrg	char *name = ptsname(*pty);
2659d522f475Smrg	if (name != 0) {	/* if filesystem is trashed, this may be null */
2660d522f475Smrg	    strcpy(ttydev, name);
2661d522f475Smrg	    result = 0;
2662d522f475Smrg	}
2663d522f475Smrg    }
2664d522f475Smrg#elif defined(__MVS__)
2665d522f475Smrg    result = pty_search(pty);
2666d522f475Smrg#else
26670bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
2668d522f475Smrg#endif
26690bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
26700bd37d32Smrg    if (!result)
26710bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
2672d522f475Smrg#endif
2673d522f475Smrg
2674d522f475Smrg#elif defined(AIXV3)
2675d522f475Smrg
2676d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
2677d522f475Smrg	strcpy(ttydev, ttyname(*pty));
2678d522f475Smrg	result = 0;
2679d522f475Smrg    }
2680d522f475Smrg#elif defined(__convex__)
2681d522f475Smrg
2682d522f475Smrg    char *pty_name;
2683d522f475Smrg    extern char *getpty(void);
2684d522f475Smrg
2685d522f475Smrg    while ((pty_name = getpty()) != NULL) {
2686d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
2687d522f475Smrg	    strcpy(ptydev, pty_name);
2688d522f475Smrg	    strcpy(ttydev, pty_name);
2689d522f475Smrg	    *x_basename(ttydev) = 't';
2690d522f475Smrg	    result = 0;
2691d522f475Smrg	    break;
2692d522f475Smrg	}
2693d522f475Smrg    }
2694d522f475Smrg
2695d522f475Smrg#elif defined(sequent)
2696d522f475Smrg
2697d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
2698d522f475Smrg
2699d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
2700d522f475Smrg
2701d522f475Smrg    char *tty_name;
2702d522f475Smrg
2703d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
2704d522f475Smrg    if (tty_name != 0) {
2705d522f475Smrg	strcpy(ttydev, tty_name);
2706d522f475Smrg	result = 0;
2707d522f475Smrg    }
2708d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
2709d522f475Smrg
2710d522f475Smrg    struct stat fstat_buf;
2711d522f475Smrg
2712d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
2713d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
2714d522f475Smrg	result = 0;
2715d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
2716d522f475Smrg    }
2717d522f475Smrg#elif defined(__hpux)
2718d522f475Smrg
2719d522f475Smrg    /*
2720d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
2721d522f475Smrg     */
2722d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
2723d522f475Smrg	char *name = ptsname(*pty);
2724d522f475Smrg	if (name != 0) {
2725d522f475Smrg	    strcpy(ttydev, name);
2726d522f475Smrg	    result = 0;
2727d522f475Smrg	} else {		/* permissions, or other unexpected problem */
2728d522f475Smrg	    close(*pty);
2729d522f475Smrg	    *pty = -1;
2730d522f475Smrg	    result = pty_search(pty);
2731d522f475Smrg	}
2732d522f475Smrg    } else {
2733d522f475Smrg	result = pty_search(pty);
2734d522f475Smrg    }
2735d522f475Smrg
2736d522f475Smrg#else
2737d522f475Smrg
2738d522f475Smrg    result = pty_search(pty);
2739d522f475Smrg
2740d522f475Smrg#endif
2741d522f475Smrg#endif
2742d522f475Smrg
2743d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
2744d522f475Smrg	   ttydev != 0 ? ttydev : "?",
2745d522f475Smrg	   ptydev != 0 ? ptydev : "?",
2746d522f475Smrg	   result ? "FAIL" : "OK",
2747d522f475Smrg	   pty != 0 ? *pty : -1));
2748d522f475Smrg    return result;
2749d522f475Smrg}
2750d522f475Smrg
2751d522f475Smrgstatic void
2752e0a2b6dfSmrgset_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
2753d522f475Smrg{
2754d522f475Smrg#ifdef USE_TTY_GROUP
2755d522f475Smrg    struct group *ttygrp;
2756d522f475Smrg
2757d522f475Smrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
2758d522f475Smrg	gid = ttygrp->gr_gid;
2759d522f475Smrg	mode &= 0660U;
2760d522f475Smrg    }
2761d522f475Smrg    endgrent();
2762d522f475Smrg#endif /* USE_TTY_GROUP */
2763d522f475Smrg
2764d522f475Smrg    TRACE_IDS;
2765d522f475Smrg    set_owner(ttydev, uid, gid, mode);
2766d522f475Smrg}
2767d522f475Smrg
2768d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
2769d522f475Smrg#undef get_pty
2770d522f475Smrg/*
2771d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
2772d522f475Smrg * result.
2773d522f475Smrg */
2774d522f475Smrgstatic int
2775d522f475Smrgget_pty(int *pty, char *from)
2776d522f475Smrg{
2777d522f475Smrg    static int m_pty = -1;
2778d522f475Smrg    int result = -1;
2779d522f475Smrg
2780d522f475Smrg    if (pty == NULL) {
2781d522f475Smrg	result = really_get_pty(&m_pty, from);
2782d522f475Smrg
2783d522f475Smrg	seteuid(0);
2784d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
2785d522f475Smrg	seteuid(save_ruid);
2786d522f475Smrg	TRACE_IDS;
2787d522f475Smrg
2788d522f475Smrg#ifdef USE_OPENPTY
2789d522f475Smrg	if (opened_tty >= 0) {
2790d522f475Smrg	    close(opened_tty);
2791d522f475Smrg	    opened_tty = -1;
2792d522f475Smrg	}
2793d522f475Smrg#endif
2794d522f475Smrg    } else if (m_pty != -1) {
2795d522f475Smrg	*pty = m_pty;
2796d522f475Smrg	result = 0;
2797d522f475Smrg    } else {
2798d522f475Smrg	result = -1;
2799d522f475Smrg    }
28000bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
28010bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
28020bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
28030bd37d32Smrg	   result ? "FAIL" : "OK",
28040bd37d32Smrg	   pty != 0 ? *pty : -1));
2805d522f475Smrg    return result;
2806d522f475Smrg}
2807d522f475Smrg#endif
2808d522f475Smrg
2809d522f475Smrg/*
2810d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
2811d522f475Smrg * we might allocate.  Used on those systems that do not have
2812d522f475Smrg * a functional interface for allocating a pty.
2813d522f475Smrg * Returns 0 if found a pty, 1 if fails.
2814d522f475Smrg */
2815d522f475Smrg#ifdef USE_PTY_SEARCH
2816d522f475Smrgstatic int
2817d522f475Smrgpty_search(int *pty)
2818d522f475Smrg{
2819d522f475Smrg    static int devindex = 0, letter = 0;
2820d522f475Smrg
2821d522f475Smrg#if defined(CRAY) || defined(__MVS__)
2822d522f475Smrg    while (devindex < MAXPTTYS) {
2823d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
2824d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
2825d522f475Smrg	devindex++;
2826d522f475Smrg
2827d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2828d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2829d522f475Smrg	    return 0;
2830d522f475Smrg	}
2831d522f475Smrg    }
2832d522f475Smrg#else /* CRAY || __MVS__ */
2833d522f475Smrg    while (PTYCHAR1[letter]) {
2834d522f475Smrg	ttydev[strlen(ttydev) - 2] =
2835d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
2836d522f475Smrg
2837d522f475Smrg	while (PTYCHAR2[devindex]) {
2838d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
2839d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
2840d522f475Smrg	    devindex++;
2841d522f475Smrg
2842d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2843d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2844d522f475Smrg#ifdef sun
2845d522f475Smrg		/* Need to check the process group of the pty.
2846d522f475Smrg		 * If it exists, then the slave pty is in use,
2847d522f475Smrg		 * and we need to get another one.
2848d522f475Smrg		 */
2849d522f475Smrg		int pgrp_rtn;
2850d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
2851d522f475Smrg		    close(*pty);
2852d522f475Smrg		    continue;
2853d522f475Smrg		}
2854d522f475Smrg#endif /* sun */
2855d522f475Smrg		return 0;
2856d522f475Smrg	    }
2857d522f475Smrg	}
2858d522f475Smrg	devindex = 0;
2859d522f475Smrg	letter++;
2860d522f475Smrg    }
2861d522f475Smrg#endif /* CRAY else */
2862d522f475Smrg    /*
2863d522f475Smrg     * We were unable to allocate a pty master!  Return an error
2864d522f475Smrg     * condition and let our caller terminate cleanly.
2865d522f475Smrg     */
2866d522f475Smrg    return 1;
2867d522f475Smrg}
2868d522f475Smrg#endif /* USE_PTY_SEARCH */
2869d522f475Smrg
2870d522f475Smrg/*
2871d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
2872d522f475Smrg * the latter has support for switching character sets.  We support the
2873d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
2874d522f475Smrg * choose 4014 over 4015.
2875d522f475Smrg *
2876d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
2877d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
2878d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
2879d522f475Smrg * later Tektronix terminals), and 4 character sizes.
2880d522f475Smrg * All of these are supported by xterm.
2881d522f475Smrg */
2882d522f475Smrg
2883d522f475Smrg#if OPT_TEK4014
288401037d57Smrgstatic const char *const tekterm[] =
2885d522f475Smrg{
2886d522f475Smrg    "tek4014",
2887d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
2888d522f475Smrg    "tek4012",			/* 4010 with lower case */
2889d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
2890d522f475Smrg    "tek4010",			/* small screen, upper-case only */
2891d522f475Smrg    "dumb",
2892d522f475Smrg    0
2893d522f475Smrg};
2894d522f475Smrg#endif
2895d522f475Smrg
2896d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
2897d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
2898d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
2899d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
2900d522f475Smrg * The VT420 has up to 48 lines on the screen.
2901d522f475Smrg */
2902d522f475Smrg
290301037d57Smrgstatic const char *const vtterm[] =
2904d522f475Smrg{
2905d522f475Smrg#ifdef USE_X11TERM
2906d522f475Smrg    "x11term",			/* for people who want special term name */
2907d522f475Smrg#endif
2908d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
2909d522f475Smrg    "xterm",			/* the prefered name, should be fastest */
2910d522f475Smrg    "vt102",
2911d522f475Smrg    "vt100",
2912d522f475Smrg    "ansi",
2913d522f475Smrg    "dumb",
2914d522f475Smrg    0
2915d522f475Smrg};
2916d522f475Smrg
2917d522f475Smrg/* ARGSUSED */
29180bd37d32Smrgstatic void
2919d522f475Smrghungtty(int i GCC_UNUSED)
2920d522f475Smrg{
29210bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
2922d522f475Smrg    siglongjmp(env, 1);
2923d522f475Smrg}
2924d522f475Smrg
2925d522f475Smrg#if OPT_PTY_HANDSHAKE
2926d522f475Smrg#define NO_FDS {-1, -1}
2927d522f475Smrg
2928d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
2929d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
2930d522f475Smrg
2931d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
2932d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
2933d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
2934d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
2935d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
2936d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
2937d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
2938d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
2939d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
2940d522f475Smrg} status_t;
2941d522f475Smrg
2942d522f475Smrgtypedef struct {
2943d522f475Smrg    status_t status;
2944d522f475Smrg    int error;
2945d522f475Smrg    int fatal_error;
2946d522f475Smrg    int tty_slot;
2947d522f475Smrg    int rows;
2948d522f475Smrg    int cols;
2949d522f475Smrg    char buffer[1024];
2950d522f475Smrg} handshake_t;
2951d522f475Smrg
2952d522f475Smrg#if OPT_TRACE
2953d522f475Smrgstatic void
2954d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
2955d522f475Smrg{
2956d522f475Smrg    const char *status = "?";
2957d522f475Smrg    switch (data->status) {
2958d522f475Smrg    case PTY_BAD:
2959d522f475Smrg	status = "PTY_BAD";
2960d522f475Smrg	break;
2961d522f475Smrg    case PTY_FATALERROR:
2962d522f475Smrg	status = "PTY_FATALERROR";
2963d522f475Smrg	break;
2964d522f475Smrg    case PTY_GOOD:
2965d522f475Smrg	status = "PTY_GOOD";
2966d522f475Smrg	break;
2967d522f475Smrg    case PTY_NEW:
2968d522f475Smrg	status = "PTY_NEW";
2969d522f475Smrg	break;
2970d522f475Smrg    case PTY_NOMORE:
2971d522f475Smrg	status = "PTY_NOMORE";
2972d522f475Smrg	break;
2973d522f475Smrg    case UTMP_ADDED:
2974d522f475Smrg	status = "UTMP_ADDED";
2975d522f475Smrg	break;
2976d522f475Smrg    case UTMP_TTYSLOT:
2977d522f475Smrg	status = "UTMP_TTYSLOT";
2978d522f475Smrg	break;
2979d522f475Smrg    case PTY_EXEC:
2980d522f475Smrg	status = "PTY_EXEC";
2981d522f475Smrg	break;
2982d522f475Smrg    }
2983d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
2984d522f475Smrg	   tag,
2985d522f475Smrg	   status,
2986d522f475Smrg	   data->error,
2987d522f475Smrg	   data->fatal_error,
2988d522f475Smrg	   data->buffer));
2989d522f475Smrg}
2990d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
2991d522f475Smrg#else
2992d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
2993d522f475Smrg#endif
2994d522f475Smrg
2995d522f475Smrg/* HsSysError()
2996d522f475Smrg *
2997d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
2998d522f475Smrg * over the errno and error exit to the master process so that it can
2999d522f475Smrg * display our error message and exit with our exit code so that the
3000d522f475Smrg * user can see it.
3001d522f475Smrg */
3002d522f475Smrg
3003d522f475Smrgstatic void
3004d522f475SmrgHsSysError(int error)
3005d522f475Smrg{
3006d522f475Smrg    handshake_t handshake;
3007d522f475Smrg
3008d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3009d522f475Smrg    handshake.status = PTY_FATALERROR;
3010d522f475Smrg    handshake.error = errno;
3011d522f475Smrg    handshake.fatal_error = error;
30120bd37d32Smrg    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
3013d522f475Smrg
3014d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
3015d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
3016d522f475Smrg	       handshake.error,
3017d522f475Smrg	       handshake.fatal_error,
3018d522f475Smrg	       handshake.buffer));
3019d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
302020d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
302120d2c4d2Smrg			(const char *) &handshake,
302220d2c4d2Smrg			sizeof(handshake)));
3023d522f475Smrg    } else {
30240bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
30250bd37d32Smrg		     handshake.error,
30260bd37d32Smrg		     handshake.fatal_error,
30270bd37d32Smrg		     handshake.buffer);
3028d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3029d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3030d522f475Smrg    }
3031d522f475Smrg    exit(error);
3032d522f475Smrg}
3033d522f475Smrg
3034d522f475Smrgvoid
3035d522f475Smrgfirst_map_occurred(void)
3036d522f475Smrg{
3037d522f475Smrg    if (resource.wait_for_map) {
3038d522f475Smrg	handshake_t handshake;
3039d522f475Smrg	TScreen *screen = TScreenOf(term);
3040d522f475Smrg
3041d522f475Smrg	memset(&handshake, 0, sizeof(handshake));
3042d522f475Smrg	handshake.status = PTY_EXEC;
3043d522f475Smrg	handshake.rows = screen->max_row;
3044d522f475Smrg	handshake.cols = screen->max_col;
3045d522f475Smrg
3046d522f475Smrg	if (pc_pipe[1] >= 0) {
3047d522f475Smrg	    TRACE(("first_map_occurred: %dx%d\n", handshake.rows, handshake.cols));
3048d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
304920d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
305020d2c4d2Smrg			    (const char *) &handshake,
305120d2c4d2Smrg			    sizeof(handshake)));
3052d522f475Smrg	    close(cp_pipe[0]);
3053d522f475Smrg	    close(pc_pipe[1]);
3054d522f475Smrg	}
3055d522f475Smrg	resource.wait_for_map = False;
3056d522f475Smrg    }
3057d522f475Smrg}
3058d522f475Smrg#else
3059d522f475Smrg/*
3060d522f475Smrg * temporary hack to get xterm working on att ptys
3061d522f475Smrg */
3062d522f475Smrgstatic void
3063d522f475SmrgHsSysError(int error)
3064d522f475Smrg{
30650bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
30660bd37d32Smrg		 error, errno, ttydev);
3067d522f475Smrg    exit(error);
3068d522f475Smrg}
3069d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3070d522f475Smrg
3071d522f475Smrg#ifndef VMS
3072d522f475Smrgstatic void
3073e0a2b6dfSmrgset_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
3074d522f475Smrg{
3075d522f475Smrg    int why;
3076d522f475Smrg
3077d522f475Smrg    TRACE_IDS;
307820d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
30790bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3080d522f475Smrg
3081d522f475Smrg    if (chown(device, uid, gid) < 0) {
3082d522f475Smrg	why = errno;
3083d522f475Smrg	if (why != ENOENT
3084d522f475Smrg	    && save_ruid == 0) {
30850bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
30860bd37d32Smrg			device, (long) uid, (long) gid);
3087d522f475Smrg	}
3088d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3089e39b573cSmrg    } else if (chmod(device, mode) < 0) {
3090d522f475Smrg	why = errno;
3091d522f475Smrg	if (why != ENOENT) {
3092d522f475Smrg	    struct stat sb;
3093d522f475Smrg	    if (stat(device, &sb) < 0) {
30940bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
30950bd37d32Smrg			    device, (unsigned) mode);
3096d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
30970bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
30980bd37d32Smrg			    device,
30990bd37d32Smrg			    (unsigned long) mode,
31000bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3101d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
31020bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3103d522f475Smrg	    }
3104d522f475Smrg	}
3105d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3106d522f475Smrg    }
3107d522f475Smrg}
3108d522f475Smrg
3109894e0ac8Smrg/*
3110894e0ac8Smrg * utmp data may not be null-terminated; even if it is, there may be garbage
3111894e0ac8Smrg * after the null.  This fills the unused part of the result with nulls.
3112894e0ac8Smrg */
3113894e0ac8Smrgstatic void
3114894e0ac8Smrgcopy_filled(char *target, const char *source, size_t len)
3115894e0ac8Smrg{
3116894e0ac8Smrg    size_t used = 0;
3117894e0ac8Smrg    while (used < len) {
3118894e0ac8Smrg	if ((target[used] = source[used]) == 0)
3119894e0ac8Smrg	    break;
3120894e0ac8Smrg	++used;
3121894e0ac8Smrg    }
3122894e0ac8Smrg    while (used < len) {
3123894e0ac8Smrg	target[used++] = '\0';
3124894e0ac8Smrg    }
3125894e0ac8Smrg}
3126894e0ac8Smrg
3127d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3128d522f475Smrg/*
3129d522f475Smrg * getutid() only looks at ut_type and ut_id.
3130d522f475Smrg * But we'll also check ut_line in find_utmp().
3131d522f475Smrg */
3132d522f475Smrgstatic void
3133d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3134d522f475Smrg{
3135d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3136d522f475Smrg    tofind->ut_type = type;
3137894e0ac8Smrg    copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3138894e0ac8Smrg    copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3139d522f475Smrg}
3140d522f475Smrg
3141d522f475Smrg/*
3142d522f475Smrg * We could use getutline() if we didn't support old systems.
3143d522f475Smrg */
3144d522f475Smrgstatic struct UTMP_STR *
3145d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3146d522f475Smrg{
3147d522f475Smrg    struct UTMP_STR *result;
31480bd37d32Smrg    struct UTMP_STR limited;
3149d522f475Smrg    struct UTMP_STR working;
3150d522f475Smrg
3151d522f475Smrg    for (;;) {
3152d522f475Smrg	memset(&working, 0, sizeof(working));
3153d522f475Smrg	working.ut_type = tofind->ut_type;
3154894e0ac8Smrg	copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3155d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3156d522f475Smrg	working.ut_type = 0;
3157d522f475Smrg#endif
3158d522f475Smrg	if ((result = call_getutid(&working)) == 0)
3159d522f475Smrg	    break;
3160894e0ac8Smrg	copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line));
31610bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3162d522f475Smrg	    break;
3163d522f475Smrg	/*
3164d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3165d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3166d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3167d522f475Smrg	 */
3168d522f475Smrg	memset(result, 0, sizeof(*result));
3169d522f475Smrg    }
3170d522f475Smrg    return result;
3171d522f475Smrg}
3172d522f475Smrg#endif /* HAVE_UTMP... */
3173d522f475Smrg
3174d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3175d522f475Smrg
317620d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
317720d2c4d2Smrg#define USE_NO_DEV_TTY 1
317820d2c4d2Smrg#else
317920d2c4d2Smrg#define USE_NO_DEV_TTY 0
318020d2c4d2Smrg#endif
318120d2c4d2Smrg
3182e0a2b6dfSmrgstatic int
3183e0a2b6dfSmrgsame_leaf(char *a, char *b)
3184e0a2b6dfSmrg{
3185e0a2b6dfSmrg    char *p = x_basename(a);
3186e0a2b6dfSmrg    char *q = x_basename(b);
3187e0a2b6dfSmrg    return !strcmp(p, q);
3188e0a2b6dfSmrg}
3189e0a2b6dfSmrg
3190e0a2b6dfSmrg/*
3191e0a2b6dfSmrg * "good enough" (inode wouldn't port to Cygwin)
3192e0a2b6dfSmrg */
3193e0a2b6dfSmrgstatic int
3194e0a2b6dfSmrgsame_file(const char *a, const char *b)
3195e0a2b6dfSmrg{
3196e0a2b6dfSmrg    struct stat asb;
3197e0a2b6dfSmrg    struct stat bsb;
3198e0a2b6dfSmrg    int result = 0;
3199e0a2b6dfSmrg
3200e0a2b6dfSmrg    if ((stat(a, &asb) == 0)
3201e0a2b6dfSmrg	&& (stat(b, &bsb) == 0)
3202e0a2b6dfSmrg	&& ((asb.st_mode & S_IFMT) == S_IFREG)
3203e0a2b6dfSmrg	&& ((bsb.st_mode & S_IFMT) == S_IFREG)
3204e0a2b6dfSmrg	&& (asb.st_mtime == bsb.st_mtime)
3205e0a2b6dfSmrg	&& (asb.st_size == bsb.st_size)) {
3206e0a2b6dfSmrg	result = 1;
3207e0a2b6dfSmrg    }
3208e0a2b6dfSmrg    return result;
3209e0a2b6dfSmrg}
3210e0a2b6dfSmrg
3211e0a2b6dfSmrg/*
3212e0a2b6dfSmrg * Only set $SHELL for paths found in the standard location.
3213e0a2b6dfSmrg */
3214e0a2b6dfSmrgstatic Boolean
3215e0a2b6dfSmrgvalidShell(const char *pathname)
3216e0a2b6dfSmrg{
3217e0a2b6dfSmrg    Boolean result = False;
3218e0a2b6dfSmrg    const char *ok_shells = "/etc/shells";
3219e0a2b6dfSmrg    char *blob;
3220e0a2b6dfSmrg    struct stat sb;
3221e0a2b6dfSmrg    size_t rc;
3222e0a2b6dfSmrg    FILE *fp;
3223e0a2b6dfSmrg
3224e0a2b6dfSmrg    if (validProgram(pathname)
3225e0a2b6dfSmrg	&& stat(ok_shells, &sb) == 0
3226e0a2b6dfSmrg	&& (sb.st_mode & S_IFMT) == S_IFREG
3227e0a2b6dfSmrg	&& (sb.st_size != 0)
3228e0a2b6dfSmrg	&& (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
3229e0a2b6dfSmrg	if ((fp = fopen(ok_shells, "r")) != 0) {
3230e0a2b6dfSmrg	    rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
3231e0a2b6dfSmrg	    if (rc == (size_t) sb.st_size) {
3232e0a2b6dfSmrg		char *p = blob;
3233e0a2b6dfSmrg		char *q, *r;
3234e0a2b6dfSmrg		blob[rc] = '\0';
3235e0a2b6dfSmrg		while (!result && (q = strtok(p, "\n")) != 0) {
3236e0a2b6dfSmrg		    if ((r = x_strtrim(q)) != 0) {
3237e0a2b6dfSmrg			TRACE(("...test \"%s\"\n", q));
3238e0a2b6dfSmrg			if (!strcmp(q, pathname)) {
3239e0a2b6dfSmrg			    result = True;
3240e0a2b6dfSmrg			} else if (same_leaf(q, (char *) pathname) &&
3241e0a2b6dfSmrg				   same_file(q, pathname)) {
3242e0a2b6dfSmrg			    result = True;
3243e0a2b6dfSmrg			}
3244e0a2b6dfSmrg			free(r);
3245e0a2b6dfSmrg		    }
3246e0a2b6dfSmrg		    p = 0;
3247e0a2b6dfSmrg		}
3248e0a2b6dfSmrg	    }
3249e0a2b6dfSmrg	    fclose(fp);
3250e0a2b6dfSmrg	}
3251e0a2b6dfSmrg	free(blob);
3252e0a2b6dfSmrg    }
3253e0a2b6dfSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3254e0a2b6dfSmrg    return result;
3255e0a2b6dfSmrg}
3256e0a2b6dfSmrg
3257e0a2b6dfSmrgstatic char *
3258e0a2b6dfSmrgresetShell(char *oldPath)
3259e0a2b6dfSmrg{
3260e0a2b6dfSmrg    char *newPath = x_strdup("/bin/sh");
3261e0a2b6dfSmrg    char *envPath = getenv("SHELL");
3262e0a2b6dfSmrg    if (oldPath != 0)
3263e0a2b6dfSmrg	free(oldPath);
3264e0a2b6dfSmrg    if (!IsEmpty(envPath))
3265e0a2b6dfSmrg	xtermSetenv("SHELL", newPath);
3266e0a2b6dfSmrg    return newPath;
3267e0a2b6dfSmrg}
3268e0a2b6dfSmrg
3269d522f475Smrg/*
3270d522f475Smrg *  Inits pty and tty and forks a login process.
3271d522f475Smrg *  Does not close fd Xsocket.
3272d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3273d522f475Smrg */
3274d522f475Smrgstatic int
3275d522f475SmrgspawnXTerm(XtermWidget xw)
3276d522f475Smrg{
3277d522f475Smrg    TScreen *screen = TScreenOf(xw);
3278d522f475Smrg    Cardinal nn;
3279d522f475Smrg#if OPT_PTY_HANDSHAKE
3280d522f475Smrg    Bool got_handshake_size = False;
3281d522f475Smrg    handshake_t handshake;
3282d522f475Smrg    int done;
3283d522f475Smrg#endif
3284d522f475Smrg#if OPT_INITIAL_ERASE
3285d522f475Smrg    int initial_erase = VAL_INITIAL_ERASE;
3286d522f475Smrg    Bool setInitialErase;
3287d522f475Smrg#endif
3288d522f475Smrg    int rc = 0;
3289d522f475Smrg    int ttyfd = -1;
3290d522f475Smrg    Bool ok_termcap;
3291d522f475Smrg    char *newtc;
3292d522f475Smrg
3293d522f475Smrg#ifdef TERMIO_STRUCT
3294d522f475Smrg    TERMIO_STRUCT tio;
3295d522f475Smrg#ifdef __MVS__
3296d522f475Smrg    TERMIO_STRUCT gio;
3297d522f475Smrg#endif /* __MVS__ */
3298d522f475Smrg#ifdef TIOCLSET
3299d522f475Smrg    unsigned lmode;
3300d522f475Smrg#endif /* TIOCLSET */
3301d522f475Smrg#ifdef HAS_LTCHARS
3302d522f475Smrg    struct ltchars ltc;
3303d522f475Smrg#endif /* HAS_LTCHARS */
3304d522f475Smrg#else /* !TERMIO_STRUCT */
3305d522f475Smrg    int ldisc = 0;
3306d522f475Smrg    int discipline;
3307d522f475Smrg    unsigned lmode;
3308d522f475Smrg    struct tchars tc;
3309d522f475Smrg    struct ltchars ltc;
3310d522f475Smrg    struct sgttyb sg;
3311d522f475Smrg#ifdef sony
3312d522f475Smrg    int jmode;
3313d522f475Smrg    struct jtchars jtc;
3314d522f475Smrg#endif /* sony */
3315d522f475Smrg#endif /* TERMIO_STRUCT */
3316d522f475Smrg
33170bd37d32Smrg    char *shell_path = 0;
33180bd37d32Smrg    char *shname, *shname_minus;
331920d2c4d2Smrg    int i;
332020d2c4d2Smrg#if USE_NO_DEV_TTY
332120d2c4d2Smrg    int no_dev_tty = False;
332220d2c4d2Smrg#endif
332301037d57Smrg    const char *const *envnew;	/* new environment */
3324d522f475Smrg    char buf[64];
3325d522f475Smrg    char *TermName = NULL;
3326d522f475Smrg#ifdef TTYSIZE_STRUCT
3327d522f475Smrg    TTYSIZE_STRUCT ts;
3328d522f475Smrg#endif
33290bd37d32Smrg    struct passwd pw;
3330d522f475Smrg    char *login_name = NULL;
3331d522f475Smrg#ifndef USE_UTEMPTER
3332d522f475Smrg#ifdef HAVE_UTMP
3333d522f475Smrg    struct UTMP_STR utmp;
3334d522f475Smrg#ifdef USE_SYSV_UTMP
3335d522f475Smrg    struct UTMP_STR *utret = NULL;
3336d522f475Smrg#endif
3337d522f475Smrg#ifdef USE_LASTLOG
3338d522f475Smrg    struct lastlog lastlog;
3339d522f475Smrg#endif
3340d522f475Smrg#ifdef USE_LASTLOGX
3341d522f475Smrg    struct lastlogx lastlogx;
3342d522f475Smrg#endif /* USE_LASTLOG */
3343d522f475Smrg#endif /* HAVE_UTMP */
3344d522f475Smrg#endif /* !USE_UTEMPTER */
3345d522f475Smrg
3346e39b573cSmrg#if OPT_TRACE
3347e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
3348e39b573cSmrg#endif
3349e39b573cSmrg
3350d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
3351d522f475Smrg    (void) rc;
3352d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3353d522f475Smrg    (void) utret;
3354d522f475Smrg#endif
3355d522f475Smrg
3356d522f475Smrg    screen->uid = save_ruid;
3357d522f475Smrg    screen->gid = save_rgid;
3358d522f475Smrg
3359d522f475Smrg#ifdef SIGTTOU
3360d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
3361d522f475Smrg    signal(SIGTTOU, SIG_IGN);
3362d522f475Smrg#endif
3363d522f475Smrg
3364d522f475Smrg#if OPT_PTY_HANDSHAKE
3365d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3366d522f475Smrg#endif
3367d522f475Smrg
3368d522f475Smrg    if (am_slave >= 0) {
3369d522f475Smrg	screen->respond = am_slave;
3370d522f475Smrg	set_pty_id(ttydev, passedPty);
3371d522f475Smrg#ifdef USE_PTY_DEVICE
3372d522f475Smrg	set_pty_id(ptydev, passedPty);
3373d522f475Smrg#endif
3374d522f475Smrg	if (xtermResetIds(screen) < 0)
3375d522f475Smrg	    exit(1);
3376d522f475Smrg    } else {
3377d522f475Smrg	Bool tty_got_hung;
3378d522f475Smrg
3379d522f475Smrg	/*
3380d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
3381d522f475Smrg	 * that has gone away).  Simply make up some reasonable
3382d522f475Smrg	 * defaults.
3383d522f475Smrg	 */
3384d522f475Smrg
3385d522f475Smrg	signal(SIGALRM, hungtty);
3386d522f475Smrg	alarm(2);		/* alarm(1) might return too soon */
3387d522f475Smrg	if (!sigsetjmp(env, 1)) {
3388d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
3389d522f475Smrg	    alarm(0);
3390d522f475Smrg	    tty_got_hung = False;
3391d522f475Smrg	} else {
3392d522f475Smrg	    tty_got_hung = True;
3393d522f475Smrg	    ttyfd = -1;
3394d522f475Smrg	    errno = ENXIO;
3395d522f475Smrg	}
33960bd37d32Smrg	memset(&pw, 0, sizeof(pw));
3397d522f475Smrg#if OPT_PTY_HANDSHAKE
3398d522f475Smrg	got_handshake_size = False;
3399d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
3400d522f475Smrg#if OPT_INITIAL_ERASE
3401d522f475Smrg	initial_erase = VAL_INITIAL_ERASE;
3402d522f475Smrg#endif
3403d522f475Smrg	signal(SIGALRM, SIG_DFL);
3404d522f475Smrg
3405d522f475Smrg	/*
3406d522f475Smrg	 * Check results and ignore current control terminal if
3407d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
3408d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
3409d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
34100bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
34110bd37d32Smrg	 * if xterm is run within a jail.
3412d522f475Smrg	 */
341320d2c4d2Smrg#if USE_NO_DEV_TTY
3414d522f475Smrg	no_dev_tty = False;
341520d2c4d2Smrg#endif
3416d522f475Smrg	if (ttyfd < 0) {
3417d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
34180bd37d32Smrg		errno == ENOENT ||
3419d522f475Smrg#ifdef ENODEV
3420d522f475Smrg		errno == ENODEV ||
3421d522f475Smrg#endif
3422d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
342320d2c4d2Smrg#if USE_NO_DEV_TTY
3424d522f475Smrg		no_dev_tty = True;
342520d2c4d2Smrg#endif
3426d522f475Smrg#ifdef HAS_LTCHARS
3427d522f475Smrg		ltc = d_ltc;
3428d522f475Smrg#endif /* HAS_LTCHARS */
3429d522f475Smrg#ifdef TIOCLSET
3430d522f475Smrg		lmode = d_lmode;
3431d522f475Smrg#endif /* TIOCLSET */
3432d522f475Smrg#ifdef TERMIO_STRUCT
3433d522f475Smrg		tio = d_tio;
3434d522f475Smrg#else /* !TERMIO_STRUCT */
3435d522f475Smrg		sg = d_sg;
3436d522f475Smrg		tc = d_tc;
3437d522f475Smrg		discipline = d_disipline;
3438d522f475Smrg#ifdef sony
3439d522f475Smrg		jmode = d_jmode;
3440d522f475Smrg		jtc = d_jtc;
3441d522f475Smrg#endif /* sony */
3442d522f475Smrg#endif /* TERMIO_STRUCT */
3443d522f475Smrg	    } else {
3444d522f475Smrg		SysError(ERROR_OPDEVTTY);
3445d522f475Smrg	    }
3446d522f475Smrg	} else {
3447d522f475Smrg
3448d522f475Smrg	    /* Get a copy of the current terminal's state,
3449d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
3450d522f475Smrg	     * may not have a controlling terminal at this point
3451d522f475Smrg	     * if started directly from xdm or xinit,
3452d522f475Smrg	     * in which case we just use the defaults as above.
3453d522f475Smrg	     */
3454d522f475Smrg#ifdef HAS_LTCHARS
3455d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
3456d522f475Smrg		ltc = d_ltc;
3457d522f475Smrg#endif /* HAS_LTCHARS */
3458d522f475Smrg#ifdef TIOCLSET
3459d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
3460d522f475Smrg		lmode = d_lmode;
3461d522f475Smrg#endif /* TIOCLSET */
3462d522f475Smrg#ifdef TERMIO_STRUCT
346320d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
346420d2c4d2Smrg	    if (rc == -1)
3465d522f475Smrg		tio = d_tio;
3466d522f475Smrg#else /* !TERMIO_STRUCT */
346720d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
346820d2c4d2Smrg	    if (rc == -1)
3469d522f475Smrg		sg = d_sg;
3470d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
3471d522f475Smrg		tc = d_tc;
3472d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
3473d522f475Smrg		discipline = d_disipline;
3474d522f475Smrg#ifdef sony
3475d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
3476d522f475Smrg		jmode = d_jmode;
3477d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
3478d522f475Smrg		jtc = d_jtc;
3479d522f475Smrg#endif /* sony */
3480d522f475Smrg#endif /* TERMIO_STRUCT */
3481d522f475Smrg
3482d522f475Smrg	    /*
3483d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
3484d522f475Smrg	     * erase value.  Just in case that will fail, first get
3485d522f475Smrg	     * the value from /dev/tty, so we will have something
3486d522f475Smrg	     * at least.
3487d522f475Smrg	     */
3488d522f475Smrg#if OPT_INITIAL_ERASE
3489d522f475Smrg	    if (resource.ptyInitialErase) {
3490d522f475Smrg#ifdef TERMIO_STRUCT
3491d522f475Smrg		initial_erase = tio.c_cc[VERASE];
3492d522f475Smrg#else /* !TERMIO_STRUCT */
3493d522f475Smrg		initial_erase = sg.sg_erase;
3494d522f475Smrg#endif /* TERMIO_STRUCT */
3495d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
3496d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
3497d522f475Smrg		       initial_erase));
3498d522f475Smrg	    }
3499d522f475Smrg#endif
3500d522f475Smrg#ifdef __MVS__
3501d522f475Smrg	    if (ttyGetAttr(ttyfd, &gio) == 0) {
3502d522f475Smrg		gio.c_cflag &= ~(HUPCL | PARENB);
3503d522f475Smrg		ttySetAttr(ttyfd, &gio);
3504d522f475Smrg	    }
3505d522f475Smrg#endif /* __MVS__ */
3506d522f475Smrg
3507d522f475Smrg	    close_fd(ttyfd);
3508d522f475Smrg	}
3509d522f475Smrg
3510d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
3511d522f475Smrg	    SysError(ERROR_PTYS);
3512d522f475Smrg	}
35130bd37d32Smrg	TRACE_TTYSIZE(screen->respond, "after get_pty");
3514d522f475Smrg#if OPT_INITIAL_ERASE
3515d522f475Smrg	if (resource.ptyInitialErase) {
3516d522f475Smrg#ifdef TERMIO_STRUCT
3517d522f475Smrg	    TERMIO_STRUCT my_tio;
351820d2c4d2Smrg	    rc = ttyGetAttr(screen->respond, &my_tio);
351920d2c4d2Smrg	    if (rc == 0)
3520d522f475Smrg		initial_erase = my_tio.c_cc[VERASE];
3521d522f475Smrg#else /* !TERMIO_STRUCT */
3522d522f475Smrg	    struct sgttyb my_sg;
352320d2c4d2Smrg	    rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg);
352420d2c4d2Smrg	    if (rc == 0)
3525d522f475Smrg		initial_erase = my_sg.sg_erase;
3526d522f475Smrg#endif /* TERMIO_STRUCT */
3527d522f475Smrg	    TRACE(("%s initial_erase:%d (from pty)\n",
3528d522f475Smrg		   (rc == 0) ? "OK" : "FAIL",
3529d522f475Smrg		   initial_erase));
3530d522f475Smrg	}
3531d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3532d522f475Smrg    }
3533d522f475Smrg
3534d522f475Smrg    /* avoid double MapWindow requests */
3535d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
3536d522f475Smrg
3537d522f475Smrg    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
3538d522f475Smrg				   False);
3539d522f475Smrg
3540d522f475Smrg    if (!TEK4014_ACTIVE(xw))
3541956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
3542d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
3543d522f475Smrg    if (Console) {
3544d522f475Smrg	/*
3545d522f475Smrg	 * Inform any running xconsole program
3546d522f475Smrg	 * that we are going to steal the console.
3547d522f475Smrg	 */
3548d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
3549d522f475Smrg	mit_console = XInternAtom(screen->display, mit_console_name, False);
3550d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
3551d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
3552d522f475Smrg		       mit_console, CurrentTime,
3553d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
3554d522f475Smrg    }
3555d522f475Smrg#endif
3556d522f475Smrg#if OPT_TEK4014
3557d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3558d522f475Smrg	envnew = tekterm;
3559d522f475Smrg    } else
3560d522f475Smrg#endif
3561d522f475Smrg    {
3562d522f475Smrg	envnew = vtterm;
3563d522f475Smrg    }
3564d522f475Smrg
3565d522f475Smrg    /*
3566d522f475Smrg     * This used to exit if no termcap entry was found for the specified
3567d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
3568d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
3569d522f475Smrg     * entry is not found.
3570d522f475Smrg     */
3571d522f475Smrg    ok_termcap = True;
357220d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
357320d2c4d2Smrg	const char *last = NULL;
357420d2c4d2Smrg	char *next;
357520d2c4d2Smrg
357620d2c4d2Smrg	TermName = x_strdup(*envnew);
3577d522f475Smrg	ok_termcap = False;
3578d522f475Smrg	while (*envnew != NULL) {
357920d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
358020d2c4d2Smrg		next = x_strdup(*envnew);
358120d2c4d2Smrg		if (get_termcap(xw, next)) {
358220d2c4d2Smrg		    free(TermName);
358320d2c4d2Smrg		    TermName = next;
35840bd37d32Smrg		    ok_termcap = True + 1;
358520d2c4d2Smrg		    break;
358620d2c4d2Smrg		} else {
358720d2c4d2Smrg		    free(next);
358820d2c4d2Smrg		}
3589d522f475Smrg	    }
3590d522f475Smrg	    last = *envnew;
3591d522f475Smrg	    envnew++;
3592d522f475Smrg	}
3593d522f475Smrg    }
3594d522f475Smrg    if (ok_termcap) {
3595a1f3da82Smrg	resource.term_name = TermName;
359620d2c4d2Smrg	resize_termcap(xw);
3597d522f475Smrg    }
3598d522f475Smrg
3599d522f475Smrg    /*
3600d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
3601d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
3602d522f475Smrg     */
3603d522f475Smrg#if OPT_INITIAL_ERASE
3604d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
3605d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
3606d522f475Smrg    setInitialErase = False;
3607d522f475Smrg    if (override_tty_modes && ttymodelist[XTTYMODE_erase].set) {
3608d522f475Smrg	initial_erase = ttymodelist[XTTYMODE_erase].value;
3609d522f475Smrg	setInitialErase = True;
3610d522f475Smrg    } else if (resource.ptyInitialErase) {
3611a1f3da82Smrg	/* EMPTY */ ;
3612d522f475Smrg    } else if (ok_termcap) {
361320d2c4d2Smrg	char *s = get_tcap_erase(xw);
3614d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
3615d522f475Smrg	if (s != 0) {
361620d2c4d2Smrg	    char *save = s;
3617d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
3618d522f475Smrg	    setInitialErase = True;
361920d2c4d2Smrg	    free(save);
3620d522f475Smrg	}
3621d522f475Smrg    }
3622d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
3623d522f475Smrg
3624d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
3625d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
3626d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
3627d522f475Smrg	if (initial_erase == ANSI_DEL) {
362820d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
3629d522f475Smrg	} else {
3630d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
3631d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
3632d522f475Smrg	}
3633d522f475Smrg	TRACE(("...sets DECBKM %s\n",
3634d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
3635d522f475Smrg    } else {
3636d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
3637d522f475Smrg    }
3638d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3639d522f475Smrg
3640d522f475Smrg#ifdef TTYSIZE_STRUCT
3641d522f475Smrg    /* tell tty how big window is */
3642d522f475Smrg#if OPT_TEK4014
3643d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3644d522f475Smrg	TTYSIZE_ROWS(ts) = 38;
3645d522f475Smrg	TTYSIZE_COLS(ts) = 81;
3646d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
364720d2c4d2Smrg	ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
364820d2c4d2Smrg	ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3649d522f475Smrg#endif
3650d522f475Smrg    } else
3651d522f475Smrg#endif
3652d522f475Smrg    {
365320d2c4d2Smrg	TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
365420d2c4d2Smrg	TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3655d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
365620d2c4d2Smrg	ts.ws_xpixel = (ttySize_t) FullWidth(screen);
365720d2c4d2Smrg	ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3658d522f475Smrg#endif
3659d522f475Smrg    }
366020d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
3661d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
3662d522f475Smrg	   TTYSIZE_ROWS(ts),
3663d522f475Smrg	   TTYSIZE_COLS(ts), i));
3664d522f475Smrg#endif /* TTYSIZE_STRUCT */
3665d522f475Smrg
36660bd37d32Smrg#if !defined(USE_OPENPTY)
36670bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
36680bd37d32Smrg    /*
36690bd37d32Smrg     * utempter checks the ownership of the device; some implementations
36700bd37d32Smrg     * set ownership in grantpt - do this first.
36710bd37d32Smrg     */
36720bd37d32Smrg    grantpt(screen->respond);
36730bd37d32Smrg#endif
36740bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
36750bd37d32Smrg    unlockpt(screen->respond);
36760bd37d32Smrg    TRACE_TTYSIZE(screen->respond, "after unlockpt");
36770bd37d32Smrg#endif
36780bd37d32Smrg#endif /* !USE_OPENPTY */
36790bd37d32Smrg
3680d522f475Smrg    added_utmp_entry = False;
3681d522f475Smrg#if defined(USE_UTEMPTER)
3682d522f475Smrg#undef UTMP
3683d522f475Smrg    if (!resource.utmpInhibit) {
3684d522f475Smrg	struct UTMP_STR dummy;
3685d522f475Smrg
3686d522f475Smrg	/* Note: utempter may trim it anyway */
3687d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
36880bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
36890bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
3690d522f475Smrg	addToUtmp(ttydev, dummy.ut_host, screen->respond);
3691d522f475Smrg	added_utmp_entry = True;
3692d522f475Smrg    }
3693d522f475Smrg#endif
3694d522f475Smrg
3695d522f475Smrg    if (am_slave < 0) {
3696d522f475Smrg#if OPT_PTY_HANDSHAKE
3697d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
3698d522f475Smrg	    SysError(ERROR_FORK);
3699d522f475Smrg#endif
3700d522f475Smrg	TRACE(("Forking...\n"));
3701d522f475Smrg	if ((screen->pid = fork()) == -1)
3702d522f475Smrg	    SysError(ERROR_FORK);
3703d522f475Smrg
3704d522f475Smrg	if (screen->pid == 0) {
3705d522f475Smrg#ifdef USE_USG_PTYS
370620d2c4d2Smrg	    int ptyfd = -1;
3707d522f475Smrg	    char *pty_name;
3708d522f475Smrg#endif
3709d522f475Smrg	    /*
3710d522f475Smrg	     * now in child process
3711d522f475Smrg	     */
3712d522f475Smrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
3713d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
3714d522f475Smrg#else
3715d522f475Smrg	    int pgrp = getpid();
3716d522f475Smrg#endif
3717d522f475Smrg	    TRACE_CHILD
3718d522f475Smrg
3719d522f475Smrg#ifdef USE_USG_PTYS
37200bd37d32Smrg#ifdef HAVE_SETPGID
37210bd37d32Smrg		setpgid(0, 0);
37220bd37d32Smrg#else
3723d522f475Smrg		setpgrp();
37240bd37d32Smrg#endif
37250bd37d32Smrg	    unlockpt(screen->respond);
37260bd37d32Smrg	    TRACE_TTYSIZE(screen->respond, "after unlockpt");
37270bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
37280bd37d32Smrg		SysError(ERROR_PTSNAME);
37290bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
37300bd37d32Smrg		SysError(ERROR_OPPTSNAME);
37310bd37d32Smrg	    }
3732d522f475Smrg#ifdef I_PUSH
37330bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ptem") < 0) {
37340bd37d32Smrg		SysError(ERROR_PTEM);
37350bd37d32Smrg	    }
3736d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
37370bd37d32Smrg	    else if (!x_getenv("CONSEM")
37380bd37d32Smrg		     && ioctl(ptyfd, I_PUSH, "consem") < 0) {
37390bd37d32Smrg		SysError(ERROR_CONSEM);
37400bd37d32Smrg	    }
3741d522f475Smrg#endif /* !SVR4 */
37420bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ldterm") < 0) {
37430bd37d32Smrg		SysError(ERROR_LDTERM);
37440bd37d32Smrg	    }
3745d522f475Smrg#ifdef SVR4			/* from Sony */
37460bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ttcompat") < 0) {
37470bd37d32Smrg		SysError(ERROR_TTCOMPAT);
37480bd37d32Smrg	    }
3749d522f475Smrg#endif /* SVR4 */
3750d522f475Smrg#endif /* I_PUSH */
37510bd37d32Smrg	    ttyfd = ptyfd;
3752d522f475Smrg#ifndef __MVS__
37530bd37d32Smrg	    close_fd(screen->respond);
3754d522f475Smrg#endif /* __MVS__ */
3755d522f475Smrg
3756d522f475Smrg#ifdef TTYSIZE_STRUCT
37570bd37d32Smrg	    /* tell tty how big window is */
3758d522f475Smrg#if OPT_TEK4014
37590bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
37600bd37d32Smrg		TTYSIZE_ROWS(ts) = 24;
37610bd37d32Smrg		TTYSIZE_COLS(ts) = 80;
3762d522f475Smrg#ifdef USE_STRUCT_WINSIZE
37630bd37d32Smrg		ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
37640bd37d32Smrg		ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3765d522f475Smrg#endif
37660bd37d32Smrg	    } else
3767d522f475Smrg#endif /* OPT_TEK4014 */
37680bd37d32Smrg	    {
37690bd37d32Smrg		TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
37700bd37d32Smrg		TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3771d522f475Smrg#ifdef USE_STRUCT_WINSIZE
37720bd37d32Smrg		ts.ws_xpixel = (ttySize_t) FullWidth(screen);
37730bd37d32Smrg		ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3774d522f475Smrg#endif
37750bd37d32Smrg	    }
3776d522f475Smrg#endif /* TTYSIZE_STRUCT */
3777d522f475Smrg
3778d522f475Smrg#endif /* USE_USG_PTYS */
3779d522f475Smrg
37800bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
3781d522f475Smrg
3782d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
37830bd37d32Smrg	    if (resource.ptyHandshake) {
37840bd37d32Smrg		char *ptr;
3785d522f475Smrg
37860bd37d32Smrg		/* close parent's sides of the pipes */
37870bd37d32Smrg		close(cp_pipe[0]);
37880bd37d32Smrg		close(pc_pipe[1]);
37890bd37d32Smrg
37900bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
37910bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
37920bd37d32Smrg		 * or err.
37930bd37d32Smrg		 */
37940bd37d32Smrg		if (cp_pipe[1] <= 2) {
37950bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
37960bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
37970bd37d32Smrg			cp_pipe[1] = i;
3798d522f475Smrg		    }
37990bd37d32Smrg		}
38000bd37d32Smrg		if (pc_pipe[0] <= 2) {
38010bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
38020bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
38030bd37d32Smrg			pc_pipe[0] = i;
3804d522f475Smrg		    }
38050bd37d32Smrg		}
3806d522f475Smrg
38070bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
38080bd37d32Smrg		close(ConnectionNumber(screen->display));
3809d522f475Smrg#ifndef __MVS__
3810894e0ac8Smrg		if (screen->respond >= 0)
3811894e0ac8Smrg		    close(screen->respond);
3812d522f475Smrg#endif /* __MVS__ */
3813d522f475Smrg
38140bd37d32Smrg		/* Now is the time to set up our process group and
38150bd37d32Smrg		 * open up the pty slave.
38160bd37d32Smrg		 */
3817d522f475Smrg#ifdef USE_SYSV_PGRP
3818d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
38190bd37d32Smrg		IGNORE_RC(setsid());
3820d522f475Smrg#else
38210bd37d32Smrg		IGNORE_RC(setpgrp());
3822d522f475Smrg#endif
3823d522f475Smrg#endif /* USE_SYSV_PGRP */
3824d522f475Smrg
3825d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
38260bd37d32Smrg		qsetlogin(getlogin(), ttydev);
3827d522f475Smrg#endif
38280bd37d32Smrg		if (ttyfd >= 0) {
3829d522f475Smrg#ifdef __MVS__
38300bd37d32Smrg		    if (ttyGetAttr(ttyfd, &gio) == 0) {
38310bd37d32Smrg			gio.c_cflag &= ~(HUPCL | PARENB);
38320bd37d32Smrg			ttySetAttr(ttyfd, &gio);
38330bd37d32Smrg		    }
3834d522f475Smrg#else /* !__MVS__ */
38350bd37d32Smrg		    close_fd(ttyfd);
3836d522f475Smrg#endif /* __MVS__ */
38370bd37d32Smrg		}
3838d522f475Smrg
38390bd37d32Smrg		for (;;) {
384020d2c4d2Smrg#if USE_NO_DEV_TTY
38410bd37d32Smrg		    if (!no_dev_tty
38420bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
38430bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
38440bd37d32Smrg			close_fd(ttyfd);
38450bd37d32Smrg		    }
384620d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
3847d522f475Smrg#ifdef CSRG_BASED
38480bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
3849d522f475Smrg#endif
38500bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
38510bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after open");
38520bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
38530bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after fixup");
3854d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
38550bd37d32Smrg			/* make /dev/tty work */
38560bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
3857d522f475Smrg#endif
3858d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
38590bd37d32Smrg			/* make /dev/tty work */
38600bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
3861d522f475Smrg#endif
3862d522f475Smrg#ifdef USE_SYSV_PGRP
38630bd37d32Smrg			/* We need to make sure that we are actually
38640bd37d32Smrg			 * the process group leader for the pty.  If
38650bd37d32Smrg			 * we are, then we should now be able to open
38660bd37d32Smrg			 * /dev/tty.
38670bd37d32Smrg			 */
38680bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
38690bd37d32Smrg			    /* success! */
38700bd37d32Smrg			    close(i);
3871d522f475Smrg			    break;
3872d522f475Smrg			}
38730bd37d32Smrg#else /* USE_SYSV_PGRP */
38740bd37d32Smrg			break;
38750bd37d32Smrg#endif /* USE_SYSV_PGRP */
38760bd37d32Smrg		    }
38770bd37d32Smrg		    perror("open ttydev");
3878d522f475Smrg#ifdef TIOCSCTTY
38790bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
3880d522f475Smrg#endif
38810bd37d32Smrg		    /* let our master know that the open failed */
38820bd37d32Smrg		    handshake.status = PTY_BAD;
38830bd37d32Smrg		    handshake.error = errno;
38840bd37d32Smrg		    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
38850bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
38860bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
38870bd37d32Smrg				    (const char *) &handshake,
38880bd37d32Smrg				    sizeof(handshake)));
3889d522f475Smrg
38900bd37d32Smrg		    /* get reply from parent */
38910bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
38920bd37d32Smrg				   sizeof(handshake));
38930bd37d32Smrg		    if (i <= 0) {
38940bd37d32Smrg			/* parent terminated */
38950bd37d32Smrg			exit(1);
3896d522f475Smrg		    }
3897d522f475Smrg
38980bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
38990bd37d32Smrg			/* No more ptys, let's shutdown. */
39000bd37d32Smrg			exit(1);
3901d522f475Smrg		    }
39020bd37d32Smrg
39030bd37d32Smrg		    /* We have a new pty to try */
39040bd37d32Smrg		    if (ttyfd >= 0)
39050bd37d32Smrg			close(ttyfd);
39060bd37d32Smrg		    free(ttydev);
39070bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
3908d522f475Smrg		}
3909d522f475Smrg
39100bd37d32Smrg		/* use the same tty name that everyone else will use
39110bd37d32Smrg		 * (from ttyname)
39120bd37d32Smrg		 */
39130bd37d32Smrg		if ((ptr = ttyname(ttyfd)) != 0) {
39140bd37d32Smrg		    free(ttydev);
39150bd37d32Smrg		    ttydev = x_strdup(ptr);
39160bd37d32Smrg		}
39170bd37d32Smrg	    }
39180bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
3919d522f475Smrg
3920d522f475Smrg	    set_pty_permissions(screen->uid,
3921d522f475Smrg				screen->gid,
3922d522f475Smrg				(resource.messages
3923d522f475Smrg				 ? 0622U
3924d522f475Smrg				 : 0600U));
3925d522f475Smrg
3926d522f475Smrg	    /*
3927d522f475Smrg	     * set up the tty modes
3928d522f475Smrg	     */
3929d522f475Smrg	    {
3930d522f475Smrg#ifdef TERMIO_STRUCT
3931d522f475Smrg#if defined(umips) || defined(CRAY) || defined(linux)
3932d522f475Smrg		/* If the control tty had its modes screwed around with,
3933d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
3934d522f475Smrg		   will have bad values.  Let's just get termio from the
3935d522f475Smrg		   new tty and tailor it.  */
3936d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
3937d522f475Smrg		    SysError(ERROR_TIOCGETP);
3938d522f475Smrg		tio.c_lflag |= ECHOE;
3939d522f475Smrg#endif /* umips */
3940d522f475Smrg		/* Now is also the time to change the modes of the
3941d522f475Smrg		 * child pty.
3942d522f475Smrg		 */
3943d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
394420d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
3945d522f475Smrg		tio.c_iflag |= ICRNL;
39460bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
3947d522f475Smrg#if OPT_LUIT_PROG
3948d522f475Smrg		if (command_to_exec_with_luit == 0)
3949d522f475Smrg#endif
3950d522f475Smrg		    if (screen->utf8_mode)
3951d522f475Smrg			tio.c_iflag |= IUTF8;
3952d522f475Smrg#endif
3953d522f475Smrg		/* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */
3954d522f475Smrg#ifndef USE_POSIX_TERMIOS
395520d2c4d2Smrg		UIntClr(tio.c_oflag,
395620d2c4d2Smrg			(OCRNL
395720d2c4d2Smrg			 | ONLRET
395820d2c4d2Smrg			 | NLDLY
395920d2c4d2Smrg			 | CRDLY
396020d2c4d2Smrg			 | TABDLY
396120d2c4d2Smrg			 | BSDLY
396220d2c4d2Smrg			 | VTDLY
396320d2c4d2Smrg			 | FFDLY));
3964d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3965d522f475Smrg#ifdef ONLCR
3966d522f475Smrg		tio.c_oflag |= ONLCR;
3967d522f475Smrg#endif /* ONLCR */
3968d522f475Smrg#ifdef OPOST
3969d522f475Smrg		tio.c_oflag |= OPOST;
3970d522f475Smrg#endif /* OPOST */
3971d522f475Smrg#ifndef USE_POSIX_TERMIOS
3972d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
3973d522f475Smrg#  define CBAUD V_CBAUD
3974d522f475Smrg# endif
397520d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
3976d522f475Smrg#ifdef BAUD_0
3977d522f475Smrg		/* baud rate is 0 (don't care) */
3978d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
3979d522f475Smrg		tio.c_ispeed = tio.c_ospeed = VAL_LINE_SPEED;
3980d522f475Smrg#else /* !BAUD_0 */
3981d522f475Smrg		tio.c_cflag |= VAL_LINE_SPEED;
3982d522f475Smrg#endif /* !BAUD_0 */
3983d522f475Smrg#else /* USE_POSIX_TERMIOS */
3984d522f475Smrg		cfsetispeed(&tio, VAL_LINE_SPEED);
3985d522f475Smrg		cfsetospeed(&tio, VAL_LINE_SPEED);
3986d522f475Smrg#ifdef __MVS__
3987d522f475Smrg		/* turn off bits that can't be set from the slave side */
3988d522f475Smrg		tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
3989d522f475Smrg#endif /* __MVS__ */
3990d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
3991d522f475Smrg		   when the xterm ends */
3992d522f475Smrg		tio.c_cflag &= ~CLOCAL;
3993d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3994d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
3995d522f475Smrg		 * echo
3996d522f475Smrg		 */
3997d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
3998d522f475Smrg#ifdef ECHOKE
3999d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
4000d522f475Smrg#endif
4001d522f475Smrg#ifdef ECHOCTL
4002d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
4003d522f475Smrg#endif
4004d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
4005d522f475Smrg		    if (validTtyChar(tio, nn)) {
4006d522f475Smrg			int sysMode = known_ttyChars[nn].sysMode;
4007d522f475Smrg#ifdef __MVS__
4008d522f475Smrg			if (tio.c_cc[sysMode] != 0) {
4009d522f475Smrg			    switch (sysMode) {
4010d522f475Smrg			    case VEOL:
4011d522f475Smrg			    case VEOF:
4012d522f475Smrg				continue;
4013d522f475Smrg			    }
4014d522f475Smrg			}
4015d522f475Smrg#endif
40160bd37d32Smrg			tio.c_cc[sysMode] = (cc_t) known_ttyChars[nn].myDefault;
4017d522f475Smrg		    }
4018d522f475Smrg		}
4019d522f475Smrg
4020d522f475Smrg		if (override_tty_modes) {
4021d522f475Smrg		    for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
4022d522f475Smrg			if (validTtyChar(tio, nn)) {
4023d522f475Smrg			    TMODE(known_ttyChars[nn].myMode,
4024d522f475Smrg				  tio.c_cc[known_ttyChars[nn].sysMode]);
4025d522f475Smrg			}
4026d522f475Smrg		    }
4027d522f475Smrg#ifdef HAS_LTCHARS
4028d522f475Smrg		    /* both SYSV and BSD have ltchars */
4029d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4030d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4031d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4032d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4033d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4034d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4035d522f475Smrg#endif
4036d522f475Smrg		}
4037d522f475Smrg#ifdef HAS_LTCHARS
4038d522f475Smrg#ifdef __hpux
4039d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
4040d522f475Smrg		 * are not set to _POSIX_VDISABLE */
4041d522f475Smrg		ltc.t_rprntc = ltc.t_rprntc = ltc.t_flushc =
4042d522f475Smrg		    ltc.t_werasc = ltc.t_lnextc = _POSIX_VDISABLE;
4043d522f475Smrg#endif /* __hpux */
4044d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
4045d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4046d522f475Smrg#endif /* HAS_LTCHARS */
4047d522f475Smrg#ifdef TIOCLSET
4048d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4049d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4050d522f475Smrg#endif /* TIOCLSET */
4051d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
4052d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4053d522f475Smrg
4054d522f475Smrg		/* ignore errors here - some platforms don't work */
405520d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
4056d522f475Smrg		if (screen->input_eight_bits)
4057d522f475Smrg		    tio.c_cflag |= CS8;
4058d522f475Smrg		else
4059d522f475Smrg		    tio.c_cflag |= CS7;
4060d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
4061d522f475Smrg
4062d522f475Smrg#else /* !TERMIO_STRUCT */
4063d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
4064d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
4065d522f475Smrg		/* make sure speed is set on pty so that editors work right */
4066d522f475Smrg		sg.sg_ispeed = VAL_LINE_SPEED;
4067d522f475Smrg		sg.sg_ospeed = VAL_LINE_SPEED;
4068d522f475Smrg		/* reset t_brkc to default value */
4069d522f475Smrg		tc.t_brkc = -1;
4070d522f475Smrg#ifdef LPASS8
4071d522f475Smrg		if (screen->input_eight_bits)
4072d522f475Smrg		    lmode |= LPASS8;
4073d522f475Smrg		else
4074d522f475Smrg		    lmode &= ~(LPASS8);
4075d522f475Smrg#endif
4076d522f475Smrg#ifdef sony
4077d522f475Smrg		jmode &= ~KM_KANJI;
4078d522f475Smrg#endif /* sony */
4079d522f475Smrg
4080d522f475Smrg		ltc = d_ltc;
4081d522f475Smrg
4082d522f475Smrg		if (override_tty_modes) {
4083d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
4084d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
4085d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
4086d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
4087d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
4088d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
4089d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
4090d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
4091d522f475Smrg		    /* both SYSV and BSD have ltchars */
4092d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4093d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4094d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4095d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4096d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4097d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4098d522f475Smrg		}
4099d522f475Smrg
4100d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
4101d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4102d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
4103d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4104d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
4105d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
4106d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
4107d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
4108d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4109d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4110d522f475Smrg#ifdef sony
4111d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
4112d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
4113d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
4114d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
4115d522f475Smrg#endif /* sony */
4116d522f475Smrg#endif /* TERMIO_STRUCT */
4117d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4118d522f475Smrg		if (Console) {
4119d522f475Smrg#ifdef TIOCCONS
4120d522f475Smrg		    int on = 1;
4121d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
41220bd37d32Smrg			xtermPerror("cannot open console");
4123d522f475Smrg#endif
4124d522f475Smrg#ifdef SRIOCSREDIR
4125d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4126d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
41270bd37d32Smrg			xtermPerror("cannot open console");
412820d2c4d2Smrg		    IGNORE_RC(close(fd));
4129d522f475Smrg#endif
4130d522f475Smrg		}
4131d522f475Smrg#endif /* TIOCCONS */
4132d522f475Smrg	    }
4133d522f475Smrg
4134d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4135d522f475Smrg#ifdef USE_SYSV_SIGHUP
4136d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4137d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4138d522f475Smrg#else
4139d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4140d522f475Smrg#endif
4141d522f475Smrg	    /* restore various signals to their defaults */
4142d522f475Smrg	    signal(SIGINT, SIG_DFL);
4143d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4144d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4145d522f475Smrg
4146d522f475Smrg	    /*
4147d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4148d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4149d522f475Smrg	     * the terminal's erase mode from our best guess.
4150d522f475Smrg	     */
4151d522f475Smrg#if OPT_INITIAL_ERASE
4152d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4153d522f475Smrg		   initial_erase,
4154d522f475Smrg		   setInitialErase ? "YES" : "NO",
4155d522f475Smrg		   resource.ptyInitialErase,
4156d522f475Smrg		   override_tty_modes,
4157d522f475Smrg		   ttymodelist[XTTYMODE_erase].set));
4158d522f475Smrg	    if (setInitialErase) {
4159d522f475Smrg#if OPT_TRACE
4160d522f475Smrg		int old_erase;
4161d522f475Smrg#endif
4162d522f475Smrg#ifdef TERMIO_STRUCT
4163d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4164d522f475Smrg		    tio = d_tio;
4165d522f475Smrg#if OPT_TRACE
4166d522f475Smrg		old_erase = tio.c_cc[VERASE];
4167d522f475Smrg#endif
41680bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
416920d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4170d522f475Smrg#else /* !TERMIO_STRUCT */
4171d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4172d522f475Smrg		    sg = d_sg;
4173d522f475Smrg#if OPT_TRACE
4174d522f475Smrg		old_erase = sg.sg_erase;
4175d522f475Smrg#endif
4176d522f475Smrg		sg.sg_erase = initial_erase;
4177d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4178d522f475Smrg#endif /* TERMIO_STRUCT */
4179d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4180d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4181d522f475Smrg	    }
4182d522f475Smrg#endif
4183d522f475Smrg
4184d522f475Smrg	    xtermCopyEnv(environ);
4185d522f475Smrg
41860bd37d32Smrg	    /*
41870bd37d32Smrg	     * standards.freedesktop.org/startup-notification-spec/
41880bd37d32Smrg	     * notes that this variable is used when a "reliable" mechanism is
41890bd37d32Smrg	     * not available; in practice it must be unset to avoid confusing
41900bd37d32Smrg	     * GTK applications.
41910bd37d32Smrg	     */
41920bd37d32Smrg	    xtermUnsetenv("DESKTOP_STARTUP_ID");
4193e0a2b6dfSmrg	    /*
4194e0a2b6dfSmrg	     * We set this temporarily to work around poor design of Xcursor.
4195e0a2b6dfSmrg	     * Unset it here to avoid confusion.
4196e0a2b6dfSmrg	     */
4197e0a2b6dfSmrg	    xtermUnsetenv("XCURSOR_PATH");
41980bd37d32Smrg
4199a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4200a1f3da82Smrg	    if (!resource.term_name)
420120d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4202d522f475Smrg
4203d522f475Smrg	    sprintf(buf, "%lu",
4204d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4205d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4206d522f475Smrg
4207d522f475Smrg	    /* put the display into the environment of the shell */
4208d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4209d522f475Smrg
4210d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4211d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4212d522f475Smrg
4213e39b573cSmrg	    /*
4214e39b573cSmrg	     * For debugging only, add environment variables that can be used
4215e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4216e39b573cSmrg	     * processes.
4217e39b573cSmrg	     */
4218e39b573cSmrg#if OPT_TRACE
4219e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4220e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4221e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4222e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4223e39b573cSmrg#endif
4224e39b573cSmrg
4225d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4226d522f475Smrg
4227d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4228d522f475Smrg	     */
4229d522f475Smrg	    {
4230d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4231d522f475Smrg		close_fd(ttyfd);
4232d522f475Smrg
423320d2c4d2Smrg		IGNORE_RC(close(0));
4234d522f475Smrg
4235d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4236d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4237d522f475Smrg		}
423820d2c4d2Smrg		IGNORE_RC(close(1));
423920d2c4d2Smrg		IGNORE_RC(close(2));
4240d522f475Smrg		dup(0);
4241d522f475Smrg		dup(0);
4242d522f475Smrg#else
4243d522f475Smrg		/* dup the tty */
4244d522f475Smrg		for (i = 0; i <= 2; i++)
4245d522f475Smrg		    if (i != ttyfd) {
424620d2c4d2Smrg			IGNORE_RC(close(i));
424720d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4248d522f475Smrg		    }
4249d522f475Smrg#ifndef ATT
4250d522f475Smrg		/* and close the tty */
4251d522f475Smrg		if (ttyfd > 2)
4252d522f475Smrg		    close_fd(ttyfd);
4253d522f475Smrg#endif
4254d522f475Smrg#endif /* CRAY */
4255d522f475Smrg	    }
4256d522f475Smrg
4257d522f475Smrg#if !defined(USE_SYSV_PGRP)
4258d522f475Smrg#ifdef TIOCSCTTY
4259d522f475Smrg	    setsid();
4260d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4261d522f475Smrg#endif
4262d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4263d522f475Smrg	    setpgrp(0, 0);
4264d522f475Smrg	    close(open(ttydev, O_WRONLY));
4265d522f475Smrg	    setpgrp(0, pgrp);
4266d522f475Smrg#if defined(__QNX__)
4267d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4268d522f475Smrg#endif
4269d522f475Smrg#endif /* !USE_SYSV_PGRP */
4270d522f475Smrg
4271d522f475Smrg#ifdef Lynx
4272d522f475Smrg	    {
4273d522f475Smrg		TERMIO_STRUCT t;
4274d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4275d522f475Smrg		    /* this gets lost somewhere on our way... */
4276d522f475Smrg		    t.c_oflag |= OPOST;
4277d522f475Smrg		    ttySetAttr(0, &t);
4278d522f475Smrg		}
4279d522f475Smrg	    }
4280d522f475Smrg#endif
4281d522f475Smrg
4282d522f475Smrg#ifdef HAVE_UTMP
4283d522f475Smrg	    login_name = NULL;
42840bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
42850bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4286d522f475Smrg	    }
4287d522f475Smrg	    if (login_name != NULL) {
4288d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4289d522f475Smrg	    }
4290d522f475Smrg#ifndef USE_UTEMPTER
4291d522f475Smrg#ifdef USE_UTMP_SETGID
4292d522f475Smrg	    setEffectiveGroup(save_egid);
4293d522f475Smrg	    TRACE_IDS;
4294d522f475Smrg#endif
4295d522f475Smrg#ifdef USE_SYSV_UTMP
4296d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4297d522f475Smrg	     * for the following reasons:
4298d522f475Smrg	     *   - It needs to have our correct process id (for
4299d522f475Smrg	     *     login).
4300d522f475Smrg	     *   - If our parent was to set it after the fork(),
4301d522f475Smrg	     *     it might make it out before we need it.
4302d522f475Smrg	     *   - We need to do it before we go and change our
4303d522f475Smrg	     *     user and group id's.
4304d522f475Smrg	     */
4305d522f475Smrg	    (void) call_setutent();
4306d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4307d522f475Smrg
4308d522f475Smrg	    /* position to entry in utmp file */
4309d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
431020d2c4d2Smrg	    utret = find_utmp(&utmp);
431120d2c4d2Smrg	    if (utret == 0) {
4312d522f475Smrg		(void) call_setutent();
4313d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
431420d2c4d2Smrg		utret = find_utmp(&utmp);
431520d2c4d2Smrg		if (utret == 0) {
4316d522f475Smrg		    (void) call_setutent();
4317d522f475Smrg		}
4318d522f475Smrg	    }
4319d522f475Smrg#if OPT_TRACE
4320d522f475Smrg	    if (!utret)
4321d522f475Smrg		TRACE(("getutid: NULL\n"));
4322d522f475Smrg	    else
43230bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
432420d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
43250bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
43260bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4327d522f475Smrg#endif
4328d522f475Smrg
4329d522f475Smrg	    /* set up the new entry */
4330d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4331d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4332d522f475Smrg	    utmp.ut_xstatus = 2;
4333d522f475Smrg#endif
4334894e0ac8Smrg	    copy_filled(utmp.ut_user,
4335894e0ac8Smrg			(login_name != NULL) ? login_name : "????",
4336894e0ac8Smrg			sizeof(utmp.ut_user));
4337d522f475Smrg	    /* why are we copying this string again?  (see above) */
4338894e0ac8Smrg	    copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4339894e0ac8Smrg	    copy_filled(utmp.ut_line,
4340894e0ac8Smrg			my_pty_name(ttydev), sizeof(utmp.ut_line));
4341d522f475Smrg
4342d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4343d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4344d522f475Smrg#endif
4345d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4346d522f475Smrg	    SetUtmpSysLen(utmp);
4347d522f475Smrg#endif
4348d522f475Smrg
4349894e0ac8Smrg	    copy_filled(utmp.ut_name,
4350894e0ac8Smrg			(login_name) ? login_name : "????",
4351894e0ac8Smrg			sizeof(utmp.ut_name));
4352d522f475Smrg
4353d522f475Smrg	    utmp.ut_pid = getpid();
4354d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4355d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4356d522f475Smrg	    utmp.ut_session = getsid(0);
4357d522f475Smrg#endif
4358d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
4359d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
4360d522f475Smrg#else
4361d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
4362d522f475Smrg#endif
4363d522f475Smrg
4364d522f475Smrg	    /* write out the entry */
4365d522f475Smrg	    if (!resource.utmpInhibit) {
4366d522f475Smrg		errno = 0;
4367d522f475Smrg		call_pututline(&utmp);
43680bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
43690bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
43700bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
4371d522f475Smrg		       (long) utmp.ut_pid,
4372d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
4373d522f475Smrg	    }
4374d522f475Smrg#ifdef WTMP
4375d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
4376d522f475Smrg	    if (xw->misc.login_shell)
4377d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
4378d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4379d522f475Smrg	    if (xw->misc.login_shell)
4380d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
4381d522f475Smrg#else
4382d522f475Smrg	    if (xw->misc.login_shell &&
4383d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
43840bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4385d522f475Smrg		close(i);
4386d522f475Smrg	    }
4387d522f475Smrg#endif
4388d522f475Smrg#endif
4389d522f475Smrg	    /* close the file */
4390d522f475Smrg	    (void) call_endutent();
4391d522f475Smrg
4392d522f475Smrg#else /* USE_SYSV_UTMP */
4393d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
4394d522f475Smrg	     * utmp entry.
4395d522f475Smrg	     */
4396d522f475Smrg	    tslot = ttyslot();
4397d522f475Smrg	    added_utmp_entry = False;
4398d522f475Smrg	    {
43990bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
4400d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
4401956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
4402894e0ac8Smrg		    copy_filled(utmp.ut_line,
4403894e0ac8Smrg				my_pty_name(ttydev),
4404894e0ac8Smrg				sizeof(utmp.ut_line));
4405894e0ac8Smrg		    copy_filled(utmp.ut_name, login_name,
4406894e0ac8Smrg				sizeof(utmp.ut_name));
4407d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4408d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
4409d522f475Smrg#endif
4410d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4411d522f475Smrg		    SetUtmpSysLen(utmp);
4412d522f475Smrg#endif
4413d522f475Smrg
4414d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
4415d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
44160bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4417d522f475Smrg		    close(i);
4418d522f475Smrg		    added_utmp_entry = True;
4419d522f475Smrg#if defined(WTMP)
4420d522f475Smrg		    if (xw->misc.login_shell &&
4421d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4422d522f475Smrg			int status;
4423d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
4424d522f475Smrg			status = close(i);
4425d522f475Smrg		    }
4426d522f475Smrg#elif defined(MNX_LASTLOG)
4427d522f475Smrg		    if (xw->misc.login_shell &&
4428d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
4429d522f475Smrg			lseek(i, (long) (screen->uid *
4430d522f475Smrg					 sizeof(utmp)), 0);
44310bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4432d522f475Smrg			close(i);
4433d522f475Smrg		    }
4434d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
4435d522f475Smrg		} else
4436d522f475Smrg		    tslot = -tslot;
4437d522f475Smrg	    }
4438d522f475Smrg
4439d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
4440d522f475Smrg	     * clean up after us.
4441d522f475Smrg	     */
4442d522f475Smrg#if OPT_PTY_HANDSHAKE
4443d522f475Smrg	    if (resource.ptyHandshake) {
4444d522f475Smrg		handshake.tty_slot = tslot;
4445d522f475Smrg	    }
4446d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4447d522f475Smrg#endif /* USE_SYSV_UTMP */
4448d522f475Smrg
4449d522f475Smrg#ifdef USE_LASTLOGX
4450d522f475Smrg	    if (xw->misc.login_shell) {
4451956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
4452d522f475Smrg		(void) strncpy(lastlogx.ll_line,
4453d522f475Smrg			       my_pty_name(ttydev),
4454d522f475Smrg			       sizeof(lastlogx.ll_line));
4455d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
4456d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
4457d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
4458d522f475Smrg	    }
4459d522f475Smrg#endif
4460d522f475Smrg
4461d522f475Smrg#ifdef USE_LASTLOG
4462d522f475Smrg	    if (xw->misc.login_shell &&
4463d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
4464d522f475Smrg		size_t size = sizeof(struct lastlog);
44650bd37d32Smrg		off_t offset = (off_t) (screen->uid * size);
4466d522f475Smrg
4467956cc18dSsnj		memset(&lastlog, 0, size);
4468d522f475Smrg		(void) strncpy(lastlog.ll_line,
4469d522f475Smrg			       my_pty_name(ttydev),
4470d522f475Smrg			       sizeof(lastlog.ll_line));
4471d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
4472d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
4473d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
44740bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
4475d522f475Smrg		}
4476d522f475Smrg		close(i);
4477d522f475Smrg	    }
4478d522f475Smrg#endif /* USE_LASTLOG */
4479d522f475Smrg
4480d522f475Smrg#if defined(USE_UTMP_SETGID)
4481d522f475Smrg	    disableSetGid();
4482d522f475Smrg	    TRACE_IDS;
4483d522f475Smrg#endif
4484d522f475Smrg
4485d522f475Smrg#if OPT_PTY_HANDSHAKE
4486d522f475Smrg	    /* Let our parent know that we set up our utmp entry
4487d522f475Smrg	     * so that it can clean up after us.
4488d522f475Smrg	     */
4489d522f475Smrg	    if (resource.ptyHandshake) {
4490d522f475Smrg		handshake.status = UTMP_ADDED;
4491d522f475Smrg		handshake.error = 0;
44920bd37d32Smrg		strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4493d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
449420d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
4495d522f475Smrg	    }
4496d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4497d522f475Smrg#endif /* USE_UTEMPTER */
4498d522f475Smrg#endif /* HAVE_UTMP */
4499d522f475Smrg
450020d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
4501d522f475Smrg	    TRACE_IDS;
4502e0a2b6dfSmrg#ifdef HAVE_INITGROUPS
45030bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
45040bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
4505d522f475Smrg		    perror("initgroups failed");
4506d522f475Smrg		    SysError(ERROR_INIGROUPS);
4507d522f475Smrg		}
4508d522f475Smrg	    }
4509d522f475Smrg#endif
4510d522f475Smrg	    if (setuid(screen->uid)) {
4511d522f475Smrg		SysError(ERROR_SETUID);
4512d522f475Smrg	    }
4513d522f475Smrg	    TRACE_IDS;
4514d522f475Smrg#if OPT_PTY_HANDSHAKE
4515d522f475Smrg	    if (resource.ptyHandshake) {
4516d522f475Smrg		/* mark the pipes as close on exec */
45170bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
45180bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
4519d522f475Smrg
4520d522f475Smrg		/* We are at the point where we are going to
4521d522f475Smrg		 * exec our shell (or whatever).  Let our parent
4522d522f475Smrg		 * know we arrived safely.
4523d522f475Smrg		 */
4524d522f475Smrg		handshake.status = PTY_GOOD;
4525d522f475Smrg		handshake.error = 0;
45260bd37d32Smrg		(void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4527d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
452820d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
452920d2c4d2Smrg				(const char *) &handshake,
453020d2c4d2Smrg				sizeof(handshake)));
4531d522f475Smrg
4532d522f475Smrg		if (resource.wait_for_map) {
453320d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
453420d2c4d2Smrg				   sizeof(handshake));
4535d522f475Smrg		    if (i != sizeof(handshake) ||
4536d522f475Smrg			handshake.status != PTY_EXEC) {
4537d522f475Smrg			/* some very bad problem occurred */
4538d522f475Smrg			exit(ERROR_PTY_EXEC);
4539d522f475Smrg		    }
4540d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
4541d522f475Smrg			TRACE(("handshake ttysize: %dx%d\n",
4542d522f475Smrg			       handshake.rows, handshake.cols));
4543d522f475Smrg			set_max_row(screen, handshake.rows);
4544d522f475Smrg			set_max_col(screen, handshake.cols);
4545d522f475Smrg#ifdef TTYSIZE_STRUCT
4546d522f475Smrg			got_handshake_size = True;
454720d2c4d2Smrg			TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
454820d2c4d2Smrg			TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
4549d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
455020d2c4d2Smrg			ts.ws_xpixel = (ttySize_t) FullWidth(screen);
455120d2c4d2Smrg			ts.ws_ypixel = (ttySize_t) FullHeight(screen);
4552d522f475Smrg#endif
4553d522f475Smrg#endif /* TTYSIZE_STRUCT */
4554d522f475Smrg		    }
4555d522f475Smrg		}
4556d522f475Smrg	    }
4557d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4558d522f475Smrg
4559d522f475Smrg#ifdef USE_SYSV_ENVVARS
4560d522f475Smrg	    {
4561d522f475Smrg		char numbuf[12];
4562d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
4563d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
4564d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
4565d522f475Smrg		xtermSetenv("LINES", numbuf);
4566d522f475Smrg	    }
4567d522f475Smrg#ifdef HAVE_UTMP
45680bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
4569d522f475Smrg		if (!x_getenv("HOME"))
45700bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
4571d522f475Smrg		if (!x_getenv("SHELL"))
45720bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
4573d522f475Smrg	    }
4574d522f475Smrg#endif /* HAVE_UTMP */
4575d522f475Smrg#ifdef OWN_TERMINFO_DIR
4576d522f475Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
4577d522f475Smrg#endif
4578d522f475Smrg#else /* USE_SYSV_ENVVARS */
457920d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
458020d2c4d2Smrg		resize_termcap(xw);
458120d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
458220d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
458320d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
458420d2c4d2Smrg		}
458520d2c4d2Smrg		/*
458620d2c4d2Smrg		 * work around broken termcap entries */
458720d2c4d2Smrg		if (resource.useInsertMode) {
458820d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
458920d2c4d2Smrg		    /* don't get duplicates */
459020d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
459120d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
459220d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
459320d2c4d2Smrg		    if (*newtc)
459420d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
459520d2c4d2Smrg		}
459620d2c4d2Smrg		if (*newtc) {
4597d522f475Smrg#if OPT_INITIAL_ERASE
459820d2c4d2Smrg		    unsigned len;
459920d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
460020d2c4d2Smrg		    len = (unsigned) strlen(newtc);
460120d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
460220d2c4d2Smrg			len--;
460320d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
460420d2c4d2Smrg			    TERMCAP_ERASE,
460520d2c4d2Smrg			    CharOf(initial_erase));
460620d2c4d2Smrg#endif
460720d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
460820d2c4d2Smrg		}
4609d522f475Smrg	    }
4610d522f475Smrg#endif /* USE_SYSV_ENVVARS */
4611d522f475Smrg
4612d522f475Smrg#if OPT_PTY_HANDSHAKE
4613d522f475Smrg	    /*
4614d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
4615d522f475Smrg	     *
4616d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
4617d522f475Smrg	     * use that to prevent races.
4618d522f475Smrg	     */
4619d522f475Smrg	    if (resource.ptyHandshake
4620d522f475Smrg		&& resource.ptySttySize
4621d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
4622d522f475Smrg#ifdef TTYSIZE_STRUCT
462320d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
4624d522f475Smrg		TRACE(("ptyHandshake SET_TTYSIZE %dx%d return %d\n",
4625d522f475Smrg		       TTYSIZE_ROWS(ts),
4626d522f475Smrg		       TTYSIZE_COLS(ts), i));
4627d522f475Smrg#endif /* TTYSIZE_STRUCT */
4628d522f475Smrg	    }
4629d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4630d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4631d522f475Smrg
46320bd37d32Smrg	    /*
4633e0a2b6dfSmrg	     * If we have an explicit shell to run, make that set $SHELL.
4634e0a2b6dfSmrg	     * Next, allow an existing setting of $SHELL, for absolute paths.
46350bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
46360bd37d32Smrg	     * password information, if possible.
46370bd37d32Smrg	     *
46380bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
46390bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
46400bd37d32Smrg	     */
4641e0a2b6dfSmrg	    if (validShell(explicit_shname)) {
4642e0a2b6dfSmrg		xtermSetenv("SHELL", explicit_shname);
4643e0a2b6dfSmrg	    } else if (validProgram(shell_path = x_getenv("SHELL"))) {
4644e0a2b6dfSmrg		if (!validShell(shell_path)) {
4645e0a2b6dfSmrg		    xtermUnsetenv("SHELL");
4646d522f475Smrg		}
4647e0a2b6dfSmrg	    } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
4648e0a2b6dfSmrg		       || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
4649e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4650e0a2b6dfSmrg	    } else if (validShell(shell_path)) {
4651e0a2b6dfSmrg		xtermSetenv("SHELL", shell_path);
4652d522f475Smrg	    } else {
4653e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4654d522f475Smrg	    }
4655e0a2b6dfSmrg
4656e0a2b6dfSmrg	    /*
4657e0a2b6dfSmrg	     * Set $XTERM_SHELL, which is not necessarily a valid shell, but
4658e0a2b6dfSmrg	     * is executable.
4659e0a2b6dfSmrg	     */
4660e0a2b6dfSmrg	    if (validProgram(explicit_shname)) {
4661e0a2b6dfSmrg		shell_path = explicit_shname;
4662e0a2b6dfSmrg	    } else if (shell_path == 0) {
4663e0a2b6dfSmrg		/* this could happen if the explicit shname lost a race */
4664e0a2b6dfSmrg		shell_path = resetShell(shell_path);
46650bd37d32Smrg	    }
46660bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
4667d522f475Smrg
46680bd37d32Smrg	    shname = x_basename(shell_path);
46690bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
4670d522f475Smrg
4671d522f475Smrg#if OPT_LUIT_PROG
4672d522f475Smrg	    /*
4673d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
4674d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
4675d522f475Smrg	     * to command that the user gave anyway.
4676d522f475Smrg	     */
46772eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
46780bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
46790bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
46800bd37d32Smrg		free(myShell);
46810bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
4682d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
46830bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
46840bd37d32Smrg		xtermWarning("cannot support your locale.\n");
4685d522f475Smrg	    }
4686d522f475Smrg#endif
4687d522f475Smrg	    if (command_to_exec) {
46880bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
46890bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
46900bd37d32Smrg		free(myShell);
46910bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
4692d522f475Smrg		execvp(*command_to_exec, command_to_exec);
4693d522f475Smrg		if (command_to_exec[1] == 0)
46940bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
46950bd37d32Smrg			   (void *) 0);
46960bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
4697d522f475Smrg	    }
4698d522f475Smrg#ifdef USE_SYSV_SIGHUP
4699d522f475Smrg	    /* fix pts sh hanging around */
4700d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4701d522f475Smrg#endif
4702d522f475Smrg
470301037d57Smrg	    if ((shname_minus = CastMallocN(char, strlen(shname) + 2)) != 0) {
470401037d57Smrg		(void) strcpy(shname_minus, "-");
470501037d57Smrg		(void) strcat(shname_minus, shname);
470601037d57Smrg	    } else {
470701037d57Smrg		static char default_minus[] = "-sh";
470801037d57Smrg		shname_minus = default_minus;
470901037d57Smrg	    }
4710d522f475Smrg#ifndef TERMIO_STRUCT
47110bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
47120bd37d32Smrg		     ? NTTYDISC
47130bd37d32Smrg		     : 0);
4714d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
4715d522f475Smrg#endif /* !TERMIO_STRUCT */
4716d522f475Smrg
4717d522f475Smrg#ifdef USE_LOGIN_DASH_P
47180bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
4719d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
4720d522f475Smrg#endif
47212eaa94a1Schristos
47222eaa94a1Schristos#if OPT_LUIT_PROG
47232eaa94a1Schristos	    if (command_to_exec_with_luit) {
47242eaa94a1Schristos		if (xw->misc.login_shell) {
47250bd37d32Smrg		    char *params[4];
47260bd37d32Smrg		    params[0] = x_strdup("-argv0");
47270bd37d32Smrg		    params[1] = shname_minus;
47280bd37d32Smrg		    params[2] = NULL;
47290bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
47300bd37d32Smrg				 + command_length_with_luit,
47310bd37d32Smrg				 params);
47322eaa94a1Schristos		}
47330bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
47342eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
47352eaa94a1Schristos		/* Exec failed. */
47360bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
47372eaa94a1Schristos	    }
47382eaa94a1Schristos#endif
47390bd37d32Smrg	    execlp(shell_path,
4740d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
4741d522f475Smrg		   (void *) 0);
4742d522f475Smrg
4743d522f475Smrg	    /* Exec failed. */
47440bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
474520d2c4d2Smrg	    IGNORE_RC(sleep(5));
47460bd37d32Smrg	    free(shell_path);
4747d522f475Smrg	    exit(ERROR_EXEC);
4748d522f475Smrg	}
4749d522f475Smrg	/* end if in child after fork */
4750d522f475Smrg#if OPT_PTY_HANDSHAKE
4751d522f475Smrg	if (resource.ptyHandshake) {
4752d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
4753d522f475Smrg	     * child process.
4754d522f475Smrg	     */
4755d522f475Smrg
4756d522f475Smrg	    /* close childs's sides of the pipes */
4757d522f475Smrg	    close(cp_pipe[1]);
4758d522f475Smrg	    close(pc_pipe[0]);
4759d522f475Smrg
4760d522f475Smrg	    for (done = 0; !done;) {
4761d522f475Smrg		if (read(cp_pipe[0],
4762d522f475Smrg			 (char *) &handshake,
4763d522f475Smrg			 sizeof(handshake)) <= 0) {
4764d522f475Smrg		    /* Our child is done talking to us.  If it terminated
4765d522f475Smrg		     * due to an error, we will catch the death of child
4766d522f475Smrg		     * and clean up.
4767d522f475Smrg		     */
4768d522f475Smrg		    break;
4769d522f475Smrg		}
4770d522f475Smrg
4771d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
4772d522f475Smrg		switch (handshake.status) {
4773d522f475Smrg		case PTY_GOOD:
4774d522f475Smrg		    /* Success!  Let's free up resources and
4775d522f475Smrg		     * continue.
4776d522f475Smrg		     */
4777d522f475Smrg		    done = 1;
4778d522f475Smrg		    break;
4779d522f475Smrg
4780d522f475Smrg		case PTY_BAD:
4781d522f475Smrg		    /* The open of the pty failed!  Let's get
4782d522f475Smrg		     * another one.
4783d522f475Smrg		     */
478420d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
4785d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
4786d522f475Smrg			/* no more ptys! */
47870bd37d32Smrg			xtermPerror("child process can find no available ptys");
4788d522f475Smrg			handshake.status = PTY_NOMORE;
4789d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
479020d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
479120d2c4d2Smrg					(const char *) &handshake,
479220d2c4d2Smrg					sizeof(handshake)));
4793d522f475Smrg			exit(ERROR_PTYS);
4794d522f475Smrg		    }
4795d522f475Smrg		    handshake.status = PTY_NEW;
47960bd37d32Smrg		    (void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4797d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
479820d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
479920d2c4d2Smrg				    (const char *) &handshake,
480020d2c4d2Smrg				    sizeof(handshake)));
4801d522f475Smrg		    break;
4802d522f475Smrg
4803d522f475Smrg		case PTY_FATALERROR:
4804d522f475Smrg		    errno = handshake.error;
4805d522f475Smrg		    close(cp_pipe[0]);
4806d522f475Smrg		    close(pc_pipe[1]);
4807d522f475Smrg		    SysError(handshake.fatal_error);
4808d522f475Smrg		    /*NOTREACHED */
4809d522f475Smrg
4810d522f475Smrg		case UTMP_ADDED:
4811d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
4812d522f475Smrg		     * this so that we can reset it later.
4813d522f475Smrg		     */
4814d522f475Smrg		    added_utmp_entry = True;
4815d522f475Smrg#ifndef	USE_SYSV_UTMP
4816d522f475Smrg		    tslot = handshake.tty_slot;
4817d522f475Smrg#endif /* USE_SYSV_UTMP */
4818d522f475Smrg		    free(ttydev);
4819d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
4820d522f475Smrg		    break;
4821d522f475Smrg		case PTY_NEW:
4822d522f475Smrg		case PTY_NOMORE:
4823d522f475Smrg		case UTMP_TTYSLOT:
4824d522f475Smrg		case PTY_EXEC:
4825d522f475Smrg		default:
48260bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
48270bd37d32Smrg				 (int) handshake.status);
4828d522f475Smrg		}
4829d522f475Smrg	    }
4830d522f475Smrg	    /* close our sides of the pipes */
4831d522f475Smrg	    if (!resource.wait_for_map) {
4832d522f475Smrg		close(cp_pipe[0]);
4833d522f475Smrg		close(pc_pipe[1]);
4834d522f475Smrg	    }
4835d522f475Smrg	}
4836d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4837d522f475Smrg    }
4838d522f475Smrg
4839d522f475Smrg    /* end if no slave */
4840d522f475Smrg    /*
4841d522f475Smrg     * still in parent (xterm process)
4842d522f475Smrg     */
4843d522f475Smrg#ifdef USE_SYSV_SIGHUP
4844d522f475Smrg    /* hung sh problem? */
4845d522f475Smrg    signal(SIGHUP, SIG_DFL);
4846d522f475Smrg#else
4847d522f475Smrg    signal(SIGHUP, SIG_IGN);
4848d522f475Smrg#endif
4849d522f475Smrg
4850d522f475Smrg/*
4851d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
4852d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
4853d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
4854d522f475Smrg * don't ignore the signals.  This is annoying.
4855d522f475Smrg */
4856d522f475Smrg
4857d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
4858d522f475Smrg    signal(SIGINT, SIG_IGN);
4859d522f475Smrg
4860d522f475Smrg#ifndef SYSV
4861d522f475Smrg    /* hung shell problem */
4862d522f475Smrg    signal(SIGQUIT, SIG_IGN);
4863d522f475Smrg#endif
4864d522f475Smrg    signal(SIGTERM, SIG_IGN);
4865d522f475Smrg#elif defined(SYSV) || defined(__osf__)
4866d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
4867d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
4868d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
4869d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
4870d522f475Smrg     * tank on everything.
4871d522f475Smrg     */
4872d522f475Smrg    if (getpid() == getpgrp()) {
4873d522f475Smrg	(void) signal(SIGINT, Exit);
4874d522f475Smrg	(void) signal(SIGQUIT, Exit);
4875d522f475Smrg	(void) signal(SIGTERM, Exit);
4876d522f475Smrg    } else {
4877d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
4878d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
4879d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
4880d522f475Smrg    }
4881d522f475Smrg    (void) signal(SIGPIPE, Exit);
4882d522f475Smrg#else /* SYSV */
4883d522f475Smrg    signal(SIGINT, Exit);
4884d522f475Smrg    signal(SIGQUIT, Exit);
4885d522f475Smrg    signal(SIGTERM, Exit);
4886d522f475Smrg    signal(SIGPIPE, Exit);
4887d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
48880bd37d32Smrg#ifdef NO_LEAKS
48890bd37d32Smrg    if (ok_termcap != True)
48900bd37d32Smrg	free(TermName);
48910bd37d32Smrg#endif
4892d522f475Smrg
4893d522f475Smrg    return 0;
4894d522f475Smrg}				/* end spawnXTerm */
4895d522f475Smrg
48960bd37d32Smrgvoid
4897d522f475SmrgExit(int n)
4898d522f475Smrg{
489920d2c4d2Smrg    XtermWidget xw = term;
490020d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
4901d522f475Smrg
4902d522f475Smrg#ifdef USE_UTEMPTER
49030bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
49040bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
49050bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
4906d522f475Smrg	removeFromUtmp();
49070bd37d32Smrg    }
4908d522f475Smrg#elif defined(HAVE_UTMP)
4909d522f475Smrg#ifdef USE_SYSV_UTMP
4910d522f475Smrg    struct UTMP_STR utmp;
4911d522f475Smrg    struct UTMP_STR *utptr;
4912d522f475Smrg
49130bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
4914d522f475Smrg    /* don't do this more than once */
49150bd37d32Smrg    if (xterm_exiting) {
49160bd37d32Smrg	exit(n);
49170bd37d32Smrg    }
4918d522f475Smrg    xterm_exiting = True;
4919d522f475Smrg
4920d522f475Smrg#ifdef PUCC_PTYD
4921d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
4922d522f475Smrg#endif /* PUCC_PTYD */
4923d522f475Smrg
4924d522f475Smrg    /* cleanup the utmp entry we forged earlier */
4925d522f475Smrg    if (!resource.utmpInhibit
4926d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
4927d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
4928d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4929d522f475Smrg	) {
4930d522f475Smrg#if defined(USE_UTMP_SETGID)
4931d522f475Smrg	setEffectiveGroup(save_egid);
4932d522f475Smrg	TRACE_IDS;
4933d522f475Smrg#endif
4934d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
4935d522f475Smrg	(void) call_setutent();
4936d522f475Smrg
4937d522f475Smrg	/*
4938d522f475Smrg	 * We could use getutline() if we didn't support old systems.
4939d522f475Smrg	 */
4940d522f475Smrg	while ((utptr = find_utmp(&utmp)) != 0) {
4941d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
4942d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
4943d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4944d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4945d522f475Smrg		utptr->ut_session = getsid(0);
4946d522f475Smrg#endif
4947d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
4948d522f475Smrg		utptr->ut_tv.tv_usec = 0;
4949d522f475Smrg#else
4950d522f475Smrg		*utptr->ut_user = 0;
4951d522f475Smrg		utptr->ut_time = time((time_t *) 0);
4952d522f475Smrg#endif
4953d522f475Smrg		(void) call_pututline(utptr);
4954d522f475Smrg#ifdef WTMP
4955d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
495620d2c4d2Smrg		if (xw->misc.login_shell)
4957d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
4958d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4959894e0ac8Smrg		copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
496020d2c4d2Smrg		if (xw->misc.login_shell)
4961d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
4962d522f475Smrg#else
4963d522f475Smrg		/* set wtmp entry if wtmp file exists */
496420d2c4d2Smrg		if (xw->misc.login_shell) {
4965d522f475Smrg		    int fd;
4966d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
49670bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
4968d522f475Smrg			close(fd);
4969d522f475Smrg		    }
4970d522f475Smrg		}
4971d522f475Smrg#endif
4972d522f475Smrg#endif
4973d522f475Smrg		break;
4974d522f475Smrg	    }
4975d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
4976d522f475Smrg	}
4977d522f475Smrg	(void) call_endutent();
4978d522f475Smrg#ifdef USE_UTMP_SETGID
4979d522f475Smrg	disableSetGid();
4980d522f475Smrg	TRACE_IDS;
4981d522f475Smrg#endif
4982d522f475Smrg    }
4983d522f475Smrg#else /* not USE_SYSV_UTMP */
4984d522f475Smrg    int wfd;
4985d522f475Smrg    struct utmp utmp;
4986d522f475Smrg
49870bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
4988d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
4989d522f475Smrg	(am_slave < 0 && tslot > 0)) {
4990d522f475Smrg#if defined(USE_UTMP_SETGID)
4991d522f475Smrg	setEffectiveGroup(save_egid);
4992d522f475Smrg	TRACE_IDS;
4993d522f475Smrg#endif
4994d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
4995956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
4996d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
49970bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
4998d522f475Smrg	    close(wfd);
4999d522f475Smrg	}
5000d522f475Smrg#ifdef WTMP
500120d2c4d2Smrg	if (xw->misc.login_shell &&
5002d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
5003894e0ac8Smrg	    copy_filled(utmp.ut_line,
5004894e0ac8Smrg			my_pty_name(ttydev),
5005894e0ac8Smrg			sizeof(utmp.ut_line));
5006d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
50070bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5008d522f475Smrg	    close(wfd);
5009d522f475Smrg	}
5010d522f475Smrg#endif /* WTMP */
5011d522f475Smrg#ifdef USE_UTMP_SETGID
5012d522f475Smrg	disableSetGid();
5013d522f475Smrg	TRACE_IDS;
5014d522f475Smrg#endif
5015d522f475Smrg    }
5016d522f475Smrg#endif /* USE_SYSV_UTMP */
5017d522f475Smrg#endif /* HAVE_UTMP */
5018d522f475Smrg
5019e0a2b6dfSmrg    cleanup_colored_cursor();
5020e0a2b6dfSmrg
5021d522f475Smrg    /*
5022d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
5023d522f475Smrg     * in the middle of the data.
5024d522f475Smrg     */
5025d522f475Smrg    ttyFlush(screen->respond);
5026d522f475Smrg
5027e39b573cSmrg#ifdef USE_PTY_SEARCH
5028d522f475Smrg    if (am_slave < 0) {
5029d522f475Smrg	TRACE_IDS;
5030d522f475Smrg	/* restore ownership of tty and pty */
5031d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
5032d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
5033d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
5034d522f475Smrg#endif
5035d522f475Smrg    }
5036e39b573cSmrg#endif
5037d522f475Smrg
5038d522f475Smrg    /*
50390bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
5040d522f475Smrg     * grabbing it, and *then* having us release ownership....
5041d522f475Smrg     */
5042d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
5043d522f475Smrg#ifdef ALLOWLOGGING
5044d522f475Smrg    if (screen->logging)
504520d2c4d2Smrg	CloseLog(xw);
5046d522f475Smrg#endif
5047d522f475Smrg
5048e39b573cSmrg    xtermPrintOnXError(xw, n);
5049e39b573cSmrg
5050d522f475Smrg#ifdef NO_LEAKS
5051d522f475Smrg    if (n == 0) {
50520bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
50530bd37d32Smrg
5054d522f475Smrg	TRACE(("Freeing memory leaks\n"));
5055d522f475Smrg
50560bd37d32Smrg	if (toplevel) {
50570bd37d32Smrg	    XtDestroyWidget(toplevel);
50580bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
50590bd37d32Smrg	}
50600bd37d32Smrg	sortedOpts(0, 0, 0);
50610bd37d32Smrg	noleaks_charproc();
50620bd37d32Smrg	noleaks_ptydata();
5063894e0ac8Smrg#if OPT_GRAPHICS
5064894e0ac8Smrg	noleaks_graphics();
5065894e0ac8Smrg#endif
5066d522f475Smrg#if OPT_WIDE_CHARS
50670bd37d32Smrg	noleaks_CharacterClass();
5068d522f475Smrg#endif
50690bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
50700bd37d32Smrg	XtCloseDisplay(dpy);
50710bd37d32Smrg	XtDestroyApplicationContext(app_con);
50720bd37d32Smrg	xtermCloseSession();
50730bd37d32Smrg	TRACE(("closed display\n"));
50740bd37d32Smrg
507520d2c4d2Smrg	TRACE_CLOSE();
5076d522f475Smrg    }
5077d522f475Smrg#endif
5078d522f475Smrg
5079d522f475Smrg    exit(n);
5080d522f475Smrg}
5081d522f475Smrg
5082d522f475Smrg/* ARGSUSED */
5083d522f475Smrgstatic void
508420d2c4d2Smrgresize_termcap(XtermWidget xw)
5085d522f475Smrg{
508620d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
508720d2c4d2Smrg
5088d522f475Smrg#ifndef USE_SYSV_ENVVARS
5089d522f475Smrg    if (!TEK4014_ACTIVE(xw) && *newtc) {
5090d522f475Smrg	TScreen *screen = TScreenOf(xw);
5091d522f475Smrg	char *ptr1, *ptr2;
5092d522f475Smrg	size_t i;
5093d522f475Smrg	int li_first = 0;
5094d522f475Smrg	char *temp;
5095d522f475Smrg	char oldtc[TERMCAP_SIZE];
5096d522f475Smrg
5097d522f475Smrg	strcpy(oldtc, newtc);
5098d522f475Smrg	TRACE(("resize %s\n", oldtc));
5099d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
5100d522f475Smrg	    strcat(oldtc, "co#80:");
5101d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
5102d522f475Smrg	}
5103d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
5104d522f475Smrg	    strcat(oldtc, "li#24:");
5105d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
5106d522f475Smrg	}
5107d522f475Smrg	if (ptr1 > ptr2) {
5108d522f475Smrg	    li_first++;
5109d522f475Smrg	    temp = ptr1;
5110d522f475Smrg	    ptr1 = ptr2;
5111d522f475Smrg	    ptr2 = temp;
5112d522f475Smrg	}
5113d522f475Smrg	ptr1 += 3;
5114d522f475Smrg	ptr2 += 3;
5115956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
5116d522f475Smrg	temp = newtc + i;
5117d522f475Smrg	sprintf(temp, "%d", (li_first
5118d522f475Smrg			     ? MaxRows(screen)
5119d522f475Smrg			     : MaxCols(screen)));
5120d522f475Smrg	temp += strlen(temp);
51210bd37d32Smrg	if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) {
51220bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
51230bd37d32Smrg	    temp += i;
51240bd37d32Smrg	    sprintf(temp, "%d", (li_first
51250bd37d32Smrg				 ? MaxCols(screen)
51260bd37d32Smrg				 : MaxRows(screen)));
51270bd37d32Smrg	    if ((ptr2 = strchr(ptr2, ':')) != 0) {
51280bd37d32Smrg		strcat(temp, ptr2);
51290bd37d32Smrg	    }
51300bd37d32Smrg	}
5131d522f475Smrg	TRACE(("   ==> %s\n", newtc));
5132d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
5133d522f475Smrg    }
5134d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5135d522f475Smrg}
5136d522f475Smrg
5137d522f475Smrg#endif /* ! VMS */
5138d522f475Smrg
5139d522f475Smrg/*
5140d522f475Smrg * Does a non-blocking wait for a child process.  If the system
5141d522f475Smrg * doesn't support non-blocking wait, do nothing.
5142d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
5143d522f475Smrg */
5144d522f475Smrgint
5145d522f475Smrgnonblocking_wait(void)
5146d522f475Smrg{
5147d522f475Smrg#ifdef USE_POSIX_WAIT
5148d522f475Smrg    pid_t pid;
5149d522f475Smrg
5150d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5151d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5152d522f475Smrg    /* cannot do non-blocking wait */
5153d522f475Smrg    int pid = 0;
5154d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5155d522f475Smrg#if defined(Lynx)
5156d522f475Smrg    int status;
5157d522f475Smrg#else
5158d522f475Smrg    union wait status;
5159d522f475Smrg#endif
5160d522f475Smrg    int pid;
5161d522f475Smrg
5162d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5163d522f475Smrg#endif /* USE_POSIX_WAIT else */
5164d522f475Smrg    return pid;
5165d522f475Smrg}
5166d522f475Smrg
5167d522f475Smrg#ifndef VMS
5168d522f475Smrg
5169d522f475Smrg/* ARGSUSED */
51700bd37d32Smrgstatic void
5171d522f475Smrgreapchild(int n GCC_UNUSED)
5172d522f475Smrg{
5173d522f475Smrg    int olderrno = errno;
5174d522f475Smrg    int pid;
5175d522f475Smrg
51760bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
51770bd37d32Smrg
5178d522f475Smrg    pid = wait(NULL);
5179d522f475Smrg
5180d522f475Smrg#ifdef USE_SYSV_SIGNALS
5181d522f475Smrg    /* cannot re-enable signal before waiting for child
5182d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5183d522f475Smrg     */
5184d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5185d522f475Smrg#endif
5186d522f475Smrg
5187d522f475Smrg    do {
518820d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
51890bd37d32Smrg	    DEBUG_MSG("Exiting\n");
5190d522f475Smrg	    if (!hold_screen)
5191d522f475Smrg		need_cleanup = True;
5192d522f475Smrg	}
5193d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5194d522f475Smrg
5195d522f475Smrg    errno = olderrno;
5196d522f475Smrg}
5197d522f475Smrg#endif /* !VMS */
5198d522f475Smrg
5199d522f475Smrgstatic void
520020d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5201d522f475Smrg{
5202d522f475Smrg    char *base = buf;
5203d522f475Smrg    char *first = base;
5204d522f475Smrg    int count = 0;
5205d522f475Smrg    size_t len = strlen(str);
5206d522f475Smrg
5207d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5208d522f475Smrg
5209d522f475Smrg    while (*buf != 0) {
5210d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5211d522f475Smrg	    while (*buf != 0) {
5212d522f475Smrg		if (*buf == '\\')
5213d522f475Smrg		    buf++;
5214d522f475Smrg		else if (*buf == ':')
5215d522f475Smrg		    break;
5216d522f475Smrg		if (*buf != 0)
5217d522f475Smrg		    buf++;
5218d522f475Smrg	    }
52190bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
52200bd37d32Smrg		;
52210bd37d32Smrg	    }
5222d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5223d522f475Smrg	    return;
5224d522f475Smrg	} else if (*buf == '\\') {
5225d522f475Smrg	    buf++;
5226d522f475Smrg	} else if (*buf == ':') {
5227d522f475Smrg	    first = buf;
5228d522f475Smrg	    count = 0;
5229d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5230d522f475Smrg	    count++;
5231d522f475Smrg	}
5232d522f475Smrg	if (*buf != 0)
5233d522f475Smrg	    buf++;
5234d522f475Smrg    }
5235d522f475Smrg    TRACE(("...cannot remove\n"));
5236d522f475Smrg}
5237d522f475Smrg
5238d522f475Smrg/*
5239d522f475Smrg * parse_tty_modes accepts lines of the following form:
5240d522f475Smrg *
5241d522f475Smrg *         [SETTING] ...
5242d522f475Smrg *
5243d522f475Smrg * where setting consists of the words in the modelist followed by a character
5244d522f475Smrg * or ^char.
5245d522f475Smrg */
5246d522f475Smrgstatic int
5247d522f475Smrgparse_tty_modes(char *s, struct _xttymodes *modelist)
5248d522f475Smrg{
5249d522f475Smrg    struct _xttymodes *mp;
5250d522f475Smrg    int c;
5251d522f475Smrg    int count = 0;
5252d522f475Smrg
5253d522f475Smrg    TRACE(("parse_tty_modes\n"));
5254a1f3da82Smrg    for (;;) {
5255d522f475Smrg	size_t len;
5256d522f475Smrg
5257d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5258d522f475Smrg	    s++;
5259d522f475Smrg	if (!*s)
5260d522f475Smrg	    return count;
5261d522f475Smrg
5262d522f475Smrg	for (len = 0; isalnum(CharOf(s[len])); ++len) ;
5263d522f475Smrg	for (mp = modelist; mp->name; mp++) {
5264d522f475Smrg	    if (len == mp->len
5265d522f475Smrg		&& strncmp(s, mp->name, mp->len) == 0)
5266d522f475Smrg		break;
5267d522f475Smrg	}
5268d522f475Smrg	if (!mp->name)
5269d522f475Smrg	    return -1;
5270d522f475Smrg
5271d522f475Smrg	s += mp->len;
5272d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5273d522f475Smrg	    s++;
5274d522f475Smrg	if (!*s)
5275d522f475Smrg	    return -1;
5276d522f475Smrg
5277d522f475Smrg	if ((c = decode_keyvalue(&s, False)) != -1) {
5278d522f475Smrg	    mp->value = c;
5279d522f475Smrg	    mp->set = 1;
5280d522f475Smrg	    count++;
5281d522f475Smrg	    TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
5282d522f475Smrg	}
5283d522f475Smrg    }
5284d522f475Smrg}
5285d522f475Smrg
5286d522f475Smrg#ifndef VMS			/* don't use pipes on OpenVMS */
5287d522f475Smrgint
5288d522f475SmrgGetBytesAvailable(int fd)
5289d522f475Smrg{
5290d522f475Smrg#if defined(FIONREAD)
5291d522f475Smrg    int arg;
5292d522f475Smrg    ioctl(fd, FIONREAD, (char *) &arg);
5293d522f475Smrg    return (int) arg;
5294d522f475Smrg#elif defined(__CYGWIN__)
5295d522f475Smrg    fd_set set;
529620d2c4d2Smrg    struct timeval select_timeout =
5297d522f475Smrg    {0, 0};
5298d522f475Smrg
5299d522f475Smrg    FD_ZERO(&set);
5300d522f475Smrg    FD_SET(fd, &set);
530120d2c4d2Smrg    if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0)
5302d522f475Smrg	return 1;
5303d522f475Smrg    else
5304d522f475Smrg	return 0;
5305d522f475Smrg#elif defined(FIORDCK)
5306d522f475Smrg    return (ioctl(fd, FIORDCHK, NULL));
5307d522f475Smrg#else /* !FIORDCK */
5308d522f475Smrg    struct pollfd pollfds[1];
5309d522f475Smrg
5310d522f475Smrg    pollfds[0].fd = fd;
5311d522f475Smrg    pollfds[0].events = POLLIN;
5312d522f475Smrg    return poll(pollfds, 1, 0);
5313d522f475Smrg#endif
5314d522f475Smrg}
5315d522f475Smrg#endif /* !VMS */
5316d522f475Smrg
5317d522f475Smrg/* Utility function to try to hide system differences from
5318d522f475Smrg   everybody who used to call killpg() */
5319d522f475Smrg
5320d522f475Smrgint
5321d522f475Smrgkill_process_group(int pid, int sig)
5322d522f475Smrg{
5323d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5324d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5325d522f475Smrg    return kill(-pid, sig);
5326d522f475Smrg#else
5327d522f475Smrg    return killpg(pid, sig);
5328d522f475Smrg#endif
5329d522f475Smrg}
5330d522f475Smrg
5331d522f475Smrg#if OPT_EBCDIC
5332d522f475Smrgint
5333d522f475SmrgA2E(int x)
5334d522f475Smrg{
5335d522f475Smrg    char c;
5336d522f475Smrg    c = x;
5337d522f475Smrg    __atoe_l(&c, 1);
5338d522f475Smrg    return c;
5339d522f475Smrg}
5340d522f475Smrg
5341d522f475Smrgint
5342d522f475SmrgE2A(int x)
5343d522f475Smrg{
5344d522f475Smrg    char c;
5345d522f475Smrg    c = x;
5346d522f475Smrg    __etoa_l(&c, 1);
5347d522f475Smrg    return c;
5348d522f475Smrg}
5349d522f475Smrg#endif
5350d522f475Smrg
5351d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
5352d522f475Smrg#include <sys/types.h>
5353d522f475Smrg#include <sys/proc_msg.h>
5354d522f475Smrg#include <sys/kernel.h>
5355d522f475Smrg#include <string.h>
5356d522f475Smrg#include <errno.h>
5357d522f475Smrg
5358d522f475Smrgstruct _proc_session ps;
5359d522f475Smrgstruct _proc_session_reply rps;
5360d522f475Smrg
5361d522f475Smrgint
5362d522f475Smrgqsetlogin(char *login, char *ttyname)
5363d522f475Smrg{
5364d522f475Smrg    int v = getsid(getpid());
5365d522f475Smrg
5366d522f475Smrg    memset(&ps, 0, sizeof(ps));
5367d522f475Smrg    memset(&rps, 0, sizeof(rps));
5368d522f475Smrg
5369d522f475Smrg    ps.type = _PROC_SESSION;
5370d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
5371d522f475Smrg    ps.sid = v;
5372d522f475Smrg    strcpy(ps.name, login);
5373d522f475Smrg
5374d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5375d522f475Smrg
5376d522f475Smrg    if (rps.status < 0)
5377d522f475Smrg	return (rps.status);
5378d522f475Smrg
5379d522f475Smrg    ps.type = _PROC_SESSION;
5380d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
5381d522f475Smrg    ps.sid = v;
5382d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
5383d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5384d522f475Smrg
5385d522f475Smrg    return (rps.status);
5386d522f475Smrg}
5387d522f475Smrg#endif
538801037d57Smrg
538901037d57Smrg#ifdef __minix
539001037d57Smrgint
539101037d57Smrgsetpgrp(void)
539201037d57Smrg{
539301037d57Smrg    return 0;
539401037d57Smrg}
539501037d57Smrg
539601037d57Smrgvoid
539701037d57Smrg_longjmp(jmp_buf _env, int _val)
539801037d57Smrg{
539901037d57Smrg    longjmp(_env, _val);
540001037d57Smrg}
540101037d57Smrg#endif
5402