main.c revision 894e0ac8
1894e0ac8Smrg/* $XTermId: main.c,v 1.758 2014/05/26 00:01:25 tom Exp $ */
20bd37d32Smrg
30bd37d32Smrg/*
4e0a2b6dfSmrg * Copyright 2002-2013,2014 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>
105d522f475Smrg#elif defined(HAVE_LIB_NEXTAW)
106d522f475Smrg#include <X11/neXtaw/Form.h>
107d522f475Smrg#elif defined(HAVE_LIB_XAWPLUS)
108d522f475Smrg#include <X11/XawPlus/Form.h>
109d522f475Smrg#endif
110d522f475Smrg
111d522f475Smrg#endif /* OPT_TOOLBAR */
112d522f475Smrg
113d522f475Smrg#include <pwd.h>
114d522f475Smrg#include <ctype.h>
115d522f475Smrg
116d522f475Smrg#include <data.h>
117d522f475Smrg#include <error.h>
118d522f475Smrg#include <menu.h>
119d522f475Smrg#include <main.h>
120d522f475Smrg#include <xstrings.h>
121d522f475Smrg#include <xtermcap.h>
122d522f475Smrg#include <xterm_io.h>
123d522f475Smrg
124d522f475Smrg#if OPT_WIDE_CHARS
125d522f475Smrg#include <charclass.h>
126d522f475Smrg#endif
127d522f475Smrg
128d522f475Smrg#ifdef __osf__
129d522f475Smrg#define USE_SYSV_SIGNALS
130d522f475Smrg#define WTMP
131d522f475Smrg#include <pty.h>		/* openpty() */
132d522f475Smrg#endif
133d522f475Smrg
134d522f475Smrg#ifdef __sgi
135d522f475Smrg#include <grp.h>		/* initgroups() */
136d522f475Smrg#endif
137d522f475Smrg
1380bd37d32Smrgstatic void Syntax(char *) GCC_NORETURN;
1390bd37d32Smrgstatic void HsSysError(int) GCC_NORETURN;
140d522f475Smrg
141d522f475Smrg#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE)
142d522f475Smrg#define USE_POSIX_SIGNALS
143d522f475Smrg#endif
144d522f475Smrg
145d522f475Smrg#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
146d522f475Smrg/* older SYSV systems cannot ignore SIGHUP.
147d522f475Smrg   Shell hangs, or you get extra shells, or something like that */
148d522f475Smrg#define USE_SYSV_SIGHUP
149d522f475Smrg#endif
150d522f475Smrg
151d522f475Smrg#if defined(sony) && defined(bsd43) && !defined(KANJI)
152d522f475Smrg#define KANJI
153d522f475Smrg#endif
154d522f475Smrg
155d522f475Smrg#ifdef linux
156d522f475Smrg#define USE_SYSV_PGRP
157d522f475Smrg#define USE_SYSV_SIGNALS
158d522f475Smrg#define WTMP
159d522f475Smrg#ifdef __GLIBC__
160d522f475Smrg#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
161d522f475Smrg#include <pty.h>
162d522f475Smrg#endif
163d522f475Smrg#endif
164d522f475Smrg#endif
165d522f475Smrg
166d522f475Smrg#ifdef __MVS__
167d522f475Smrg#define USE_SYSV_PGRP
168d522f475Smrg#define USE_SYSV_SIGNALS
169d522f475Smrg#endif
170d522f475Smrg
171d522f475Smrg#ifdef __CYGWIN__
172d522f475Smrg#define WTMP
173d522f475Smrg#endif
174d522f475Smrg
175d522f475Smrg#ifdef __SCO__
176d522f475Smrg#ifndef _SVID3
177d522f475Smrg#define _SVID3
178d522f475Smrg#endif
179d522f475Smrg#endif
180d522f475Smrg
181d522f475Smrg#if defined(__GLIBC__) && !defined(linux)
182d522f475Smrg#define USE_SYSV_PGRP
183d522f475Smrg#define WTMP
184d522f475Smrg#endif
185d522f475Smrg
186d522f475Smrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID)
187d522f475Smrg#include <grp.h>
188d522f475Smrg#endif
189d522f475Smrg
190d522f475Smrg#ifndef TTY_GROUP_NAME
191d522f475Smrg#define TTY_GROUP_NAME "tty"
192d522f475Smrg#endif
193d522f475Smrg
194d522f475Smrg#include <sys/stat.h>
195d522f475Smrg
196d522f475Smrg#ifdef Lynx
197d522f475Smrg#ifndef BSDLY
198d522f475Smrg#define BSDLY	0
199d522f475Smrg#endif
200d522f475Smrg#ifndef VTDLY
201d522f475Smrg#define VTDLY	0
202d522f475Smrg#endif
203d522f475Smrg#ifndef FFDLY
204d522f475Smrg#define FFDLY	0
205d522f475Smrg#endif
206d522f475Smrg#endif
207d522f475Smrg
208d522f475Smrg#ifdef SYSV			/* { */
209d522f475Smrg
210d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
211d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
212d522f475Smrg#include <poll.h>		/* for POLLIN */
213d522f475Smrg#endif /* USE_USG_PTYS */
214d522f475Smrg
215d522f475Smrg#define USE_SYSV_SIGNALS
216d522f475Smrg#define	USE_SYSV_PGRP
217d522f475Smrg
218d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
219d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
220d522f475Smrg#endif
221d522f475Smrg
222d522f475Smrg/*
223d522f475Smrg * now get system-specific includes
224d522f475Smrg */
225d522f475Smrg#ifdef macII
226d522f475Smrg#include <sys/ttychars.h>
227d522f475Smrg#undef USE_SYSV_ENVVARS
228d522f475Smrg#undef FIOCLEX
229d522f475Smrg#undef FIONCLEX
230d522f475Smrg#define setpgrp2 setpgrp
231d522f475Smrg#include <sgtty.h>
232d522f475Smrg#include <sys/resource.h>
233d522f475Smrg#endif
234d522f475Smrg
235d522f475Smrg#ifdef __hpux
236d522f475Smrg#include <sys/ptyio.h>
237d522f475Smrg#endif /* __hpux */
238d522f475Smrg
239d522f475Smrg#ifdef __osf__
240d522f475Smrg#undef  USE_SYSV_PGRP
241d522f475Smrg#define setpgrp setpgid
242d522f475Smrg#endif
243d522f475Smrg
244d522f475Smrg#ifdef __sgi
245d522f475Smrg#include <sys/sysmacros.h>
246d522f475Smrg#endif /* __sgi */
247d522f475Smrg
248d522f475Smrg#ifdef sun
249d522f475Smrg#include <sys/strredir.h>
250d522f475Smrg#endif
251d522f475Smrg
252e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
253d522f475Smrg
254d522f475Smrg#ifdef __QNX__
255d522f475Smrg
256d522f475Smrg#ifndef __QNXNTO__
257d522f475Smrg#define ttyslot() 1
258d522f475Smrg#else
259d522f475Smrg#define USE_SYSV_PGRP
260d522f475Smrgextern __inline__
261d522f475Smrgint
262d522f475Smrgttyslot(void)
263d522f475Smrg{
264d522f475Smrg    return 1;			/* yuk */
265d522f475Smrg}
266d522f475Smrg#endif
267d522f475Smrg
268d522f475Smrg#else
269d522f475Smrg
270d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
271d522f475Smrg#define setpgrp setpgid
272d522f475Smrg#endif
273d522f475Smrg
274d522f475Smrg#ifndef linux
275d522f475Smrg#ifndef VMS
276d522f475Smrg#ifndef USE_POSIX_TERMIOS
277d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
278d522f475Smrg#include <sgtty.h>
279d522f475Smrg#endif
280d522f475Smrg#endif /* USE_POSIX_TERMIOS */
281d522f475Smrg#ifdef Lynx
282d522f475Smrg#include <resource.h>
283d522f475Smrg#else
284d522f475Smrg#include <sys/resource.h>
285d522f475Smrg#endif
286d522f475Smrg#endif /* !VMS */
287d522f475Smrg#endif /* !linux */
288d522f475Smrg
289d522f475Smrg#endif /* __QNX__ */
290d522f475Smrg
291d522f475Smrg#endif /* } !SYSV */
292d522f475Smrg
293d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
294d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
295d522f475Smrg#ifndef NOFILE
296d522f475Smrg#define NOFILE OPEN_MAX
297d522f475Smrg#endif
298d522f475Smrg#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
299d522f475Smrg#include <sys/param.h>		/* for NOFILE */
300d522f475Smrg#endif
301d522f475Smrg
302d522f475Smrg#if defined(BSD) && (BSD >= 199103)
303d522f475Smrg#define WTMP
304d522f475Smrg#endif
305d522f475Smrg
306d522f475Smrg#include <stdio.h>
307d522f475Smrg
308d522f475Smrg#ifdef __hpux
309d522f475Smrg#include <sys/utsname.h>
310d522f475Smrg#endif /* __hpux */
311d522f475Smrg
312d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
313d522f475Smrg#define ttyslot() 1
314d522f475Smrg#endif /* apollo */
315d522f475Smrg
316d522f475Smrg#if defined(UTMPX_FOR_UTMP)
317d522f475Smrg#define UTMP_STR utmpx
318d522f475Smrg#else
319d522f475Smrg#define UTMP_STR utmp
320d522f475Smrg#endif
321d522f475Smrg
322d522f475Smrg#if defined(USE_UTEMPTER)
323d522f475Smrg#include <utempter.h>
324d522f475Smrg#endif
325d522f475Smrg
326d522f475Smrg#if defined(UTMPX_FOR_UTMP)
327d522f475Smrg
328d522f475Smrg#include <utmpx.h>
329d522f475Smrg
330d522f475Smrg#define call_endutent  endutxent
331d522f475Smrg#define call_getutid   getutxid
332d522f475Smrg#define call_pututline pututxline
333d522f475Smrg#define call_setutent  setutxent
334d522f475Smrg#define call_updwtmp   updwtmpx
335d522f475Smrg
336d522f475Smrg#elif defined(HAVE_UTMP)
337d522f475Smrg
338d522f475Smrg#include <utmp.h>
339d522f475Smrg
340d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
341d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
342d522f475Smrg#endif
343d522f475Smrg
344d522f475Smrg#define call_endutent  endutent
345d522f475Smrg#define call_getutid   getutid
346d522f475Smrg#define call_pututline pututline
347d522f475Smrg#define call_setutent  setutent
348d522f475Smrg#define call_updwtmp   updwtmp
349d522f475Smrg
350d522f475Smrg#endif
351d522f475Smrg
352d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
353d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
354d522f475Smrg#endif
355d522f475Smrg
356d522f475Smrg#ifndef USE_LASTLOGX
357d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
358d522f475Smrg#define USE_LASTLOGX 1
359d522f475Smrg#endif
360d522f475Smrg#endif
361d522f475Smrg
362d522f475Smrg#ifdef  PUCC_PTYD
363d522f475Smrg#include <local/openpty.h>
364d522f475Smrg#endif /* PUCC_PTYD */
365d522f475Smrg
366d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
367d522f475Smrg#include <util.h>		/* openpty() */
368d522f475Smrg#endif
369d522f475Smrg
370956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
371d522f475Smrg#include <libutil.h>		/* openpty() */
372d522f475Smrg#endif
373d522f475Smrg
374d522f475Smrg#if !defined(UTMP_FILENAME)
375d522f475Smrg#if defined(UTMP_FILE)
376d522f475Smrg#define UTMP_FILENAME UTMP_FILE
377d522f475Smrg#elif defined(_PATH_UTMP)
378d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
379d522f475Smrg#else
380d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
381d522f475Smrg#endif
382d522f475Smrg#endif
383d522f475Smrg
384d522f475Smrg#ifndef LASTLOG_FILENAME
385d522f475Smrg#ifdef _PATH_LASTLOG
386d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
387d522f475Smrg#else
388d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
389d522f475Smrg#endif
390d522f475Smrg#endif
391d522f475Smrg
392d522f475Smrg#if !defined(WTMP_FILENAME)
393d522f475Smrg#if defined(WTMP_FILE)
394d522f475Smrg#define WTMP_FILENAME WTMP_FILE
395d522f475Smrg#elif defined(_PATH_WTMP)
396d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
397d522f475Smrg#elif defined(SYSV)
398d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
399d522f475Smrg#else
400d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
401d522f475Smrg#endif
402d522f475Smrg#endif
403d522f475Smrg
404d522f475Smrg#include <signal.h>
405d522f475Smrg
406d522f475Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
407d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
408d522f475Smrg#endif
409d522f475Smrg
410d522f475Smrg#ifdef SIGTSTP
411d522f475Smrg#include <sys/wait.h>
412d522f475Smrg#endif
413d522f475Smrg
414d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
415d522f475Smrg#undef ECHOKE
416d522f475Smrg#undef ECHOCTL
417d522f475Smrg#endif
418d522f475Smrg
419d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
420d522f475Smrg#include <sys/ttydefaults.h>
421d522f475Smrg#endif
422d522f475Smrg
423d522f475Smrg#ifdef X_NOT_POSIX
424d522f475Smrgextern long lseek();
425d522f475Smrg#if defined(USG) || defined(SVR4)
426d522f475Smrgextern unsigned sleep();
427d522f475Smrg#else
428d522f475Smrgextern void sleep();
429d522f475Smrg#endif
430d522f475Smrgextern char *ttyname();
431d522f475Smrg#endif
432d522f475Smrg
433d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
434d522f475Smrgextern char *ptsname(int);
435d522f475Smrg#endif
436d522f475Smrg
437d522f475Smrg#ifndef VMS
4380bd37d32Smrgstatic void reapchild(int /* n */ );
439d522f475Smrgstatic int spawnXTerm(XtermWidget /* xw */ );
44020d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
441d522f475Smrg#ifdef USE_PTY_SEARCH
44220d2c4d2Smrgstatic int pty_search(int * /* pty */ );
443d522f475Smrg#endif
444d522f475Smrg#endif /* ! VMS */
445d522f475Smrg
446d522f475Smrgstatic int get_pty(int *pty, char *from);
44720d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
448e0a2b6dfSmrgstatic void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
449d522f475Smrg
450d522f475Smrgstatic Bool added_utmp_entry = False;
451d522f475Smrg
452d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
453d522f475Smrgstatic uid_t save_euid;
454d522f475Smrgstatic gid_t save_egid;
455d522f475Smrg#endif
456d522f475Smrg
457d522f475Smrgstatic uid_t save_ruid;
458d522f475Smrgstatic gid_t save_rgid;
459d522f475Smrg
460d522f475Smrg#if defined(USE_UTMP_SETGID)
461d522f475Smrgstatic int really_get_pty(int *pty, char *from);
462d522f475Smrg#endif
463d522f475Smrg
464d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
465d522f475Smrgstatic Bool xterm_exiting = False;
466d522f475Smrg#endif
467d522f475Smrg
468d522f475Smrgstatic char *explicit_shname = NULL;
469d522f475Smrg
470d522f475Smrg/*
471d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
472d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
473d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
474d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
475d522f475Smrg** SEGV.
476d522f475Smrg*/
477d522f475Smrgstatic char **command_to_exec = NULL;
478d522f475Smrg
479d522f475Smrg#if OPT_LUIT_PROG
480d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
4810bd37d32Smrgstatic unsigned command_length_with_luit = 0;
482d522f475Smrg#endif
483d522f475Smrg
484d522f475Smrg#define TERMCAP_ERASE "kb"
485d522f475Smrg#define VAL_INITIAL_ERASE A2E(8)
486d522f475Smrg
487d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
488d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
489d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
490d522f475Smrg * about padding generally store the code in a short, which does not have
491d522f475Smrg * enough bits for the extended values.
492d522f475Smrg */
493d522f475Smrg#ifdef B38400			/* everyone should define this */
494d522f475Smrg#define VAL_LINE_SPEED B38400
495d522f475Smrg#else /* ...but xterm's used this for a long time */
496d522f475Smrg#define VAL_LINE_SPEED B9600
497d522f475Smrg#endif
498d522f475Smrg
499d522f475Smrg/*
500d522f475Smrg * Allow use of system default characters if defined and reasonable.
501d522f475Smrg * These are based on the BSD ttydefaults.h
502d522f475Smrg */
503d522f475Smrg#ifndef CBRK
504d522f475Smrg#define CBRK     0xff		/* was 0 */
505d522f475Smrg#endif
506d522f475Smrg#ifndef CDISCARD
507d522f475Smrg#define CDISCARD CONTROL('O')
508d522f475Smrg#endif
509d522f475Smrg#ifndef CDSUSP
510d522f475Smrg#define CDSUSP   CONTROL('Y')
511d522f475Smrg#endif
512d522f475Smrg#ifndef CEOF
513d522f475Smrg#define CEOF     CONTROL('D')
514d522f475Smrg#endif
515d522f475Smrg#ifndef CEOL
516d522f475Smrg#define CEOL	 0xff		/* was 0 */
517d522f475Smrg#endif
518d522f475Smrg#ifndef CERASE
519d522f475Smrg#define CERASE   0177
520d522f475Smrg#endif
521d522f475Smrg#ifndef CERASE2
522d522f475Smrg#define	CERASE2  CONTROL('H')
523d522f475Smrg#endif
524d522f475Smrg#ifndef CFLUSH
525d522f475Smrg#define CFLUSH   CONTROL('O')
526d522f475Smrg#endif
527d522f475Smrg#ifndef CINTR
528d522f475Smrg#define CINTR    CONTROL('C')
529d522f475Smrg#endif
530d522f475Smrg#ifndef CKILL
531d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
532d522f475Smrg#endif
533d522f475Smrg#ifndef CLNEXT
534d522f475Smrg#define CLNEXT   CONTROL('V')
535d522f475Smrg#endif
536d522f475Smrg#ifndef CNUL
537d522f475Smrg#define CNUL     0
538d522f475Smrg#endif
539d522f475Smrg#ifndef CQUIT
540d522f475Smrg#define CQUIT    CONTROL('\\')
541d522f475Smrg#endif
542d522f475Smrg#ifndef CRPRNT
543d522f475Smrg#define CRPRNT   CONTROL('R')
544d522f475Smrg#endif
545d522f475Smrg#ifndef CREPRINT
546d522f475Smrg#define CREPRINT CRPRNT
547d522f475Smrg#endif
548d522f475Smrg#ifndef CSTART
549d522f475Smrg#define CSTART   CONTROL('Q')
550d522f475Smrg#endif
551d522f475Smrg#ifndef CSTATUS
552d522f475Smrg#define	CSTATUS  CONTROL('T')
553d522f475Smrg#endif
554d522f475Smrg#ifndef CSTOP
555d522f475Smrg#define CSTOP    CONTROL('S')
556d522f475Smrg#endif
557d522f475Smrg#ifndef CSUSP
558d522f475Smrg#define CSUSP    CONTROL('Z')
559d522f475Smrg#endif
560d522f475Smrg#ifndef CSWTCH
561d522f475Smrg#define CSWTCH   0
562d522f475Smrg#endif
563d522f475Smrg#ifndef CWERASE
564d522f475Smrg#define CWERASE  CONTROL('W')
565d522f475Smrg#endif
566d522f475Smrg
567d522f475Smrg#ifdef USE_ANY_SYSV_TERMIO
568d522f475Smrg#define TERMIO_STRUCT struct termio
569d522f475Smrg#define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
570d522f475Smrg#define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
571d522f475Smrg#define ttyFlush(fd)          ioctl(fd, TCFLSH, 1)
572d522f475Smrg#elif defined(USE_POSIX_TERMIOS)
573d522f475Smrg#define TERMIO_STRUCT struct termios
574d522f475Smrg#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
575d522f475Smrg#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
576d522f475Smrg#define ttyFlush(fd)          tcflush(fd, TCOFLUSH)
577d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO */
578d522f475Smrg
579d522f475Smrg#ifndef VMS
580d522f475Smrg#ifdef TERMIO_STRUCT
581d522f475Smrg/* The following structures are initialized in main() in order
582d522f475Smrg** to eliminate any assumptions about the internal order of their
583d522f475Smrg** contents.
584d522f475Smrg*/
585d522f475Smrgstatic TERMIO_STRUCT d_tio;
586d522f475Smrg
587d522f475Smrg#ifdef HAS_LTCHARS
588d522f475Smrgstatic struct ltchars d_ltc;
589d522f475Smrg#endif /* HAS_LTCHARS */
590d522f475Smrg
591d522f475Smrg#ifdef TIOCLSET
592d522f475Smrgstatic unsigned int d_lmode;
593d522f475Smrg#endif /* TIOCLSET */
594d522f475Smrg
595d522f475Smrg#else /* !TERMIO_STRUCT */
596d522f475Smrgstatic struct sgttyb d_sg =
597d522f475Smrg{
598d522f475Smrg    0, 0, 0177, CKILL, (EVENP | ODDP | ECHO | XTABS | CRMOD)
599d522f475Smrg};
600d522f475Smrgstatic struct tchars d_tc =
601d522f475Smrg{
602d522f475Smrg    CINTR, CQUIT, CSTART,
603d522f475Smrg    CSTOP, CEOF, CBRK
604d522f475Smrg};
605d522f475Smrgstatic struct ltchars d_ltc =
606d522f475Smrg{
607d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
608d522f475Smrg    CFLUSH, CWERASE, CLNEXT
609d522f475Smrg};
610d522f475Smrgstatic int d_disipline = NTTYDISC;
611d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
612d522f475Smrg#ifdef sony
613d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
614d522f475Smrgstatic struct jtchars d_jtc =
615d522f475Smrg{
616d522f475Smrg    'J', 'B'
617d522f475Smrg};
618d522f475Smrg#endif /* sony */
619d522f475Smrg#endif /* TERMIO_STRUCT */
620d522f475Smrg#endif /* ! VMS */
621d522f475Smrg
622d522f475Smrg/*
623d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
624d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
625d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
626d522f475Smrg */
627d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
628d522f475Smrgstatic Boolean override_tty_modes = False;
629d522f475Smrg/* *INDENT-OFF* */
630d522f475Smrgstatic struct _xttymodes {
63120d2c4d2Smrg    const char *name;
632d522f475Smrg    size_t len;
633d522f475Smrg    int set;
634d522f475Smrg    int value;
635d522f475Smrg} ttymodelist[] = {
636d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
637d522f475Smrg#define XTTYMODE_intr	0
638d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
639d522f475Smrg#define XTTYMODE_quit	1
640d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
641d522f475Smrg#define XTTYMODE_erase	2
642d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
643d522f475Smrg#define XTTYMODE_kill	3
644d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
645d522f475Smrg#define XTTYMODE_eof	4
646d522f475Smrg    TTYMODE("eol"),		/* VEOL */
647d522f475Smrg#define XTTYMODE_eol	5
648d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
649d522f475Smrg#define XTTYMODE_swtch	6
650d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
651d522f475Smrg#define XTTYMODE_start	7
652d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
653d522f475Smrg#define XTTYMODE_stop	8
654d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
655d522f475Smrg#define XTTYMODE_brk	9
656d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
657d522f475Smrg#define XTTYMODE_susp	10
658d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
659d522f475Smrg#define XTTYMODE_dsusp	11
660d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
661d522f475Smrg#define XTTYMODE_rprnt	12
662d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
663d522f475Smrg#define XTTYMODE_flush	13
664d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
665d522f475Smrg#define XTTYMODE_weras	14
666d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
667d522f475Smrg#define XTTYMODE_lnext	15
668d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
669d522f475Smrg#define XTTYMODE_status	16
670d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
671d522f475Smrg#define XTTYMODE_erase2	17
672d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
673d522f475Smrg#define XTTYMODE_eol2	18
674d522f475Smrg    { NULL,	0, 0, '\0' },	/* end of data */
675d522f475Smrg};
676d522f475Smrg
677d522f475Smrg#define validTtyChar(data, n) \
678d522f475Smrg	    (known_ttyChars[n].sysMode >= 0 && \
679d522f475Smrg	     known_ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
680d522f475Smrg
681d522f475Smrgstatic const struct {
682d522f475Smrg    int sysMode;
683d522f475Smrg    int myMode;
684d522f475Smrg    int myDefault;
685d522f475Smrg} known_ttyChars[] = {
686d522f475Smrg#ifdef VINTR
687d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
688d522f475Smrg#endif
689d522f475Smrg#ifdef VQUIT
690d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
691d522f475Smrg#endif
692d522f475Smrg#ifdef VERASE
693d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
694d522f475Smrg#endif
695d522f475Smrg#ifdef VKILL
696d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
697d522f475Smrg#endif
698d522f475Smrg#ifdef VEOF
699d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
700d522f475Smrg#endif
701d522f475Smrg#ifdef VEOL
702d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
703d522f475Smrg#endif
704d522f475Smrg#ifdef VSWTCH
705d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
706d522f475Smrg#endif
707d522f475Smrg#ifdef VSTART
708d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
709d522f475Smrg#endif
710d522f475Smrg#ifdef VSTOP
711d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
712d522f475Smrg#endif
713d522f475Smrg#ifdef VSUSP
714d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
715d522f475Smrg#endif
716d522f475Smrg#ifdef VDSUSP
717d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
718d522f475Smrg#endif
719d522f475Smrg#ifdef VREPRINT
720d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
721d522f475Smrg#endif
722d522f475Smrg#ifdef VDISCARD
723d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
724d522f475Smrg#endif
725d522f475Smrg#ifdef VWERASE
726d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
727d522f475Smrg#endif
728d522f475Smrg#ifdef VLNEXT
729d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
730d522f475Smrg#endif
731d522f475Smrg#ifdef VSTATUS
732d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
733d522f475Smrg#endif
734d522f475Smrg#ifdef VERASE2
735d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
736d522f475Smrg#endif
737d522f475Smrg#ifdef VEOL2
738d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
739d522f475Smrg#endif
740d522f475Smrg};
741d522f475Smrg/* *INDENT-ON* */
742d522f475Smrg
7430bd37d32Smrg#define TMODE(ind,var) if (ttymodelist[ind].set) var = (cc_t) ttymodelist[ind].value
744d522f475Smrg
745d522f475Smrgstatic int parse_tty_modes(char *s, struct _xttymodes *modelist);
746d522f475Smrg
747d522f475Smrg#ifndef USE_UTEMPTER
748d522f475Smrg#ifdef USE_SYSV_UTMP
749d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
750d522f475Smrgextern struct utmp *getutid();
751d522f475Smrg#endif /* AIXV3 */
752d522f475Smrg
753d522f475Smrg#else /* not USE_SYSV_UTMP */
754d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
755d522f475Smrg#endif /* USE_SYSV_UTMP */
756d522f475Smrg
757d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
758d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
759d522f475Smrg#else
760d522f475Smrg#undef USE_LASTLOG
761d522f475Smrg#endif
762d522f475Smrg
763d522f475Smrg#ifdef WTMP
764d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
765d522f475Smrg#endif
766d522f475Smrg#endif /* !USE_UTEMPTER */
767d522f475Smrg
768d522f475Smrg/*
769d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
770d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
771d522f475Smrg * WTMP and USE_LASTLOG.
772d522f475Smrg */
773d522f475Smrg#ifdef USE_LOGIN_DASH_P
774d522f475Smrg#ifndef LOGIN_FILENAME
775d522f475Smrg#define LOGIN_FILENAME "/bin/login"
776d522f475Smrg#endif
777d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
778d522f475Smrg#endif
779d522f475Smrg
780d522f475Smrgstatic char passedPty[PTYCHARLEN + 1];	/* name if pty if slave */
781d522f475Smrg
782d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
783d522f475Smrgstatic int Console;
784d522f475Smrg#include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
785d522f475Smrg#define MIT_CONSOLE_LEN	12
786d522f475Smrg#define MIT_CONSOLE "MIT_CONSOLE_"
787d522f475Smrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
788d522f475Smrgstatic Atom mit_console;
789d522f475Smrg#endif /* TIOCCONS */
790d522f475Smrg
791d522f475Smrg#ifndef USE_SYSV_UTMP
792d522f475Smrgstatic int tslot;
793d522f475Smrg#endif /* USE_SYSV_UTMP */
794d522f475Smrgstatic sigjmp_buf env;
795d522f475Smrg
796d522f475Smrg#define SetUtmpHost(dst, screen) \
797d522f475Smrg	{ \
798d522f475Smrg	    char host[sizeof(dst) + 1]; \
799d522f475Smrg	    strncpy(host, DisplayString(screen->display), sizeof(host)); \
800d522f475Smrg	    TRACE(("DisplayString(%s)\n", host)); \
801d522f475Smrg	    if (!resource.utmpDisplayId) { \
802d522f475Smrg		char *endptr = strrchr(host, ':'); \
803d522f475Smrg		if (endptr) { \
804d522f475Smrg		    TRACE(("trimming display-id '%s'\n", host)); \
805d522f475Smrg		    *endptr = '\0'; \
806d522f475Smrg		} \
807d522f475Smrg	    } \
808894e0ac8Smrg	    copy_filled(dst, host, sizeof(dst)); \
809d522f475Smrg	}
810d522f475Smrg
811d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
812d522f475Smrg#  define SetUtmpSysLen(utmp) 			   \
813d522f475Smrg	{ \
814d522f475Smrg	    utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
815d522f475Smrg	    utmp.ut_syslen = strlen(utmp.ut_host) + 1; \
816d522f475Smrg	}
817d522f475Smrg#endif
818d522f475Smrg
819d522f475Smrg/* used by VT (charproc.c) */
820d522f475Smrg
821d522f475Smrgstatic XtResource application_resources[] =
822d522f475Smrg{
823d522f475Smrg    Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
824d522f475Smrg    Sres(XtNtitle, XtCTitle, title, NULL),
8250bd37d32Smrg    Sres(XtNiconHint, XtCIconHint, icon_hint, NULL),
826d522f475Smrg    Sres(XtNiconName, XtCIconName, icon_name, NULL),
827d522f475Smrg    Sres("termName", "TermName", term_name, NULL),
828d522f475Smrg    Sres("ttyModes", "TtyModes", tty_modes, NULL),
829d522f475Smrg    Bres("hold", "Hold", hold_screen, False),
830d522f475Smrg    Bres("utmpInhibit", "UtmpInhibit", utmpInhibit, False),
831d522f475Smrg    Bres("utmpDisplayId", "UtmpDisplayId", utmpDisplayId, True),
832d522f475Smrg    Bres("messages", "Messages", messages, True),
833d522f475Smrg    Ires("minBufSize", "MinBufSize", minBufSize, 4096),
834d522f475Smrg    Ires("maxBufSize", "MaxBufSize", maxBufSize, 32768),
83520d2c4d2Smrg    Sres("menuLocale", "MenuLocale", menuLocale, DEF_MENU_LOCALE),
836a1f3da82Smrg    Sres("omitTranslation", "OmitTranslation", omitTranslation, NULL),
837d522f475Smrg    Sres("keyboardType", "KeyboardType", keyboardType, "unknown"),
838e39b573cSmrg#if OPT_PRINT_ON_EXIT
839e39b573cSmrg    Ires("printModeImmediate", "PrintModeImmediate", printModeNow, 0),
840e39b573cSmrg    Ires("printOptsImmediate", "PrintOptsImmediate", printOptsNow, 9),
841e39b573cSmrg    Sres("printFileImmediate", "PrintFileImmediate", printFileNow, NULL),
842e39b573cSmrg    Ires("printModeOnXError", "PrintModeOnXError", printModeOnXError, 0),
843e39b573cSmrg    Ires("printOptsOnXError", "PrintOptsOnXError", printOptsOnXError, 9),
844e39b573cSmrg    Sres("printFileOnXError", "PrintFileOnXError", printFileOnXError, NULL),
845e39b573cSmrg#endif
846d522f475Smrg#if OPT_SUNPC_KBD
847d522f475Smrg    Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
848d522f475Smrg#endif
849d522f475Smrg#if OPT_HP_FUNC_KEYS
850d522f475Smrg    Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
851d522f475Smrg#endif
852d522f475Smrg#if OPT_SCO_FUNC_KEYS
853d522f475Smrg    Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
854d522f475Smrg#endif
855d522f475Smrg#if OPT_SUN_FUNC_KEYS
856d522f475Smrg    Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
857d522f475Smrg#endif
858d522f475Smrg#if OPT_TCAP_FKEYS
859d522f475Smrg    Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
860d522f475Smrg#endif
861d522f475Smrg#if OPT_INITIAL_ERASE
862d522f475Smrg    Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
863d522f475Smrg    Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
864d522f475Smrg#endif
865d522f475Smrg    Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
866d522f475Smrg#if OPT_ZICONBEEP
867d522f475Smrg    Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
8680bd37d32Smrg    Sres("zIconTitleFormat", "ZIconTitleFormat", zIconFormat, "*** %s"),
869d522f475Smrg#endif
870d522f475Smrg#if OPT_PTY_HANDSHAKE
871d522f475Smrg    Bres("waitForMap", "WaitForMap", wait_for_map, False),
872d522f475Smrg    Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
873d522f475Smrg    Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
874d522f475Smrg#endif
875e0a2b6dfSmrg#if OPT_REPORT_COLORS
876e0a2b6dfSmrg    Bres("reportColors", "ReportColors", reportColors, False),
877e0a2b6dfSmrg#endif
878e0a2b6dfSmrg#if OPT_REPORT_FONTS
879e0a2b6dfSmrg    Bres("reportFonts", "ReportFonts", reportFonts, False),
880e0a2b6dfSmrg#endif
881d522f475Smrg#if OPT_SAME_NAME
882d522f475Smrg    Bres("sameName", "SameName", sameName, True),
883d522f475Smrg#endif
884d522f475Smrg#if OPT_SESSION_MGT
885d522f475Smrg    Bres("sessionMgt", "SessionMgt", sessionMgt, True),
886d522f475Smrg#endif
887d522f475Smrg#if OPT_TOOLBAR
888d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
889d522f475Smrg#endif
890956cc18dSsnj#if OPT_MAXIMIZE
891956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
892a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
893956cc18dSsnj#endif
894d522f475Smrg};
895d522f475Smrg
89620d2c4d2Smrgstatic String fallback_resources[] =
897d522f475Smrg{
898e39b573cSmrg#if OPT_TOOLBAR
899e39b573cSmrg    "*toolBar: false",
900e39b573cSmrg#endif
901d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
902d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
903d522f475Smrg    "*SimpleMenu*Sme.height: 16",
904d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
905d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
906d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
907d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
908d522f475Smrg#if OPT_TEK4014
909d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
910d522f475Smrg#endif
911d522f475Smrg    NULL
912d522f475Smrg};
913d522f475Smrg
914d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
915d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
916d522f475Smrg/* *INDENT-OFF* */
917d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
91820d2c4d2Smrg{"-geometry",	"*vt100.geometry",XrmoptionSepArg,	(XPointer) NULL},
91920d2c4d2Smrg{"-132",	"*c132",	XrmoptionNoArg,		(XPointer) "on"},
92020d2c4d2Smrg{"+132",	"*c132",	XrmoptionNoArg,		(XPointer) "off"},
92120d2c4d2Smrg{"-ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "on"},
92220d2c4d2Smrg{"+ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "off"},
92320d2c4d2Smrg{"-aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "on"},
92420d2c4d2Smrg{"+aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "off"},
925d522f475Smrg#ifndef NO_ACTIVE_ICON
92620d2c4d2Smrg{"-ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "off"},
92720d2c4d2Smrg{"+ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "on"},
928d522f475Smrg#endif /* NO_ACTIVE_ICON */
92920d2c4d2Smrg{"-b",		"*internalBorder",XrmoptionSepArg,	(XPointer) NULL},
93020d2c4d2Smrg{"-bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "on"},
93120d2c4d2Smrg{"+bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "off"},
93220d2c4d2Smrg{"-bcf",	"*cursorOffTime",XrmoptionSepArg,	(XPointer) NULL},
93320d2c4d2Smrg{"-bcn",	"*cursorOnTime",XrmoptionSepArg,	(XPointer) NULL},
93420d2c4d2Smrg{"-bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "off"},
93520d2c4d2Smrg{"+bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "on"},
93620d2c4d2Smrg{"-cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "off"},
93720d2c4d2Smrg{"+cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "on"},
93820d2c4d2Smrg{"-cc",		"*charClass",	XrmoptionSepArg,	(XPointer) NULL},
93920d2c4d2Smrg{"-cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "off"},
94020d2c4d2Smrg{"+cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "on"},
94120d2c4d2Smrg{"-cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "off"},
94220d2c4d2Smrg{"+cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "on"},
94320d2c4d2Smrg{"-cr",		"*cursorColor",	XrmoptionSepArg,	(XPointer) NULL},
94420d2c4d2Smrg{"-cu",		"*curses",	XrmoptionNoArg,		(XPointer) "on"},
94520d2c4d2Smrg{"+cu",		"*curses",	XrmoptionNoArg,		(XPointer) "off"},
94620d2c4d2Smrg{"-dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "off"},
94720d2c4d2Smrg{"+dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "on"},
94820d2c4d2Smrg{"-fb",		"*boldFont",	XrmoptionSepArg,	(XPointer) NULL},
94920d2c4d2Smrg{"-fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"off"},
95020d2c4d2Smrg{"+fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"on"},
95120d2c4d2Smrg{"-fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"off"},
95220d2c4d2Smrg{"+fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"on"},
953d522f475Smrg#ifndef NO_ACTIVE_ICON
95420d2c4d2Smrg{"-fi",		"*iconFont",	XrmoptionSepArg,	(XPointer) NULL},
955d522f475Smrg#endif /* NO_ACTIVE_ICON */
956d522f475Smrg#if OPT_RENDERFONT
95720d2c4d2Smrg{"-fa",		"*faceName",	XrmoptionSepArg,	(XPointer) NULL},
95820d2c4d2Smrg{"-fd",		"*faceNameDoublesize", XrmoptionSepArg,	(XPointer) NULL},
95920d2c4d2Smrg{"-fs",		"*faceSize",	XrmoptionSepArg,	(XPointer) NULL},
960d522f475Smrg#endif
961d522f475Smrg#if OPT_WIDE_CHARS
96220d2c4d2Smrg{"-fw",		"*wideFont",	XrmoptionSepArg,	(XPointer) NULL},
96320d2c4d2Smrg{"-fwb",	"*wideBoldFont", XrmoptionSepArg,	(XPointer) NULL},
964d522f475Smrg#endif
965d522f475Smrg#if OPT_INPUT_METHOD
96620d2c4d2Smrg{"-fx",		"*ximFont",	XrmoptionSepArg,	(XPointer) NULL},
967d522f475Smrg#endif
968d522f475Smrg#if OPT_HIGHLIGHT_COLOR
96920d2c4d2Smrg{"-hc",		"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
97020d2c4d2Smrg{"-hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "on"},
97120d2c4d2Smrg{"+hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "off"},
97220d2c4d2Smrg{"-selfg",	"*highlightTextColor", XrmoptionSepArg,	(XPointer) NULL},
97320d2c4d2Smrg{"-selbg",	"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
974d522f475Smrg#endif
975d522f475Smrg#if OPT_HP_FUNC_KEYS
97620d2c4d2Smrg{"-hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "on"},
97720d2c4d2Smrg{"+hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "off"},
978d522f475Smrg#endif
97920d2c4d2Smrg{"-hold",	"*hold",	XrmoptionNoArg,		(XPointer) "on"},
98020d2c4d2Smrg{"+hold",	"*hold",	XrmoptionNoArg,		(XPointer) "off"},
981d522f475Smrg#if OPT_INITIAL_ERASE
98220d2c4d2Smrg{"-ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "on"},
98320d2c4d2Smrg{"+ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "off"},
984d522f475Smrg#endif
98520d2c4d2Smrg{"-j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "on"},
98620d2c4d2Smrg{"+j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "off"},
987d522f475Smrg#if OPT_C1_PRINT
98820d2c4d2Smrg{"-k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "on"},
98920d2c4d2Smrg{"+k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "off"},
990d522f475Smrg#endif
99120d2c4d2Smrg{"-kt",		"*keyboardType", XrmoptionSepArg,	(XPointer) NULL},
992d522f475Smrg/* parse logging options anyway for compatibility */
99320d2c4d2Smrg{"-l",		"*logging",	XrmoptionNoArg,		(XPointer) "on"},
99420d2c4d2Smrg{"+l",		"*logging",	XrmoptionNoArg,		(XPointer) "off"},
99520d2c4d2Smrg{"-lf",		"*logFile",	XrmoptionSepArg,	(XPointer) NULL},
99620d2c4d2Smrg{"-ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "on"},
99720d2c4d2Smrg{"+ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "off"},
99820d2c4d2Smrg{"-mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "on"},
99920d2c4d2Smrg{"+mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "off"},
100020d2c4d2Smrg{"-mc",		"*multiClickTime", XrmoptionSepArg,	(XPointer) NULL},
100120d2c4d2Smrg{"-mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "off"},
100220d2c4d2Smrg{"+mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "on"},
100320d2c4d2Smrg{"-ms",		"*pointerColor",XrmoptionSepArg,	(XPointer) NULL},
100420d2c4d2Smrg{"-nb",		"*nMarginBell",	XrmoptionSepArg,	(XPointer) NULL},
100520d2c4d2Smrg{"-nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "off"},
100620d2c4d2Smrg{"+nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "on"},
100720d2c4d2Smrg{"-pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "on"},
100820d2c4d2Smrg{"+pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "off"},
100920d2c4d2Smrg{"-rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "on"},
101020d2c4d2Smrg{"+rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "off"},
101120d2c4d2Smrg{"-s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "on"},
101220d2c4d2Smrg{"+s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "off"},
101320d2c4d2Smrg{"-sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "on"},
101420d2c4d2Smrg{"+sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "off"},
1015e0a2b6dfSmrg#if OPT_REPORT_COLORS
1016e0a2b6dfSmrg{"-report-colors","*reportColors", XrmoptionNoArg,	(XPointer) "on"},
1017e0a2b6dfSmrg#endif
1018e0a2b6dfSmrg#if OPT_REPORT_FONTS
1019e0a2b6dfSmrg{"-report-fonts","*reportFonts", XrmoptionNoArg,	(XPointer) "on"},
1020e0a2b6dfSmrg#endif
1021d522f475Smrg#ifdef SCROLLBAR_RIGHT
102220d2c4d2Smrg{"-leftbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "off"},
102320d2c4d2Smrg{"-rightbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "on"},
102420d2c4d2Smrg#endif
102520d2c4d2Smrg{"-rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "off"},
102620d2c4d2Smrg{"+rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "on"},
102720d2c4d2Smrg{"-sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "on"},
102820d2c4d2Smrg{"+sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "off"},
10290bd37d32Smrg{"-sh",		"*scaleHeight", XrmoptionSepArg,	(XPointer) NULL},
103020d2c4d2Smrg{"-si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "off"},
103120d2c4d2Smrg{"+si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "on"},
103220d2c4d2Smrg{"-sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "on"},
103320d2c4d2Smrg{"+sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "off"},
103420d2c4d2Smrg{"-sl",		"*saveLines",	XrmoptionSepArg,	(XPointer) NULL},
1035d522f475Smrg#if OPT_SUNPC_KBD
103620d2c4d2Smrg{"-sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "on"},
103720d2c4d2Smrg{"+sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "off"},
1038d522f475Smrg#endif
1039d522f475Smrg#if OPT_TEK4014
104020d2c4d2Smrg{"-t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "on"},
104120d2c4d2Smrg{"+t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "off"},
1042d522f475Smrg#endif
104320d2c4d2Smrg{"-ti",		"*decTerminalID",XrmoptionSepArg,	(XPointer) NULL},
104420d2c4d2Smrg{"-tm",		"*ttyModes",	XrmoptionSepArg,	(XPointer) NULL},
104520d2c4d2Smrg{"-tn",		"*termName",	XrmoptionSepArg,	(XPointer) NULL},
1046d522f475Smrg#if OPT_WIDE_CHARS
104720d2c4d2Smrg{"-u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "2"},
104820d2c4d2Smrg{"+u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "0"},
1049d522f475Smrg#endif
1050d522f475Smrg#if OPT_LUIT_PROG
105120d2c4d2Smrg{"-lc",		"*locale",	XrmoptionNoArg,		(XPointer) "on"},
105220d2c4d2Smrg{"+lc",		"*locale",	XrmoptionNoArg,		(XPointer) "off"},
105320d2c4d2Smrg{"-lcc",	"*localeFilter",XrmoptionSepArg,	(XPointer) NULL},
105420d2c4d2Smrg{"-en",		"*locale",	XrmoptionSepArg,	(XPointer) NULL},
105520d2c4d2Smrg#endif
105620d2c4d2Smrg{"-uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "on"},
105720d2c4d2Smrg{"+uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "off"},
105820d2c4d2Smrg{"-ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "off"},
105920d2c4d2Smrg{"+ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "on"},
106020d2c4d2Smrg{"-ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "off"},
106120d2c4d2Smrg{"+ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "on"},
106220d2c4d2Smrg{"-ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "on"},
106320d2c4d2Smrg{"+ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "off"},
106420d2c4d2Smrg{"-im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "on"},
106520d2c4d2Smrg{"+im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "off"},
106620d2c4d2Smrg{"-vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "on"},
106720d2c4d2Smrg{"+vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "off"},
106820d2c4d2Smrg{"-pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "on"},
106920d2c4d2Smrg{"+pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "off"},
1070d522f475Smrg#if OPT_WIDE_CHARS
107120d2c4d2Smrg{"-wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "on"},
107220d2c4d2Smrg{"+wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "off"},
107320d2c4d2Smrg{"-mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "on"},
107420d2c4d2Smrg{"+mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "off"},
107520d2c4d2Smrg{"-cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "on"},
107620d2c4d2Smrg{"+cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "off"},
107720d2c4d2Smrg#endif
107820d2c4d2Smrg{"-wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "on"},
107920d2c4d2Smrg{"+wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "off"},
1080d522f475Smrg#if OPT_ZICONBEEP
108120d2c4d2Smrg{"-ziconbeep",	"*zIconBeep",	XrmoptionSepArg,	(XPointer) NULL},
1082d522f475Smrg#endif
1083d522f475Smrg#if OPT_SAME_NAME
108420d2c4d2Smrg{"-samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "on"},
108520d2c4d2Smrg{"+samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "off"},
1086d522f475Smrg#endif
1087d522f475Smrg#if OPT_SESSION_MGT
108820d2c4d2Smrg{"-sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "on"},
108920d2c4d2Smrg{"+sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "off"},
1090d522f475Smrg#endif
1091d522f475Smrg#if OPT_TOOLBAR
109220d2c4d2Smrg{"-tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "on"},
109320d2c4d2Smrg{"+tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "off"},
1094d522f475Smrg#endif
1095956cc18dSsnj#if OPT_MAXIMIZE
109620d2c4d2Smrg{"-maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "on"},
109720d2c4d2Smrg{"+maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "off"},
1098a1f3da82Smrg{"-fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "on"},
1099a1f3da82Smrg{"+fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "off"},
1100956cc18dSsnj#endif
1101d522f475Smrg/* options that we process ourselves */
110220d2c4d2Smrg{"-help",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
110320d2c4d2Smrg{"-version",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
110420d2c4d2Smrg{"-class",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
110520d2c4d2Smrg{"-e",		NULL,		XrmoptionSkipLine,	(XPointer) NULL},
110620d2c4d2Smrg{"-into",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
1107d522f475Smrg/* bogus old compatibility stuff for which there are
1108d522f475Smrg   standard XtOpenApplication options now */
110920d2c4d2Smrg{"%",		"*tekGeometry",	XrmoptionStickyArg,	(XPointer) NULL},
111020d2c4d2Smrg{"#",		".iconGeometry",XrmoptionStickyArg,	(XPointer) NULL},
111120d2c4d2Smrg{"-T",		".title",	XrmoptionSepArg,	(XPointer) NULL},
111220d2c4d2Smrg{"-n",		"*iconName",	XrmoptionSepArg,	(XPointer) NULL},
111320d2c4d2Smrg{"-r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
111420d2c4d2Smrg{"+r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
111520d2c4d2Smrg{"-rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
111620d2c4d2Smrg{"+rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
111720d2c4d2Smrg{"-w",		".borderWidth", XrmoptionSepArg,	(XPointer) NULL},
1118d522f475Smrg};
1119d522f475Smrg
1120d522f475Smrgstatic OptionHelp xtermOptions[] = {
1121d522f475Smrg{ "-version",              "print the version number" },
1122d522f475Smrg{ "-help",                 "print out this message" },
1123d522f475Smrg{ "-display displayname",  "X server to contact" },
1124d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1125d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1126d522f475Smrg{ "-bg color",             "background color" },
1127d522f475Smrg{ "-fg color",             "foreground color" },
1128d522f475Smrg{ "-bd color",             "border color" },
1129d522f475Smrg{ "-bw number",            "border width in pixels" },
1130d522f475Smrg{ "-fn fontname",          "normal text font" },
1131d522f475Smrg{ "-fb fontname",          "bold text font" },
1132d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1133d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1134d522f475Smrg#if OPT_RENDERFONT
1135d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1136d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1137d522f475Smrg{ "-fs size",              "FreeType font-size" },
1138d522f475Smrg#endif
1139d522f475Smrg#if OPT_WIDE_CHARS
1140d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1141d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1142d522f475Smrg#endif
1143d522f475Smrg#if OPT_INPUT_METHOD
1144d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1145d522f475Smrg#endif
1146d522f475Smrg{ "-iconic",               "start iconic" },
1147d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
1148d522f475Smrg{ "-class string",         "class string (XTerm)" },
1149d522f475Smrg{ "-title string",         "title string" },
1150d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1151d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1152d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1153d522f475Smrg#ifndef NO_ACTIVE_ICON
1154d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1155d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1156d522f475Smrg#endif /* NO_ACTIVE_ICON */
1157d522f475Smrg{ "-b number",             "internal border in pixels" },
1158d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1159d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1160d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1161d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1162d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1163d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1164d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1165d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1166d522f475Smrg{ "-cr color",             "text cursor color" },
1167d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1168d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1169d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1170d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1171d522f475Smrg{ "-selbg color",          "selection background color" },
1172d522f475Smrg{ "-selfg color",          "selection foreground color" },
11730bd37d32Smrg/* -hc is deprecated, not shown in help message */
1174d522f475Smrg#endif
1175d522f475Smrg#if OPT_HP_FUNC_KEYS
1176d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1177d522f475Smrg#endif
1178d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1179d522f475Smrg#if OPT_INITIAL_ERASE
1180d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1181d522f475Smrg#endif
1182d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1183d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1184d522f475Smrg#if OPT_C1_PRINT
1185d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1186d522f475Smrg#endif
1187d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1188d522f475Smrg#ifdef ALLOWLOGGING
1189d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1190d522f475Smrg{ "-lf filename",          "logging filename" },
1191d522f475Smrg#else
1192d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1193d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1194d522f475Smrg#endif
1195d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1196d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1197d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1198d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1199d522f475Smrg{ "-ms color",             "pointer color" },
1200d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
1201d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1202d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1203d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1204d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1205d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1206d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1207e0a2b6dfSmrg#if OPT_REPORT_COLORS
1208e0a2b6dfSmrg{ "-report-colors",        "report colors as they are allocated" },
1209e0a2b6dfSmrg#endif
1210e0a2b6dfSmrg#if OPT_REPORT_FONTS
1211e0a2b6dfSmrg{ "-report-fonts",         "report fonts as loaded to stdout" },
1212e0a2b6dfSmrg#endif
1213d522f475Smrg#ifdef SCROLLBAR_RIGHT
1214d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1215d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1216d522f475Smrg#endif
1217d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1218d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1219894e0ac8Smrg{ "-sh number",            "scale line-height values by the given number" },
1220d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1221d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1222d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1223d522f475Smrg#if OPT_SUNPC_KBD
1224d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1225d522f475Smrg#endif
1226d522f475Smrg#if OPT_TEK4014
1227d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1228d522f475Smrg#endif
1229d522f475Smrg#if OPT_TOOLBAR
1230d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1231d522f475Smrg#endif
1232d522f475Smrg{ "-ti termid",            "terminal identifier" },
1233d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1234d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1235d522f475Smrg#if OPT_WIDE_CHARS
1236d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1237d522f475Smrg#endif
1238d522f475Smrg#if OPT_LUIT_PROG
1239d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1240d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
12410bd37d32Smrg/* -en is deprecated, not shown in help message */
1242d522f475Smrg#endif
12432eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1244d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1245d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1246d522f475Smrg#ifdef HAVE_UTMP
1247d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1248d522f475Smrg#else
1249d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1250d522f475Smrg#endif
1251d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1252d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
1253d522f475Smrg#if OPT_WIDE_CHARS
1254d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1255d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1256d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1257d522f475Smrg#endif
1258d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1259d522f475Smrg{ "-e command args ...",   "command to execute" },
1260d522f475Smrg#if OPT_TEK4014
1261d522f475Smrg{ "%geom",                 "Tek window geometry" },
1262d522f475Smrg#endif
1263d522f475Smrg{ "#geom",                 "icon window geometry" },
1264d522f475Smrg{ "-T string",             "title name for window" },
1265d522f475Smrg{ "-n string",             "icon name for window" },
1266d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1267d522f475Smrg{ "-C",                    "intercept console messages" },
1268d522f475Smrg#else
1269d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1270d522f475Smrg#endif
1271d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1272d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1273d522f475Smrg#if OPT_ZICONBEEP
1274d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1275d522f475Smrg#endif
1276d522f475Smrg#if OPT_SAME_NAME
1277d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1278d522f475Smrg#endif
1279d522f475Smrg#if OPT_SESSION_MGT
1280d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1281d522f475Smrg#endif
1282956cc18dSsnj#if OPT_MAXIMIZE
1283956cc18dSsnj{"-/+maximized",           "turn on/off maxmize on startup" },
1284a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1285956cc18dSsnj#endif
1286d522f475Smrg{ NULL, NULL }};
1287d522f475Smrg/* *INDENT-ON* */
1288d522f475Smrg
128920d2c4d2Smrgstatic const char *message[] =
1290d522f475Smrg{
1291d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1292d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1293d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1294d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1295d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
1296d522f475Smrg    NULL};
1297d522f475Smrg
1298d522f475Smrg/*
1299d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1300d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1301d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1302d522f475Smrg */
1303d522f475Smrgstatic int
1304d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1305d522f475Smrg{
1306d522f475Smrg    char *string = *ptr;
1307d522f475Smrg    int value = -1;
1308d522f475Smrg
130920d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1310d522f475Smrg    if (*string == '^') {
1311d522f475Smrg	switch (*++string) {
1312d522f475Smrg	case '?':
1313d522f475Smrg	    value = A2E(ANSI_DEL);
1314d522f475Smrg	    break;
1315d522f475Smrg	case '-':
1316d522f475Smrg	    if (!termcap) {
1317d522f475Smrg		errno = 0;
1318d522f475Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
1319d522f475Smrg		value = _POSIX_VDISABLE;
1320d522f475Smrg#endif
1321d522f475Smrg#if defined(_PC_VDISABLE)
1322d522f475Smrg		if (value == -1) {
132320d2c4d2Smrg		    value = (int) fpathconf(0, _PC_VDISABLE);
1324d522f475Smrg		    if (value == -1) {
1325d522f475Smrg			if (errno != 0)
1326d522f475Smrg			    break;	/* skip this (error) */
1327d522f475Smrg			value = 0377;
1328d522f475Smrg		    }
1329d522f475Smrg		}
1330d522f475Smrg#elif defined(VDISABLE)
1331d522f475Smrg		if (value == -1)
1332d522f475Smrg		    value = VDISABLE;
1333d522f475Smrg#endif
1334d522f475Smrg		break;
1335d522f475Smrg	    }
1336d522f475Smrg	    /* FALLTHRU */
1337d522f475Smrg	default:
1338d522f475Smrg	    value = CONTROL(*string);
1339d522f475Smrg	    break;
1340d522f475Smrg	}
1341d522f475Smrg	++string;
1342d522f475Smrg    } else if (termcap && (*string == '\\')) {
1343d522f475Smrg	char *d;
134420d2c4d2Smrg	int temp = (int) strtol(string + 1, &d, 8);
1345d522f475Smrg	if (temp > 0 && d != string) {
1346d522f475Smrg	    value = temp;
1347d522f475Smrg	    string = d;
1348d522f475Smrg	}
1349d522f475Smrg    } else {
1350d522f475Smrg	value = CharOf(*string);
1351d522f475Smrg	++string;
1352d522f475Smrg    }
1353d522f475Smrg    *ptr = string;
135420d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1355d522f475Smrg    return value;
1356d522f475Smrg}
1357d522f475Smrg
1358d522f475Smrgstatic int
13590bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
13600bd37d32Smrg{
13610bd37d32Smrg    int result = -1;
13620bd37d32Smrg    int n;
13630bd37d32Smrg    int ch;
13640bd37d32Smrg
13650bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
13660bd37d32Smrg	if (param[n] == ch) {
13670bd37d32Smrg	    result = n;
13680bd37d32Smrg	} else {
13690bd37d32Smrg	    if (param[n] != '\0')
13700bd37d32Smrg		result = -1;
13710bd37d32Smrg	    break;
13720bd37d32Smrg	}
13730bd37d32Smrg    }
13740bd37d32Smrg
13750bd37d32Smrg    return result;
13760bd37d32Smrg}
13770bd37d32Smrg
13780bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
13790bd37d32Smrgstatic int
13800bd37d32SmrgcountArg(XrmOptionDescRec * item)
1381d522f475Smrg{
13820bd37d32Smrg    int result = 0;
13830bd37d32Smrg
13840bd37d32Smrg    switch (item->argKind) {
13850bd37d32Smrg    case XrmoptionNoArg:
13860bd37d32Smrg	/* FALLTHRU */
13870bd37d32Smrg    case XrmoptionIsArg:
13880bd37d32Smrg	/* FALLTHRU */
13890bd37d32Smrg    case XrmoptionStickyArg:
13900bd37d32Smrg	break;
13910bd37d32Smrg    case XrmoptionSepArg:
13920bd37d32Smrg	/* FALLTHRU */
13930bd37d32Smrg    case XrmoptionResArg:
13940bd37d32Smrg	/* FALLTHRU */
13950bd37d32Smrg    case XrmoptionSkipArg:
13960bd37d32Smrg	result = 1;
13970bd37d32Smrg	break;
13980bd37d32Smrg    case XrmoptionSkipLine:
13990bd37d32Smrg	break;
14000bd37d32Smrg    case XrmoptionSkipNArgs:
14010bd37d32Smrg	result = (int) (long) (item->value);
14020bd37d32Smrg	break;
14030bd37d32Smrg    }
14040bd37d32Smrg    return result;
14050bd37d32Smrg}
14060bd37d32Smrg
14070bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
14080bd37d32Smrg
14090bd37d32Smrg/*
14100bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
14110bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
14120bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
14130bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
14140bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
14150bd37d32Smrg * standard table (something that the X libraries should do).
14160bd37d32Smrg */
14170bd37d32Smrgstatic XrmOptionDescRec *
14180bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
14190bd37d32Smrg{
14200bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
14210bd37d32Smrg    /* *INDENT-OFF* */
14220bd37d32Smrg#define DATA(option,kind) { option, NULL, kind, (XtPointer) NULL }
14230bd37d32Smrg    static XrmOptionDescRec opTable[] = {
14240bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
14250bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
14260bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
14270bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
14280bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
14290bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
14300bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
14310bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
14320bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
14330bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
14340bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
14350bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
14360bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
14370bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
14380bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
14390bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
14400bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
14410bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
14420bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
14430bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
14440bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
14450bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
14460bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
14470bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
14480bd37d32Smrg#endif /* TIOCCONS */
14490bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
14500bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
14510bd37d32Smrg    };
14520bd37d32Smrg#undef DATA
14530bd37d32Smrg    /* *INDENT-ON* */
14540bd37d32Smrg
14550bd37d32Smrg    XrmOptionDescRec *result = 0;
14560bd37d32Smrg    Cardinal inlist;
14570bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
14580bd37d32Smrg    int atbest = -1;
14590bd37d32Smrg    int best = -1;
14600bd37d32Smrg    int test;
14610bd37d32Smrg    Boolean exact = False;
14620bd37d32Smrg    int ambiguous1 = -1;
14630bd37d32Smrg    int ambiguous2 = -1;
14640bd37d32Smrg    char *option;
14650bd37d32Smrg    char *value;
14660bd37d32Smrg
14670bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
14680bd37d32Smrg		 ? &optionDescList[n] \
14690bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
14700bd37d32Smrg
14710bd37d32Smrg    if ((option = argv[*num]) != 0) {
14720bd37d32Smrg	Boolean need_value;
14730bd37d32Smrg	Boolean have_value = False;
14740bd37d32Smrg
14750bd37d32Smrg	TRACE(("parseArg %s\n", option));
14760bd37d32Smrg	if ((value = argv[(*num) + 1]) != 0) {
1477e0a2b6dfSmrg	    have_value = (Boolean) !isOption(value);
14780bd37d32Smrg	}
14790bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
14800bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
14810bd37d32Smrg
14820bd37d32Smrg	    test = matchArg(check, option);
14830bd37d32Smrg	    if (test < 0)
14840bd37d32Smrg		continue;
14850bd37d32Smrg
14860bd37d32Smrg	    /* check for exact match */
14870bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
14880bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
14890bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
14900bd37d32Smrg			exact = True;
14910bd37d32Smrg			atbest = (int) inlist;
14920bd37d32Smrg			break;
14930bd37d32Smrg		    }
14940bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
14950bd37d32Smrg		    exact = True;
14960bd37d32Smrg		    atbest = (int) inlist;
14970bd37d32Smrg		    break;
14980bd37d32Smrg		}
14990bd37d32Smrg	    }
15000bd37d32Smrg
15010bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
15020bd37d32Smrg
15030bd37d32Smrg	    if (need_value && value != 0) {
15040bd37d32Smrg		;
15050bd37d32Smrg	    } else if (need_value ^ have_value) {
15060bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
15070bd37d32Smrg		continue;
15080bd37d32Smrg	    }
15090bd37d32Smrg
15100bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
15110bd37d32Smrg	    if (test > 0
15120bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
15130bd37d32Smrg		atbest = (int) inlist;
1514e0a2b6dfSmrg		if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
1515e0a2b6dfSmrg		    /* in particular, silence a warning about ambiguity */
1516e0a2b6dfSmrg		    exact = 1;
1517e0a2b6dfSmrg		}
15180bd37d32Smrg		break;
15190bd37d32Smrg	    }
15200bd37d32Smrg	    if (test > best) {
15210bd37d32Smrg		best = test;
15220bd37d32Smrg		atbest = (int) inlist;
15230bd37d32Smrg	    } else if (test == best) {
15240bd37d32Smrg		if (atbest >= 0) {
15250bd37d32Smrg		    if (atbest > 0) {
15260bd37d32Smrg			ambiguous1 = (int) inlist;
15270bd37d32Smrg			ambiguous2 = (int) atbest;
15280bd37d32Smrg		    }
15290bd37d32Smrg		    atbest = -1;
15300bd37d32Smrg		}
15310bd37d32Smrg	    }
15320bd37d32Smrg	}
15330bd37d32Smrg    }
15340bd37d32Smrg
15350bd37d32Smrg    *valuep = 0;
15360bd37d32Smrg    if (atbest >= 0) {
15370bd37d32Smrg	result = ITEM(atbest);
15380bd37d32Smrg	if (!exact) {
15390bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
15400bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
15410bd37d32Smrg			     ITEM(ambiguous1)->option,
15420bd37d32Smrg			     ITEM(ambiguous2)->option);
15430bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
15440bd37d32Smrg		result = 0;
15450bd37d32Smrg	    }
15460bd37d32Smrg	}
15470bd37d32Smrg	if (result != 0) {
15480bd37d32Smrg	    TRACE(("...result %s\n", result->option));
15490bd37d32Smrg	    /* expand abbreviations */
15500bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
15510bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
15520bd37d32Smrg		    argv[*num] = x_strdup(result->option);
15530bd37d32Smrg		}
15540bd37d32Smrg	    }
15550bd37d32Smrg
15560bd37d32Smrg	    /* adjust (*num) to skip option value */
15570bd37d32Smrg	    (*num) += countArg(result);
15580bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
15590bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
15600bd37d32Smrg		*valuep = argv[*num];
15610bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
15620bd37d32Smrg	    }
15630bd37d32Smrg	}
15640bd37d32Smrg    }
15650bd37d32Smrg#undef ITEM
15660bd37d32Smrg    return result;
1567d522f475Smrg}
1568d522f475Smrg
1569d522f475Smrgstatic void
1570d522f475SmrgSyntax(char *badOption)
1571d522f475Smrg{
1572d522f475Smrg    OptionHelp *opt;
1573d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1574d522f475Smrg    int col;
1575d522f475Smrg
15760bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
15770bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1578d522f475Smrg
1579d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1580956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1581d522f475Smrg    for (opt = list; opt->opt; opt++) {
1582956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1583d522f475Smrg	if (col + len > 79) {
1584d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1585d522f475Smrg	    col = 3;
1586d522f475Smrg	}
1587d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1588d522f475Smrg	col += len;
1589d522f475Smrg    }
1590d522f475Smrg
1591d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1592d522f475Smrg	    ProgramName);
1593d522f475Smrg    exit(1);
1594d522f475Smrg}
1595d522f475Smrg
1596d522f475Smrgstatic void
1597d522f475SmrgVersion(void)
1598d522f475Smrg{
1599d522f475Smrg    printf("%s\n", xtermVersion());
1600d522f475Smrg    fflush(stdout);
1601d522f475Smrg}
1602d522f475Smrg
1603d522f475Smrgstatic void
1604d522f475SmrgHelp(void)
1605d522f475Smrg{
1606d522f475Smrg    OptionHelp *opt;
1607d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
160820d2c4d2Smrg    const char **cpp;
1609d522f475Smrg
1610d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1611d522f475Smrg	   xtermVersion(), ProgramName);
1612d522f475Smrg    printf("where options include:\n");
1613d522f475Smrg    for (opt = list; opt->opt; opt++) {
1614d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1615d522f475Smrg    }
1616d522f475Smrg
1617d522f475Smrg    putchar('\n');
1618d522f475Smrg    for (cpp = message; *cpp; cpp++)
1619d522f475Smrg	puts(*cpp);
1620d522f475Smrg    putchar('\n');
1621d522f475Smrg    fflush(stdout);
1622d522f475Smrg}
1623d522f475Smrg
1624d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1625d522f475Smrg/* ARGSUSED */
1626d522f475Smrgstatic Boolean
1627d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1628894e0ac8Smrg			Atom *selection GCC_UNUSED,
1629894e0ac8Smrg			Atom *target GCC_UNUSED,
1630894e0ac8Smrg			Atom *type GCC_UNUSED,
1631d522f475Smrg			XtPointer *value GCC_UNUSED,
1632d522f475Smrg			unsigned long *length GCC_UNUSED,
1633d522f475Smrg			int *format GCC_UNUSED)
1634d522f475Smrg{
1635d522f475Smrg    /* we don't save console output, so can't offer it */
1636d522f475Smrg    return False;
1637d522f475Smrg}
1638d522f475Smrg#endif /* TIOCCONS */
1639d522f475Smrg
1640d522f475Smrg/*
1641d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1642d522f475Smrg */
1643d522f475Smrg/* ARGSUSED */
1644d522f475Smrgstatic void
1645d522f475SmrgDeleteWindow(Widget w,
1646894e0ac8Smrg	     XEvent *event GCC_UNUSED,
1647e0a2b6dfSmrg	     String *params GCC_UNUSED,
1648d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1649d522f475Smrg{
1650d522f475Smrg#if OPT_TEK4014
1651d522f475Smrg    if (w == toplevel) {
1652d522f475Smrg	if (TEK4014_SHOWN(term))
1653d522f475Smrg	    hide_vt_window();
1654d522f475Smrg	else
1655d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
165620d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1657d522f475Smrg	hide_tek_window();
1658d522f475Smrg    else
1659d522f475Smrg#endif
1660d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1661d522f475Smrg}
1662d522f475Smrg
1663d522f475Smrg/* ARGSUSED */
1664d522f475Smrgstatic void
1665d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1666894e0ac8Smrg		XEvent *event,
1667e0a2b6dfSmrg		String *params GCC_UNUSED,
1668d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1669d522f475Smrg{
1670d522f475Smrg    switch (event->type) {
1671d522f475Smrg    case MappingNotify:
1672d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1673d522f475Smrg	break;
1674d522f475Smrg    }
1675d522f475Smrg}
1676d522f475Smrg
1677d522f475Smrgstatic XtActionsRec actionProcs[] =
1678d522f475Smrg{
1679d522f475Smrg    {"DeleteWindow", DeleteWindow},
1680d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1681d522f475Smrg};
1682d522f475Smrg
1683d522f475Smrg/*
1684d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1685d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1686d522f475Smrg * utmp.
1687d522f475Smrg */
1688d522f475Smrgstatic char *
1689d522f475Smrgmy_pty_name(char *device)
1690d522f475Smrg{
1691d522f475Smrg    size_t len = strlen(device);
1692d522f475Smrg    Bool name = False;
1693d522f475Smrg
1694d522f475Smrg    while (len != 0) {
1695d522f475Smrg	int ch = device[len - 1];
1696d522f475Smrg	if (isdigit(ch)) {
1697d522f475Smrg	    len--;
1698d522f475Smrg	} else if (ch == '/') {
1699d522f475Smrg	    if (name)
1700d522f475Smrg		break;
1701d522f475Smrg	    len--;
1702d522f475Smrg	} else if (isalpha(ch)) {
1703d522f475Smrg	    name = True;
1704d522f475Smrg	    len--;
1705d522f475Smrg	} else {
1706d522f475Smrg	    break;
1707d522f475Smrg	}
1708d522f475Smrg    }
1709d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1710d522f475Smrg    return device + len;
1711d522f475Smrg}
1712d522f475Smrg
1713d522f475Smrg/*
1714d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1715d522f475Smrg * last few characters for a utmp identifier.
1716d522f475Smrg */
1717d522f475Smrgstatic char *
1718d522f475Smrgmy_pty_id(char *device)
1719d522f475Smrg{
1720d522f475Smrg    char *name = my_pty_name(device);
1721d522f475Smrg    char *leaf = x_basename(name);
1722d522f475Smrg
1723d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1724956cc18dSsnj	int len = (int) strlen(leaf);
1725d522f475Smrg	if (PTYCHARLEN < len)
1726d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1727d522f475Smrg    }
1728d522f475Smrg    TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
1729d522f475Smrg    return leaf;
1730d522f475Smrg}
1731d522f475Smrg
1732d522f475Smrg/*
1733d522f475Smrg * Set the tty/pty identifier
1734d522f475Smrg */
1735d522f475Smrgstatic void
1736d522f475Smrgset_pty_id(char *device, char *id)
1737d522f475Smrg{
1738d522f475Smrg    char *name = my_pty_name(device);
1739d522f475Smrg    char *leaf = x_basename(name);
1740d522f475Smrg
1741d522f475Smrg    if (name == leaf) {
1742d522f475Smrg	strcpy(my_pty_id(device), id);
1743d522f475Smrg    } else {
1744d522f475Smrg	strcpy(leaf, id);
1745d522f475Smrg    }
1746d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
1747d522f475Smrg}
1748d522f475Smrg
1749d522f475Smrg/*
1750d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
1751d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
1752d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
1753d522f475Smrg * not, fall-thru to the original logic.
1754d522f475Smrg */
1755d522f475Smrgstatic Bool
1756d522f475SmrgParseSccn(char *option)
1757d522f475Smrg{
1758d522f475Smrg    char *leaf = x_basename(option);
1759d522f475Smrg    Bool code = False;
1760d522f475Smrg
1761d522f475Smrg    if (leaf != option) {
1762d522f475Smrg	if (leaf - option > 0
1763d522f475Smrg	    && isdigit(CharOf(*leaf))
1764d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
1765956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
1766d522f475Smrg	    /*
1767d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
1768d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
1769d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
1770d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
1771d522f475Smrg	     */
1772d522f475Smrg	    strncpy(passedPty, option, len);
1773d522f475Smrg	    passedPty[len] = 0;
1774d522f475Smrg	    code = True;
1775d522f475Smrg	}
1776d522f475Smrg    } else {
1777d522f475Smrg	code = (sscanf(option, "%c%c%d",
1778d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
1779d522f475Smrg    }
1780d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
1781d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
1782d522f475Smrg    return code;
1783d522f475Smrg}
1784d522f475Smrg
1785d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
1786d522f475Smrg/*
1787d522f475Smrg * From "man utmp":
1788d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
1789d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
1790d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
1791d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
1792d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
1793d522f475Smrg * ut_time, ut_user and ut_host as well.
1794d522f475Smrg *
1795d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
1796d522f475Smrg * pty implementation allows more than 3 digits.
1797d522f475Smrg */
1798d522f475Smrgstatic char *
1799d522f475Smrgmy_utmp_id(char *device)
1800d522f475Smrg{
1801d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
1802d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
1803d522f475Smrg    static char result[UTIDSIZE + 1];
1804d522f475Smrg
1805d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
1806d522f475Smrg    /*
1807d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
1808d522f475Smrg     * issues, and can use the available space in ut_id differently from the
1809d522f475Smrg     * default convention.
1810d522f475Smrg     *
1811d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
1812d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
1813d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
1814d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
1815d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
1816d522f475Smrg     * last three digits of the device name, regardless of the format of the
1817d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
1818d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
1819d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
1820d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
1821d522f475Smrg     */
1822d522f475Smrg    int len, n;
1823d522f475Smrg
1824d522f475Smrg    len = strlen(device);
1825d522f475Smrg    n = UTIDSIZE;
1826d522f475Smrg    result[n] = '\0';
1827d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
1828d522f475Smrg	result[--n] = device[--len];
1829d522f475Smrg    while (n > 0)
1830d522f475Smrg	result[--n] = '0';
1831d522f475Smrg    result[0] = 'x';
1832d522f475Smrg#else
1833d522f475Smrg    char *name = my_pty_name(device);
1834d522f475Smrg    char *leaf = x_basename(name);
1835d522f475Smrg    size_t len = strlen(leaf);
1836d522f475Smrg
1837d522f475Smrg    if ((UTIDSIZE - 1) < len)
1838d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
1839d522f475Smrg    sprintf(result, "p%s", leaf);
1840d522f475Smrg#endif
1841d522f475Smrg
1842d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
1843d522f475Smrg    return result;
1844d522f475Smrg}
1845d522f475Smrg#endif /* USE_SYSV_UTMP */
1846d522f475Smrg
1847d522f475Smrg#ifdef USE_POSIX_SIGNALS
1848d522f475Smrg
1849d522f475Smrgtypedef void (*sigfunc) (int);
1850d522f475Smrg
1851d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
1852d522f475Smrg   has just been stopped and not actually killed */
1853d522f475Smrg
1854d522f475Smrgstatic sigfunc
1855d522f475Smrgposix_signal(int signo, sigfunc func)
1856d522f475Smrg{
1857d522f475Smrg    struct sigaction act, oact;
1858d522f475Smrg
1859d522f475Smrg    act.sa_handler = func;
1860d522f475Smrg    sigemptyset(&act.sa_mask);
1861d522f475Smrg#ifdef SA_RESTART
1862d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
1863d522f475Smrg#else
1864d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
1865d522f475Smrg#endif
1866d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
1867d522f475Smrg	return (SIG_ERR);
1868d522f475Smrg    return (oact.sa_handler);
1869d522f475Smrg}
1870d522f475Smrg
18710bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
1872d522f475Smrg
1873d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
1874d522f475Smrgstatic void
1875d522f475SmrgdisableSetUid(void)
1876d522f475Smrg{
1877d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
1878d522f475Smrg    if (setuid(save_ruid) == -1) {
18790bd37d32Smrg	xtermWarning("unable to reset uid\n");
1880d522f475Smrg	exit(1);
1881d522f475Smrg    }
1882d522f475Smrg    TRACE_IDS;
1883d522f475Smrg}
1884d522f475Smrg#else
1885d522f475Smrg#define disableSetUid()		/* nothing */
1886d522f475Smrg#endif /* DISABLE_SETUID */
1887d522f475Smrg
1888d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
1889d522f475Smrgstatic void
1890d522f475SmrgdisableSetGid(void)
1891d522f475Smrg{
1892d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
1893d522f475Smrg    if (setegid(save_rgid) == -1) {
18940bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
1895d522f475Smrg	exit(1);
1896d522f475Smrg    }
1897d522f475Smrg    TRACE_IDS;
1898d522f475Smrg}
1899d522f475Smrg#else
1900d522f475Smrg#define disableSetGid()		/* nothing */
1901d522f475Smrg#endif /* DISABLE_SETGID */
1902d522f475Smrg
1903d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
1904d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
1905d522f475Smrgstatic void
1906d522f475SmrgsetEffectiveGroup(gid_t group)
1907d522f475Smrg{
1908d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
1909d522f475Smrg    if (setegid(group) == -1) {
1910d522f475Smrg#ifdef __MVS__
1911d522f475Smrg	if (!(errno == EMVSERR))	/* could happen if _BPX_SHAREAS=REUSE */
1912d522f475Smrg#endif
1913d522f475Smrg	{
19140bd37d32Smrg	    xtermPerror("setegid(%d)", (int) group);
1915d522f475Smrg	}
1916d522f475Smrg    }
1917d522f475Smrg    TRACE_IDS;
1918d522f475Smrg}
1919d522f475Smrg#endif
1920d522f475Smrg
1921d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
1922d522f475Smrgstatic void
1923d522f475SmrgsetEffectiveUser(uid_t user)
1924d522f475Smrg{
1925d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
1926d522f475Smrg    if (seteuid(user) == -1) {
1927d522f475Smrg#ifdef __MVS__
1928d522f475Smrg	if (!(errno == EMVSERR))
1929d522f475Smrg#endif
1930d522f475Smrg	{
19310bd37d32Smrg	    xtermPerror("seteuid(%d)", (int) user);
1932d522f475Smrg	}
1933d522f475Smrg    }
1934d522f475Smrg    TRACE_IDS;
1935d522f475Smrg}
1936d522f475Smrg#endif
1937d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
1938d522f475Smrg
1939d522f475Smrgint
1940d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
1941d522f475Smrg{
1942a1f3da82Smrg#if OPT_MAXIMIZE
1943a1f3da82Smrg#define DATA(name) { #name, es##name }
1944a1f3da82Smrg    static FlagList tblFullscreen[] =
1945a1f3da82Smrg    {
1946a1f3da82Smrg	DATA(Always),
1947a1f3da82Smrg	DATA(Never)
1948a1f3da82Smrg    };
1949a1f3da82Smrg#undef DATA
1950a1f3da82Smrg#endif
1951a1f3da82Smrg
1952d522f475Smrg    Widget form_top, menu_top;
1953d522f475Smrg    Dimension menu_high;
1954d522f475Smrg    TScreen *screen;
1955d522f475Smrg    int mode;
1956e0a2b6dfSmrg    char *my_class = x_strdup(DEFCLASS);
1957d522f475Smrg    Window winToEmbedInto = None;
1958d522f475Smrg
1959d522f475Smrg    ProgramName = argv[0];
1960d522f475Smrg
1961d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
1962d522f475Smrg    save_euid = geteuid();
1963d522f475Smrg    save_egid = getegid();
1964d522f475Smrg#endif
1965d522f475Smrg
1966d522f475Smrg    save_ruid = getuid();
1967d522f475Smrg    save_rgid = getgid();
1968d522f475Smrg
1969d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
1970d522f475Smrg#if defined(DISABLE_SETUID)
1971d522f475Smrg    disableSetUid();
1972d522f475Smrg#endif
1973d522f475Smrg#if defined(DISABLE_SETGID)
1974d522f475Smrg    disableSetGid();
1975d522f475Smrg#endif
1976d522f475Smrg    TRACE_IDS;
1977d522f475Smrg#endif
1978d522f475Smrg
1979d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
1980d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
1981d522f475Smrg#ifdef USE_PTY_DEVICE
1982d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
1983d522f475Smrg    if (!ttydev || !ptydev)
1984d522f475Smrg#else
1985d522f475Smrg    if (!ttydev)
1986d522f475Smrg#endif
1987d522f475Smrg    {
19880bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
1989d522f475Smrg	exit(1);
1990d522f475Smrg    }
1991d522f475Smrg    strcpy(ttydev, TTYDEV);
1992d522f475Smrg#ifdef USE_PTY_DEVICE
1993d522f475Smrg    strcpy(ptydev, PTYDEV);
1994d522f475Smrg#endif
1995d522f475Smrg
1996d522f475Smrg#if defined(USE_UTMP_SETGID)
1997d522f475Smrg    get_pty(NULL, NULL);
1998d522f475Smrg    disableSetUid();
1999d522f475Smrg    disableSetGid();
2000d522f475Smrg    TRACE_IDS;
2001d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
2002d522f475Smrg#endif
2003d522f475Smrg
2004d522f475Smrg    /* Do these first, since we may not be able to open the display */
2005d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
2006d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
2007d522f475Smrg    if (argc > 1) {
20080bd37d32Smrg	XrmOptionDescRec *option_ptr;
20090bd37d32Smrg	char *option_value;
2010d522f475Smrg	int n;
2011e39b573cSmrg	Bool quit = False;
2012d522f475Smrg
2013d522f475Smrg	for (n = 1; n < argc; n++) {
20140bd37d32Smrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
20150bd37d32Smrg		if (argv[n] == 0) {
20160bd37d32Smrg		    break;
20170bd37d32Smrg		} else if (isOption(argv[n])) {
20180bd37d32Smrg		    Syntax(argv[n]);
20190bd37d32Smrg		} else if (explicit_shname != 0) {
20200bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
20210bd37d32Smrg		    Syntax(argv[n]);
20220bd37d32Smrg		}
20230bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
20240bd37d32Smrg		if (explicit_shname == 0)
20250bd37d32Smrg		    exit(0);
20260bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
20270bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
20280bd37d32Smrg		command_to_exec = (argv + n + 1);
20290bd37d32Smrg		if (!command_to_exec[0])
20300bd37d32Smrg		    Syntax(argv[n]);
20310bd37d32Smrg		break;
20320bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2033d522f475Smrg		Version();
2034e39b573cSmrg		quit = True;
20350bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2036d522f475Smrg		Help();
2037e39b573cSmrg		quit = True;
20380bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
2039e0a2b6dfSmrg		free(my_class);
20400bd37d32Smrg		if ((my_class = x_strdup(option_value)) == 0) {
2041d522f475Smrg		    Help();
2042e39b573cSmrg		    quit = True;
2043d522f475Smrg		}
20440bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
20450bd37d32Smrg		char *endPtr;
20460bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
2047d522f475Smrg	    }
2048d522f475Smrg	}
2049d522f475Smrg	if (quit)
2050d522f475Smrg	    exit(0);
20510bd37d32Smrg	/*
20520bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
20530bd37d32Smrg	 * then give up.
20540bd37d32Smrg	 */
20550bd37d32Smrg	if (n < argc && !command_to_exec) {
20560bd37d32Smrg	    Syntax(argv[n]);
20570bd37d32Smrg	}
2058d522f475Smrg    }
2059d522f475Smrg
20600bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2061d522f475Smrg#if OPT_I18N_SUPPORT
2062d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2063d522f475Smrg#endif
2064d522f475Smrg
2065d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2066d522f475Smrg    /* Initialization is done here rather than above in order
2067d522f475Smrg     * to prevent any assumptions about the order of the contents
2068d522f475Smrg     * of the various terminal structures (which may change from
2069d522f475Smrg     * implementation to implementation).
2070d522f475Smrg     */
2071d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2072d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2073d522f475Smrg#ifdef TAB3
2074d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR | TAB3;
2075d522f475Smrg#else
2076d522f475Smrg#ifdef ONLCR
2077d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR;
2078d522f475Smrg#else
2079d522f475Smrg    d_tio.c_oflag = OPOST;
2080d522f475Smrg#endif
2081d522f475Smrg#endif
2082d522f475Smrg    {
2083d522f475Smrg	Cardinal nn;
2084d522f475Smrg
2085d522f475Smrg	/* fill in default-values */
2086d522f475Smrg	for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2087d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2088d522f475Smrg		d_tio.c_cc[known_ttyChars[nn].sysMode] =
20890bd37d32Smrg		    (cc_t) known_ttyChars[nn].myDefault;
2090d522f475Smrg	    }
2091d522f475Smrg	}
2092d522f475Smrg    }
2093d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
2094d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2095d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2096d522f475Smrg#ifdef ECHOKE
2097d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2098d522f475Smrg#endif
2099d522f475Smrg#ifdef ECHOCTL
2100d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2101d522f475Smrg#endif
2102d522f475Smrg#ifndef USE_TERMIOS		/* { */
2103d522f475Smrg    d_tio.c_line = 0;
2104d522f475Smrg#endif /* } */
2105d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2106d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2107d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2108d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2109d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2110d522f475Smrg    d_ltc.t_werasc = CWERASE;
2111d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2112d522f475Smrg#endif /* } HAS_LTCHARS */
2113d522f475Smrg#ifdef TIOCLSET			/* { */
2114d522f475Smrg    d_lmode = 0;
2115d522f475Smrg#endif /* } TIOCLSET */
2116d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2117d522f475Smrg#ifndef USE_POSIX_TERMIOS
2118d522f475Smrg#ifdef BAUD_0			/* { */
2119d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2120d522f475Smrg#else /* }{ !BAUD_0 */
2121d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2122d522f475Smrg#endif /* } !BAUD_0 */
2123d522f475Smrg#else /* USE_POSIX_TERMIOS */
2124d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2125d522f475Smrg    cfsetispeed(&d_tio, VAL_LINE_SPEED);
2126d522f475Smrg    cfsetospeed(&d_tio, VAL_LINE_SPEED);
2127d522f475Smrg#endif
2128d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2129d522f475Smrg#ifdef ECHOKE
2130d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2131d522f475Smrg#endif
2132d522f475Smrg#ifdef ECHOCTL
2133d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2134d522f475Smrg#endif
2135d522f475Smrg#ifndef USE_POSIX_TERMIOS
2136d522f475Smrg#ifdef NTTYDISC
2137d522f475Smrg    d_tio.c_line = NTTYDISC;
2138d522f475Smrg#else
2139d522f475Smrg    d_tio.c_line = 0;
2140d522f475Smrg#endif
2141d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2142d522f475Smrg#ifdef __sgi
2143d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2144d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2145d522f475Smrg#endif
2146d522f475Smrg#ifdef __MVS__
2147d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2148d522f475Smrg#endif
2149d522f475Smrg    {
2150d522f475Smrg	Cardinal nn;
2151d522f475Smrg	int i;
2152d522f475Smrg
2153d522f475Smrg	/* try to inherit tty settings */
2154d522f475Smrg	for (i = 0; i <= 2; i++) {
2155d522f475Smrg	    TERMIO_STRUCT deftio;
2156d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2157d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2158d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2159d522f475Smrg			d_tio.c_cc[known_ttyChars[nn].sysMode] =
2160d522f475Smrg			    deftio.c_cc[known_ttyChars[nn].sysMode];
2161d522f475Smrg		    }
2162d522f475Smrg		}
2163d522f475Smrg		break;
2164d522f475Smrg	    }
2165d522f475Smrg	}
2166d522f475Smrg    }
2167d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2168d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2169d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2170d522f475Smrg#endif /* } */
2171d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2172d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2173d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2174d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2175d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2176d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2177d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2178d522f475Smrg#endif /* } HAS_LTCHARS */
2179d522f475Smrg
2180d522f475Smrg#ifdef TIOCLSET			/* { */
2181d522f475Smrg    d_lmode = 0;
2182d522f475Smrg#endif /* } TIOCLSET */
2183d522f475Smrg#endif /* } macII, ATT, CRAY */
2184d522f475Smrg#endif /* } TERMIO_STRUCT */
2185d522f475Smrg
2186d522f475Smrg    /* Init the Toolkit. */
2187d522f475Smrg    {
2188d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2189d522f475Smrg	setEffectiveGroup(save_rgid);
2190d522f475Smrg	setEffectiveUser(save_ruid);
2191d522f475Smrg	TRACE_IDS;
2192d522f475Smrg#endif
2193e0a2b6dfSmrg	init_colored_cursor();
2194d522f475Smrg
21950bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
21960bd37d32Smrg					my_class,
21970bd37d32Smrg					optionDescList,
21980bd37d32Smrg					XtNumber(optionDescList),
21990bd37d32Smrg					&argc, (String *) argv,
22000bd37d32Smrg					fallback_resources,
22010bd37d32Smrg					sessionShellWidgetClass,
22020bd37d32Smrg					NULL, 0);
2203d522f475Smrg
2204d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2205d522f475Smrg				  application_resources,
2206d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2207d522f475Smrg	TRACE_XRES();
2208a1f3da82Smrg#if OPT_MAXIMIZE
2209a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2210a1f3da82Smrg					      tblFullscreen,
2211a1f3da82Smrg					      XtNumber(tblFullscreen));
2212a1f3da82Smrg#endif
2213e39b573cSmrg	VTInitTranslations();
2214d522f475Smrg#if OPT_PTY_HANDSHAKE
2215d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2216d522f475Smrg#endif
2217d522f475Smrg
2218d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2219d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2220d522f475Smrg#if !defined(DISABLE_SETUID)
2221d522f475Smrg	setEffectiveUser(save_euid);
2222d522f475Smrg#endif
2223d522f475Smrg#if !defined(DISABLE_SETGID)
2224d522f475Smrg	setEffectiveGroup(save_egid);
2225d522f475Smrg#endif
2226d522f475Smrg	TRACE_IDS;
2227d522f475Smrg#endif
2228d522f475Smrg#endif
2229d522f475Smrg    }
2230d522f475Smrg
2231d522f475Smrg    /*
2232d522f475Smrg     * ICCCM delete_window.
2233d522f475Smrg     */
2234d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2235d522f475Smrg
2236d522f475Smrg    /*
2237d522f475Smrg     * fill in terminal modes
2238d522f475Smrg     */
2239d522f475Smrg    if (resource.tty_modes) {
2240d522f475Smrg	int n = parse_tty_modes(resource.tty_modes, ttymodelist);
2241d522f475Smrg	if (n < 0) {
22420bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2243d522f475Smrg	} else if (n > 0) {
2244d522f475Smrg	    override_tty_modes = True;
2245d522f475Smrg	}
2246d522f475Smrg    }
22470bd37d32Smrg    initZIconBeep();
2248d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2249d522f475Smrg    if (resource.icon_geometry != NULL) {
2250d522f475Smrg	int scr, junk;
2251d522f475Smrg	int ix, iy;
2252d522f475Smrg	Arg args[2];
2253d522f475Smrg
2254d522f475Smrg	for (scr = 0;		/* yyuucchh */
2255d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2256d522f475Smrg	     scr++) ;
2257d522f475Smrg
2258d522f475Smrg	args[0].name = XtNiconX;
2259d522f475Smrg	args[1].name = XtNiconY;
2260d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2261d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2262d522f475Smrg	args[0].value = (XtArgVal) ix;
2263d522f475Smrg	args[1].value = (XtArgVal) iy;
2264d522f475Smrg	XtSetValues(toplevel, args, 2);
2265d522f475Smrg    }
2266d522f475Smrg
2267d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2268d522f475Smrg		number_ourTopLevelShellArgs);
2269d522f475Smrg
2270d522f475Smrg#if OPT_WIDE_CHARS
2271d522f475Smrg    /* seems as good a place as any */
2272d522f475Smrg    init_classtab();
2273d522f475Smrg#endif
2274d522f475Smrg
2275d522f475Smrg    /* Parse the rest of the command line */
2276d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2277d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
22780bd37d32Smrg	if (!isOption(*argv)) {
2279d522f475Smrg#ifdef VMS
2280d522f475Smrg	    Syntax(*argv);
2281d522f475Smrg#else
2282d522f475Smrg	    if (argc > 1)
2283d522f475Smrg		Syntax(*argv);
2284d522f475Smrg	    continue;
2285d522f475Smrg#endif
22860bd37d32Smrg	}
2287d522f475Smrg
2288d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2289d522f475Smrg	switch (argv[0][1]) {
2290d522f475Smrg	case 'C':
2291d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2292d522f475Smrg#ifndef __sgi
2293d522f475Smrg	    {
2294d522f475Smrg		struct stat sbuf;
2295d522f475Smrg
2296d522f475Smrg		/* Must be owner and have read/write permission.
2297d522f475Smrg		   xdm cooperates to give the console the right user. */
2298d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2299d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2300d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2301d522f475Smrg		    Console = True;
2302d522f475Smrg		} else
2303d522f475Smrg		    Console = False;
2304d522f475Smrg	    }
2305d522f475Smrg#else /* __sgi */
2306d522f475Smrg	    Console = True;
2307d522f475Smrg#endif /* __sgi */
2308d522f475Smrg#endif /* TIOCCONS */
2309d522f475Smrg	    continue;
2310d522f475Smrg	case 'S':
2311d522f475Smrg	    if (!ParseSccn(*argv + 2))
2312d522f475Smrg		Syntax(*argv);
2313d522f475Smrg	    continue;
2314d522f475Smrg#ifdef DEBUG
2315d522f475Smrg	case 'D':
2316d522f475Smrg	    debug = True;
2317d522f475Smrg	    continue;
2318d522f475Smrg#endif /* DEBUG */
23190bd37d32Smrg	case 'c':
23200bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2321d522f475Smrg		Syntax(*argv);
23220bd37d32Smrg	    argc--, argv++;
2323d522f475Smrg	    continue;
2324d522f475Smrg	case 'e':
23250bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2326d522f475Smrg		Syntax(*argv);
23270bd37d32Smrg	    command_to_exec = (argv + 1);
2328d522f475Smrg	    break;
2329d522f475Smrg	case 'i':
23300bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2331d522f475Smrg		Syntax(*argv);
23320bd37d32Smrg	    argc--, argv++;
2333d522f475Smrg	    continue;
2334d522f475Smrg
2335d522f475Smrg	default:
2336d522f475Smrg	    Syntax(*argv);
2337d522f475Smrg	}
2338d522f475Smrg	break;
2339d522f475Smrg    }
2340d522f475Smrg
2341d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2342d522f475Smrg
2343d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2344d522f475Smrg						 form_top,
2345d522f475Smrg#if OPT_TOOLBAR
2346d522f475Smrg						 XtNmenuBar, menu_top,
2347d522f475Smrg						 XtNresizable, True,
2348d522f475Smrg						 XtNfromVert, menu_top,
2349d522f475Smrg						 XtNleft, XawChainLeft,
2350d522f475Smrg						 XtNright, XawChainRight,
2351d522f475Smrg						 XtNtop, XawChainTop,
2352d522f475Smrg						 XtNbottom, XawChainBottom,
2353d522f475Smrg						 XtNmenuHeight, menu_high,
2354d522f475Smrg#endif
2355d522f475Smrg						 (XtPointer) 0);
2356d522f475Smrg    decode_keyboard_type(term, &resource);
2357d522f475Smrg
2358d522f475Smrg    screen = TScreenOf(term);
2359d522f475Smrg    screen->inhibit = 0;
2360d522f475Smrg
2361d522f475Smrg#ifdef ALLOWLOGGING
2362d522f475Smrg    if (term->misc.logInhibit)
2363d522f475Smrg	screen->inhibit |= I_LOG;
2364d522f475Smrg#endif
2365d522f475Smrg    if (term->misc.signalInhibit)
2366d522f475Smrg	screen->inhibit |= I_SIGNAL;
2367d522f475Smrg#if OPT_TEK4014
2368d522f475Smrg    if (term->misc.tekInhibit)
2369d522f475Smrg	screen->inhibit |= I_TEK;
2370d522f475Smrg#endif
2371d522f475Smrg
2372d522f475Smrg    /*
2373d522f475Smrg     * We might start by showing the tek4014 window.
2374d522f475Smrg     */
2375d522f475Smrg#if OPT_TEK4014
2376d522f475Smrg    if (screen->inhibit & I_TEK)
2377d522f475Smrg	TEK4014_ACTIVE(term) = False;
2378d522f475Smrg
2379d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2380d522f475Smrg	SysError(ERROR_INIT);
2381d522f475Smrg#endif
2382d522f475Smrg
2383d522f475Smrg    /*
2384d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2385d522f475Smrg     */
2386d522f475Smrg#if OPT_TOOLBAR
2387d522f475Smrg    ShowToolbar(resource.toolBar);
2388d522f475Smrg#endif
2389d522f475Smrg
23900bd37d32Smrg    xtermOpenSession();
2391d522f475Smrg
2392d522f475Smrg    /*
2393d522f475Smrg     * Set title and icon name if not specified
2394d522f475Smrg     */
2395d522f475Smrg    if (command_to_exec) {
2396d522f475Smrg	Arg args[2];
2397d522f475Smrg
2398d522f475Smrg	if (!resource.title) {
2399d522f475Smrg	    if (command_to_exec) {
2400d522f475Smrg		resource.title = x_basename(command_to_exec[0]);
2401d522f475Smrg	    }			/* else not reached */
2402d522f475Smrg	}
2403d522f475Smrg
2404d522f475Smrg	if (!resource.icon_name)
2405d522f475Smrg	    resource.icon_name = resource.title;
2406d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2407d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2408d522f475Smrg
24090bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2410d522f475Smrg	       resource.title,
2411d522f475Smrg	       resource.icon_name,
24120bd37d32Smrg	       NonNull(resource.icon_hint),
2413d522f475Smrg	       *command_to_exec));
2414d522f475Smrg
2415d522f475Smrg	XtSetValues(toplevel, args, 2);
2416d522f475Smrg    }
2417d522f475Smrg#if OPT_LUIT_PROG
2418d522f475Smrg    if (term->misc.callfilter) {
24190bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
24200bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
24210bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
24220bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
24230bd37d32Smrg
24240bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
24250bd37d32Smrg						  (count_split
24260bd37d32Smrg						   + count_exec
24270bd37d32Smrg						   + count_using
24280bd37d32Smrg						   + 8));
24290bd37d32Smrg	if (command_to_exec_with_luit == NULL)
24300bd37d32Smrg	    SysError(ERROR_LUMALLOC);
24310bd37d32Smrg
24320bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
24330bd37d32Smrg	if (count_using) {
24340bd37d32Smrg	    char *encoding_opt[4];
24350bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
24360bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
24370bd37d32Smrg	    encoding_opt[2] = 0;
24380bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
24390bd37d32Smrg	}
24400bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
24410bd37d32Smrg	if (count_exec) {
24420bd37d32Smrg	    char *delimiter[2];
24430bd37d32Smrg	    delimiter[0] = x_strdup("--");
24440bd37d32Smrg	    delimiter[1] = 0;
24450bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
24460bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2447d522f475Smrg	}
24480bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
24490bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2450d522f475Smrg    }
2451d522f475Smrg#endif
2452d522f475Smrg
24530bd37d32Smrg    if_DEBUG({
2454d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2455d522f475Smrg	   done securely by a privileged xterm process (although we try),
2456d522f475Smrg	   so the debug feature is disabled by default. */
2457e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2458d522f475Smrg	int i = -1;
24590bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
24600bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
24610bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2462d522f475Smrg	}
2463d522f475Smrg	if (i >= 0) {
2464d522f475Smrg	    dup2(i, 2);
2465d522f475Smrg
2466d522f475Smrg	    /* mark this file as close on exec */
2467d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2468d522f475Smrg	}
24690bd37d32Smrg    });
2470d522f475Smrg
2471d522f475Smrg    spawnXTerm(term);
2472d522f475Smrg
2473d522f475Smrg#ifndef VMS
2474d522f475Smrg    /* Child process is out there, let's catch its termination */
2475d522f475Smrg
2476d522f475Smrg#ifdef USE_POSIX_SIGNALS
2477d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2478d522f475Smrg#else
2479d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2480d522f475Smrg#endif
2481d522f475Smrg    /* Realize procs have now been executed */
2482d522f475Smrg
2483d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2484d522f475Smrg	char buf[80];
2485d522f475Smrg
2486d522f475Smrg	buf[0] = '\0';
2487d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
248820d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2489d522f475Smrg    }
2490d522f475Smrg#ifdef AIXV3
2491d522f475Smrg#if (OSMAJORVERSION < 4)
2492d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2493d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2494d522f475Smrg     * to the slave-pty process when xterm exits.
2495d522f475Smrg     */
2496d522f475Smrg
2497d522f475Smrg    {
2498d522f475Smrg	TERMIO_STRUCT tio;
2499d522f475Smrg
2500d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
2501d522f475Smrg	    SysError(ERROR_TIOCGETP);
2502d522f475Smrg
2503d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
2504d522f475Smrg
2505d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
2506d522f475Smrg	    SysError(ERROR_TIOCSETP);
2507d522f475Smrg    }
2508d522f475Smrg#endif
2509d522f475Smrg#endif
2510d522f475Smrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__)
2511d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
2512d522f475Smrg	SysError(ERROR_F_GETFL);
2513d522f475Smrg#ifdef O_NDELAY
2514d522f475Smrg    mode |= O_NDELAY;
2515d522f475Smrg#else
2516d522f475Smrg    mode |= O_NONBLOCK;
2517d522f475Smrg#endif /* O_NDELAY */
2518d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
2519d522f475Smrg	SysError(ERROR_F_SETFL);
2520d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
2521d522f475Smrg    mode = 1;
2522d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
2523d522f475Smrg	SysError(ERROR_FIONBIO);
2524d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
2525d522f475Smrg
2526d522f475Smrg    /* The erase character is used to delete the current completion */
2527d522f475Smrg#if OPT_DABBREV
2528d522f475Smrg#ifdef TERMIO_STRUCT
2529d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
2530d522f475Smrg#else
2531d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
2532d522f475Smrg#endif
2533d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
2534d522f475Smrg#endif
2535d522f475Smrg
2536d522f475Smrg    FD_ZERO(&pty_mask);
2537d522f475Smrg    FD_ZERO(&X_mask);
2538d522f475Smrg    FD_ZERO(&Select_mask);
2539d522f475Smrg    FD_SET(screen->respond, &pty_mask);
2540d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
2541d522f475Smrg    FD_SET(screen->respond, &Select_mask);
2542d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
2543d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
2544d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
2545d522f475Smrg		 : (1 + screen->respond));
2546d522f475Smrg
2547d522f475Smrg#endif /* !VMS */
25480bd37d32Smrg    if_DEBUG({
25490bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
25500bd37d32Smrg    });
2551d522f475Smrg    XSetErrorHandler(xerror);
2552d522f475Smrg    XSetIOErrorHandler(xioerror);
2553e39b573cSmrg    IceSetIOErrorHandler(ice_error);
2554d522f475Smrg
2555d522f475Smrg    initPtyData(&VTbuffer);
2556d522f475Smrg#ifdef ALLOWLOGGING
2557d522f475Smrg    if (term->misc.log_on) {
255820d2c4d2Smrg	StartLog(term);
2559d522f475Smrg    }
2560d522f475Smrg#endif
2561d522f475Smrg
25620bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
2563d522f475Smrg#if OPT_COLOR_RES
2564a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
2565a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
256620d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
256720d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2568d522f475Smrg
2569a1f3da82Smrg    if (term->misc.re_verse0) {
2570a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
2571a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
2572a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
2573a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
2574a1f3da82Smrg	} else {
2575a1f3da82Smrg	    ReverseVideo(term);
2576a1f3da82Smrg	}
2577a1f3da82Smrg	term->misc.re_verse = True;
2578a1f3da82Smrg	update_reversevideo();
2579a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
2580a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
2581a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
2582a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2583a1f3da82Smrg    }
2584d522f475Smrg#endif /* OPT_COLOR_RES */
2585d522f475Smrg
2586956cc18dSsnj#if OPT_MAXIMIZE
2587956cc18dSsnj    if (resource.maximized)
2588956cc18dSsnj	RequestMaximize(term, True);
2589956cc18dSsnj#endif
2590d522f475Smrg    for (;;) {
2591d522f475Smrg#if OPT_TEK4014
2592d522f475Smrg	if (TEK4014_ACTIVE(term))
2593d522f475Smrg	    TekRun();
2594d522f475Smrg	else
2595d522f475Smrg#endif
2596956cc18dSsnj	    VTRun(term);
2597d522f475Smrg    }
2598d522f475Smrg}
2599d522f475Smrg
2600956cc18dSsnj#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2601d522f475Smrg#define USE_OPENPTY 1
2602d522f475Smrgstatic int opened_tty = -1;
2603d522f475Smrg#endif
2604d522f475Smrg
2605d522f475Smrg/*
2606d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
2607d522f475Smrg *
2608d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
2609d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
2610d522f475Smrg * so that if a pty master is found and later, we find that the slave
2611d522f475Smrg * has problems, we can re-enter this function and get another one.
2612d522f475Smrg */
2613d522f475Smrgstatic int
2614d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
2615d522f475Smrg{
2616d522f475Smrg    int result = 1;
2617d522f475Smrg
26180bd37d32Smrg#if defined(USE_OPENPTY)
26190bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
26200bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
26210bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
26220bd37d32Smrg	char *name = ptsname(*pty);
26230bd37d32Smrg	if (name != 0) {
26240bd37d32Smrg	    strcpy(ttydev, name);
26250bd37d32Smrg	    result = 0;
26260bd37d32Smrg	}
26270bd37d32Smrg    }
26280bd37d32Smrg#ifdef USE_PTY_SEARCH
26290bd37d32Smrg    if (result) {
26300bd37d32Smrg	result = pty_search(pty);
26310bd37d32Smrg    }
26320bd37d32Smrg#endif
26330bd37d32Smrg#elif defined(PUCC_PTYD)
2634d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
2635d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
2636d522f475Smrg			       save_ruid, from)) < 0);
2637d522f475Smrg#elif defined(__QNXNTO__)
2638d522f475Smrg    result = pty_search(pty);
2639d522f475Smrg#else
2640d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
2641d522f475Smrg#ifdef __GLIBC__		/* if __GLIBC__ and USE_USG_PTYS, we know glibc >= 2.1 */
2642d522f475Smrg    /* GNU libc 2 allows us to abstract away from having to know the
2643d522f475Smrg       master pty device name. */
2644d522f475Smrg    if ((*pty = getpt()) >= 0) {
2645d522f475Smrg	char *name = ptsname(*pty);
2646d522f475Smrg	if (name != 0) {	/* if filesystem is trashed, this may be null */
2647d522f475Smrg	    strcpy(ttydev, name);
2648d522f475Smrg	    result = 0;
2649d522f475Smrg	}
2650d522f475Smrg    }
2651d522f475Smrg#elif defined(__MVS__)
2652d522f475Smrg    result = pty_search(pty);
2653d522f475Smrg#else
26540bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
2655d522f475Smrg#endif
26560bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
26570bd37d32Smrg    if (!result)
26580bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
2659d522f475Smrg#endif
2660d522f475Smrg
2661d522f475Smrg#elif defined(AIXV3)
2662d522f475Smrg
2663d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
2664d522f475Smrg	strcpy(ttydev, ttyname(*pty));
2665d522f475Smrg	result = 0;
2666d522f475Smrg    }
2667d522f475Smrg#elif defined(__convex__)
2668d522f475Smrg
2669d522f475Smrg    char *pty_name;
2670d522f475Smrg    extern char *getpty(void);
2671d522f475Smrg
2672d522f475Smrg    while ((pty_name = getpty()) != NULL) {
2673d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
2674d522f475Smrg	    strcpy(ptydev, pty_name);
2675d522f475Smrg	    strcpy(ttydev, pty_name);
2676d522f475Smrg	    *x_basename(ttydev) = 't';
2677d522f475Smrg	    result = 0;
2678d522f475Smrg	    break;
2679d522f475Smrg	}
2680d522f475Smrg    }
2681d522f475Smrg
2682d522f475Smrg#elif defined(sequent)
2683d522f475Smrg
2684d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
2685d522f475Smrg
2686d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
2687d522f475Smrg
2688d522f475Smrg    char *tty_name;
2689d522f475Smrg
2690d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
2691d522f475Smrg    if (tty_name != 0) {
2692d522f475Smrg	strcpy(ttydev, tty_name);
2693d522f475Smrg	result = 0;
2694d522f475Smrg    }
2695d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
2696d522f475Smrg
2697d522f475Smrg    struct stat fstat_buf;
2698d522f475Smrg
2699d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
2700d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
2701d522f475Smrg	result = 0;
2702d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
2703d522f475Smrg    }
2704d522f475Smrg#elif defined(__hpux)
2705d522f475Smrg
2706d522f475Smrg    /*
2707d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
2708d522f475Smrg     */
2709d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
2710d522f475Smrg	char *name = ptsname(*pty);
2711d522f475Smrg	if (name != 0) {
2712d522f475Smrg	    strcpy(ttydev, name);
2713d522f475Smrg	    result = 0;
2714d522f475Smrg	} else {		/* permissions, or other unexpected problem */
2715d522f475Smrg	    close(*pty);
2716d522f475Smrg	    *pty = -1;
2717d522f475Smrg	    result = pty_search(pty);
2718d522f475Smrg	}
2719d522f475Smrg    } else {
2720d522f475Smrg	result = pty_search(pty);
2721d522f475Smrg    }
2722d522f475Smrg
2723d522f475Smrg#else
2724d522f475Smrg
2725d522f475Smrg    result = pty_search(pty);
2726d522f475Smrg
2727d522f475Smrg#endif
2728d522f475Smrg#endif
2729d522f475Smrg
2730d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
2731d522f475Smrg	   ttydev != 0 ? ttydev : "?",
2732d522f475Smrg	   ptydev != 0 ? ptydev : "?",
2733d522f475Smrg	   result ? "FAIL" : "OK",
2734d522f475Smrg	   pty != 0 ? *pty : -1));
2735d522f475Smrg    return result;
2736d522f475Smrg}
2737d522f475Smrg
2738d522f475Smrgstatic void
2739e0a2b6dfSmrgset_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
2740d522f475Smrg{
2741d522f475Smrg#ifdef USE_TTY_GROUP
2742d522f475Smrg    struct group *ttygrp;
2743d522f475Smrg
2744d522f475Smrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
2745d522f475Smrg	gid = ttygrp->gr_gid;
2746d522f475Smrg	mode &= 0660U;
2747d522f475Smrg    }
2748d522f475Smrg    endgrent();
2749d522f475Smrg#endif /* USE_TTY_GROUP */
2750d522f475Smrg
2751d522f475Smrg    TRACE_IDS;
2752d522f475Smrg    set_owner(ttydev, uid, gid, mode);
2753d522f475Smrg}
2754d522f475Smrg
2755d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
2756d522f475Smrg#undef get_pty
2757d522f475Smrg/*
2758d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
2759d522f475Smrg * result.
2760d522f475Smrg */
2761d522f475Smrgstatic int
2762d522f475Smrgget_pty(int *pty, char *from)
2763d522f475Smrg{
2764d522f475Smrg    static int m_pty = -1;
2765d522f475Smrg    int result = -1;
2766d522f475Smrg
2767d522f475Smrg    if (pty == NULL) {
2768d522f475Smrg	result = really_get_pty(&m_pty, from);
2769d522f475Smrg
2770d522f475Smrg	seteuid(0);
2771d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
2772d522f475Smrg	seteuid(save_ruid);
2773d522f475Smrg	TRACE_IDS;
2774d522f475Smrg
2775d522f475Smrg#ifdef USE_OPENPTY
2776d522f475Smrg	if (opened_tty >= 0) {
2777d522f475Smrg	    close(opened_tty);
2778d522f475Smrg	    opened_tty = -1;
2779d522f475Smrg	}
2780d522f475Smrg#endif
2781d522f475Smrg    } else if (m_pty != -1) {
2782d522f475Smrg	*pty = m_pty;
2783d522f475Smrg	result = 0;
2784d522f475Smrg    } else {
2785d522f475Smrg	result = -1;
2786d522f475Smrg    }
27870bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
27880bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
27890bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
27900bd37d32Smrg	   result ? "FAIL" : "OK",
27910bd37d32Smrg	   pty != 0 ? *pty : -1));
2792d522f475Smrg    return result;
2793d522f475Smrg}
2794d522f475Smrg#endif
2795d522f475Smrg
2796d522f475Smrg/*
2797d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
2798d522f475Smrg * we might allocate.  Used on those systems that do not have
2799d522f475Smrg * a functional interface for allocating a pty.
2800d522f475Smrg * Returns 0 if found a pty, 1 if fails.
2801d522f475Smrg */
2802d522f475Smrg#ifdef USE_PTY_SEARCH
2803d522f475Smrgstatic int
2804d522f475Smrgpty_search(int *pty)
2805d522f475Smrg{
2806d522f475Smrg    static int devindex = 0, letter = 0;
2807d522f475Smrg
2808d522f475Smrg#if defined(CRAY) || defined(__MVS__)
2809d522f475Smrg    while (devindex < MAXPTTYS) {
2810d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
2811d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
2812d522f475Smrg	devindex++;
2813d522f475Smrg
2814d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2815d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2816d522f475Smrg	    return 0;
2817d522f475Smrg	}
2818d522f475Smrg    }
2819d522f475Smrg#else /* CRAY || __MVS__ */
2820d522f475Smrg    while (PTYCHAR1[letter]) {
2821d522f475Smrg	ttydev[strlen(ttydev) - 2] =
2822d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
2823d522f475Smrg
2824d522f475Smrg	while (PTYCHAR2[devindex]) {
2825d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
2826d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
2827d522f475Smrg	    devindex++;
2828d522f475Smrg
2829d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2830d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2831d522f475Smrg#ifdef sun
2832d522f475Smrg		/* Need to check the process group of the pty.
2833d522f475Smrg		 * If it exists, then the slave pty is in use,
2834d522f475Smrg		 * and we need to get another one.
2835d522f475Smrg		 */
2836d522f475Smrg		int pgrp_rtn;
2837d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
2838d522f475Smrg		    close(*pty);
2839d522f475Smrg		    continue;
2840d522f475Smrg		}
2841d522f475Smrg#endif /* sun */
2842d522f475Smrg		return 0;
2843d522f475Smrg	    }
2844d522f475Smrg	}
2845d522f475Smrg	devindex = 0;
2846d522f475Smrg	letter++;
2847d522f475Smrg    }
2848d522f475Smrg#endif /* CRAY else */
2849d522f475Smrg    /*
2850d522f475Smrg     * We were unable to allocate a pty master!  Return an error
2851d522f475Smrg     * condition and let our caller terminate cleanly.
2852d522f475Smrg     */
2853d522f475Smrg    return 1;
2854d522f475Smrg}
2855d522f475Smrg#endif /* USE_PTY_SEARCH */
2856d522f475Smrg
2857d522f475Smrg/*
2858d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
2859d522f475Smrg * the latter has support for switching character sets.  We support the
2860d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
2861d522f475Smrg * choose 4014 over 4015.
2862d522f475Smrg *
2863d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
2864d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
2865d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
2866d522f475Smrg * later Tektronix terminals), and 4 character sizes.
2867d522f475Smrg * All of these are supported by xterm.
2868d522f475Smrg */
2869d522f475Smrg
2870d522f475Smrg#if OPT_TEK4014
287120d2c4d2Smrgstatic const char *tekterm[] =
2872d522f475Smrg{
2873d522f475Smrg    "tek4014",
2874d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
2875d522f475Smrg    "tek4012",			/* 4010 with lower case */
2876d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
2877d522f475Smrg    "tek4010",			/* small screen, upper-case only */
2878d522f475Smrg    "dumb",
2879d522f475Smrg    0
2880d522f475Smrg};
2881d522f475Smrg#endif
2882d522f475Smrg
2883d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
2884d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
2885d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
2886d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
2887d522f475Smrg * The VT420 has up to 48 lines on the screen.
2888d522f475Smrg */
2889d522f475Smrg
289020d2c4d2Smrgstatic const char *vtterm[] =
2891d522f475Smrg{
2892d522f475Smrg#ifdef USE_X11TERM
2893d522f475Smrg    "x11term",			/* for people who want special term name */
2894d522f475Smrg#endif
2895d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
2896d522f475Smrg    "xterm",			/* the prefered name, should be fastest */
2897d522f475Smrg    "vt102",
2898d522f475Smrg    "vt100",
2899d522f475Smrg    "ansi",
2900d522f475Smrg    "dumb",
2901d522f475Smrg    0
2902d522f475Smrg};
2903d522f475Smrg
2904d522f475Smrg/* ARGSUSED */
29050bd37d32Smrgstatic void
2906d522f475Smrghungtty(int i GCC_UNUSED)
2907d522f475Smrg{
29080bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
2909d522f475Smrg    siglongjmp(env, 1);
2910d522f475Smrg}
2911d522f475Smrg
2912d522f475Smrg#if OPT_PTY_HANDSHAKE
2913d522f475Smrg#define NO_FDS {-1, -1}
2914d522f475Smrg
2915d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
2916d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
2917d522f475Smrg
2918d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
2919d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
2920d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
2921d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
2922d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
2923d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
2924d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
2925d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
2926d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
2927d522f475Smrg} status_t;
2928d522f475Smrg
2929d522f475Smrgtypedef struct {
2930d522f475Smrg    status_t status;
2931d522f475Smrg    int error;
2932d522f475Smrg    int fatal_error;
2933d522f475Smrg    int tty_slot;
2934d522f475Smrg    int rows;
2935d522f475Smrg    int cols;
2936d522f475Smrg    char buffer[1024];
2937d522f475Smrg} handshake_t;
2938d522f475Smrg
2939d522f475Smrg#if OPT_TRACE
2940d522f475Smrgstatic void
2941d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
2942d522f475Smrg{
2943d522f475Smrg    const char *status = "?";
2944d522f475Smrg    switch (data->status) {
2945d522f475Smrg    case PTY_BAD:
2946d522f475Smrg	status = "PTY_BAD";
2947d522f475Smrg	break;
2948d522f475Smrg    case PTY_FATALERROR:
2949d522f475Smrg	status = "PTY_FATALERROR";
2950d522f475Smrg	break;
2951d522f475Smrg    case PTY_GOOD:
2952d522f475Smrg	status = "PTY_GOOD";
2953d522f475Smrg	break;
2954d522f475Smrg    case PTY_NEW:
2955d522f475Smrg	status = "PTY_NEW";
2956d522f475Smrg	break;
2957d522f475Smrg    case PTY_NOMORE:
2958d522f475Smrg	status = "PTY_NOMORE";
2959d522f475Smrg	break;
2960d522f475Smrg    case UTMP_ADDED:
2961d522f475Smrg	status = "UTMP_ADDED";
2962d522f475Smrg	break;
2963d522f475Smrg    case UTMP_TTYSLOT:
2964d522f475Smrg	status = "UTMP_TTYSLOT";
2965d522f475Smrg	break;
2966d522f475Smrg    case PTY_EXEC:
2967d522f475Smrg	status = "PTY_EXEC";
2968d522f475Smrg	break;
2969d522f475Smrg    }
2970d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
2971d522f475Smrg	   tag,
2972d522f475Smrg	   status,
2973d522f475Smrg	   data->error,
2974d522f475Smrg	   data->fatal_error,
2975d522f475Smrg	   data->buffer));
2976d522f475Smrg}
2977d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
2978d522f475Smrg#else
2979d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
2980d522f475Smrg#endif
2981d522f475Smrg
2982d522f475Smrg/* HsSysError()
2983d522f475Smrg *
2984d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
2985d522f475Smrg * over the errno and error exit to the master process so that it can
2986d522f475Smrg * display our error message and exit with our exit code so that the
2987d522f475Smrg * user can see it.
2988d522f475Smrg */
2989d522f475Smrg
2990d522f475Smrgstatic void
2991d522f475SmrgHsSysError(int error)
2992d522f475Smrg{
2993d522f475Smrg    handshake_t handshake;
2994d522f475Smrg
2995d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
2996d522f475Smrg    handshake.status = PTY_FATALERROR;
2997d522f475Smrg    handshake.error = errno;
2998d522f475Smrg    handshake.fatal_error = error;
29990bd37d32Smrg    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
3000d522f475Smrg
3001d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
3002d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
3003d522f475Smrg	       handshake.error,
3004d522f475Smrg	       handshake.fatal_error,
3005d522f475Smrg	       handshake.buffer));
3006d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
300720d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
300820d2c4d2Smrg			(const char *) &handshake,
300920d2c4d2Smrg			sizeof(handshake)));
3010d522f475Smrg    } else {
30110bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
30120bd37d32Smrg		     handshake.error,
30130bd37d32Smrg		     handshake.fatal_error,
30140bd37d32Smrg		     handshake.buffer);
3015d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3016d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3017d522f475Smrg    }
3018d522f475Smrg    exit(error);
3019d522f475Smrg}
3020d522f475Smrg
3021d522f475Smrgvoid
3022d522f475Smrgfirst_map_occurred(void)
3023d522f475Smrg{
3024d522f475Smrg    if (resource.wait_for_map) {
3025d522f475Smrg	handshake_t handshake;
3026d522f475Smrg	TScreen *screen = TScreenOf(term);
3027d522f475Smrg
3028d522f475Smrg	memset(&handshake, 0, sizeof(handshake));
3029d522f475Smrg	handshake.status = PTY_EXEC;
3030d522f475Smrg	handshake.rows = screen->max_row;
3031d522f475Smrg	handshake.cols = screen->max_col;
3032d522f475Smrg
3033d522f475Smrg	if (pc_pipe[1] >= 0) {
3034d522f475Smrg	    TRACE(("first_map_occurred: %dx%d\n", handshake.rows, handshake.cols));
3035d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
303620d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
303720d2c4d2Smrg			    (const char *) &handshake,
303820d2c4d2Smrg			    sizeof(handshake)));
3039d522f475Smrg	    close(cp_pipe[0]);
3040d522f475Smrg	    close(pc_pipe[1]);
3041d522f475Smrg	}
3042d522f475Smrg	resource.wait_for_map = False;
3043d522f475Smrg    }
3044d522f475Smrg}
3045d522f475Smrg#else
3046d522f475Smrg/*
3047d522f475Smrg * temporary hack to get xterm working on att ptys
3048d522f475Smrg */
3049d522f475Smrgstatic void
3050d522f475SmrgHsSysError(int error)
3051d522f475Smrg{
30520bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
30530bd37d32Smrg		 error, errno, ttydev);
3054d522f475Smrg    exit(error);
3055d522f475Smrg}
3056d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3057d522f475Smrg
3058d522f475Smrg#ifndef VMS
3059d522f475Smrgstatic void
3060e0a2b6dfSmrgset_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
3061d522f475Smrg{
3062d522f475Smrg    int why;
3063d522f475Smrg
3064d522f475Smrg    TRACE_IDS;
306520d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
30660bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3067d522f475Smrg
3068d522f475Smrg    if (chown(device, uid, gid) < 0) {
3069d522f475Smrg	why = errno;
3070d522f475Smrg	if (why != ENOENT
3071d522f475Smrg	    && save_ruid == 0) {
30720bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
30730bd37d32Smrg			device, (long) uid, (long) gid);
3074d522f475Smrg	}
3075d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3076e39b573cSmrg    } else if (chmod(device, mode) < 0) {
3077d522f475Smrg	why = errno;
3078d522f475Smrg	if (why != ENOENT) {
3079d522f475Smrg	    struct stat sb;
3080d522f475Smrg	    if (stat(device, &sb) < 0) {
30810bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
30820bd37d32Smrg			    device, (unsigned) mode);
3083d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
30840bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
30850bd37d32Smrg			    device,
30860bd37d32Smrg			    (unsigned long) mode,
30870bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3088d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
30890bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3090d522f475Smrg	    }
3091d522f475Smrg	}
3092d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3093d522f475Smrg    }
3094d522f475Smrg}
3095d522f475Smrg
3096894e0ac8Smrg/*
3097894e0ac8Smrg * utmp data may not be null-terminated; even if it is, there may be garbage
3098894e0ac8Smrg * after the null.  This fills the unused part of the result with nulls.
3099894e0ac8Smrg */
3100894e0ac8Smrgstatic void
3101894e0ac8Smrgcopy_filled(char *target, const char *source, size_t len)
3102894e0ac8Smrg{
3103894e0ac8Smrg    size_t used = 0;
3104894e0ac8Smrg    while (used < len) {
3105894e0ac8Smrg	if ((target[used] = source[used]) == 0)
3106894e0ac8Smrg	    break;
3107894e0ac8Smrg	++used;
3108894e0ac8Smrg    }
3109894e0ac8Smrg    while (used < len) {
3110894e0ac8Smrg	target[used++] = '\0';
3111894e0ac8Smrg    }
3112894e0ac8Smrg}
3113894e0ac8Smrg
3114d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3115d522f475Smrg/*
3116d522f475Smrg * getutid() only looks at ut_type and ut_id.
3117d522f475Smrg * But we'll also check ut_line in find_utmp().
3118d522f475Smrg */
3119d522f475Smrgstatic void
3120d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3121d522f475Smrg{
3122d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3123d522f475Smrg    tofind->ut_type = type;
3124894e0ac8Smrg    copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3125894e0ac8Smrg    copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3126d522f475Smrg}
3127d522f475Smrg
3128d522f475Smrg/*
3129d522f475Smrg * We could use getutline() if we didn't support old systems.
3130d522f475Smrg */
3131d522f475Smrgstatic struct UTMP_STR *
3132d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3133d522f475Smrg{
3134d522f475Smrg    struct UTMP_STR *result;
31350bd37d32Smrg    struct UTMP_STR limited;
3136d522f475Smrg    struct UTMP_STR working;
3137d522f475Smrg
3138d522f475Smrg    for (;;) {
3139d522f475Smrg	memset(&working, 0, sizeof(working));
3140d522f475Smrg	working.ut_type = tofind->ut_type;
3141894e0ac8Smrg	copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3142d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3143d522f475Smrg	working.ut_type = 0;
3144d522f475Smrg#endif
3145d522f475Smrg	if ((result = call_getutid(&working)) == 0)
3146d522f475Smrg	    break;
3147894e0ac8Smrg	copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line));
31480bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3149d522f475Smrg	    break;
3150d522f475Smrg	/*
3151d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3152d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3153d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3154d522f475Smrg	 */
3155d522f475Smrg	memset(result, 0, sizeof(*result));
3156d522f475Smrg    }
3157d522f475Smrg    return result;
3158d522f475Smrg}
3159d522f475Smrg#endif /* HAVE_UTMP... */
3160d522f475Smrg
3161d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3162d522f475Smrg
316320d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
316420d2c4d2Smrg#define USE_NO_DEV_TTY 1
316520d2c4d2Smrg#else
316620d2c4d2Smrg#define USE_NO_DEV_TTY 0
316720d2c4d2Smrg#endif
316820d2c4d2Smrg
3169e0a2b6dfSmrgstatic int
3170e0a2b6dfSmrgsame_leaf(char *a, char *b)
3171e0a2b6dfSmrg{
3172e0a2b6dfSmrg    char *p = x_basename(a);
3173e0a2b6dfSmrg    char *q = x_basename(b);
3174e0a2b6dfSmrg    return !strcmp(p, q);
3175e0a2b6dfSmrg}
3176e0a2b6dfSmrg
3177e0a2b6dfSmrg/*
3178e0a2b6dfSmrg * "good enough" (inode wouldn't port to Cygwin)
3179e0a2b6dfSmrg */
3180e0a2b6dfSmrgstatic int
3181e0a2b6dfSmrgsame_file(const char *a, const char *b)
3182e0a2b6dfSmrg{
3183e0a2b6dfSmrg    struct stat asb;
3184e0a2b6dfSmrg    struct stat bsb;
3185e0a2b6dfSmrg    int result = 0;
3186e0a2b6dfSmrg
3187e0a2b6dfSmrg    if ((stat(a, &asb) == 0)
3188e0a2b6dfSmrg	&& (stat(b, &bsb) == 0)
3189e0a2b6dfSmrg	&& ((asb.st_mode & S_IFMT) == S_IFREG)
3190e0a2b6dfSmrg	&& ((bsb.st_mode & S_IFMT) == S_IFREG)
3191e0a2b6dfSmrg	&& (asb.st_mtime == bsb.st_mtime)
3192e0a2b6dfSmrg	&& (asb.st_size == bsb.st_size)) {
3193e0a2b6dfSmrg	result = 1;
3194e0a2b6dfSmrg    }
3195e0a2b6dfSmrg    return result;
3196e0a2b6dfSmrg}
3197e0a2b6dfSmrg
3198e0a2b6dfSmrg/*
3199e0a2b6dfSmrg * Only set $SHELL for paths found in the standard location.
3200e0a2b6dfSmrg */
3201e0a2b6dfSmrgstatic Boolean
3202e0a2b6dfSmrgvalidShell(const char *pathname)
3203e0a2b6dfSmrg{
3204e0a2b6dfSmrg    Boolean result = False;
3205e0a2b6dfSmrg    const char *ok_shells = "/etc/shells";
3206e0a2b6dfSmrg    char *blob;
3207e0a2b6dfSmrg    struct stat sb;
3208e0a2b6dfSmrg    size_t rc;
3209e0a2b6dfSmrg    FILE *fp;
3210e0a2b6dfSmrg
3211e0a2b6dfSmrg    if (validProgram(pathname)
3212e0a2b6dfSmrg	&& stat(ok_shells, &sb) == 0
3213e0a2b6dfSmrg	&& (sb.st_mode & S_IFMT) == S_IFREG
3214e0a2b6dfSmrg	&& (sb.st_size != 0)
3215e0a2b6dfSmrg	&& (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
3216e0a2b6dfSmrg	if ((fp = fopen(ok_shells, "r")) != 0) {
3217e0a2b6dfSmrg	    rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
3218e0a2b6dfSmrg	    if (rc == (size_t) sb.st_size) {
3219e0a2b6dfSmrg		char *p = blob;
3220e0a2b6dfSmrg		char *q, *r;
3221e0a2b6dfSmrg		blob[rc] = '\0';
3222e0a2b6dfSmrg		while (!result && (q = strtok(p, "\n")) != 0) {
3223e0a2b6dfSmrg		    if ((r = x_strtrim(q)) != 0) {
3224e0a2b6dfSmrg			TRACE(("...test \"%s\"\n", q));
3225e0a2b6dfSmrg			if (!strcmp(q, pathname)) {
3226e0a2b6dfSmrg			    result = True;
3227e0a2b6dfSmrg			} else if (same_leaf(q, (char *) pathname) &&
3228e0a2b6dfSmrg				   same_file(q, pathname)) {
3229e0a2b6dfSmrg			    result = True;
3230e0a2b6dfSmrg			}
3231e0a2b6dfSmrg			free(r);
3232e0a2b6dfSmrg		    }
3233e0a2b6dfSmrg		    p = 0;
3234e0a2b6dfSmrg		}
3235e0a2b6dfSmrg	    }
3236e0a2b6dfSmrg	    fclose(fp);
3237e0a2b6dfSmrg	}
3238e0a2b6dfSmrg	free(blob);
3239e0a2b6dfSmrg    }
3240e0a2b6dfSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3241e0a2b6dfSmrg    return result;
3242e0a2b6dfSmrg}
3243e0a2b6dfSmrg
3244e0a2b6dfSmrgstatic char *
3245e0a2b6dfSmrgresetShell(char *oldPath)
3246e0a2b6dfSmrg{
3247e0a2b6dfSmrg    char *newPath = x_strdup("/bin/sh");
3248e0a2b6dfSmrg    char *envPath = getenv("SHELL");
3249e0a2b6dfSmrg    if (oldPath != 0)
3250e0a2b6dfSmrg	free(oldPath);
3251e0a2b6dfSmrg    if (!IsEmpty(envPath))
3252e0a2b6dfSmrg	xtermSetenv("SHELL", newPath);
3253e0a2b6dfSmrg    return newPath;
3254e0a2b6dfSmrg}
3255e0a2b6dfSmrg
3256d522f475Smrg/*
3257d522f475Smrg *  Inits pty and tty and forks a login process.
3258d522f475Smrg *  Does not close fd Xsocket.
3259d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3260d522f475Smrg */
3261d522f475Smrgstatic int
3262d522f475SmrgspawnXTerm(XtermWidget xw)
3263d522f475Smrg{
3264d522f475Smrg    TScreen *screen = TScreenOf(xw);
3265d522f475Smrg    Cardinal nn;
3266d522f475Smrg#if OPT_PTY_HANDSHAKE
3267d522f475Smrg    Bool got_handshake_size = False;
3268d522f475Smrg    handshake_t handshake;
3269d522f475Smrg    int done;
3270d522f475Smrg#endif
3271d522f475Smrg#if OPT_INITIAL_ERASE
3272d522f475Smrg    int initial_erase = VAL_INITIAL_ERASE;
3273d522f475Smrg    Bool setInitialErase;
3274d522f475Smrg#endif
3275d522f475Smrg    int rc = 0;
3276d522f475Smrg    int ttyfd = -1;
3277d522f475Smrg    Bool ok_termcap;
3278d522f475Smrg    char *newtc;
3279d522f475Smrg
3280d522f475Smrg#ifdef TERMIO_STRUCT
3281d522f475Smrg    TERMIO_STRUCT tio;
3282d522f475Smrg#ifdef __MVS__
3283d522f475Smrg    TERMIO_STRUCT gio;
3284d522f475Smrg#endif /* __MVS__ */
3285d522f475Smrg#ifdef TIOCLSET
3286d522f475Smrg    unsigned lmode;
3287d522f475Smrg#endif /* TIOCLSET */
3288d522f475Smrg#ifdef HAS_LTCHARS
3289d522f475Smrg    struct ltchars ltc;
3290d522f475Smrg#endif /* HAS_LTCHARS */
3291d522f475Smrg#else /* !TERMIO_STRUCT */
3292d522f475Smrg    int ldisc = 0;
3293d522f475Smrg    int discipline;
3294d522f475Smrg    unsigned lmode;
3295d522f475Smrg    struct tchars tc;
3296d522f475Smrg    struct ltchars ltc;
3297d522f475Smrg    struct sgttyb sg;
3298d522f475Smrg#ifdef sony
3299d522f475Smrg    int jmode;
3300d522f475Smrg    struct jtchars jtc;
3301d522f475Smrg#endif /* sony */
3302d522f475Smrg#endif /* TERMIO_STRUCT */
3303d522f475Smrg
33040bd37d32Smrg    char *shell_path = 0;
33050bd37d32Smrg    char *shname, *shname_minus;
330620d2c4d2Smrg    int i;
330720d2c4d2Smrg#if USE_NO_DEV_TTY
330820d2c4d2Smrg    int no_dev_tty = False;
330920d2c4d2Smrg#endif
331020d2c4d2Smrg    const char **envnew;	/* new environment */
3311d522f475Smrg    char buf[64];
3312d522f475Smrg    char *TermName = NULL;
3313d522f475Smrg#ifdef TTYSIZE_STRUCT
3314d522f475Smrg    TTYSIZE_STRUCT ts;
3315d522f475Smrg#endif
33160bd37d32Smrg    struct passwd pw;
3317d522f475Smrg    char *login_name = NULL;
3318d522f475Smrg#ifndef USE_UTEMPTER
3319d522f475Smrg#ifdef HAVE_UTMP
3320d522f475Smrg    struct UTMP_STR utmp;
3321d522f475Smrg#ifdef USE_SYSV_UTMP
3322d522f475Smrg    struct UTMP_STR *utret = NULL;
3323d522f475Smrg#endif
3324d522f475Smrg#ifdef USE_LASTLOG
3325d522f475Smrg    struct lastlog lastlog;
3326d522f475Smrg#endif
3327d522f475Smrg#ifdef USE_LASTLOGX
3328d522f475Smrg    struct lastlogx lastlogx;
3329d522f475Smrg#endif /* USE_LASTLOG */
3330d522f475Smrg#endif /* HAVE_UTMP */
3331d522f475Smrg#endif /* !USE_UTEMPTER */
3332d522f475Smrg
3333e39b573cSmrg#if OPT_TRACE
3334e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
3335e39b573cSmrg#endif
3336e39b573cSmrg
3337d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
3338d522f475Smrg    (void) rc;
3339d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3340d522f475Smrg    (void) utret;
3341d522f475Smrg#endif
3342d522f475Smrg
3343d522f475Smrg    screen->uid = save_ruid;
3344d522f475Smrg    screen->gid = save_rgid;
3345d522f475Smrg
3346d522f475Smrg#ifdef SIGTTOU
3347d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
3348d522f475Smrg    signal(SIGTTOU, SIG_IGN);
3349d522f475Smrg#endif
3350d522f475Smrg
3351d522f475Smrg#if OPT_PTY_HANDSHAKE
3352d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3353d522f475Smrg#endif
3354d522f475Smrg
3355d522f475Smrg    if (am_slave >= 0) {
3356d522f475Smrg	screen->respond = am_slave;
3357d522f475Smrg	set_pty_id(ttydev, passedPty);
3358d522f475Smrg#ifdef USE_PTY_DEVICE
3359d522f475Smrg	set_pty_id(ptydev, passedPty);
3360d522f475Smrg#endif
3361d522f475Smrg	if (xtermResetIds(screen) < 0)
3362d522f475Smrg	    exit(1);
3363d522f475Smrg    } else {
3364d522f475Smrg	Bool tty_got_hung;
3365d522f475Smrg
3366d522f475Smrg	/*
3367d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
3368d522f475Smrg	 * that has gone away).  Simply make up some reasonable
3369d522f475Smrg	 * defaults.
3370d522f475Smrg	 */
3371d522f475Smrg
3372d522f475Smrg	signal(SIGALRM, hungtty);
3373d522f475Smrg	alarm(2);		/* alarm(1) might return too soon */
3374d522f475Smrg	if (!sigsetjmp(env, 1)) {
3375d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
3376d522f475Smrg	    alarm(0);
3377d522f475Smrg	    tty_got_hung = False;
3378d522f475Smrg	} else {
3379d522f475Smrg	    tty_got_hung = True;
3380d522f475Smrg	    ttyfd = -1;
3381d522f475Smrg	    errno = ENXIO;
3382d522f475Smrg	}
33830bd37d32Smrg	memset(&pw, 0, sizeof(pw));
3384d522f475Smrg#if OPT_PTY_HANDSHAKE
3385d522f475Smrg	got_handshake_size = False;
3386d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
3387d522f475Smrg#if OPT_INITIAL_ERASE
3388d522f475Smrg	initial_erase = VAL_INITIAL_ERASE;
3389d522f475Smrg#endif
3390d522f475Smrg	signal(SIGALRM, SIG_DFL);
3391d522f475Smrg
3392d522f475Smrg	/*
3393d522f475Smrg	 * Check results and ignore current control terminal if
3394d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
3395d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
3396d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
33970bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
33980bd37d32Smrg	 * if xterm is run within a jail.
3399d522f475Smrg	 */
340020d2c4d2Smrg#if USE_NO_DEV_TTY
3401d522f475Smrg	no_dev_tty = False;
340220d2c4d2Smrg#endif
3403d522f475Smrg	if (ttyfd < 0) {
3404d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
34050bd37d32Smrg		errno == ENOENT ||
3406d522f475Smrg#ifdef ENODEV
3407d522f475Smrg		errno == ENODEV ||
3408d522f475Smrg#endif
3409d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
341020d2c4d2Smrg#if USE_NO_DEV_TTY
3411d522f475Smrg		no_dev_tty = True;
341220d2c4d2Smrg#endif
3413d522f475Smrg#ifdef HAS_LTCHARS
3414d522f475Smrg		ltc = d_ltc;
3415d522f475Smrg#endif /* HAS_LTCHARS */
3416d522f475Smrg#ifdef TIOCLSET
3417d522f475Smrg		lmode = d_lmode;
3418d522f475Smrg#endif /* TIOCLSET */
3419d522f475Smrg#ifdef TERMIO_STRUCT
3420d522f475Smrg		tio = d_tio;
3421d522f475Smrg#else /* !TERMIO_STRUCT */
3422d522f475Smrg		sg = d_sg;
3423d522f475Smrg		tc = d_tc;
3424d522f475Smrg		discipline = d_disipline;
3425d522f475Smrg#ifdef sony
3426d522f475Smrg		jmode = d_jmode;
3427d522f475Smrg		jtc = d_jtc;
3428d522f475Smrg#endif /* sony */
3429d522f475Smrg#endif /* TERMIO_STRUCT */
3430d522f475Smrg	    } else {
3431d522f475Smrg		SysError(ERROR_OPDEVTTY);
3432d522f475Smrg	    }
3433d522f475Smrg	} else {
3434d522f475Smrg
3435d522f475Smrg	    /* Get a copy of the current terminal's state,
3436d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
3437d522f475Smrg	     * may not have a controlling terminal at this point
3438d522f475Smrg	     * if started directly from xdm or xinit,
3439d522f475Smrg	     * in which case we just use the defaults as above.
3440d522f475Smrg	     */
3441d522f475Smrg#ifdef HAS_LTCHARS
3442d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
3443d522f475Smrg		ltc = d_ltc;
3444d522f475Smrg#endif /* HAS_LTCHARS */
3445d522f475Smrg#ifdef TIOCLSET
3446d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
3447d522f475Smrg		lmode = d_lmode;
3448d522f475Smrg#endif /* TIOCLSET */
3449d522f475Smrg#ifdef TERMIO_STRUCT
345020d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
345120d2c4d2Smrg	    if (rc == -1)
3452d522f475Smrg		tio = d_tio;
3453d522f475Smrg#else /* !TERMIO_STRUCT */
345420d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
345520d2c4d2Smrg	    if (rc == -1)
3456d522f475Smrg		sg = d_sg;
3457d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
3458d522f475Smrg		tc = d_tc;
3459d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
3460d522f475Smrg		discipline = d_disipline;
3461d522f475Smrg#ifdef sony
3462d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
3463d522f475Smrg		jmode = d_jmode;
3464d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
3465d522f475Smrg		jtc = d_jtc;
3466d522f475Smrg#endif /* sony */
3467d522f475Smrg#endif /* TERMIO_STRUCT */
3468d522f475Smrg
3469d522f475Smrg	    /*
3470d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
3471d522f475Smrg	     * erase value.  Just in case that will fail, first get
3472d522f475Smrg	     * the value from /dev/tty, so we will have something
3473d522f475Smrg	     * at least.
3474d522f475Smrg	     */
3475d522f475Smrg#if OPT_INITIAL_ERASE
3476d522f475Smrg	    if (resource.ptyInitialErase) {
3477d522f475Smrg#ifdef TERMIO_STRUCT
3478d522f475Smrg		initial_erase = tio.c_cc[VERASE];
3479d522f475Smrg#else /* !TERMIO_STRUCT */
3480d522f475Smrg		initial_erase = sg.sg_erase;
3481d522f475Smrg#endif /* TERMIO_STRUCT */
3482d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
3483d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
3484d522f475Smrg		       initial_erase));
3485d522f475Smrg	    }
3486d522f475Smrg#endif
3487d522f475Smrg#ifdef __MVS__
3488d522f475Smrg	    if (ttyGetAttr(ttyfd, &gio) == 0) {
3489d522f475Smrg		gio.c_cflag &= ~(HUPCL | PARENB);
3490d522f475Smrg		ttySetAttr(ttyfd, &gio);
3491d522f475Smrg	    }
3492d522f475Smrg#endif /* __MVS__ */
3493d522f475Smrg
3494d522f475Smrg	    close_fd(ttyfd);
3495d522f475Smrg	}
3496d522f475Smrg
3497d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
3498d522f475Smrg	    SysError(ERROR_PTYS);
3499d522f475Smrg	}
35000bd37d32Smrg	TRACE_TTYSIZE(screen->respond, "after get_pty");
3501d522f475Smrg#if OPT_INITIAL_ERASE
3502d522f475Smrg	if (resource.ptyInitialErase) {
3503d522f475Smrg#ifdef TERMIO_STRUCT
3504d522f475Smrg	    TERMIO_STRUCT my_tio;
350520d2c4d2Smrg	    rc = ttyGetAttr(screen->respond, &my_tio);
350620d2c4d2Smrg	    if (rc == 0)
3507d522f475Smrg		initial_erase = my_tio.c_cc[VERASE];
3508d522f475Smrg#else /* !TERMIO_STRUCT */
3509d522f475Smrg	    struct sgttyb my_sg;
351020d2c4d2Smrg	    rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg);
351120d2c4d2Smrg	    if (rc == 0)
3512d522f475Smrg		initial_erase = my_sg.sg_erase;
3513d522f475Smrg#endif /* TERMIO_STRUCT */
3514d522f475Smrg	    TRACE(("%s initial_erase:%d (from pty)\n",
3515d522f475Smrg		   (rc == 0) ? "OK" : "FAIL",
3516d522f475Smrg		   initial_erase));
3517d522f475Smrg	}
3518d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3519d522f475Smrg    }
3520d522f475Smrg
3521d522f475Smrg    /* avoid double MapWindow requests */
3522d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
3523d522f475Smrg
3524d522f475Smrg    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
3525d522f475Smrg				   False);
3526d522f475Smrg
3527d522f475Smrg    if (!TEK4014_ACTIVE(xw))
3528956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
3529d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
3530d522f475Smrg    if (Console) {
3531d522f475Smrg	/*
3532d522f475Smrg	 * Inform any running xconsole program
3533d522f475Smrg	 * that we are going to steal the console.
3534d522f475Smrg	 */
3535d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
3536d522f475Smrg	mit_console = XInternAtom(screen->display, mit_console_name, False);
3537d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
3538d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
3539d522f475Smrg		       mit_console, CurrentTime,
3540d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
3541d522f475Smrg    }
3542d522f475Smrg#endif
3543d522f475Smrg#if OPT_TEK4014
3544d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3545d522f475Smrg	envnew = tekterm;
3546d522f475Smrg    } else
3547d522f475Smrg#endif
3548d522f475Smrg    {
3549d522f475Smrg	envnew = vtterm;
3550d522f475Smrg    }
3551d522f475Smrg
3552d522f475Smrg    /*
3553d522f475Smrg     * This used to exit if no termcap entry was found for the specified
3554d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
3555d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
3556d522f475Smrg     * entry is not found.
3557d522f475Smrg     */
3558d522f475Smrg    ok_termcap = True;
355920d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
356020d2c4d2Smrg	const char *last = NULL;
356120d2c4d2Smrg	char *next;
356220d2c4d2Smrg
356320d2c4d2Smrg	TermName = x_strdup(*envnew);
3564d522f475Smrg	ok_termcap = False;
3565d522f475Smrg	while (*envnew != NULL) {
356620d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
356720d2c4d2Smrg		next = x_strdup(*envnew);
356820d2c4d2Smrg		if (get_termcap(xw, next)) {
356920d2c4d2Smrg		    free(TermName);
357020d2c4d2Smrg		    TermName = next;
35710bd37d32Smrg		    ok_termcap = True + 1;
357220d2c4d2Smrg		    break;
357320d2c4d2Smrg		} else {
357420d2c4d2Smrg		    free(next);
357520d2c4d2Smrg		}
3576d522f475Smrg	    }
3577d522f475Smrg	    last = *envnew;
3578d522f475Smrg	    envnew++;
3579d522f475Smrg	}
3580d522f475Smrg    }
3581d522f475Smrg    if (ok_termcap) {
3582a1f3da82Smrg	resource.term_name = TermName;
358320d2c4d2Smrg	resize_termcap(xw);
3584d522f475Smrg    }
3585d522f475Smrg
3586d522f475Smrg    /*
3587d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
3588d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
3589d522f475Smrg     */
3590d522f475Smrg#if OPT_INITIAL_ERASE
3591d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
3592d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
3593d522f475Smrg    setInitialErase = False;
3594d522f475Smrg    if (override_tty_modes && ttymodelist[XTTYMODE_erase].set) {
3595d522f475Smrg	initial_erase = ttymodelist[XTTYMODE_erase].value;
3596d522f475Smrg	setInitialErase = True;
3597d522f475Smrg    } else if (resource.ptyInitialErase) {
3598a1f3da82Smrg	/* EMPTY */ ;
3599d522f475Smrg    } else if (ok_termcap) {
360020d2c4d2Smrg	char *s = get_tcap_erase(xw);
3601d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
3602d522f475Smrg	if (s != 0) {
360320d2c4d2Smrg	    char *save = s;
3604d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
3605d522f475Smrg	    setInitialErase = True;
360620d2c4d2Smrg	    free(save);
3607d522f475Smrg	}
3608d522f475Smrg    }
3609d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
3610d522f475Smrg
3611d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
3612d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
3613d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
3614d522f475Smrg	if (initial_erase == ANSI_DEL) {
361520d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
3616d522f475Smrg	} else {
3617d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
3618d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
3619d522f475Smrg	}
3620d522f475Smrg	TRACE(("...sets DECBKM %s\n",
3621d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
3622d522f475Smrg    } else {
3623d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
3624d522f475Smrg    }
3625d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3626d522f475Smrg
3627d522f475Smrg#ifdef TTYSIZE_STRUCT
3628d522f475Smrg    /* tell tty how big window is */
3629d522f475Smrg#if OPT_TEK4014
3630d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3631d522f475Smrg	TTYSIZE_ROWS(ts) = 38;
3632d522f475Smrg	TTYSIZE_COLS(ts) = 81;
3633d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
363420d2c4d2Smrg	ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
363520d2c4d2Smrg	ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3636d522f475Smrg#endif
3637d522f475Smrg    } else
3638d522f475Smrg#endif
3639d522f475Smrg    {
364020d2c4d2Smrg	TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
364120d2c4d2Smrg	TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3642d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
364320d2c4d2Smrg	ts.ws_xpixel = (ttySize_t) FullWidth(screen);
364420d2c4d2Smrg	ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3645d522f475Smrg#endif
3646d522f475Smrg    }
364720d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
3648d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
3649d522f475Smrg	   TTYSIZE_ROWS(ts),
3650d522f475Smrg	   TTYSIZE_COLS(ts), i));
3651d522f475Smrg#endif /* TTYSIZE_STRUCT */
3652d522f475Smrg
36530bd37d32Smrg#if !defined(USE_OPENPTY)
36540bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
36550bd37d32Smrg    /*
36560bd37d32Smrg     * utempter checks the ownership of the device; some implementations
36570bd37d32Smrg     * set ownership in grantpt - do this first.
36580bd37d32Smrg     */
36590bd37d32Smrg    grantpt(screen->respond);
36600bd37d32Smrg#endif
36610bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
36620bd37d32Smrg    unlockpt(screen->respond);
36630bd37d32Smrg    TRACE_TTYSIZE(screen->respond, "after unlockpt");
36640bd37d32Smrg#endif
36650bd37d32Smrg#endif /* !USE_OPENPTY */
36660bd37d32Smrg
3667d522f475Smrg    added_utmp_entry = False;
3668d522f475Smrg#if defined(USE_UTEMPTER)
3669d522f475Smrg#undef UTMP
3670d522f475Smrg    if (!resource.utmpInhibit) {
3671d522f475Smrg	struct UTMP_STR dummy;
3672d522f475Smrg
3673d522f475Smrg	/* Note: utempter may trim it anyway */
3674d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
36750bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
36760bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
3677d522f475Smrg	addToUtmp(ttydev, dummy.ut_host, screen->respond);
3678d522f475Smrg	added_utmp_entry = True;
3679d522f475Smrg    }
3680d522f475Smrg#endif
3681d522f475Smrg
3682d522f475Smrg    if (am_slave < 0) {
3683d522f475Smrg#if OPT_PTY_HANDSHAKE
3684d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
3685d522f475Smrg	    SysError(ERROR_FORK);
3686d522f475Smrg#endif
3687d522f475Smrg	TRACE(("Forking...\n"));
3688d522f475Smrg	if ((screen->pid = fork()) == -1)
3689d522f475Smrg	    SysError(ERROR_FORK);
3690d522f475Smrg
3691d522f475Smrg	if (screen->pid == 0) {
3692d522f475Smrg#ifdef USE_USG_PTYS
369320d2c4d2Smrg	    int ptyfd = -1;
3694d522f475Smrg	    char *pty_name;
3695d522f475Smrg#endif
3696d522f475Smrg	    /*
3697d522f475Smrg	     * now in child process
3698d522f475Smrg	     */
3699d522f475Smrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
3700d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
3701d522f475Smrg#else
3702d522f475Smrg	    int pgrp = getpid();
3703d522f475Smrg#endif
3704d522f475Smrg	    TRACE_CHILD
3705d522f475Smrg
3706d522f475Smrg#ifdef USE_USG_PTYS
37070bd37d32Smrg#ifdef HAVE_SETPGID
37080bd37d32Smrg		setpgid(0, 0);
37090bd37d32Smrg#else
3710d522f475Smrg		setpgrp();
37110bd37d32Smrg#endif
37120bd37d32Smrg	    unlockpt(screen->respond);
37130bd37d32Smrg	    TRACE_TTYSIZE(screen->respond, "after unlockpt");
37140bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
37150bd37d32Smrg		SysError(ERROR_PTSNAME);
37160bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
37170bd37d32Smrg		SysError(ERROR_OPPTSNAME);
37180bd37d32Smrg	    }
3719d522f475Smrg#ifdef I_PUSH
37200bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ptem") < 0) {
37210bd37d32Smrg		SysError(ERROR_PTEM);
37220bd37d32Smrg	    }
3723d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
37240bd37d32Smrg	    else if (!x_getenv("CONSEM")
37250bd37d32Smrg		     && ioctl(ptyfd, I_PUSH, "consem") < 0) {
37260bd37d32Smrg		SysError(ERROR_CONSEM);
37270bd37d32Smrg	    }
3728d522f475Smrg#endif /* !SVR4 */
37290bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ldterm") < 0) {
37300bd37d32Smrg		SysError(ERROR_LDTERM);
37310bd37d32Smrg	    }
3732d522f475Smrg#ifdef SVR4			/* from Sony */
37330bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ttcompat") < 0) {
37340bd37d32Smrg		SysError(ERROR_TTCOMPAT);
37350bd37d32Smrg	    }
3736d522f475Smrg#endif /* SVR4 */
3737d522f475Smrg#endif /* I_PUSH */
37380bd37d32Smrg	    ttyfd = ptyfd;
3739d522f475Smrg#ifndef __MVS__
37400bd37d32Smrg	    close_fd(screen->respond);
3741d522f475Smrg#endif /* __MVS__ */
3742d522f475Smrg
3743d522f475Smrg#ifdef TTYSIZE_STRUCT
37440bd37d32Smrg	    /* tell tty how big window is */
3745d522f475Smrg#if OPT_TEK4014
37460bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
37470bd37d32Smrg		TTYSIZE_ROWS(ts) = 24;
37480bd37d32Smrg		TTYSIZE_COLS(ts) = 80;
3749d522f475Smrg#ifdef USE_STRUCT_WINSIZE
37500bd37d32Smrg		ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
37510bd37d32Smrg		ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3752d522f475Smrg#endif
37530bd37d32Smrg	    } else
3754d522f475Smrg#endif /* OPT_TEK4014 */
37550bd37d32Smrg	    {
37560bd37d32Smrg		TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
37570bd37d32Smrg		TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3758d522f475Smrg#ifdef USE_STRUCT_WINSIZE
37590bd37d32Smrg		ts.ws_xpixel = (ttySize_t) FullWidth(screen);
37600bd37d32Smrg		ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3761d522f475Smrg#endif
37620bd37d32Smrg	    }
3763d522f475Smrg#endif /* TTYSIZE_STRUCT */
3764d522f475Smrg
3765d522f475Smrg#endif /* USE_USG_PTYS */
3766d522f475Smrg
37670bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
3768d522f475Smrg
3769d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
37700bd37d32Smrg	    if (resource.ptyHandshake) {
37710bd37d32Smrg		char *ptr;
3772d522f475Smrg
37730bd37d32Smrg		/* close parent's sides of the pipes */
37740bd37d32Smrg		close(cp_pipe[0]);
37750bd37d32Smrg		close(pc_pipe[1]);
37760bd37d32Smrg
37770bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
37780bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
37790bd37d32Smrg		 * or err.
37800bd37d32Smrg		 */
37810bd37d32Smrg		if (cp_pipe[1] <= 2) {
37820bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
37830bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
37840bd37d32Smrg			cp_pipe[1] = i;
3785d522f475Smrg		    }
37860bd37d32Smrg		}
37870bd37d32Smrg		if (pc_pipe[0] <= 2) {
37880bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
37890bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
37900bd37d32Smrg			pc_pipe[0] = i;
3791d522f475Smrg		    }
37920bd37d32Smrg		}
3793d522f475Smrg
37940bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
37950bd37d32Smrg		close(ConnectionNumber(screen->display));
3796d522f475Smrg#ifndef __MVS__
3797894e0ac8Smrg		if (screen->respond >= 0)
3798894e0ac8Smrg		    close(screen->respond);
3799d522f475Smrg#endif /* __MVS__ */
3800d522f475Smrg
38010bd37d32Smrg		/* Now is the time to set up our process group and
38020bd37d32Smrg		 * open up the pty slave.
38030bd37d32Smrg		 */
3804d522f475Smrg#ifdef USE_SYSV_PGRP
3805d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
38060bd37d32Smrg		IGNORE_RC(setsid());
3807d522f475Smrg#else
38080bd37d32Smrg		IGNORE_RC(setpgrp());
3809d522f475Smrg#endif
3810d522f475Smrg#endif /* USE_SYSV_PGRP */
3811d522f475Smrg
3812d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
38130bd37d32Smrg		qsetlogin(getlogin(), ttydev);
3814d522f475Smrg#endif
38150bd37d32Smrg		if (ttyfd >= 0) {
3816d522f475Smrg#ifdef __MVS__
38170bd37d32Smrg		    if (ttyGetAttr(ttyfd, &gio) == 0) {
38180bd37d32Smrg			gio.c_cflag &= ~(HUPCL | PARENB);
38190bd37d32Smrg			ttySetAttr(ttyfd, &gio);
38200bd37d32Smrg		    }
3821d522f475Smrg#else /* !__MVS__ */
38220bd37d32Smrg		    close_fd(ttyfd);
3823d522f475Smrg#endif /* __MVS__ */
38240bd37d32Smrg		}
3825d522f475Smrg
38260bd37d32Smrg		for (;;) {
382720d2c4d2Smrg#if USE_NO_DEV_TTY
38280bd37d32Smrg		    if (!no_dev_tty
38290bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
38300bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
38310bd37d32Smrg			close_fd(ttyfd);
38320bd37d32Smrg		    }
383320d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
3834d522f475Smrg#ifdef CSRG_BASED
38350bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
3836d522f475Smrg#endif
38370bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
38380bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after open");
38390bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
38400bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after fixup");
3841d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
38420bd37d32Smrg			/* make /dev/tty work */
38430bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
3844d522f475Smrg#endif
3845d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
38460bd37d32Smrg			/* make /dev/tty work */
38470bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
3848d522f475Smrg#endif
3849d522f475Smrg#ifdef USE_SYSV_PGRP
38500bd37d32Smrg			/* We need to make sure that we are actually
38510bd37d32Smrg			 * the process group leader for the pty.  If
38520bd37d32Smrg			 * we are, then we should now be able to open
38530bd37d32Smrg			 * /dev/tty.
38540bd37d32Smrg			 */
38550bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
38560bd37d32Smrg			    /* success! */
38570bd37d32Smrg			    close(i);
3858d522f475Smrg			    break;
3859d522f475Smrg			}
38600bd37d32Smrg#else /* USE_SYSV_PGRP */
38610bd37d32Smrg			break;
38620bd37d32Smrg#endif /* USE_SYSV_PGRP */
38630bd37d32Smrg		    }
38640bd37d32Smrg		    perror("open ttydev");
3865d522f475Smrg#ifdef TIOCSCTTY
38660bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
3867d522f475Smrg#endif
38680bd37d32Smrg		    /* let our master know that the open failed */
38690bd37d32Smrg		    handshake.status = PTY_BAD;
38700bd37d32Smrg		    handshake.error = errno;
38710bd37d32Smrg		    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
38720bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
38730bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
38740bd37d32Smrg				    (const char *) &handshake,
38750bd37d32Smrg				    sizeof(handshake)));
3876d522f475Smrg
38770bd37d32Smrg		    /* get reply from parent */
38780bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
38790bd37d32Smrg				   sizeof(handshake));
38800bd37d32Smrg		    if (i <= 0) {
38810bd37d32Smrg			/* parent terminated */
38820bd37d32Smrg			exit(1);
3883d522f475Smrg		    }
3884d522f475Smrg
38850bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
38860bd37d32Smrg			/* No more ptys, let's shutdown. */
38870bd37d32Smrg			exit(1);
3888d522f475Smrg		    }
38890bd37d32Smrg
38900bd37d32Smrg		    /* We have a new pty to try */
38910bd37d32Smrg		    if (ttyfd >= 0)
38920bd37d32Smrg			close(ttyfd);
38930bd37d32Smrg		    free(ttydev);
38940bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
3895d522f475Smrg		}
3896d522f475Smrg
38970bd37d32Smrg		/* use the same tty name that everyone else will use
38980bd37d32Smrg		 * (from ttyname)
38990bd37d32Smrg		 */
39000bd37d32Smrg		if ((ptr = ttyname(ttyfd)) != 0) {
39010bd37d32Smrg		    free(ttydev);
39020bd37d32Smrg		    ttydev = x_strdup(ptr);
39030bd37d32Smrg		}
39040bd37d32Smrg	    }
39050bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
3906d522f475Smrg
3907d522f475Smrg	    set_pty_permissions(screen->uid,
3908d522f475Smrg				screen->gid,
3909d522f475Smrg				(resource.messages
3910d522f475Smrg				 ? 0622U
3911d522f475Smrg				 : 0600U));
3912d522f475Smrg
3913d522f475Smrg	    /*
3914d522f475Smrg	     * set up the tty modes
3915d522f475Smrg	     */
3916d522f475Smrg	    {
3917d522f475Smrg#ifdef TERMIO_STRUCT
3918d522f475Smrg#if defined(umips) || defined(CRAY) || defined(linux)
3919d522f475Smrg		/* If the control tty had its modes screwed around with,
3920d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
3921d522f475Smrg		   will have bad values.  Let's just get termio from the
3922d522f475Smrg		   new tty and tailor it.  */
3923d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
3924d522f475Smrg		    SysError(ERROR_TIOCGETP);
3925d522f475Smrg		tio.c_lflag |= ECHOE;
3926d522f475Smrg#endif /* umips */
3927d522f475Smrg		/* Now is also the time to change the modes of the
3928d522f475Smrg		 * child pty.
3929d522f475Smrg		 */
3930d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
393120d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
3932d522f475Smrg		tio.c_iflag |= ICRNL;
39330bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
3934d522f475Smrg#if OPT_LUIT_PROG
3935d522f475Smrg		if (command_to_exec_with_luit == 0)
3936d522f475Smrg#endif
3937d522f475Smrg		    if (screen->utf8_mode)
3938d522f475Smrg			tio.c_iflag |= IUTF8;
3939d522f475Smrg#endif
3940d522f475Smrg		/* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */
3941d522f475Smrg#ifndef USE_POSIX_TERMIOS
394220d2c4d2Smrg		UIntClr(tio.c_oflag,
394320d2c4d2Smrg			(OCRNL
394420d2c4d2Smrg			 | ONLRET
394520d2c4d2Smrg			 | NLDLY
394620d2c4d2Smrg			 | CRDLY
394720d2c4d2Smrg			 | TABDLY
394820d2c4d2Smrg			 | BSDLY
394920d2c4d2Smrg			 | VTDLY
395020d2c4d2Smrg			 | FFDLY));
3951d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3952d522f475Smrg#ifdef ONLCR
3953d522f475Smrg		tio.c_oflag |= ONLCR;
3954d522f475Smrg#endif /* ONLCR */
3955d522f475Smrg#ifdef OPOST
3956d522f475Smrg		tio.c_oflag |= OPOST;
3957d522f475Smrg#endif /* OPOST */
3958d522f475Smrg#ifndef USE_POSIX_TERMIOS
3959d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
3960d522f475Smrg#  define CBAUD V_CBAUD
3961d522f475Smrg# endif
396220d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
3963d522f475Smrg#ifdef BAUD_0
3964d522f475Smrg		/* baud rate is 0 (don't care) */
3965d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
3966d522f475Smrg		tio.c_ispeed = tio.c_ospeed = VAL_LINE_SPEED;
3967d522f475Smrg#else /* !BAUD_0 */
3968d522f475Smrg		tio.c_cflag |= VAL_LINE_SPEED;
3969d522f475Smrg#endif /* !BAUD_0 */
3970d522f475Smrg#else /* USE_POSIX_TERMIOS */
3971d522f475Smrg		cfsetispeed(&tio, VAL_LINE_SPEED);
3972d522f475Smrg		cfsetospeed(&tio, VAL_LINE_SPEED);
3973d522f475Smrg#ifdef __MVS__
3974d522f475Smrg		/* turn off bits that can't be set from the slave side */
3975d522f475Smrg		tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
3976d522f475Smrg#endif /* __MVS__ */
3977d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
3978d522f475Smrg		   when the xterm ends */
3979d522f475Smrg		tio.c_cflag &= ~CLOCAL;
3980d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3981d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
3982d522f475Smrg		 * echo
3983d522f475Smrg		 */
3984d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
3985d522f475Smrg#ifdef ECHOKE
3986d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
3987d522f475Smrg#endif
3988d522f475Smrg#ifdef ECHOCTL
3989d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
3990d522f475Smrg#endif
3991d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
3992d522f475Smrg		    if (validTtyChar(tio, nn)) {
3993d522f475Smrg			int sysMode = known_ttyChars[nn].sysMode;
3994d522f475Smrg#ifdef __MVS__
3995d522f475Smrg			if (tio.c_cc[sysMode] != 0) {
3996d522f475Smrg			    switch (sysMode) {
3997d522f475Smrg			    case VEOL:
3998d522f475Smrg			    case VEOF:
3999d522f475Smrg				continue;
4000d522f475Smrg			    }
4001d522f475Smrg			}
4002d522f475Smrg#endif
40030bd37d32Smrg			tio.c_cc[sysMode] = (cc_t) known_ttyChars[nn].myDefault;
4004d522f475Smrg		    }
4005d522f475Smrg		}
4006d522f475Smrg
4007d522f475Smrg		if (override_tty_modes) {
4008d522f475Smrg		    for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
4009d522f475Smrg			if (validTtyChar(tio, nn)) {
4010d522f475Smrg			    TMODE(known_ttyChars[nn].myMode,
4011d522f475Smrg				  tio.c_cc[known_ttyChars[nn].sysMode]);
4012d522f475Smrg			}
4013d522f475Smrg		    }
4014d522f475Smrg#ifdef HAS_LTCHARS
4015d522f475Smrg		    /* both SYSV and BSD have ltchars */
4016d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4017d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4018d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4019d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4020d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4021d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4022d522f475Smrg#endif
4023d522f475Smrg		}
4024d522f475Smrg#ifdef HAS_LTCHARS
4025d522f475Smrg#ifdef __hpux
4026d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
4027d522f475Smrg		 * are not set to _POSIX_VDISABLE */
4028d522f475Smrg		ltc.t_rprntc = ltc.t_rprntc = ltc.t_flushc =
4029d522f475Smrg		    ltc.t_werasc = ltc.t_lnextc = _POSIX_VDISABLE;
4030d522f475Smrg#endif /* __hpux */
4031d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
4032d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4033d522f475Smrg#endif /* HAS_LTCHARS */
4034d522f475Smrg#ifdef TIOCLSET
4035d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4036d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4037d522f475Smrg#endif /* TIOCLSET */
4038d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
4039d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4040d522f475Smrg
4041d522f475Smrg		/* ignore errors here - some platforms don't work */
404220d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
4043d522f475Smrg		if (screen->input_eight_bits)
4044d522f475Smrg		    tio.c_cflag |= CS8;
4045d522f475Smrg		else
4046d522f475Smrg		    tio.c_cflag |= CS7;
4047d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
4048d522f475Smrg
4049d522f475Smrg#else /* !TERMIO_STRUCT */
4050d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
4051d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
4052d522f475Smrg		/* make sure speed is set on pty so that editors work right */
4053d522f475Smrg		sg.sg_ispeed = VAL_LINE_SPEED;
4054d522f475Smrg		sg.sg_ospeed = VAL_LINE_SPEED;
4055d522f475Smrg		/* reset t_brkc to default value */
4056d522f475Smrg		tc.t_brkc = -1;
4057d522f475Smrg#ifdef LPASS8
4058d522f475Smrg		if (screen->input_eight_bits)
4059d522f475Smrg		    lmode |= LPASS8;
4060d522f475Smrg		else
4061d522f475Smrg		    lmode &= ~(LPASS8);
4062d522f475Smrg#endif
4063d522f475Smrg#ifdef sony
4064d522f475Smrg		jmode &= ~KM_KANJI;
4065d522f475Smrg#endif /* sony */
4066d522f475Smrg
4067d522f475Smrg		ltc = d_ltc;
4068d522f475Smrg
4069d522f475Smrg		if (override_tty_modes) {
4070d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
4071d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
4072d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
4073d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
4074d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
4075d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
4076d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
4077d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
4078d522f475Smrg		    /* both SYSV and BSD have ltchars */
4079d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4080d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4081d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4082d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4083d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4084d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4085d522f475Smrg		}
4086d522f475Smrg
4087d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
4088d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4089d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
4090d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4091d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
4092d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
4093d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
4094d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
4095d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4096d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4097d522f475Smrg#ifdef sony
4098d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
4099d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
4100d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
4101d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
4102d522f475Smrg#endif /* sony */
4103d522f475Smrg#endif /* TERMIO_STRUCT */
4104d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4105d522f475Smrg		if (Console) {
4106d522f475Smrg#ifdef TIOCCONS
4107d522f475Smrg		    int on = 1;
4108d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
41090bd37d32Smrg			xtermPerror("cannot open console");
4110d522f475Smrg#endif
4111d522f475Smrg#ifdef SRIOCSREDIR
4112d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4113d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
41140bd37d32Smrg			xtermPerror("cannot open console");
411520d2c4d2Smrg		    IGNORE_RC(close(fd));
4116d522f475Smrg#endif
4117d522f475Smrg		}
4118d522f475Smrg#endif /* TIOCCONS */
4119d522f475Smrg	    }
4120d522f475Smrg
4121d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4122d522f475Smrg#ifdef USE_SYSV_SIGHUP
4123d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4124d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4125d522f475Smrg#else
4126d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4127d522f475Smrg#endif
4128d522f475Smrg	    /* restore various signals to their defaults */
4129d522f475Smrg	    signal(SIGINT, SIG_DFL);
4130d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4131d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4132d522f475Smrg
4133d522f475Smrg	    /*
4134d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4135d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4136d522f475Smrg	     * the terminal's erase mode from our best guess.
4137d522f475Smrg	     */
4138d522f475Smrg#if OPT_INITIAL_ERASE
4139d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4140d522f475Smrg		   initial_erase,
4141d522f475Smrg		   setInitialErase ? "YES" : "NO",
4142d522f475Smrg		   resource.ptyInitialErase,
4143d522f475Smrg		   override_tty_modes,
4144d522f475Smrg		   ttymodelist[XTTYMODE_erase].set));
4145d522f475Smrg	    if (setInitialErase) {
4146d522f475Smrg#if OPT_TRACE
4147d522f475Smrg		int old_erase;
4148d522f475Smrg#endif
4149d522f475Smrg#ifdef TERMIO_STRUCT
4150d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4151d522f475Smrg		    tio = d_tio;
4152d522f475Smrg#if OPT_TRACE
4153d522f475Smrg		old_erase = tio.c_cc[VERASE];
4154d522f475Smrg#endif
41550bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
415620d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4157d522f475Smrg#else /* !TERMIO_STRUCT */
4158d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4159d522f475Smrg		    sg = d_sg;
4160d522f475Smrg#if OPT_TRACE
4161d522f475Smrg		old_erase = sg.sg_erase;
4162d522f475Smrg#endif
4163d522f475Smrg		sg.sg_erase = initial_erase;
4164d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4165d522f475Smrg#endif /* TERMIO_STRUCT */
4166d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4167d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4168d522f475Smrg	    }
4169d522f475Smrg#endif
4170d522f475Smrg
4171d522f475Smrg	    xtermCopyEnv(environ);
4172d522f475Smrg
41730bd37d32Smrg	    /*
41740bd37d32Smrg	     * standards.freedesktop.org/startup-notification-spec/
41750bd37d32Smrg	     * notes that this variable is used when a "reliable" mechanism is
41760bd37d32Smrg	     * not available; in practice it must be unset to avoid confusing
41770bd37d32Smrg	     * GTK applications.
41780bd37d32Smrg	     */
41790bd37d32Smrg	    xtermUnsetenv("DESKTOP_STARTUP_ID");
4180e0a2b6dfSmrg	    /*
4181e0a2b6dfSmrg	     * We set this temporarily to work around poor design of Xcursor.
4182e0a2b6dfSmrg	     * Unset it here to avoid confusion.
4183e0a2b6dfSmrg	     */
4184e0a2b6dfSmrg	    xtermUnsetenv("XCURSOR_PATH");
41850bd37d32Smrg
4186a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4187a1f3da82Smrg	    if (!resource.term_name)
418820d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4189d522f475Smrg
4190d522f475Smrg	    sprintf(buf, "%lu",
4191d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4192d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4193d522f475Smrg
4194d522f475Smrg	    /* put the display into the environment of the shell */
4195d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4196d522f475Smrg
4197d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4198d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4199d522f475Smrg
4200e39b573cSmrg	    /*
4201e39b573cSmrg	     * For debugging only, add environment variables that can be used
4202e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4203e39b573cSmrg	     * processes.
4204e39b573cSmrg	     */
4205e39b573cSmrg#if OPT_TRACE
4206e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4207e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4208e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4209e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4210e39b573cSmrg#endif
4211e39b573cSmrg
4212d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4213d522f475Smrg
4214d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4215d522f475Smrg	     */
4216d522f475Smrg	    {
4217d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4218d522f475Smrg		close_fd(ttyfd);
4219d522f475Smrg
422020d2c4d2Smrg		IGNORE_RC(close(0));
4221d522f475Smrg
4222d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4223d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4224d522f475Smrg		}
422520d2c4d2Smrg		IGNORE_RC(close(1));
422620d2c4d2Smrg		IGNORE_RC(close(2));
4227d522f475Smrg		dup(0);
4228d522f475Smrg		dup(0);
4229d522f475Smrg#else
4230d522f475Smrg		/* dup the tty */
4231d522f475Smrg		for (i = 0; i <= 2; i++)
4232d522f475Smrg		    if (i != ttyfd) {
423320d2c4d2Smrg			IGNORE_RC(close(i));
423420d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4235d522f475Smrg		    }
4236d522f475Smrg#ifndef ATT
4237d522f475Smrg		/* and close the tty */
4238d522f475Smrg		if (ttyfd > 2)
4239d522f475Smrg		    close_fd(ttyfd);
4240d522f475Smrg#endif
4241d522f475Smrg#endif /* CRAY */
4242d522f475Smrg	    }
4243d522f475Smrg
4244d522f475Smrg#if !defined(USE_SYSV_PGRP)
4245d522f475Smrg#ifdef TIOCSCTTY
4246d522f475Smrg	    setsid();
4247d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4248d522f475Smrg#endif
4249d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4250d522f475Smrg	    setpgrp(0, 0);
4251d522f475Smrg	    close(open(ttydev, O_WRONLY));
4252d522f475Smrg	    setpgrp(0, pgrp);
4253d522f475Smrg#if defined(__QNX__)
4254d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4255d522f475Smrg#endif
4256d522f475Smrg#endif /* !USE_SYSV_PGRP */
4257d522f475Smrg
4258d522f475Smrg#ifdef Lynx
4259d522f475Smrg	    {
4260d522f475Smrg		TERMIO_STRUCT t;
4261d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4262d522f475Smrg		    /* this gets lost somewhere on our way... */
4263d522f475Smrg		    t.c_oflag |= OPOST;
4264d522f475Smrg		    ttySetAttr(0, &t);
4265d522f475Smrg		}
4266d522f475Smrg	    }
4267d522f475Smrg#endif
4268d522f475Smrg
4269d522f475Smrg#ifdef HAVE_UTMP
4270d522f475Smrg	    login_name = NULL;
42710bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
42720bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4273d522f475Smrg	    }
4274d522f475Smrg	    if (login_name != NULL) {
4275d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4276d522f475Smrg	    }
4277d522f475Smrg#ifndef USE_UTEMPTER
4278d522f475Smrg#ifdef USE_UTMP_SETGID
4279d522f475Smrg	    setEffectiveGroup(save_egid);
4280d522f475Smrg	    TRACE_IDS;
4281d522f475Smrg#endif
4282d522f475Smrg#ifdef USE_SYSV_UTMP
4283d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4284d522f475Smrg	     * for the following reasons:
4285d522f475Smrg	     *   - It needs to have our correct process id (for
4286d522f475Smrg	     *     login).
4287d522f475Smrg	     *   - If our parent was to set it after the fork(),
4288d522f475Smrg	     *     it might make it out before we need it.
4289d522f475Smrg	     *   - We need to do it before we go and change our
4290d522f475Smrg	     *     user and group id's.
4291d522f475Smrg	     */
4292d522f475Smrg	    (void) call_setutent();
4293d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4294d522f475Smrg
4295d522f475Smrg	    /* position to entry in utmp file */
4296d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
429720d2c4d2Smrg	    utret = find_utmp(&utmp);
429820d2c4d2Smrg	    if (utret == 0) {
4299d522f475Smrg		(void) call_setutent();
4300d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
430120d2c4d2Smrg		utret = find_utmp(&utmp);
430220d2c4d2Smrg		if (utret == 0) {
4303d522f475Smrg		    (void) call_setutent();
4304d522f475Smrg		}
4305d522f475Smrg	    }
4306d522f475Smrg#if OPT_TRACE
4307d522f475Smrg	    if (!utret)
4308d522f475Smrg		TRACE(("getutid: NULL\n"));
4309d522f475Smrg	    else
43100bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
431120d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
43120bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
43130bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4314d522f475Smrg#endif
4315d522f475Smrg
4316d522f475Smrg	    /* set up the new entry */
4317d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4318d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4319d522f475Smrg	    utmp.ut_xstatus = 2;
4320d522f475Smrg#endif
4321894e0ac8Smrg	    copy_filled(utmp.ut_user,
4322894e0ac8Smrg			(login_name != NULL) ? login_name : "????",
4323894e0ac8Smrg			sizeof(utmp.ut_user));
4324d522f475Smrg	    /* why are we copying this string again?  (see above) */
4325894e0ac8Smrg	    copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4326894e0ac8Smrg	    copy_filled(utmp.ut_line,
4327894e0ac8Smrg			my_pty_name(ttydev), sizeof(utmp.ut_line));
4328d522f475Smrg
4329d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4330d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4331d522f475Smrg#endif
4332d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4333d522f475Smrg	    SetUtmpSysLen(utmp);
4334d522f475Smrg#endif
4335d522f475Smrg
4336894e0ac8Smrg	    copy_filled(utmp.ut_name,
4337894e0ac8Smrg			(login_name) ? login_name : "????",
4338894e0ac8Smrg			sizeof(utmp.ut_name));
4339d522f475Smrg
4340d522f475Smrg	    utmp.ut_pid = getpid();
4341d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4342d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4343d522f475Smrg	    utmp.ut_session = getsid(0);
4344d522f475Smrg#endif
4345d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
4346d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
4347d522f475Smrg#else
4348d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
4349d522f475Smrg#endif
4350d522f475Smrg
4351d522f475Smrg	    /* write out the entry */
4352d522f475Smrg	    if (!resource.utmpInhibit) {
4353d522f475Smrg		errno = 0;
4354d522f475Smrg		call_pututline(&utmp);
43550bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
43560bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
43570bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
4358d522f475Smrg		       (long) utmp.ut_pid,
4359d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
4360d522f475Smrg	    }
4361d522f475Smrg#ifdef WTMP
4362d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
4363d522f475Smrg	    if (xw->misc.login_shell)
4364d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
4365d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4366d522f475Smrg	    if (xw->misc.login_shell)
4367d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
4368d522f475Smrg#else
4369d522f475Smrg	    if (xw->misc.login_shell &&
4370d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
43710bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4372d522f475Smrg		close(i);
4373d522f475Smrg	    }
4374d522f475Smrg#endif
4375d522f475Smrg#endif
4376d522f475Smrg	    /* close the file */
4377d522f475Smrg	    (void) call_endutent();
4378d522f475Smrg
4379d522f475Smrg#else /* USE_SYSV_UTMP */
4380d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
4381d522f475Smrg	     * utmp entry.
4382d522f475Smrg	     */
4383d522f475Smrg	    tslot = ttyslot();
4384d522f475Smrg	    added_utmp_entry = False;
4385d522f475Smrg	    {
43860bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
4387d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
4388956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
4389894e0ac8Smrg		    copy_filled(utmp.ut_line,
4390894e0ac8Smrg				my_pty_name(ttydev),
4391894e0ac8Smrg				sizeof(utmp.ut_line));
4392894e0ac8Smrg		    copy_filled(utmp.ut_name, login_name,
4393894e0ac8Smrg				sizeof(utmp.ut_name));
4394d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4395d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
4396d522f475Smrg#endif
4397d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4398d522f475Smrg		    SetUtmpSysLen(utmp);
4399d522f475Smrg#endif
4400d522f475Smrg
4401d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
4402d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
44030bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4404d522f475Smrg		    close(i);
4405d522f475Smrg		    added_utmp_entry = True;
4406d522f475Smrg#if defined(WTMP)
4407d522f475Smrg		    if (xw->misc.login_shell &&
4408d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4409d522f475Smrg			int status;
4410d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
4411d522f475Smrg			status = close(i);
4412d522f475Smrg		    }
4413d522f475Smrg#elif defined(MNX_LASTLOG)
4414d522f475Smrg		    if (xw->misc.login_shell &&
4415d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
4416d522f475Smrg			lseek(i, (long) (screen->uid *
4417d522f475Smrg					 sizeof(utmp)), 0);
44180bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4419d522f475Smrg			close(i);
4420d522f475Smrg		    }
4421d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
4422d522f475Smrg		} else
4423d522f475Smrg		    tslot = -tslot;
4424d522f475Smrg	    }
4425d522f475Smrg
4426d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
4427d522f475Smrg	     * clean up after us.
4428d522f475Smrg	     */
4429d522f475Smrg#if OPT_PTY_HANDSHAKE
4430d522f475Smrg	    if (resource.ptyHandshake) {
4431d522f475Smrg		handshake.tty_slot = tslot;
4432d522f475Smrg	    }
4433d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4434d522f475Smrg#endif /* USE_SYSV_UTMP */
4435d522f475Smrg
4436d522f475Smrg#ifdef USE_LASTLOGX
4437d522f475Smrg	    if (xw->misc.login_shell) {
4438956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
4439d522f475Smrg		(void) strncpy(lastlogx.ll_line,
4440d522f475Smrg			       my_pty_name(ttydev),
4441d522f475Smrg			       sizeof(lastlogx.ll_line));
4442d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
4443d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
4444d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
4445d522f475Smrg	    }
4446d522f475Smrg#endif
4447d522f475Smrg
4448d522f475Smrg#ifdef USE_LASTLOG
4449d522f475Smrg	    if (xw->misc.login_shell &&
4450d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
4451d522f475Smrg		size_t size = sizeof(struct lastlog);
44520bd37d32Smrg		off_t offset = (off_t) (screen->uid * size);
4453d522f475Smrg
4454956cc18dSsnj		memset(&lastlog, 0, size);
4455d522f475Smrg		(void) strncpy(lastlog.ll_line,
4456d522f475Smrg			       my_pty_name(ttydev),
4457d522f475Smrg			       sizeof(lastlog.ll_line));
4458d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
4459d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
4460d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
44610bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
4462d522f475Smrg		}
4463d522f475Smrg		close(i);
4464d522f475Smrg	    }
4465d522f475Smrg#endif /* USE_LASTLOG */
4466d522f475Smrg
4467d522f475Smrg#if defined(USE_UTMP_SETGID)
4468d522f475Smrg	    disableSetGid();
4469d522f475Smrg	    TRACE_IDS;
4470d522f475Smrg#endif
4471d522f475Smrg
4472d522f475Smrg#if OPT_PTY_HANDSHAKE
4473d522f475Smrg	    /* Let our parent know that we set up our utmp entry
4474d522f475Smrg	     * so that it can clean up after us.
4475d522f475Smrg	     */
4476d522f475Smrg	    if (resource.ptyHandshake) {
4477d522f475Smrg		handshake.status = UTMP_ADDED;
4478d522f475Smrg		handshake.error = 0;
44790bd37d32Smrg		strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4480d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
448120d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
4482d522f475Smrg	    }
4483d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4484d522f475Smrg#endif /* USE_UTEMPTER */
4485d522f475Smrg#endif /* HAVE_UTMP */
4486d522f475Smrg
448720d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
4488d522f475Smrg	    TRACE_IDS;
4489e0a2b6dfSmrg#ifdef HAVE_INITGROUPS
44900bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
44910bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
4492d522f475Smrg		    perror("initgroups failed");
4493d522f475Smrg		    SysError(ERROR_INIGROUPS);
4494d522f475Smrg		}
4495d522f475Smrg	    }
4496d522f475Smrg#endif
4497d522f475Smrg	    if (setuid(screen->uid)) {
4498d522f475Smrg		SysError(ERROR_SETUID);
4499d522f475Smrg	    }
4500d522f475Smrg	    TRACE_IDS;
4501d522f475Smrg#if OPT_PTY_HANDSHAKE
4502d522f475Smrg	    if (resource.ptyHandshake) {
4503d522f475Smrg		/* mark the pipes as close on exec */
45040bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
45050bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
4506d522f475Smrg
4507d522f475Smrg		/* We are at the point where we are going to
4508d522f475Smrg		 * exec our shell (or whatever).  Let our parent
4509d522f475Smrg		 * know we arrived safely.
4510d522f475Smrg		 */
4511d522f475Smrg		handshake.status = PTY_GOOD;
4512d522f475Smrg		handshake.error = 0;
45130bd37d32Smrg		(void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4514d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
451520d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
451620d2c4d2Smrg				(const char *) &handshake,
451720d2c4d2Smrg				sizeof(handshake)));
4518d522f475Smrg
4519d522f475Smrg		if (resource.wait_for_map) {
452020d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
452120d2c4d2Smrg				   sizeof(handshake));
4522d522f475Smrg		    if (i != sizeof(handshake) ||
4523d522f475Smrg			handshake.status != PTY_EXEC) {
4524d522f475Smrg			/* some very bad problem occurred */
4525d522f475Smrg			exit(ERROR_PTY_EXEC);
4526d522f475Smrg		    }
4527d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
4528d522f475Smrg			TRACE(("handshake ttysize: %dx%d\n",
4529d522f475Smrg			       handshake.rows, handshake.cols));
4530d522f475Smrg			set_max_row(screen, handshake.rows);
4531d522f475Smrg			set_max_col(screen, handshake.cols);
4532d522f475Smrg#ifdef TTYSIZE_STRUCT
4533d522f475Smrg			got_handshake_size = True;
453420d2c4d2Smrg			TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
453520d2c4d2Smrg			TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
4536d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
453720d2c4d2Smrg			ts.ws_xpixel = (ttySize_t) FullWidth(screen);
453820d2c4d2Smrg			ts.ws_ypixel = (ttySize_t) FullHeight(screen);
4539d522f475Smrg#endif
4540d522f475Smrg#endif /* TTYSIZE_STRUCT */
4541d522f475Smrg		    }
4542d522f475Smrg		}
4543d522f475Smrg	    }
4544d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4545d522f475Smrg
4546d522f475Smrg#ifdef USE_SYSV_ENVVARS
4547d522f475Smrg	    {
4548d522f475Smrg		char numbuf[12];
4549d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
4550d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
4551d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
4552d522f475Smrg		xtermSetenv("LINES", numbuf);
4553d522f475Smrg	    }
4554d522f475Smrg#ifdef HAVE_UTMP
45550bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
4556d522f475Smrg		if (!x_getenv("HOME"))
45570bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
4558d522f475Smrg		if (!x_getenv("SHELL"))
45590bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
4560d522f475Smrg	    }
4561d522f475Smrg#endif /* HAVE_UTMP */
4562d522f475Smrg#ifdef OWN_TERMINFO_DIR
4563d522f475Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
4564d522f475Smrg#endif
4565d522f475Smrg#else /* USE_SYSV_ENVVARS */
456620d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
456720d2c4d2Smrg		resize_termcap(xw);
456820d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
456920d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
457020d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
457120d2c4d2Smrg		}
457220d2c4d2Smrg		/*
457320d2c4d2Smrg		 * work around broken termcap entries */
457420d2c4d2Smrg		if (resource.useInsertMode) {
457520d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
457620d2c4d2Smrg		    /* don't get duplicates */
457720d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
457820d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
457920d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
458020d2c4d2Smrg		    if (*newtc)
458120d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
458220d2c4d2Smrg		}
458320d2c4d2Smrg		if (*newtc) {
4584d522f475Smrg#if OPT_INITIAL_ERASE
458520d2c4d2Smrg		    unsigned len;
458620d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
458720d2c4d2Smrg		    len = (unsigned) strlen(newtc);
458820d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
458920d2c4d2Smrg			len--;
459020d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
459120d2c4d2Smrg			    TERMCAP_ERASE,
459220d2c4d2Smrg			    CharOf(initial_erase));
459320d2c4d2Smrg#endif
459420d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
459520d2c4d2Smrg		}
4596d522f475Smrg	    }
4597d522f475Smrg#endif /* USE_SYSV_ENVVARS */
4598d522f475Smrg
4599d522f475Smrg#if OPT_PTY_HANDSHAKE
4600d522f475Smrg	    /*
4601d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
4602d522f475Smrg	     *
4603d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
4604d522f475Smrg	     * use that to prevent races.
4605d522f475Smrg	     */
4606d522f475Smrg	    if (resource.ptyHandshake
4607d522f475Smrg		&& resource.ptySttySize
4608d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
4609d522f475Smrg#ifdef TTYSIZE_STRUCT
461020d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
4611d522f475Smrg		TRACE(("ptyHandshake SET_TTYSIZE %dx%d return %d\n",
4612d522f475Smrg		       TTYSIZE_ROWS(ts),
4613d522f475Smrg		       TTYSIZE_COLS(ts), i));
4614d522f475Smrg#endif /* TTYSIZE_STRUCT */
4615d522f475Smrg	    }
4616d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4617d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4618d522f475Smrg
46190bd37d32Smrg	    /*
4620e0a2b6dfSmrg	     * If we have an explicit shell to run, make that set $SHELL.
4621e0a2b6dfSmrg	     * Next, allow an existing setting of $SHELL, for absolute paths.
46220bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
46230bd37d32Smrg	     * password information, if possible.
46240bd37d32Smrg	     *
46250bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
46260bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
46270bd37d32Smrg	     */
4628e0a2b6dfSmrg	    if (validShell(explicit_shname)) {
4629e0a2b6dfSmrg		xtermSetenv("SHELL", explicit_shname);
4630e0a2b6dfSmrg	    } else if (validProgram(shell_path = x_getenv("SHELL"))) {
4631e0a2b6dfSmrg		if (!validShell(shell_path)) {
4632e0a2b6dfSmrg		    xtermUnsetenv("SHELL");
4633d522f475Smrg		}
4634e0a2b6dfSmrg	    } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
4635e0a2b6dfSmrg		       || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
4636e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4637e0a2b6dfSmrg	    } else if (validShell(shell_path)) {
4638e0a2b6dfSmrg		xtermSetenv("SHELL", shell_path);
4639d522f475Smrg	    } else {
4640e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4641d522f475Smrg	    }
4642e0a2b6dfSmrg
4643e0a2b6dfSmrg	    /*
4644e0a2b6dfSmrg	     * Set $XTERM_SHELL, which is not necessarily a valid shell, but
4645e0a2b6dfSmrg	     * is executable.
4646e0a2b6dfSmrg	     */
4647e0a2b6dfSmrg	    if (validProgram(explicit_shname)) {
4648e0a2b6dfSmrg		shell_path = explicit_shname;
4649e0a2b6dfSmrg	    } else if (shell_path == 0) {
4650e0a2b6dfSmrg		/* this could happen if the explicit shname lost a race */
4651e0a2b6dfSmrg		shell_path = resetShell(shell_path);
46520bd37d32Smrg	    }
46530bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
4654d522f475Smrg
46550bd37d32Smrg	    shname = x_basename(shell_path);
46560bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
4657d522f475Smrg
4658d522f475Smrg#if OPT_LUIT_PROG
4659d522f475Smrg	    /*
4660d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
4661d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
4662d522f475Smrg	     * to command that the user gave anyway.
4663d522f475Smrg	     */
46642eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
46650bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
46660bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
46670bd37d32Smrg		free(myShell);
46680bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
4669d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
46700bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
46710bd37d32Smrg		xtermWarning("cannot support your locale.\n");
4672d522f475Smrg	    }
4673d522f475Smrg#endif
4674d522f475Smrg	    if (command_to_exec) {
46750bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
46760bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
46770bd37d32Smrg		free(myShell);
46780bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
4679d522f475Smrg		execvp(*command_to_exec, command_to_exec);
4680d522f475Smrg		if (command_to_exec[1] == 0)
46810bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
46820bd37d32Smrg			   (void *) 0);
46830bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
4684d522f475Smrg	    }
4685d522f475Smrg#ifdef USE_SYSV_SIGHUP
4686d522f475Smrg	    /* fix pts sh hanging around */
4687d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4688d522f475Smrg#endif
4689d522f475Smrg
4690d522f475Smrg	    shname_minus = CastMallocN(char, strlen(shname) + 2);
4691d522f475Smrg	    (void) strcpy(shname_minus, "-");
4692d522f475Smrg	    (void) strcat(shname_minus, shname);
4693d522f475Smrg#ifndef TERMIO_STRUCT
46940bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
46950bd37d32Smrg		     ? NTTYDISC
46960bd37d32Smrg		     : 0);
4697d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
4698d522f475Smrg#endif /* !TERMIO_STRUCT */
4699d522f475Smrg
4700d522f475Smrg#ifdef USE_LOGIN_DASH_P
47010bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
4702d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
4703d522f475Smrg#endif
47042eaa94a1Schristos
47052eaa94a1Schristos#if OPT_LUIT_PROG
47062eaa94a1Schristos	    if (command_to_exec_with_luit) {
47072eaa94a1Schristos		if (xw->misc.login_shell) {
47080bd37d32Smrg		    char *params[4];
47090bd37d32Smrg		    params[0] = x_strdup("-argv0");
47100bd37d32Smrg		    params[1] = shname_minus;
47110bd37d32Smrg		    params[2] = NULL;
47120bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
47130bd37d32Smrg				 + command_length_with_luit,
47140bd37d32Smrg				 params);
47152eaa94a1Schristos		}
47160bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
47172eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
47182eaa94a1Schristos		/* Exec failed. */
47190bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
47202eaa94a1Schristos	    }
47212eaa94a1Schristos#endif
47220bd37d32Smrg	    execlp(shell_path,
4723d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
4724d522f475Smrg		   (void *) 0);
4725d522f475Smrg
4726d522f475Smrg	    /* Exec failed. */
47270bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
472820d2c4d2Smrg	    IGNORE_RC(sleep(5));
47290bd37d32Smrg	    free(shell_path);
4730d522f475Smrg	    exit(ERROR_EXEC);
4731d522f475Smrg	}
4732d522f475Smrg	/* end if in child after fork */
4733d522f475Smrg#if OPT_PTY_HANDSHAKE
4734d522f475Smrg	if (resource.ptyHandshake) {
4735d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
4736d522f475Smrg	     * child process.
4737d522f475Smrg	     */
4738d522f475Smrg
4739d522f475Smrg	    /* close childs's sides of the pipes */
4740d522f475Smrg	    close(cp_pipe[1]);
4741d522f475Smrg	    close(pc_pipe[0]);
4742d522f475Smrg
4743d522f475Smrg	    for (done = 0; !done;) {
4744d522f475Smrg		if (read(cp_pipe[0],
4745d522f475Smrg			 (char *) &handshake,
4746d522f475Smrg			 sizeof(handshake)) <= 0) {
4747d522f475Smrg		    /* Our child is done talking to us.  If it terminated
4748d522f475Smrg		     * due to an error, we will catch the death of child
4749d522f475Smrg		     * and clean up.
4750d522f475Smrg		     */
4751d522f475Smrg		    break;
4752d522f475Smrg		}
4753d522f475Smrg
4754d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
4755d522f475Smrg		switch (handshake.status) {
4756d522f475Smrg		case PTY_GOOD:
4757d522f475Smrg		    /* Success!  Let's free up resources and
4758d522f475Smrg		     * continue.
4759d522f475Smrg		     */
4760d522f475Smrg		    done = 1;
4761d522f475Smrg		    break;
4762d522f475Smrg
4763d522f475Smrg		case PTY_BAD:
4764d522f475Smrg		    /* The open of the pty failed!  Let's get
4765d522f475Smrg		     * another one.
4766d522f475Smrg		     */
476720d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
4768d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
4769d522f475Smrg			/* no more ptys! */
47700bd37d32Smrg			xtermPerror("child process can find no available ptys");
4771d522f475Smrg			handshake.status = PTY_NOMORE;
4772d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
477320d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
477420d2c4d2Smrg					(const char *) &handshake,
477520d2c4d2Smrg					sizeof(handshake)));
4776d522f475Smrg			exit(ERROR_PTYS);
4777d522f475Smrg		    }
4778d522f475Smrg		    handshake.status = PTY_NEW;
47790bd37d32Smrg		    (void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4780d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
478120d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
478220d2c4d2Smrg				    (const char *) &handshake,
478320d2c4d2Smrg				    sizeof(handshake)));
4784d522f475Smrg		    break;
4785d522f475Smrg
4786d522f475Smrg		case PTY_FATALERROR:
4787d522f475Smrg		    errno = handshake.error;
4788d522f475Smrg		    close(cp_pipe[0]);
4789d522f475Smrg		    close(pc_pipe[1]);
4790d522f475Smrg		    SysError(handshake.fatal_error);
4791d522f475Smrg		    /*NOTREACHED */
4792d522f475Smrg
4793d522f475Smrg		case UTMP_ADDED:
4794d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
4795d522f475Smrg		     * this so that we can reset it later.
4796d522f475Smrg		     */
4797d522f475Smrg		    added_utmp_entry = True;
4798d522f475Smrg#ifndef	USE_SYSV_UTMP
4799d522f475Smrg		    tslot = handshake.tty_slot;
4800d522f475Smrg#endif /* USE_SYSV_UTMP */
4801d522f475Smrg		    free(ttydev);
4802d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
4803d522f475Smrg		    break;
4804d522f475Smrg		case PTY_NEW:
4805d522f475Smrg		case PTY_NOMORE:
4806d522f475Smrg		case UTMP_TTYSLOT:
4807d522f475Smrg		case PTY_EXEC:
4808d522f475Smrg		default:
48090bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
48100bd37d32Smrg				 (int) handshake.status);
4811d522f475Smrg		}
4812d522f475Smrg	    }
4813d522f475Smrg	    /* close our sides of the pipes */
4814d522f475Smrg	    if (!resource.wait_for_map) {
4815d522f475Smrg		close(cp_pipe[0]);
4816d522f475Smrg		close(pc_pipe[1]);
4817d522f475Smrg	    }
4818d522f475Smrg	}
4819d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4820d522f475Smrg    }
4821d522f475Smrg
4822d522f475Smrg    /* end if no slave */
4823d522f475Smrg    /*
4824d522f475Smrg     * still in parent (xterm process)
4825d522f475Smrg     */
4826d522f475Smrg#ifdef USE_SYSV_SIGHUP
4827d522f475Smrg    /* hung sh problem? */
4828d522f475Smrg    signal(SIGHUP, SIG_DFL);
4829d522f475Smrg#else
4830d522f475Smrg    signal(SIGHUP, SIG_IGN);
4831d522f475Smrg#endif
4832d522f475Smrg
4833d522f475Smrg/*
4834d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
4835d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
4836d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
4837d522f475Smrg * don't ignore the signals.  This is annoying.
4838d522f475Smrg */
4839d522f475Smrg
4840d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
4841d522f475Smrg    signal(SIGINT, SIG_IGN);
4842d522f475Smrg
4843d522f475Smrg#ifndef SYSV
4844d522f475Smrg    /* hung shell problem */
4845d522f475Smrg    signal(SIGQUIT, SIG_IGN);
4846d522f475Smrg#endif
4847d522f475Smrg    signal(SIGTERM, SIG_IGN);
4848d522f475Smrg#elif defined(SYSV) || defined(__osf__)
4849d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
4850d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
4851d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
4852d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
4853d522f475Smrg     * tank on everything.
4854d522f475Smrg     */
4855d522f475Smrg    if (getpid() == getpgrp()) {
4856d522f475Smrg	(void) signal(SIGINT, Exit);
4857d522f475Smrg	(void) signal(SIGQUIT, Exit);
4858d522f475Smrg	(void) signal(SIGTERM, Exit);
4859d522f475Smrg    } else {
4860d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
4861d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
4862d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
4863d522f475Smrg    }
4864d522f475Smrg    (void) signal(SIGPIPE, Exit);
4865d522f475Smrg#else /* SYSV */
4866d522f475Smrg    signal(SIGINT, Exit);
4867d522f475Smrg    signal(SIGQUIT, Exit);
4868d522f475Smrg    signal(SIGTERM, Exit);
4869d522f475Smrg    signal(SIGPIPE, Exit);
4870d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
48710bd37d32Smrg#ifdef NO_LEAKS
48720bd37d32Smrg    if (ok_termcap != True)
48730bd37d32Smrg	free(TermName);
48740bd37d32Smrg#endif
4875d522f475Smrg
4876d522f475Smrg    return 0;
4877d522f475Smrg}				/* end spawnXTerm */
4878d522f475Smrg
48790bd37d32Smrgvoid
4880d522f475SmrgExit(int n)
4881d522f475Smrg{
488220d2c4d2Smrg    XtermWidget xw = term;
488320d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
4884d522f475Smrg
4885d522f475Smrg#ifdef USE_UTEMPTER
48860bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
48870bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
48880bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
4889d522f475Smrg	removeFromUtmp();
48900bd37d32Smrg    }
4891d522f475Smrg#elif defined(HAVE_UTMP)
4892d522f475Smrg#ifdef USE_SYSV_UTMP
4893d522f475Smrg    struct UTMP_STR utmp;
4894d522f475Smrg    struct UTMP_STR *utptr;
4895d522f475Smrg
48960bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
4897d522f475Smrg    /* don't do this more than once */
48980bd37d32Smrg    if (xterm_exiting) {
48990bd37d32Smrg	exit(n);
49000bd37d32Smrg    }
4901d522f475Smrg    xterm_exiting = True;
4902d522f475Smrg
4903d522f475Smrg#ifdef PUCC_PTYD
4904d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
4905d522f475Smrg#endif /* PUCC_PTYD */
4906d522f475Smrg
4907d522f475Smrg    /* cleanup the utmp entry we forged earlier */
4908d522f475Smrg    if (!resource.utmpInhibit
4909d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
4910d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
4911d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4912d522f475Smrg	) {
4913d522f475Smrg#if defined(USE_UTMP_SETGID)
4914d522f475Smrg	setEffectiveGroup(save_egid);
4915d522f475Smrg	TRACE_IDS;
4916d522f475Smrg#endif
4917d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
4918d522f475Smrg	(void) call_setutent();
4919d522f475Smrg
4920d522f475Smrg	/*
4921d522f475Smrg	 * We could use getutline() if we didn't support old systems.
4922d522f475Smrg	 */
4923d522f475Smrg	while ((utptr = find_utmp(&utmp)) != 0) {
4924d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
4925d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
4926d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4927d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4928d522f475Smrg		utptr->ut_session = getsid(0);
4929d522f475Smrg#endif
4930d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
4931d522f475Smrg		utptr->ut_tv.tv_usec = 0;
4932d522f475Smrg#else
4933d522f475Smrg		*utptr->ut_user = 0;
4934d522f475Smrg		utptr->ut_time = time((time_t *) 0);
4935d522f475Smrg#endif
4936d522f475Smrg		(void) call_pututline(utptr);
4937d522f475Smrg#ifdef WTMP
4938d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
493920d2c4d2Smrg		if (xw->misc.login_shell)
4940d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
4941d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4942894e0ac8Smrg		copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
494320d2c4d2Smrg		if (xw->misc.login_shell)
4944d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
4945d522f475Smrg#else
4946d522f475Smrg		/* set wtmp entry if wtmp file exists */
494720d2c4d2Smrg		if (xw->misc.login_shell) {
4948d522f475Smrg		    int fd;
4949d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
49500bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
4951d522f475Smrg			close(fd);
4952d522f475Smrg		    }
4953d522f475Smrg		}
4954d522f475Smrg#endif
4955d522f475Smrg#endif
4956d522f475Smrg		break;
4957d522f475Smrg	    }
4958d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
4959d522f475Smrg	}
4960d522f475Smrg	(void) call_endutent();
4961d522f475Smrg#ifdef USE_UTMP_SETGID
4962d522f475Smrg	disableSetGid();
4963d522f475Smrg	TRACE_IDS;
4964d522f475Smrg#endif
4965d522f475Smrg    }
4966d522f475Smrg#else /* not USE_SYSV_UTMP */
4967d522f475Smrg    int wfd;
4968d522f475Smrg    struct utmp utmp;
4969d522f475Smrg
49700bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
4971d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
4972d522f475Smrg	(am_slave < 0 && tslot > 0)) {
4973d522f475Smrg#if defined(USE_UTMP_SETGID)
4974d522f475Smrg	setEffectiveGroup(save_egid);
4975d522f475Smrg	TRACE_IDS;
4976d522f475Smrg#endif
4977d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
4978956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
4979d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
49800bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
4981d522f475Smrg	    close(wfd);
4982d522f475Smrg	}
4983d522f475Smrg#ifdef WTMP
498420d2c4d2Smrg	if (xw->misc.login_shell &&
4985d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4986894e0ac8Smrg	    copy_filled(utmp.ut_line,
4987894e0ac8Smrg			my_pty_name(ttydev),
4988894e0ac8Smrg			sizeof(utmp.ut_line));
4989d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
49900bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
4991d522f475Smrg	    close(wfd);
4992d522f475Smrg	}
4993d522f475Smrg#endif /* WTMP */
4994d522f475Smrg#ifdef USE_UTMP_SETGID
4995d522f475Smrg	disableSetGid();
4996d522f475Smrg	TRACE_IDS;
4997d522f475Smrg#endif
4998d522f475Smrg    }
4999d522f475Smrg#endif /* USE_SYSV_UTMP */
5000d522f475Smrg#endif /* HAVE_UTMP */
5001d522f475Smrg
5002e0a2b6dfSmrg    cleanup_colored_cursor();
5003e0a2b6dfSmrg
5004d522f475Smrg    /*
5005d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
5006d522f475Smrg     * in the middle of the data.
5007d522f475Smrg     */
5008d522f475Smrg    ttyFlush(screen->respond);
5009d522f475Smrg
5010e39b573cSmrg#ifdef USE_PTY_SEARCH
5011d522f475Smrg    if (am_slave < 0) {
5012d522f475Smrg	TRACE_IDS;
5013d522f475Smrg	/* restore ownership of tty and pty */
5014d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
5015d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
5016d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
5017d522f475Smrg#endif
5018d522f475Smrg    }
5019e39b573cSmrg#endif
5020d522f475Smrg
5021d522f475Smrg    /*
50220bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
5023d522f475Smrg     * grabbing it, and *then* having us release ownership....
5024d522f475Smrg     */
5025d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
5026d522f475Smrg#ifdef ALLOWLOGGING
5027d522f475Smrg    if (screen->logging)
502820d2c4d2Smrg	CloseLog(xw);
5029d522f475Smrg#endif
5030d522f475Smrg
5031e39b573cSmrg    xtermPrintOnXError(xw, n);
5032e39b573cSmrg
5033d522f475Smrg#ifdef NO_LEAKS
5034d522f475Smrg    if (n == 0) {
50350bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
50360bd37d32Smrg
5037d522f475Smrg	TRACE(("Freeing memory leaks\n"));
5038d522f475Smrg
50390bd37d32Smrg	if (toplevel) {
50400bd37d32Smrg	    XtDestroyWidget(toplevel);
50410bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
50420bd37d32Smrg	}
50430bd37d32Smrg	sortedOpts(0, 0, 0);
50440bd37d32Smrg	noleaks_charproc();
50450bd37d32Smrg	noleaks_ptydata();
5046894e0ac8Smrg#if OPT_GRAPHICS
5047894e0ac8Smrg	noleaks_graphics();
5048894e0ac8Smrg#endif
5049d522f475Smrg#if OPT_WIDE_CHARS
50500bd37d32Smrg	noleaks_CharacterClass();
5051d522f475Smrg#endif
50520bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
50530bd37d32Smrg	XtCloseDisplay(dpy);
50540bd37d32Smrg	XtDestroyApplicationContext(app_con);
50550bd37d32Smrg	xtermCloseSession();
50560bd37d32Smrg	TRACE(("closed display\n"));
50570bd37d32Smrg
505820d2c4d2Smrg	TRACE_CLOSE();
5059d522f475Smrg    }
5060d522f475Smrg#endif
5061d522f475Smrg
5062d522f475Smrg    exit(n);
5063d522f475Smrg}
5064d522f475Smrg
5065d522f475Smrg/* ARGSUSED */
5066d522f475Smrgstatic void
506720d2c4d2Smrgresize_termcap(XtermWidget xw)
5068d522f475Smrg{
506920d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
507020d2c4d2Smrg
5071d522f475Smrg#ifndef USE_SYSV_ENVVARS
5072d522f475Smrg    if (!TEK4014_ACTIVE(xw) && *newtc) {
5073d522f475Smrg	TScreen *screen = TScreenOf(xw);
5074d522f475Smrg	char *ptr1, *ptr2;
5075d522f475Smrg	size_t i;
5076d522f475Smrg	int li_first = 0;
5077d522f475Smrg	char *temp;
5078d522f475Smrg	char oldtc[TERMCAP_SIZE];
5079d522f475Smrg
5080d522f475Smrg	strcpy(oldtc, newtc);
5081d522f475Smrg	TRACE(("resize %s\n", oldtc));
5082d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
5083d522f475Smrg	    strcat(oldtc, "co#80:");
5084d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
5085d522f475Smrg	}
5086d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
5087d522f475Smrg	    strcat(oldtc, "li#24:");
5088d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
5089d522f475Smrg	}
5090d522f475Smrg	if (ptr1 > ptr2) {
5091d522f475Smrg	    li_first++;
5092d522f475Smrg	    temp = ptr1;
5093d522f475Smrg	    ptr1 = ptr2;
5094d522f475Smrg	    ptr2 = temp;
5095d522f475Smrg	}
5096d522f475Smrg	ptr1 += 3;
5097d522f475Smrg	ptr2 += 3;
5098956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
5099d522f475Smrg	temp = newtc + i;
5100d522f475Smrg	sprintf(temp, "%d", (li_first
5101d522f475Smrg			     ? MaxRows(screen)
5102d522f475Smrg			     : MaxCols(screen)));
5103d522f475Smrg	temp += strlen(temp);
51040bd37d32Smrg	if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) {
51050bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
51060bd37d32Smrg	    temp += i;
51070bd37d32Smrg	    sprintf(temp, "%d", (li_first
51080bd37d32Smrg				 ? MaxCols(screen)
51090bd37d32Smrg				 : MaxRows(screen)));
51100bd37d32Smrg	    if ((ptr2 = strchr(ptr2, ':')) != 0) {
51110bd37d32Smrg		strcat(temp, ptr2);
51120bd37d32Smrg	    }
51130bd37d32Smrg	}
5114d522f475Smrg	TRACE(("   ==> %s\n", newtc));
5115d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
5116d522f475Smrg    }
5117d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5118d522f475Smrg}
5119d522f475Smrg
5120d522f475Smrg#endif /* ! VMS */
5121d522f475Smrg
5122d522f475Smrg/*
5123d522f475Smrg * Does a non-blocking wait for a child process.  If the system
5124d522f475Smrg * doesn't support non-blocking wait, do nothing.
5125d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
5126d522f475Smrg */
5127d522f475Smrgint
5128d522f475Smrgnonblocking_wait(void)
5129d522f475Smrg{
5130d522f475Smrg#ifdef USE_POSIX_WAIT
5131d522f475Smrg    pid_t pid;
5132d522f475Smrg
5133d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5134d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5135d522f475Smrg    /* cannot do non-blocking wait */
5136d522f475Smrg    int pid = 0;
5137d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5138d522f475Smrg#if defined(Lynx)
5139d522f475Smrg    int status;
5140d522f475Smrg#else
5141d522f475Smrg    union wait status;
5142d522f475Smrg#endif
5143d522f475Smrg    int pid;
5144d522f475Smrg
5145d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5146d522f475Smrg#endif /* USE_POSIX_WAIT else */
5147d522f475Smrg    return pid;
5148d522f475Smrg}
5149d522f475Smrg
5150d522f475Smrg#ifndef VMS
5151d522f475Smrg
5152d522f475Smrg/* ARGSUSED */
51530bd37d32Smrgstatic void
5154d522f475Smrgreapchild(int n GCC_UNUSED)
5155d522f475Smrg{
5156d522f475Smrg    int olderrno = errno;
5157d522f475Smrg    int pid;
5158d522f475Smrg
51590bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
51600bd37d32Smrg
5161d522f475Smrg    pid = wait(NULL);
5162d522f475Smrg
5163d522f475Smrg#ifdef USE_SYSV_SIGNALS
5164d522f475Smrg    /* cannot re-enable signal before waiting for child
5165d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5166d522f475Smrg     */
5167d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5168d522f475Smrg#endif
5169d522f475Smrg
5170d522f475Smrg    do {
517120d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
51720bd37d32Smrg	    DEBUG_MSG("Exiting\n");
5173d522f475Smrg	    if (!hold_screen)
5174d522f475Smrg		need_cleanup = True;
5175d522f475Smrg	}
5176d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5177d522f475Smrg
5178d522f475Smrg    errno = olderrno;
5179d522f475Smrg}
5180d522f475Smrg#endif /* !VMS */
5181d522f475Smrg
5182d522f475Smrgstatic void
518320d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5184d522f475Smrg{
5185d522f475Smrg    char *base = buf;
5186d522f475Smrg    char *first = base;
5187d522f475Smrg    int count = 0;
5188d522f475Smrg    size_t len = strlen(str);
5189d522f475Smrg
5190d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5191d522f475Smrg
5192d522f475Smrg    while (*buf != 0) {
5193d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5194d522f475Smrg	    while (*buf != 0) {
5195d522f475Smrg		if (*buf == '\\')
5196d522f475Smrg		    buf++;
5197d522f475Smrg		else if (*buf == ':')
5198d522f475Smrg		    break;
5199d522f475Smrg		if (*buf != 0)
5200d522f475Smrg		    buf++;
5201d522f475Smrg	    }
52020bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
52030bd37d32Smrg		;
52040bd37d32Smrg	    }
5205d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5206d522f475Smrg	    return;
5207d522f475Smrg	} else if (*buf == '\\') {
5208d522f475Smrg	    buf++;
5209d522f475Smrg	} else if (*buf == ':') {
5210d522f475Smrg	    first = buf;
5211d522f475Smrg	    count = 0;
5212d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5213d522f475Smrg	    count++;
5214d522f475Smrg	}
5215d522f475Smrg	if (*buf != 0)
5216d522f475Smrg	    buf++;
5217d522f475Smrg    }
5218d522f475Smrg    TRACE(("...cannot remove\n"));
5219d522f475Smrg}
5220d522f475Smrg
5221d522f475Smrg/*
5222d522f475Smrg * parse_tty_modes accepts lines of the following form:
5223d522f475Smrg *
5224d522f475Smrg *         [SETTING] ...
5225d522f475Smrg *
5226d522f475Smrg * where setting consists of the words in the modelist followed by a character
5227d522f475Smrg * or ^char.
5228d522f475Smrg */
5229d522f475Smrgstatic int
5230d522f475Smrgparse_tty_modes(char *s, struct _xttymodes *modelist)
5231d522f475Smrg{
5232d522f475Smrg    struct _xttymodes *mp;
5233d522f475Smrg    int c;
5234d522f475Smrg    int count = 0;
5235d522f475Smrg
5236d522f475Smrg    TRACE(("parse_tty_modes\n"));
5237a1f3da82Smrg    for (;;) {
5238d522f475Smrg	size_t len;
5239d522f475Smrg
5240d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5241d522f475Smrg	    s++;
5242d522f475Smrg	if (!*s)
5243d522f475Smrg	    return count;
5244d522f475Smrg
5245d522f475Smrg	for (len = 0; isalnum(CharOf(s[len])); ++len) ;
5246d522f475Smrg	for (mp = modelist; mp->name; mp++) {
5247d522f475Smrg	    if (len == mp->len
5248d522f475Smrg		&& strncmp(s, mp->name, mp->len) == 0)
5249d522f475Smrg		break;
5250d522f475Smrg	}
5251d522f475Smrg	if (!mp->name)
5252d522f475Smrg	    return -1;
5253d522f475Smrg
5254d522f475Smrg	s += mp->len;
5255d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5256d522f475Smrg	    s++;
5257d522f475Smrg	if (!*s)
5258d522f475Smrg	    return -1;
5259d522f475Smrg
5260d522f475Smrg	if ((c = decode_keyvalue(&s, False)) != -1) {
5261d522f475Smrg	    mp->value = c;
5262d522f475Smrg	    mp->set = 1;
5263d522f475Smrg	    count++;
5264d522f475Smrg	    TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
5265d522f475Smrg	}
5266d522f475Smrg    }
5267d522f475Smrg}
5268d522f475Smrg
5269d522f475Smrg#ifndef VMS			/* don't use pipes on OpenVMS */
5270d522f475Smrgint
5271d522f475SmrgGetBytesAvailable(int fd)
5272d522f475Smrg{
5273d522f475Smrg#if defined(FIONREAD)
5274d522f475Smrg    int arg;
5275d522f475Smrg    ioctl(fd, FIONREAD, (char *) &arg);
5276d522f475Smrg    return (int) arg;
5277d522f475Smrg#elif defined(__CYGWIN__)
5278d522f475Smrg    fd_set set;
527920d2c4d2Smrg    struct timeval select_timeout =
5280d522f475Smrg    {0, 0};
5281d522f475Smrg
5282d522f475Smrg    FD_ZERO(&set);
5283d522f475Smrg    FD_SET(fd, &set);
528420d2c4d2Smrg    if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0)
5285d522f475Smrg	return 1;
5286d522f475Smrg    else
5287d522f475Smrg	return 0;
5288d522f475Smrg#elif defined(FIORDCK)
5289d522f475Smrg    return (ioctl(fd, FIORDCHK, NULL));
5290d522f475Smrg#else /* !FIORDCK */
5291d522f475Smrg    struct pollfd pollfds[1];
5292d522f475Smrg
5293d522f475Smrg    pollfds[0].fd = fd;
5294d522f475Smrg    pollfds[0].events = POLLIN;
5295d522f475Smrg    return poll(pollfds, 1, 0);
5296d522f475Smrg#endif
5297d522f475Smrg}
5298d522f475Smrg#endif /* !VMS */
5299d522f475Smrg
5300d522f475Smrg/* Utility function to try to hide system differences from
5301d522f475Smrg   everybody who used to call killpg() */
5302d522f475Smrg
5303d522f475Smrgint
5304d522f475Smrgkill_process_group(int pid, int sig)
5305d522f475Smrg{
5306d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5307d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5308d522f475Smrg    return kill(-pid, sig);
5309d522f475Smrg#else
5310d522f475Smrg    return killpg(pid, sig);
5311d522f475Smrg#endif
5312d522f475Smrg}
5313d522f475Smrg
5314d522f475Smrg#if OPT_EBCDIC
5315d522f475Smrgint
5316d522f475SmrgA2E(int x)
5317d522f475Smrg{
5318d522f475Smrg    char c;
5319d522f475Smrg    c = x;
5320d522f475Smrg    __atoe_l(&c, 1);
5321d522f475Smrg    return c;
5322d522f475Smrg}
5323d522f475Smrg
5324d522f475Smrgint
5325d522f475SmrgE2A(int x)
5326d522f475Smrg{
5327d522f475Smrg    char c;
5328d522f475Smrg    c = x;
5329d522f475Smrg    __etoa_l(&c, 1);
5330d522f475Smrg    return c;
5331d522f475Smrg}
5332d522f475Smrg#endif
5333d522f475Smrg
5334d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
5335d522f475Smrg#include <sys/types.h>
5336d522f475Smrg#include <sys/proc_msg.h>
5337d522f475Smrg#include <sys/kernel.h>
5338d522f475Smrg#include <string.h>
5339d522f475Smrg#include <errno.h>
5340d522f475Smrg
5341d522f475Smrgstruct _proc_session ps;
5342d522f475Smrgstruct _proc_session_reply rps;
5343d522f475Smrg
5344d522f475Smrgint
5345d522f475Smrgqsetlogin(char *login, char *ttyname)
5346d522f475Smrg{
5347d522f475Smrg    int v = getsid(getpid());
5348d522f475Smrg
5349d522f475Smrg    memset(&ps, 0, sizeof(ps));
5350d522f475Smrg    memset(&rps, 0, sizeof(rps));
5351d522f475Smrg
5352d522f475Smrg    ps.type = _PROC_SESSION;
5353d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
5354d522f475Smrg    ps.sid = v;
5355d522f475Smrg    strcpy(ps.name, login);
5356d522f475Smrg
5357d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5358d522f475Smrg
5359d522f475Smrg    if (rps.status < 0)
5360d522f475Smrg	return (rps.status);
5361d522f475Smrg
5362d522f475Smrg    ps.type = _PROC_SESSION;
5363d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
5364d522f475Smrg    ps.sid = v;
5365d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
5366d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5367d522f475Smrg
5368d522f475Smrg    return (rps.status);
5369d522f475Smrg}
5370d522f475Smrg#endif
5371