main.c revision e0a2b6df
1e0a2b6dfSmrg/* $XTermId: main.c,v 1.751 2014/03/07 02:35:39 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>
94d522f475Smrg
95d522f475Smrg#include <X11/cursorfont.h>
96d522f475Smrg#include <X11/Xlocale.h>
97d522f475Smrg
98d522f475Smrg#if OPT_TOOLBAR
99d522f475Smrg
100d522f475Smrg#if defined(HAVE_LIB_XAW)
101d522f475Smrg#include <X11/Xaw/Form.h>
102d522f475Smrg#elif defined(HAVE_LIB_XAW3D)
103d522f475Smrg#include <X11/Xaw3d/Form.h>
104d522f475Smrg#elif defined(HAVE_LIB_NEXTAW)
105d522f475Smrg#include <X11/neXtaw/Form.h>
106d522f475Smrg#elif defined(HAVE_LIB_XAWPLUS)
107d522f475Smrg#include <X11/XawPlus/Form.h>
108d522f475Smrg#endif
109d522f475Smrg
110d522f475Smrg#endif /* OPT_TOOLBAR */
111d522f475Smrg
112d522f475Smrg#include <pwd.h>
113d522f475Smrg#include <ctype.h>
114d522f475Smrg
115d522f475Smrg#include <data.h>
116d522f475Smrg#include <error.h>
117d522f475Smrg#include <menu.h>
118d522f475Smrg#include <main.h>
119d522f475Smrg#include <xstrings.h>
120d522f475Smrg#include <xtermcap.h>
121d522f475Smrg#include <xterm_io.h>
122d522f475Smrg
123d522f475Smrg#if OPT_WIDE_CHARS
124d522f475Smrg#include <charclass.h>
125d522f475Smrg#endif
126d522f475Smrg
127d522f475Smrg#ifdef __osf__
128d522f475Smrg#define USE_SYSV_SIGNALS
129d522f475Smrg#define WTMP
130d522f475Smrg#include <pty.h>		/* openpty() */
131d522f475Smrg#endif
132d522f475Smrg
133d522f475Smrg#ifdef __sgi
134d522f475Smrg#include <grp.h>		/* initgroups() */
135d522f475Smrg#endif
136d522f475Smrg
1370bd37d32Smrgstatic void Syntax(char *) GCC_NORETURN;
1380bd37d32Smrgstatic void HsSysError(int) GCC_NORETURN;
139d522f475Smrg
140d522f475Smrg#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE)
141d522f475Smrg#define USE_POSIX_SIGNALS
142d522f475Smrg#endif
143d522f475Smrg
144d522f475Smrg#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
145d522f475Smrg/* older SYSV systems cannot ignore SIGHUP.
146d522f475Smrg   Shell hangs, or you get extra shells, or something like that */
147d522f475Smrg#define USE_SYSV_SIGHUP
148d522f475Smrg#endif
149d522f475Smrg
150d522f475Smrg#if defined(sony) && defined(bsd43) && !defined(KANJI)
151d522f475Smrg#define KANJI
152d522f475Smrg#endif
153d522f475Smrg
154d522f475Smrg#ifdef linux
155d522f475Smrg#define USE_SYSV_PGRP
156d522f475Smrg#define USE_SYSV_SIGNALS
157d522f475Smrg#define WTMP
158d522f475Smrg#ifdef __GLIBC__
159d522f475Smrg#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
160d522f475Smrg#include <pty.h>
161d522f475Smrg#endif
162d522f475Smrg#endif
163d522f475Smrg#endif
164d522f475Smrg
165d522f475Smrg#ifdef __MVS__
166d522f475Smrg#define USE_SYSV_PGRP
167d522f475Smrg#define USE_SYSV_SIGNALS
168d522f475Smrg#endif
169d522f475Smrg
170d522f475Smrg#ifdef __CYGWIN__
171d522f475Smrg#define WTMP
172d522f475Smrg#endif
173d522f475Smrg
174d522f475Smrg#ifdef __SCO__
175d522f475Smrg#ifndef _SVID3
176d522f475Smrg#define _SVID3
177d522f475Smrg#endif
178d522f475Smrg#endif
179d522f475Smrg
180d522f475Smrg#if defined(__GLIBC__) && !defined(linux)
181d522f475Smrg#define USE_SYSV_PGRP
182d522f475Smrg#define WTMP
183d522f475Smrg#endif
184d522f475Smrg
185d522f475Smrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID)
186d522f475Smrg#include <grp.h>
187d522f475Smrg#endif
188d522f475Smrg
189d522f475Smrg#ifndef TTY_GROUP_NAME
190d522f475Smrg#define TTY_GROUP_NAME "tty"
191d522f475Smrg#endif
192d522f475Smrg
193d522f475Smrg#include <sys/stat.h>
194d522f475Smrg
195d522f475Smrg#ifdef Lynx
196d522f475Smrg#ifndef BSDLY
197d522f475Smrg#define BSDLY	0
198d522f475Smrg#endif
199d522f475Smrg#ifndef VTDLY
200d522f475Smrg#define VTDLY	0
201d522f475Smrg#endif
202d522f475Smrg#ifndef FFDLY
203d522f475Smrg#define FFDLY	0
204d522f475Smrg#endif
205d522f475Smrg#endif
206d522f475Smrg
207d522f475Smrg#ifdef SYSV			/* { */
208d522f475Smrg
209d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
210d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
211d522f475Smrg#include <poll.h>		/* for POLLIN */
212d522f475Smrg#endif /* USE_USG_PTYS */
213d522f475Smrg
214d522f475Smrg#define USE_SYSV_SIGNALS
215d522f475Smrg#define	USE_SYSV_PGRP
216d522f475Smrg
217d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
218d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
219d522f475Smrg#endif
220d522f475Smrg
221d522f475Smrg/*
222d522f475Smrg * now get system-specific includes
223d522f475Smrg */
224d522f475Smrg#ifdef macII
225d522f475Smrg#include <sys/ttychars.h>
226d522f475Smrg#undef USE_SYSV_ENVVARS
227d522f475Smrg#undef FIOCLEX
228d522f475Smrg#undef FIONCLEX
229d522f475Smrg#define setpgrp2 setpgrp
230d522f475Smrg#include <sgtty.h>
231d522f475Smrg#include <sys/resource.h>
232d522f475Smrg#endif
233d522f475Smrg
234d522f475Smrg#ifdef __hpux
235d522f475Smrg#include <sys/ptyio.h>
236d522f475Smrg#endif /* __hpux */
237d522f475Smrg
238d522f475Smrg#ifdef __osf__
239d522f475Smrg#undef  USE_SYSV_PGRP
240d522f475Smrg#define setpgrp setpgid
241d522f475Smrg#endif
242d522f475Smrg
243d522f475Smrg#ifdef __sgi
244d522f475Smrg#include <sys/sysmacros.h>
245d522f475Smrg#endif /* __sgi */
246d522f475Smrg
247d522f475Smrg#ifdef sun
248d522f475Smrg#include <sys/strredir.h>
249d522f475Smrg#endif
250d522f475Smrg
251e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
252d522f475Smrg
253d522f475Smrg#ifdef __QNX__
254d522f475Smrg
255d522f475Smrg#ifndef __QNXNTO__
256d522f475Smrg#define ttyslot() 1
257d522f475Smrg#else
258d522f475Smrg#define USE_SYSV_PGRP
259d522f475Smrgextern __inline__
260d522f475Smrgint
261d522f475Smrgttyslot(void)
262d522f475Smrg{
263d522f475Smrg    return 1;			/* yuk */
264d522f475Smrg}
265d522f475Smrg#endif
266d522f475Smrg
267d522f475Smrg#else
268d522f475Smrg
269d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
270d522f475Smrg#define setpgrp setpgid
271d522f475Smrg#endif
272d522f475Smrg
273d522f475Smrg#ifndef linux
274d522f475Smrg#ifndef VMS
275d522f475Smrg#ifndef USE_POSIX_TERMIOS
276d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
277d522f475Smrg#include <sgtty.h>
278d522f475Smrg#endif
279d522f475Smrg#endif /* USE_POSIX_TERMIOS */
280d522f475Smrg#ifdef Lynx
281d522f475Smrg#include <resource.h>
282d522f475Smrg#else
283d522f475Smrg#include <sys/resource.h>
284d522f475Smrg#endif
285d522f475Smrg#endif /* !VMS */
286d522f475Smrg#endif /* !linux */
287d522f475Smrg
288d522f475Smrg#endif /* __QNX__ */
289d522f475Smrg
290d522f475Smrg#endif /* } !SYSV */
291d522f475Smrg
292d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
293d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
294d522f475Smrg#ifndef NOFILE
295d522f475Smrg#define NOFILE OPEN_MAX
296d522f475Smrg#endif
297d522f475Smrg#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
298d522f475Smrg#include <sys/param.h>		/* for NOFILE */
299d522f475Smrg#endif
300d522f475Smrg
301d522f475Smrg#if defined(BSD) && (BSD >= 199103)
302d522f475Smrg#define WTMP
303d522f475Smrg#endif
304d522f475Smrg
305d522f475Smrg#include <stdio.h>
306d522f475Smrg
307d522f475Smrg#ifdef __hpux
308d522f475Smrg#include <sys/utsname.h>
309d522f475Smrg#endif /* __hpux */
310d522f475Smrg
311d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
312d522f475Smrg#define ttyslot() 1
313d522f475Smrg#endif /* apollo */
314d522f475Smrg
315d522f475Smrg#if defined(UTMPX_FOR_UTMP)
316d522f475Smrg#define UTMP_STR utmpx
317d522f475Smrg#else
318d522f475Smrg#define UTMP_STR utmp
319d522f475Smrg#endif
320d522f475Smrg
321d522f475Smrg#if defined(USE_UTEMPTER)
322d522f475Smrg#include <utempter.h>
323d522f475Smrg#endif
324d522f475Smrg
325d522f475Smrg#if defined(UTMPX_FOR_UTMP)
326d522f475Smrg
327d522f475Smrg#include <utmpx.h>
328d522f475Smrg
329d522f475Smrg#define call_endutent  endutxent
330d522f475Smrg#define call_getutid   getutxid
331d522f475Smrg#define call_pututline pututxline
332d522f475Smrg#define call_setutent  setutxent
333d522f475Smrg#define call_updwtmp   updwtmpx
334d522f475Smrg
335d522f475Smrg#elif defined(HAVE_UTMP)
336d522f475Smrg
337d522f475Smrg#include <utmp.h>
338d522f475Smrg
339d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
340d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
341d522f475Smrg#endif
342d522f475Smrg
343d522f475Smrg#define call_endutent  endutent
344d522f475Smrg#define call_getutid   getutid
345d522f475Smrg#define call_pututline pututline
346d522f475Smrg#define call_setutent  setutent
347d522f475Smrg#define call_updwtmp   updwtmp
348d522f475Smrg
349d522f475Smrg#endif
350d522f475Smrg
351d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
352d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
353d522f475Smrg#endif
354d522f475Smrg
355d522f475Smrg#ifndef USE_LASTLOGX
356d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
357d522f475Smrg#define USE_LASTLOGX 1
358d522f475Smrg#endif
359d522f475Smrg#endif
360d522f475Smrg
361d522f475Smrg#ifdef  PUCC_PTYD
362d522f475Smrg#include <local/openpty.h>
363d522f475Smrg#endif /* PUCC_PTYD */
364d522f475Smrg
365d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
366d522f475Smrg#include <util.h>		/* openpty() */
367d522f475Smrg#endif
368d522f475Smrg
369956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
370d522f475Smrg#include <libutil.h>		/* openpty() */
371d522f475Smrg#endif
372d522f475Smrg
373d522f475Smrg#if !defined(UTMP_FILENAME)
374d522f475Smrg#if defined(UTMP_FILE)
375d522f475Smrg#define UTMP_FILENAME UTMP_FILE
376d522f475Smrg#elif defined(_PATH_UTMP)
377d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
378d522f475Smrg#else
379d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
380d522f475Smrg#endif
381d522f475Smrg#endif
382d522f475Smrg
383d522f475Smrg#ifndef LASTLOG_FILENAME
384d522f475Smrg#ifdef _PATH_LASTLOG
385d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
386d522f475Smrg#else
387d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
388d522f475Smrg#endif
389d522f475Smrg#endif
390d522f475Smrg
391d522f475Smrg#if !defined(WTMP_FILENAME)
392d522f475Smrg#if defined(WTMP_FILE)
393d522f475Smrg#define WTMP_FILENAME WTMP_FILE
394d522f475Smrg#elif defined(_PATH_WTMP)
395d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
396d522f475Smrg#elif defined(SYSV)
397d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
398d522f475Smrg#else
399d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
400d522f475Smrg#endif
401d522f475Smrg#endif
402d522f475Smrg
403d522f475Smrg#include <signal.h>
404d522f475Smrg
405d522f475Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
406d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
407d522f475Smrg#endif
408d522f475Smrg
409d522f475Smrg#ifdef SIGTSTP
410d522f475Smrg#include <sys/wait.h>
411d522f475Smrg#endif
412d522f475Smrg
413d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
414d522f475Smrg#undef ECHOKE
415d522f475Smrg#undef ECHOCTL
416d522f475Smrg#endif
417d522f475Smrg
418d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
419d522f475Smrg#include <sys/ttydefaults.h>
420d522f475Smrg#endif
421d522f475Smrg
422d522f475Smrg#ifdef X_NOT_POSIX
423d522f475Smrgextern long lseek();
424d522f475Smrg#if defined(USG) || defined(SVR4)
425d522f475Smrgextern unsigned sleep();
426d522f475Smrg#else
427d522f475Smrgextern void sleep();
428d522f475Smrg#endif
429d522f475Smrgextern char *ttyname();
430d522f475Smrg#endif
431d522f475Smrg
432d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
433d522f475Smrgextern char *ptsname(int);
434d522f475Smrg#endif
435d522f475Smrg
436d522f475Smrg#ifndef VMS
4370bd37d32Smrgstatic void reapchild(int /* n */ );
438d522f475Smrgstatic int spawnXTerm(XtermWidget /* xw */ );
43920d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
440d522f475Smrg#ifdef USE_PTY_SEARCH
44120d2c4d2Smrgstatic int pty_search(int * /* pty */ );
442d522f475Smrg#endif
443d522f475Smrg#endif /* ! VMS */
444d522f475Smrg
445d522f475Smrgstatic int get_pty(int *pty, char *from);
44620d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
447e0a2b6dfSmrgstatic void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
448d522f475Smrg
449d522f475Smrgstatic Bool added_utmp_entry = False;
450d522f475Smrg
451d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
452d522f475Smrgstatic uid_t save_euid;
453d522f475Smrgstatic gid_t save_egid;
454d522f475Smrg#endif
455d522f475Smrg
456d522f475Smrgstatic uid_t save_ruid;
457d522f475Smrgstatic gid_t save_rgid;
458d522f475Smrg
459d522f475Smrg#if defined(USE_UTMP_SETGID)
460d522f475Smrgstatic int really_get_pty(int *pty, char *from);
461d522f475Smrg#endif
462d522f475Smrg
463d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
464d522f475Smrgstatic Bool xterm_exiting = False;
465d522f475Smrg#endif
466d522f475Smrg
467d522f475Smrgstatic char *explicit_shname = NULL;
468d522f475Smrg
469d522f475Smrg/*
470d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
471d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
472d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
473d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
474d522f475Smrg** SEGV.
475d522f475Smrg*/
476d522f475Smrgstatic char **command_to_exec = NULL;
477d522f475Smrg
478d522f475Smrg#if OPT_LUIT_PROG
479d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
4800bd37d32Smrgstatic unsigned command_length_with_luit = 0;
481d522f475Smrg#endif
482d522f475Smrg
483d522f475Smrg#define TERMCAP_ERASE "kb"
484d522f475Smrg#define VAL_INITIAL_ERASE A2E(8)
485d522f475Smrg
486d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
487d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
488d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
489d522f475Smrg * about padding generally store the code in a short, which does not have
490d522f475Smrg * enough bits for the extended values.
491d522f475Smrg */
492d522f475Smrg#ifdef B38400			/* everyone should define this */
493d522f475Smrg#define VAL_LINE_SPEED B38400
494d522f475Smrg#else /* ...but xterm's used this for a long time */
495d522f475Smrg#define VAL_LINE_SPEED B9600
496d522f475Smrg#endif
497d522f475Smrg
498d522f475Smrg/*
499d522f475Smrg * Allow use of system default characters if defined and reasonable.
500d522f475Smrg * These are based on the BSD ttydefaults.h
501d522f475Smrg */
502d522f475Smrg#ifndef CBRK
503d522f475Smrg#define CBRK     0xff		/* was 0 */
504d522f475Smrg#endif
505d522f475Smrg#ifndef CDISCARD
506d522f475Smrg#define CDISCARD CONTROL('O')
507d522f475Smrg#endif
508d522f475Smrg#ifndef CDSUSP
509d522f475Smrg#define CDSUSP   CONTROL('Y')
510d522f475Smrg#endif
511d522f475Smrg#ifndef CEOF
512d522f475Smrg#define CEOF     CONTROL('D')
513d522f475Smrg#endif
514d522f475Smrg#ifndef CEOL
515d522f475Smrg#define CEOL	 0xff		/* was 0 */
516d522f475Smrg#endif
517d522f475Smrg#ifndef CERASE
518d522f475Smrg#define CERASE   0177
519d522f475Smrg#endif
520d522f475Smrg#ifndef CERASE2
521d522f475Smrg#define	CERASE2  CONTROL('H')
522d522f475Smrg#endif
523d522f475Smrg#ifndef CFLUSH
524d522f475Smrg#define CFLUSH   CONTROL('O')
525d522f475Smrg#endif
526d522f475Smrg#ifndef CINTR
527d522f475Smrg#define CINTR    CONTROL('C')
528d522f475Smrg#endif
529d522f475Smrg#ifndef CKILL
530d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
531d522f475Smrg#endif
532d522f475Smrg#ifndef CLNEXT
533d522f475Smrg#define CLNEXT   CONTROL('V')
534d522f475Smrg#endif
535d522f475Smrg#ifndef CNUL
536d522f475Smrg#define CNUL     0
537d522f475Smrg#endif
538d522f475Smrg#ifndef CQUIT
539d522f475Smrg#define CQUIT    CONTROL('\\')
540d522f475Smrg#endif
541d522f475Smrg#ifndef CRPRNT
542d522f475Smrg#define CRPRNT   CONTROL('R')
543d522f475Smrg#endif
544d522f475Smrg#ifndef CREPRINT
545d522f475Smrg#define CREPRINT CRPRNT
546d522f475Smrg#endif
547d522f475Smrg#ifndef CSTART
548d522f475Smrg#define CSTART   CONTROL('Q')
549d522f475Smrg#endif
550d522f475Smrg#ifndef CSTATUS
551d522f475Smrg#define	CSTATUS  CONTROL('T')
552d522f475Smrg#endif
553d522f475Smrg#ifndef CSTOP
554d522f475Smrg#define CSTOP    CONTROL('S')
555d522f475Smrg#endif
556d522f475Smrg#ifndef CSUSP
557d522f475Smrg#define CSUSP    CONTROL('Z')
558d522f475Smrg#endif
559d522f475Smrg#ifndef CSWTCH
560d522f475Smrg#define CSWTCH   0
561d522f475Smrg#endif
562d522f475Smrg#ifndef CWERASE
563d522f475Smrg#define CWERASE  CONTROL('W')
564d522f475Smrg#endif
565d522f475Smrg
566d522f475Smrg#ifdef USE_ANY_SYSV_TERMIO
567d522f475Smrg#define TERMIO_STRUCT struct termio
568d522f475Smrg#define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
569d522f475Smrg#define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
570d522f475Smrg#define ttyFlush(fd)          ioctl(fd, TCFLSH, 1)
571d522f475Smrg#elif defined(USE_POSIX_TERMIOS)
572d522f475Smrg#define TERMIO_STRUCT struct termios
573d522f475Smrg#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
574d522f475Smrg#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
575d522f475Smrg#define ttyFlush(fd)          tcflush(fd, TCOFLUSH)
576d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO */
577d522f475Smrg
578d522f475Smrg#ifndef VMS
579d522f475Smrg#ifdef TERMIO_STRUCT
580d522f475Smrg/* The following structures are initialized in main() in order
581d522f475Smrg** to eliminate any assumptions about the internal order of their
582d522f475Smrg** contents.
583d522f475Smrg*/
584d522f475Smrgstatic TERMIO_STRUCT d_tio;
585d522f475Smrg
586d522f475Smrg#ifdef HAS_LTCHARS
587d522f475Smrgstatic struct ltchars d_ltc;
588d522f475Smrg#endif /* HAS_LTCHARS */
589d522f475Smrg
590d522f475Smrg#ifdef TIOCLSET
591d522f475Smrgstatic unsigned int d_lmode;
592d522f475Smrg#endif /* TIOCLSET */
593d522f475Smrg
594d522f475Smrg#else /* !TERMIO_STRUCT */
595d522f475Smrgstatic struct sgttyb d_sg =
596d522f475Smrg{
597d522f475Smrg    0, 0, 0177, CKILL, (EVENP | ODDP | ECHO | XTABS | CRMOD)
598d522f475Smrg};
599d522f475Smrgstatic struct tchars d_tc =
600d522f475Smrg{
601d522f475Smrg    CINTR, CQUIT, CSTART,
602d522f475Smrg    CSTOP, CEOF, CBRK
603d522f475Smrg};
604d522f475Smrgstatic struct ltchars d_ltc =
605d522f475Smrg{
606d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
607d522f475Smrg    CFLUSH, CWERASE, CLNEXT
608d522f475Smrg};
609d522f475Smrgstatic int d_disipline = NTTYDISC;
610d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
611d522f475Smrg#ifdef sony
612d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
613d522f475Smrgstatic struct jtchars d_jtc =
614d522f475Smrg{
615d522f475Smrg    'J', 'B'
616d522f475Smrg};
617d522f475Smrg#endif /* sony */
618d522f475Smrg#endif /* TERMIO_STRUCT */
619d522f475Smrg#endif /* ! VMS */
620d522f475Smrg
621d522f475Smrg/*
622d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
623d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
624d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
625d522f475Smrg */
626d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
627d522f475Smrgstatic Boolean override_tty_modes = False;
628d522f475Smrg/* *INDENT-OFF* */
629d522f475Smrgstatic struct _xttymodes {
63020d2c4d2Smrg    const char *name;
631d522f475Smrg    size_t len;
632d522f475Smrg    int set;
633d522f475Smrg    int value;
634d522f475Smrg} ttymodelist[] = {
635d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
636d522f475Smrg#define XTTYMODE_intr	0
637d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
638d522f475Smrg#define XTTYMODE_quit	1
639d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
640d522f475Smrg#define XTTYMODE_erase	2
641d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
642d522f475Smrg#define XTTYMODE_kill	3
643d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
644d522f475Smrg#define XTTYMODE_eof	4
645d522f475Smrg    TTYMODE("eol"),		/* VEOL */
646d522f475Smrg#define XTTYMODE_eol	5
647d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
648d522f475Smrg#define XTTYMODE_swtch	6
649d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
650d522f475Smrg#define XTTYMODE_start	7
651d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
652d522f475Smrg#define XTTYMODE_stop	8
653d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
654d522f475Smrg#define XTTYMODE_brk	9
655d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
656d522f475Smrg#define XTTYMODE_susp	10
657d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
658d522f475Smrg#define XTTYMODE_dsusp	11
659d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
660d522f475Smrg#define XTTYMODE_rprnt	12
661d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
662d522f475Smrg#define XTTYMODE_flush	13
663d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
664d522f475Smrg#define XTTYMODE_weras	14
665d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
666d522f475Smrg#define XTTYMODE_lnext	15
667d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
668d522f475Smrg#define XTTYMODE_status	16
669d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
670d522f475Smrg#define XTTYMODE_erase2	17
671d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
672d522f475Smrg#define XTTYMODE_eol2	18
673d522f475Smrg    { NULL,	0, 0, '\0' },	/* end of data */
674d522f475Smrg};
675d522f475Smrg
676d522f475Smrg#define validTtyChar(data, n) \
677d522f475Smrg	    (known_ttyChars[n].sysMode >= 0 && \
678d522f475Smrg	     known_ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
679d522f475Smrg
680d522f475Smrgstatic const struct {
681d522f475Smrg    int sysMode;
682d522f475Smrg    int myMode;
683d522f475Smrg    int myDefault;
684d522f475Smrg} known_ttyChars[] = {
685d522f475Smrg#ifdef VINTR
686d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
687d522f475Smrg#endif
688d522f475Smrg#ifdef VQUIT
689d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
690d522f475Smrg#endif
691d522f475Smrg#ifdef VERASE
692d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
693d522f475Smrg#endif
694d522f475Smrg#ifdef VKILL
695d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
696d522f475Smrg#endif
697d522f475Smrg#ifdef VEOF
698d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
699d522f475Smrg#endif
700d522f475Smrg#ifdef VEOL
701d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
702d522f475Smrg#endif
703d522f475Smrg#ifdef VSWTCH
704d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
705d522f475Smrg#endif
706d522f475Smrg#ifdef VSTART
707d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
708d522f475Smrg#endif
709d522f475Smrg#ifdef VSTOP
710d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
711d522f475Smrg#endif
712d522f475Smrg#ifdef VSUSP
713d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
714d522f475Smrg#endif
715d522f475Smrg#ifdef VDSUSP
716d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
717d522f475Smrg#endif
718d522f475Smrg#ifdef VREPRINT
719d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
720d522f475Smrg#endif
721d522f475Smrg#ifdef VDISCARD
722d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
723d522f475Smrg#endif
724d522f475Smrg#ifdef VWERASE
725d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
726d522f475Smrg#endif
727d522f475Smrg#ifdef VLNEXT
728d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
729d522f475Smrg#endif
730d522f475Smrg#ifdef VSTATUS
731d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
732d522f475Smrg#endif
733d522f475Smrg#ifdef VERASE2
734d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
735d522f475Smrg#endif
736d522f475Smrg#ifdef VEOL2
737d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
738d522f475Smrg#endif
739d522f475Smrg};
740d522f475Smrg/* *INDENT-ON* */
741d522f475Smrg
7420bd37d32Smrg#define TMODE(ind,var) if (ttymodelist[ind].set) var = (cc_t) ttymodelist[ind].value
743d522f475Smrg
744d522f475Smrgstatic int parse_tty_modes(char *s, struct _xttymodes *modelist);
745d522f475Smrg
746d522f475Smrg#ifndef USE_UTEMPTER
747d522f475Smrg#ifdef USE_SYSV_UTMP
748d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
749d522f475Smrgextern struct utmp *getutid();
750d522f475Smrg#endif /* AIXV3 */
751d522f475Smrg
752d522f475Smrg#else /* not USE_SYSV_UTMP */
753d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
754d522f475Smrg#endif /* USE_SYSV_UTMP */
755d522f475Smrg
756d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
757d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
758d522f475Smrg#else
759d522f475Smrg#undef USE_LASTLOG
760d522f475Smrg#endif
761d522f475Smrg
762d522f475Smrg#ifdef WTMP
763d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
764d522f475Smrg#endif
765d522f475Smrg#endif /* !USE_UTEMPTER */
766d522f475Smrg
767d522f475Smrg/*
768d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
769d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
770d522f475Smrg * WTMP and USE_LASTLOG.
771d522f475Smrg */
772d522f475Smrg#ifdef USE_LOGIN_DASH_P
773d522f475Smrg#ifndef LOGIN_FILENAME
774d522f475Smrg#define LOGIN_FILENAME "/bin/login"
775d522f475Smrg#endif
776d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
777d522f475Smrg#endif
778d522f475Smrg
779d522f475Smrgstatic char passedPty[PTYCHARLEN + 1];	/* name if pty if slave */
780d522f475Smrg
781d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
782d522f475Smrgstatic int Console;
783d522f475Smrg#include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
784d522f475Smrg#define MIT_CONSOLE_LEN	12
785d522f475Smrg#define MIT_CONSOLE "MIT_CONSOLE_"
786d522f475Smrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
787d522f475Smrgstatic Atom mit_console;
788d522f475Smrg#endif /* TIOCCONS */
789d522f475Smrg
790d522f475Smrg#ifndef USE_SYSV_UTMP
791d522f475Smrgstatic int tslot;
792d522f475Smrg#endif /* USE_SYSV_UTMP */
793d522f475Smrgstatic sigjmp_buf env;
794d522f475Smrg
795d522f475Smrg#define SetUtmpHost(dst, screen) \
796d522f475Smrg	{ \
797d522f475Smrg	    char host[sizeof(dst) + 1]; \
798d522f475Smrg	    strncpy(host, DisplayString(screen->display), sizeof(host)); \
799d522f475Smrg	    TRACE(("DisplayString(%s)\n", host)); \
800d522f475Smrg	    if (!resource.utmpDisplayId) { \
801d522f475Smrg		char *endptr = strrchr(host, ':'); \
802d522f475Smrg		if (endptr) { \
803d522f475Smrg		    TRACE(("trimming display-id '%s'\n", host)); \
804d522f475Smrg		    *endptr = '\0'; \
805d522f475Smrg		} \
806d522f475Smrg	    } \
807d522f475Smrg	    strncpy(dst, host, sizeof(dst)); \
808d522f475Smrg	}
809d522f475Smrg
810d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
811d522f475Smrg#  define SetUtmpSysLen(utmp) 			   \
812d522f475Smrg	{ \
813d522f475Smrg	    utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
814d522f475Smrg	    utmp.ut_syslen = strlen(utmp.ut_host) + 1; \
815d522f475Smrg	}
816d522f475Smrg#endif
817d522f475Smrg
818d522f475Smrg/* used by VT (charproc.c) */
819d522f475Smrg
820d522f475Smrgstatic XtResource application_resources[] =
821d522f475Smrg{
822d522f475Smrg    Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
823d522f475Smrg    Sres(XtNtitle, XtCTitle, title, NULL),
8240bd37d32Smrg    Sres(XtNiconHint, XtCIconHint, icon_hint, NULL),
825d522f475Smrg    Sres(XtNiconName, XtCIconName, icon_name, NULL),
826d522f475Smrg    Sres("termName", "TermName", term_name, NULL),
827d522f475Smrg    Sres("ttyModes", "TtyModes", tty_modes, NULL),
828d522f475Smrg    Bres("hold", "Hold", hold_screen, False),
829d522f475Smrg    Bres("utmpInhibit", "UtmpInhibit", utmpInhibit, False),
830d522f475Smrg    Bres("utmpDisplayId", "UtmpDisplayId", utmpDisplayId, True),
831d522f475Smrg    Bres("messages", "Messages", messages, True),
832d522f475Smrg    Ires("minBufSize", "MinBufSize", minBufSize, 4096),
833d522f475Smrg    Ires("maxBufSize", "MaxBufSize", maxBufSize, 32768),
83420d2c4d2Smrg    Sres("menuLocale", "MenuLocale", menuLocale, DEF_MENU_LOCALE),
835a1f3da82Smrg    Sres("omitTranslation", "OmitTranslation", omitTranslation, NULL),
836d522f475Smrg    Sres("keyboardType", "KeyboardType", keyboardType, "unknown"),
837e39b573cSmrg#if OPT_PRINT_ON_EXIT
838e39b573cSmrg    Ires("printModeImmediate", "PrintModeImmediate", printModeNow, 0),
839e39b573cSmrg    Ires("printOptsImmediate", "PrintOptsImmediate", printOptsNow, 9),
840e39b573cSmrg    Sres("printFileImmediate", "PrintFileImmediate", printFileNow, NULL),
841e39b573cSmrg    Ires("printModeOnXError", "PrintModeOnXError", printModeOnXError, 0),
842e39b573cSmrg    Ires("printOptsOnXError", "PrintOptsOnXError", printOptsOnXError, 9),
843e39b573cSmrg    Sres("printFileOnXError", "PrintFileOnXError", printFileOnXError, NULL),
844e39b573cSmrg#endif
845d522f475Smrg#if OPT_SUNPC_KBD
846d522f475Smrg    Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
847d522f475Smrg#endif
848d522f475Smrg#if OPT_HP_FUNC_KEYS
849d522f475Smrg    Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
850d522f475Smrg#endif
851d522f475Smrg#if OPT_SCO_FUNC_KEYS
852d522f475Smrg    Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
853d522f475Smrg#endif
854d522f475Smrg#if OPT_SUN_FUNC_KEYS
855d522f475Smrg    Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
856d522f475Smrg#endif
857d522f475Smrg#if OPT_TCAP_FKEYS
858d522f475Smrg    Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
859d522f475Smrg#endif
860d522f475Smrg#if OPT_INITIAL_ERASE
861d522f475Smrg    Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
862d522f475Smrg    Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
863d522f475Smrg#endif
864d522f475Smrg    Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
865d522f475Smrg#if OPT_ZICONBEEP
866d522f475Smrg    Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
8670bd37d32Smrg    Sres("zIconTitleFormat", "ZIconTitleFormat", zIconFormat, "*** %s"),
868d522f475Smrg#endif
869d522f475Smrg#if OPT_PTY_HANDSHAKE
870d522f475Smrg    Bres("waitForMap", "WaitForMap", wait_for_map, False),
871d522f475Smrg    Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
872d522f475Smrg    Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
873d522f475Smrg#endif
874e0a2b6dfSmrg#if OPT_REPORT_COLORS
875e0a2b6dfSmrg    Bres("reportColors", "ReportColors", reportColors, False),
876e0a2b6dfSmrg#endif
877e0a2b6dfSmrg#if OPT_REPORT_FONTS
878e0a2b6dfSmrg    Bres("reportFonts", "ReportFonts", reportFonts, False),
879e0a2b6dfSmrg#endif
880d522f475Smrg#if OPT_SAME_NAME
881d522f475Smrg    Bres("sameName", "SameName", sameName, True),
882d522f475Smrg#endif
883d522f475Smrg#if OPT_SESSION_MGT
884d522f475Smrg    Bres("sessionMgt", "SessionMgt", sessionMgt, True),
885d522f475Smrg#endif
886d522f475Smrg#if OPT_TOOLBAR
887d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
888d522f475Smrg#endif
889956cc18dSsnj#if OPT_MAXIMIZE
890956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
891a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
892956cc18dSsnj#endif
893d522f475Smrg};
894d522f475Smrg
89520d2c4d2Smrgstatic String fallback_resources[] =
896d522f475Smrg{
897e39b573cSmrg#if OPT_TOOLBAR
898e39b573cSmrg    "*toolBar: false",
899e39b573cSmrg#endif
900d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
901d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
902d522f475Smrg    "*SimpleMenu*Sme.height: 16",
903d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
904d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
905d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
906d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
907d522f475Smrg#if OPT_TEK4014
908d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
909d522f475Smrg#endif
910d522f475Smrg    NULL
911d522f475Smrg};
912d522f475Smrg
913d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
914d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
915d522f475Smrg/* *INDENT-OFF* */
916d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
91720d2c4d2Smrg{"-geometry",	"*vt100.geometry",XrmoptionSepArg,	(XPointer) NULL},
91820d2c4d2Smrg{"-132",	"*c132",	XrmoptionNoArg,		(XPointer) "on"},
91920d2c4d2Smrg{"+132",	"*c132",	XrmoptionNoArg,		(XPointer) "off"},
92020d2c4d2Smrg{"-ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "on"},
92120d2c4d2Smrg{"+ah",		"*alwaysHighlight", XrmoptionNoArg,	(XPointer) "off"},
92220d2c4d2Smrg{"-aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "on"},
92320d2c4d2Smrg{"+aw",		"*autoWrap",	XrmoptionNoArg,		(XPointer) "off"},
924d522f475Smrg#ifndef NO_ACTIVE_ICON
92520d2c4d2Smrg{"-ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "off"},
92620d2c4d2Smrg{"+ai",		"*activeIcon",	XrmoptionNoArg,		(XPointer) "on"},
927d522f475Smrg#endif /* NO_ACTIVE_ICON */
92820d2c4d2Smrg{"-b",		"*internalBorder",XrmoptionSepArg,	(XPointer) NULL},
92920d2c4d2Smrg{"-bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "on"},
93020d2c4d2Smrg{"+bc",		"*cursorBlink",	XrmoptionNoArg,		(XPointer) "off"},
93120d2c4d2Smrg{"-bcf",	"*cursorOffTime",XrmoptionSepArg,	(XPointer) NULL},
93220d2c4d2Smrg{"-bcn",	"*cursorOnTime",XrmoptionSepArg,	(XPointer) NULL},
93320d2c4d2Smrg{"-bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "off"},
93420d2c4d2Smrg{"+bdc",	"*colorBDMode",	XrmoptionNoArg,		(XPointer) "on"},
93520d2c4d2Smrg{"-cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "off"},
93620d2c4d2Smrg{"+cb",		"*cutToBeginningOfLine", XrmoptionNoArg, (XPointer) "on"},
93720d2c4d2Smrg{"-cc",		"*charClass",	XrmoptionSepArg,	(XPointer) NULL},
93820d2c4d2Smrg{"-cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "off"},
93920d2c4d2Smrg{"+cm",		"*colorMode",	XrmoptionNoArg,		(XPointer) "on"},
94020d2c4d2Smrg{"-cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "off"},
94120d2c4d2Smrg{"+cn",		"*cutNewline",	XrmoptionNoArg,		(XPointer) "on"},
94220d2c4d2Smrg{"-cr",		"*cursorColor",	XrmoptionSepArg,	(XPointer) NULL},
94320d2c4d2Smrg{"-cu",		"*curses",	XrmoptionNoArg,		(XPointer) "on"},
94420d2c4d2Smrg{"+cu",		"*curses",	XrmoptionNoArg,		(XPointer) "off"},
94520d2c4d2Smrg{"-dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "off"},
94620d2c4d2Smrg{"+dc",		"*dynamicColors",XrmoptionNoArg,	(XPointer) "on"},
94720d2c4d2Smrg{"-fb",		"*boldFont",	XrmoptionSepArg,	(XPointer) NULL},
94820d2c4d2Smrg{"-fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"off"},
94920d2c4d2Smrg{"+fbb",	"*freeBoldBox", XrmoptionNoArg,		(XPointer)"on"},
95020d2c4d2Smrg{"-fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"off"},
95120d2c4d2Smrg{"+fbx",	"*forceBoxChars", XrmoptionNoArg,	(XPointer)"on"},
952d522f475Smrg#ifndef NO_ACTIVE_ICON
95320d2c4d2Smrg{"-fi",		"*iconFont",	XrmoptionSepArg,	(XPointer) NULL},
954d522f475Smrg#endif /* NO_ACTIVE_ICON */
955d522f475Smrg#if OPT_RENDERFONT
95620d2c4d2Smrg{"-fa",		"*faceName",	XrmoptionSepArg,	(XPointer) NULL},
95720d2c4d2Smrg{"-fd",		"*faceNameDoublesize", XrmoptionSepArg,	(XPointer) NULL},
95820d2c4d2Smrg{"-fs",		"*faceSize",	XrmoptionSepArg,	(XPointer) NULL},
959d522f475Smrg#endif
960d522f475Smrg#if OPT_WIDE_CHARS
96120d2c4d2Smrg{"-fw",		"*wideFont",	XrmoptionSepArg,	(XPointer) NULL},
96220d2c4d2Smrg{"-fwb",	"*wideBoldFont", XrmoptionSepArg,	(XPointer) NULL},
963d522f475Smrg#endif
964d522f475Smrg#if OPT_INPUT_METHOD
96520d2c4d2Smrg{"-fx",		"*ximFont",	XrmoptionSepArg,	(XPointer) NULL},
966d522f475Smrg#endif
967d522f475Smrg#if OPT_HIGHLIGHT_COLOR
96820d2c4d2Smrg{"-hc",		"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
96920d2c4d2Smrg{"-hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "on"},
97020d2c4d2Smrg{"+hm",		"*highlightColorMode", XrmoptionNoArg,	(XPointer) "off"},
97120d2c4d2Smrg{"-selfg",	"*highlightTextColor", XrmoptionSepArg,	(XPointer) NULL},
97220d2c4d2Smrg{"-selbg",	"*highlightColor", XrmoptionSepArg,	(XPointer) NULL},
973d522f475Smrg#endif
974d522f475Smrg#if OPT_HP_FUNC_KEYS
97520d2c4d2Smrg{"-hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "on"},
97620d2c4d2Smrg{"+hf",		"*hpFunctionKeys",XrmoptionNoArg,	(XPointer) "off"},
977d522f475Smrg#endif
97820d2c4d2Smrg{"-hold",	"*hold",	XrmoptionNoArg,		(XPointer) "on"},
97920d2c4d2Smrg{"+hold",	"*hold",	XrmoptionNoArg,		(XPointer) "off"},
980d522f475Smrg#if OPT_INITIAL_ERASE
98120d2c4d2Smrg{"-ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "on"},
98220d2c4d2Smrg{"+ie",		"*ptyInitialErase", XrmoptionNoArg,	(XPointer) "off"},
983d522f475Smrg#endif
98420d2c4d2Smrg{"-j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "on"},
98520d2c4d2Smrg{"+j",		"*jumpScroll",	XrmoptionNoArg,		(XPointer) "off"},
986d522f475Smrg#if OPT_C1_PRINT
98720d2c4d2Smrg{"-k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "on"},
98820d2c4d2Smrg{"+k8",		"*allowC1Printable", XrmoptionNoArg,	(XPointer) "off"},
989d522f475Smrg#endif
99020d2c4d2Smrg{"-kt",		"*keyboardType", XrmoptionSepArg,	(XPointer) NULL},
991d522f475Smrg/* parse logging options anyway for compatibility */
99220d2c4d2Smrg{"-l",		"*logging",	XrmoptionNoArg,		(XPointer) "on"},
99320d2c4d2Smrg{"+l",		"*logging",	XrmoptionNoArg,		(XPointer) "off"},
99420d2c4d2Smrg{"-lf",		"*logFile",	XrmoptionSepArg,	(XPointer) NULL},
99520d2c4d2Smrg{"-ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "on"},
99620d2c4d2Smrg{"+ls",		"*loginShell",	XrmoptionNoArg,		(XPointer) "off"},
99720d2c4d2Smrg{"-mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "on"},
99820d2c4d2Smrg{"+mb",		"*marginBell",	XrmoptionNoArg,		(XPointer) "off"},
99920d2c4d2Smrg{"-mc",		"*multiClickTime", XrmoptionSepArg,	(XPointer) NULL},
100020d2c4d2Smrg{"-mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "off"},
100120d2c4d2Smrg{"+mesg",	"*messages",	XrmoptionNoArg,		(XPointer) "on"},
100220d2c4d2Smrg{"-ms",		"*pointerColor",XrmoptionSepArg,	(XPointer) NULL},
100320d2c4d2Smrg{"-nb",		"*nMarginBell",	XrmoptionSepArg,	(XPointer) NULL},
100420d2c4d2Smrg{"-nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "off"},
100520d2c4d2Smrg{"+nul",	"*underLine",	XrmoptionNoArg,		(XPointer) "on"},
100620d2c4d2Smrg{"-pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "on"},
100720d2c4d2Smrg{"+pc",		"*boldColors",	XrmoptionNoArg,		(XPointer) "off"},
100820d2c4d2Smrg{"-rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "on"},
100920d2c4d2Smrg{"+rw",		"*reverseWrap",	XrmoptionNoArg,		(XPointer) "off"},
101020d2c4d2Smrg{"-s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "on"},
101120d2c4d2Smrg{"+s",		"*multiScroll",	XrmoptionNoArg,		(XPointer) "off"},
101220d2c4d2Smrg{"-sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "on"},
101320d2c4d2Smrg{"+sb",		"*scrollBar",	XrmoptionNoArg,		(XPointer) "off"},
1014e0a2b6dfSmrg#if OPT_REPORT_COLORS
1015e0a2b6dfSmrg{"-report-colors","*reportColors", XrmoptionNoArg,	(XPointer) "on"},
1016e0a2b6dfSmrg#endif
1017e0a2b6dfSmrg#if OPT_REPORT_FONTS
1018e0a2b6dfSmrg{"-report-fonts","*reportFonts", XrmoptionNoArg,	(XPointer) "on"},
1019e0a2b6dfSmrg#endif
1020d522f475Smrg#ifdef SCROLLBAR_RIGHT
102120d2c4d2Smrg{"-leftbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "off"},
102220d2c4d2Smrg{"-rightbar",	"*rightScrollBar", XrmoptionNoArg,	(XPointer) "on"},
102320d2c4d2Smrg#endif
102420d2c4d2Smrg{"-rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "off"},
102520d2c4d2Smrg{"+rvc",	"*colorRVMode",	XrmoptionNoArg,		(XPointer) "on"},
102620d2c4d2Smrg{"-sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "on"},
102720d2c4d2Smrg{"+sf",		"*sunFunctionKeys", XrmoptionNoArg,	(XPointer) "off"},
10280bd37d32Smrg{"-sh",		"*scaleHeight", XrmoptionSepArg,	(XPointer) NULL},
102920d2c4d2Smrg{"-si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "off"},
103020d2c4d2Smrg{"+si",		"*scrollTtyOutput", XrmoptionNoArg,	(XPointer) "on"},
103120d2c4d2Smrg{"-sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "on"},
103220d2c4d2Smrg{"+sk",		"*scrollKey",	XrmoptionNoArg,		(XPointer) "off"},
103320d2c4d2Smrg{"-sl",		"*saveLines",	XrmoptionSepArg,	(XPointer) NULL},
1034d522f475Smrg#if OPT_SUNPC_KBD
103520d2c4d2Smrg{"-sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "on"},
103620d2c4d2Smrg{"+sp",		"*sunKeyboard", XrmoptionNoArg,		(XPointer) "off"},
1037d522f475Smrg#endif
1038d522f475Smrg#if OPT_TEK4014
103920d2c4d2Smrg{"-t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "on"},
104020d2c4d2Smrg{"+t",		"*tekStartup",	XrmoptionNoArg,		(XPointer) "off"},
1041d522f475Smrg#endif
104220d2c4d2Smrg{"-ti",		"*decTerminalID",XrmoptionSepArg,	(XPointer) NULL},
104320d2c4d2Smrg{"-tm",		"*ttyModes",	XrmoptionSepArg,	(XPointer) NULL},
104420d2c4d2Smrg{"-tn",		"*termName",	XrmoptionSepArg,	(XPointer) NULL},
1045d522f475Smrg#if OPT_WIDE_CHARS
104620d2c4d2Smrg{"-u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "2"},
104720d2c4d2Smrg{"+u8",		"*utf8",	XrmoptionNoArg,		(XPointer) "0"},
1048d522f475Smrg#endif
1049d522f475Smrg#if OPT_LUIT_PROG
105020d2c4d2Smrg{"-lc",		"*locale",	XrmoptionNoArg,		(XPointer) "on"},
105120d2c4d2Smrg{"+lc",		"*locale",	XrmoptionNoArg,		(XPointer) "off"},
105220d2c4d2Smrg{"-lcc",	"*localeFilter",XrmoptionSepArg,	(XPointer) NULL},
105320d2c4d2Smrg{"-en",		"*locale",	XrmoptionSepArg,	(XPointer) NULL},
105420d2c4d2Smrg#endif
105520d2c4d2Smrg{"-uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "on"},
105620d2c4d2Smrg{"+uc",		"*cursorUnderLine", XrmoptionNoArg,	(XPointer) "off"},
105720d2c4d2Smrg{"-ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "off"},
105820d2c4d2Smrg{"+ulc",	"*colorULMode",	XrmoptionNoArg,		(XPointer) "on"},
105920d2c4d2Smrg{"-ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "off"},
106020d2c4d2Smrg{"+ulit",       "*italicULMode", XrmoptionNoArg,        (XPointer) "on"},
106120d2c4d2Smrg{"-ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "on"},
106220d2c4d2Smrg{"+ut",		"*utmpInhibit",	XrmoptionNoArg,		(XPointer) "off"},
106320d2c4d2Smrg{"-im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "on"},
106420d2c4d2Smrg{"+im",		"*useInsertMode", XrmoptionNoArg,	(XPointer) "off"},
106520d2c4d2Smrg{"-vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "on"},
106620d2c4d2Smrg{"+vb",		"*visualBell",	XrmoptionNoArg,		(XPointer) "off"},
106720d2c4d2Smrg{"-pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "on"},
106820d2c4d2Smrg{"+pob",	"*popOnBell",	XrmoptionNoArg,		(XPointer) "off"},
1069d522f475Smrg#if OPT_WIDE_CHARS
107020d2c4d2Smrg{"-wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "on"},
107120d2c4d2Smrg{"+wc",		"*wideChars",	XrmoptionNoArg,		(XPointer) "off"},
107220d2c4d2Smrg{"-mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "on"},
107320d2c4d2Smrg{"+mk_width",	"*mkWidth",	XrmoptionNoArg,		(XPointer) "off"},
107420d2c4d2Smrg{"-cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "on"},
107520d2c4d2Smrg{"+cjk_width",	"*cjkWidth",	XrmoptionNoArg,		(XPointer) "off"},
107620d2c4d2Smrg#endif
107720d2c4d2Smrg{"-wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "on"},
107820d2c4d2Smrg{"+wf",		"*waitForMap",	XrmoptionNoArg,		(XPointer) "off"},
1079d522f475Smrg#if OPT_ZICONBEEP
108020d2c4d2Smrg{"-ziconbeep",	"*zIconBeep",	XrmoptionSepArg,	(XPointer) NULL},
1081d522f475Smrg#endif
1082d522f475Smrg#if OPT_SAME_NAME
108320d2c4d2Smrg{"-samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "on"},
108420d2c4d2Smrg{"+samename",	"*sameName",	XrmoptionNoArg,		(XPointer) "off"},
1085d522f475Smrg#endif
1086d522f475Smrg#if OPT_SESSION_MGT
108720d2c4d2Smrg{"-sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "on"},
108820d2c4d2Smrg{"+sm",		"*sessionMgt",	XrmoptionNoArg,		(XPointer) "off"},
1089d522f475Smrg#endif
1090d522f475Smrg#if OPT_TOOLBAR
109120d2c4d2Smrg{"-tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "on"},
109220d2c4d2Smrg{"+tb",		"*"XtNtoolBar,	XrmoptionNoArg,		(XPointer) "off"},
1093d522f475Smrg#endif
1094956cc18dSsnj#if OPT_MAXIMIZE
109520d2c4d2Smrg{"-maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "on"},
109620d2c4d2Smrg{"+maximized",	"*maximized",	XrmoptionNoArg,		(XPointer) "off"},
1097a1f3da82Smrg{"-fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "on"},
1098a1f3da82Smrg{"+fullscreen",	"*fullscreen",	XrmoptionNoArg,		(XPointer) "off"},
1099956cc18dSsnj#endif
1100d522f475Smrg/* options that we process ourselves */
110120d2c4d2Smrg{"-help",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
110220d2c4d2Smrg{"-version",	NULL,		XrmoptionSkipNArgs,	(XPointer) NULL},
110320d2c4d2Smrg{"-class",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
110420d2c4d2Smrg{"-e",		NULL,		XrmoptionSkipLine,	(XPointer) NULL},
110520d2c4d2Smrg{"-into",	NULL,		XrmoptionSkipArg,	(XPointer) NULL},
1106d522f475Smrg/* bogus old compatibility stuff for which there are
1107d522f475Smrg   standard XtOpenApplication options now */
110820d2c4d2Smrg{"%",		"*tekGeometry",	XrmoptionStickyArg,	(XPointer) NULL},
110920d2c4d2Smrg{"#",		".iconGeometry",XrmoptionStickyArg,	(XPointer) NULL},
111020d2c4d2Smrg{"-T",		".title",	XrmoptionSepArg,	(XPointer) NULL},
111120d2c4d2Smrg{"-n",		"*iconName",	XrmoptionSepArg,	(XPointer) NULL},
111220d2c4d2Smrg{"-r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
111320d2c4d2Smrg{"+r",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
111420d2c4d2Smrg{"-rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "on"},
111520d2c4d2Smrg{"+rv",		"*reverseVideo",XrmoptionNoArg,		(XPointer) "off"},
111620d2c4d2Smrg{"-w",		".borderWidth", XrmoptionSepArg,	(XPointer) NULL},
1117d522f475Smrg};
1118d522f475Smrg
1119d522f475Smrgstatic OptionHelp xtermOptions[] = {
1120d522f475Smrg{ "-version",              "print the version number" },
1121d522f475Smrg{ "-help",                 "print out this message" },
1122d522f475Smrg{ "-display displayname",  "X server to contact" },
1123d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1124d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1125d522f475Smrg{ "-bg color",             "background color" },
1126d522f475Smrg{ "-fg color",             "foreground color" },
1127d522f475Smrg{ "-bd color",             "border color" },
1128d522f475Smrg{ "-bw number",            "border width in pixels" },
1129d522f475Smrg{ "-fn fontname",          "normal text font" },
1130d522f475Smrg{ "-fb fontname",          "bold text font" },
1131d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1132d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1133d522f475Smrg#if OPT_RENDERFONT
1134d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1135d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1136d522f475Smrg{ "-fs size",              "FreeType font-size" },
1137d522f475Smrg#endif
1138d522f475Smrg#if OPT_WIDE_CHARS
1139d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1140d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1141d522f475Smrg#endif
1142d522f475Smrg#if OPT_INPUT_METHOD
1143d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1144d522f475Smrg#endif
1145d522f475Smrg{ "-iconic",               "start iconic" },
1146d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
1147d522f475Smrg{ "-class string",         "class string (XTerm)" },
1148d522f475Smrg{ "-title string",         "title string" },
1149d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1150d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1151d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1152d522f475Smrg#ifndef NO_ACTIVE_ICON
1153d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1154d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1155d522f475Smrg#endif /* NO_ACTIVE_ICON */
1156d522f475Smrg{ "-b number",             "internal border in pixels" },
1157d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1158d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1159d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1160d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1161d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1162d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1163d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1164d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1165d522f475Smrg{ "-cr color",             "text cursor color" },
1166d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1167d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1168d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1169d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1170d522f475Smrg{ "-selbg color",          "selection background color" },
1171d522f475Smrg{ "-selfg color",          "selection foreground color" },
11720bd37d32Smrg/* -hc is deprecated, not shown in help message */
1173d522f475Smrg#endif
1174d522f475Smrg#if OPT_HP_FUNC_KEYS
1175d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1176d522f475Smrg#endif
1177d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1178d522f475Smrg#if OPT_INITIAL_ERASE
1179d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1180d522f475Smrg#endif
1181d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1182d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1183d522f475Smrg#if OPT_C1_PRINT
1184d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1185d522f475Smrg#endif
1186d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1187d522f475Smrg#ifdef ALLOWLOGGING
1188d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1189d522f475Smrg{ "-lf filename",          "logging filename" },
1190d522f475Smrg#else
1191d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1192d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1193d522f475Smrg#endif
1194d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1195d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1196d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1197d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1198d522f475Smrg{ "-ms color",             "pointer color" },
1199d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
1200d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1201d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1202d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1203d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1204d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1205d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1206e0a2b6dfSmrg#if OPT_REPORT_COLORS
1207e0a2b6dfSmrg{ "-report-colors",        "report colors as they are allocated" },
1208e0a2b6dfSmrg#endif
1209e0a2b6dfSmrg#if OPT_REPORT_FONTS
1210e0a2b6dfSmrg{ "-report-fonts",         "report fonts as loaded to stdout" },
1211e0a2b6dfSmrg#endif
1212d522f475Smrg#ifdef SCROLLBAR_RIGHT
1213d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1214d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1215d522f475Smrg#endif
1216d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1217d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1218d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1219d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1220d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1221d522f475Smrg#if OPT_SUNPC_KBD
1222d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1223d522f475Smrg#endif
1224d522f475Smrg#if OPT_TEK4014
1225d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1226d522f475Smrg#endif
1227d522f475Smrg#if OPT_TOOLBAR
1228d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1229d522f475Smrg#endif
1230d522f475Smrg{ "-ti termid",            "terminal identifier" },
1231d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1232d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1233d522f475Smrg#if OPT_WIDE_CHARS
1234d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1235d522f475Smrg#endif
1236d522f475Smrg#if OPT_LUIT_PROG
1237d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1238d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
12390bd37d32Smrg/* -en is deprecated, not shown in help message */
1240d522f475Smrg#endif
12412eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1242d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1243d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1244d522f475Smrg#ifdef HAVE_UTMP
1245d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1246d522f475Smrg#else
1247d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1248d522f475Smrg#endif
1249d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1250d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
1251d522f475Smrg#if OPT_WIDE_CHARS
1252d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1253d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1254d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1255d522f475Smrg#endif
1256d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1257d522f475Smrg{ "-e command args ...",   "command to execute" },
1258d522f475Smrg#if OPT_TEK4014
1259d522f475Smrg{ "%geom",                 "Tek window geometry" },
1260d522f475Smrg#endif
1261d522f475Smrg{ "#geom",                 "icon window geometry" },
1262d522f475Smrg{ "-T string",             "title name for window" },
1263d522f475Smrg{ "-n string",             "icon name for window" },
1264d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1265d522f475Smrg{ "-C",                    "intercept console messages" },
1266d522f475Smrg#else
1267d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1268d522f475Smrg#endif
1269d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1270d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1271d522f475Smrg#if OPT_ZICONBEEP
1272d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1273d522f475Smrg#endif
1274d522f475Smrg#if OPT_SAME_NAME
1275d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1276d522f475Smrg#endif
1277d522f475Smrg#if OPT_SESSION_MGT
1278d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1279d522f475Smrg#endif
1280956cc18dSsnj#if OPT_MAXIMIZE
1281956cc18dSsnj{"-/+maximized",           "turn on/off maxmize on startup" },
1282a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1283956cc18dSsnj#endif
1284d522f475Smrg{ NULL, NULL }};
1285d522f475Smrg/* *INDENT-ON* */
1286d522f475Smrg
128720d2c4d2Smrgstatic const char *message[] =
1288d522f475Smrg{
1289d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1290d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1291d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1292d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1293d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
1294d522f475Smrg    NULL};
1295d522f475Smrg
1296d522f475Smrg/*
1297d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1298d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1299d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1300d522f475Smrg */
1301d522f475Smrgstatic int
1302d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1303d522f475Smrg{
1304d522f475Smrg    char *string = *ptr;
1305d522f475Smrg    int value = -1;
1306d522f475Smrg
130720d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1308d522f475Smrg    if (*string == '^') {
1309d522f475Smrg	switch (*++string) {
1310d522f475Smrg	case '?':
1311d522f475Smrg	    value = A2E(ANSI_DEL);
1312d522f475Smrg	    break;
1313d522f475Smrg	case '-':
1314d522f475Smrg	    if (!termcap) {
1315d522f475Smrg		errno = 0;
1316d522f475Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
1317d522f475Smrg		value = _POSIX_VDISABLE;
1318d522f475Smrg#endif
1319d522f475Smrg#if defined(_PC_VDISABLE)
1320d522f475Smrg		if (value == -1) {
132120d2c4d2Smrg		    value = (int) fpathconf(0, _PC_VDISABLE);
1322d522f475Smrg		    if (value == -1) {
1323d522f475Smrg			if (errno != 0)
1324d522f475Smrg			    break;	/* skip this (error) */
1325d522f475Smrg			value = 0377;
1326d522f475Smrg		    }
1327d522f475Smrg		}
1328d522f475Smrg#elif defined(VDISABLE)
1329d522f475Smrg		if (value == -1)
1330d522f475Smrg		    value = VDISABLE;
1331d522f475Smrg#endif
1332d522f475Smrg		break;
1333d522f475Smrg	    }
1334d522f475Smrg	    /* FALLTHRU */
1335d522f475Smrg	default:
1336d522f475Smrg	    value = CONTROL(*string);
1337d522f475Smrg	    break;
1338d522f475Smrg	}
1339d522f475Smrg	++string;
1340d522f475Smrg    } else if (termcap && (*string == '\\')) {
1341d522f475Smrg	char *d;
134220d2c4d2Smrg	int temp = (int) strtol(string + 1, &d, 8);
1343d522f475Smrg	if (temp > 0 && d != string) {
1344d522f475Smrg	    value = temp;
1345d522f475Smrg	    string = d;
1346d522f475Smrg	}
1347d522f475Smrg    } else {
1348d522f475Smrg	value = CharOf(*string);
1349d522f475Smrg	++string;
1350d522f475Smrg    }
1351d522f475Smrg    *ptr = string;
135220d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1353d522f475Smrg    return value;
1354d522f475Smrg}
1355d522f475Smrg
1356d522f475Smrgstatic int
13570bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
13580bd37d32Smrg{
13590bd37d32Smrg    int result = -1;
13600bd37d32Smrg    int n;
13610bd37d32Smrg    int ch;
13620bd37d32Smrg
13630bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
13640bd37d32Smrg	if (param[n] == ch) {
13650bd37d32Smrg	    result = n;
13660bd37d32Smrg	} else {
13670bd37d32Smrg	    if (param[n] != '\0')
13680bd37d32Smrg		result = -1;
13690bd37d32Smrg	    break;
13700bd37d32Smrg	}
13710bd37d32Smrg    }
13720bd37d32Smrg
13730bd37d32Smrg    return result;
13740bd37d32Smrg}
13750bd37d32Smrg
13760bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
13770bd37d32Smrgstatic int
13780bd37d32SmrgcountArg(XrmOptionDescRec * item)
1379d522f475Smrg{
13800bd37d32Smrg    int result = 0;
13810bd37d32Smrg
13820bd37d32Smrg    switch (item->argKind) {
13830bd37d32Smrg    case XrmoptionNoArg:
13840bd37d32Smrg	/* FALLTHRU */
13850bd37d32Smrg    case XrmoptionIsArg:
13860bd37d32Smrg	/* FALLTHRU */
13870bd37d32Smrg    case XrmoptionStickyArg:
13880bd37d32Smrg	break;
13890bd37d32Smrg    case XrmoptionSepArg:
13900bd37d32Smrg	/* FALLTHRU */
13910bd37d32Smrg    case XrmoptionResArg:
13920bd37d32Smrg	/* FALLTHRU */
13930bd37d32Smrg    case XrmoptionSkipArg:
13940bd37d32Smrg	result = 1;
13950bd37d32Smrg	break;
13960bd37d32Smrg    case XrmoptionSkipLine:
13970bd37d32Smrg	break;
13980bd37d32Smrg    case XrmoptionSkipNArgs:
13990bd37d32Smrg	result = (int) (long) (item->value);
14000bd37d32Smrg	break;
14010bd37d32Smrg    }
14020bd37d32Smrg    return result;
14030bd37d32Smrg}
14040bd37d32Smrg
14050bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
14060bd37d32Smrg
14070bd37d32Smrg/*
14080bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
14090bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
14100bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
14110bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
14120bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
14130bd37d32Smrg * standard table (something that the X libraries should do).
14140bd37d32Smrg */
14150bd37d32Smrgstatic XrmOptionDescRec *
14160bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
14170bd37d32Smrg{
14180bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
14190bd37d32Smrg    /* *INDENT-OFF* */
14200bd37d32Smrg#define DATA(option,kind) { option, NULL, kind, (XtPointer) NULL }
14210bd37d32Smrg    static XrmOptionDescRec opTable[] = {
14220bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
14230bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
14240bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
14250bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
14260bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
14270bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
14280bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
14290bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
14300bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
14310bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
14320bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
14330bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
14340bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
14350bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
14360bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
14370bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
14380bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
14390bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
14400bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
14410bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
14420bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
14430bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
14440bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
14450bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
14460bd37d32Smrg#endif /* TIOCCONS */
14470bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
14480bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
14490bd37d32Smrg    };
14500bd37d32Smrg#undef DATA
14510bd37d32Smrg    /* *INDENT-ON* */
14520bd37d32Smrg
14530bd37d32Smrg    XrmOptionDescRec *result = 0;
14540bd37d32Smrg    Cardinal inlist;
14550bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
14560bd37d32Smrg    int atbest = -1;
14570bd37d32Smrg    int best = -1;
14580bd37d32Smrg    int test;
14590bd37d32Smrg    Boolean exact = False;
14600bd37d32Smrg    int ambiguous1 = -1;
14610bd37d32Smrg    int ambiguous2 = -1;
14620bd37d32Smrg    char *option;
14630bd37d32Smrg    char *value;
14640bd37d32Smrg
14650bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
14660bd37d32Smrg		 ? &optionDescList[n] \
14670bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
14680bd37d32Smrg
14690bd37d32Smrg    if ((option = argv[*num]) != 0) {
14700bd37d32Smrg	Boolean need_value;
14710bd37d32Smrg	Boolean have_value = False;
14720bd37d32Smrg
14730bd37d32Smrg	TRACE(("parseArg %s\n", option));
14740bd37d32Smrg	if ((value = argv[(*num) + 1]) != 0) {
1475e0a2b6dfSmrg	    have_value = (Boolean) !isOption(value);
14760bd37d32Smrg	}
14770bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
14780bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
14790bd37d32Smrg
14800bd37d32Smrg	    test = matchArg(check, option);
14810bd37d32Smrg	    if (test < 0)
14820bd37d32Smrg		continue;
14830bd37d32Smrg
14840bd37d32Smrg	    /* check for exact match */
14850bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
14860bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
14870bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
14880bd37d32Smrg			exact = True;
14890bd37d32Smrg			atbest = (int) inlist;
14900bd37d32Smrg			break;
14910bd37d32Smrg		    }
14920bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
14930bd37d32Smrg		    exact = True;
14940bd37d32Smrg		    atbest = (int) inlist;
14950bd37d32Smrg		    break;
14960bd37d32Smrg		}
14970bd37d32Smrg	    }
14980bd37d32Smrg
14990bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
15000bd37d32Smrg
15010bd37d32Smrg	    if (need_value && value != 0) {
15020bd37d32Smrg		;
15030bd37d32Smrg	    } else if (need_value ^ have_value) {
15040bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
15050bd37d32Smrg		continue;
15060bd37d32Smrg	    }
15070bd37d32Smrg
15080bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
15090bd37d32Smrg	    if (test > 0
15100bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
15110bd37d32Smrg		atbest = (int) inlist;
1512e0a2b6dfSmrg		if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
1513e0a2b6dfSmrg		    /* in particular, silence a warning about ambiguity */
1514e0a2b6dfSmrg		    exact = 1;
1515e0a2b6dfSmrg		}
15160bd37d32Smrg		break;
15170bd37d32Smrg	    }
15180bd37d32Smrg	    if (test > best) {
15190bd37d32Smrg		best = test;
15200bd37d32Smrg		atbest = (int) inlist;
15210bd37d32Smrg	    } else if (test == best) {
15220bd37d32Smrg		if (atbest >= 0) {
15230bd37d32Smrg		    if (atbest > 0) {
15240bd37d32Smrg			ambiguous1 = (int) inlist;
15250bd37d32Smrg			ambiguous2 = (int) atbest;
15260bd37d32Smrg		    }
15270bd37d32Smrg		    atbest = -1;
15280bd37d32Smrg		}
15290bd37d32Smrg	    }
15300bd37d32Smrg	}
15310bd37d32Smrg    }
15320bd37d32Smrg
15330bd37d32Smrg    *valuep = 0;
15340bd37d32Smrg    if (atbest >= 0) {
15350bd37d32Smrg	result = ITEM(atbest);
15360bd37d32Smrg	if (!exact) {
15370bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
15380bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
15390bd37d32Smrg			     ITEM(ambiguous1)->option,
15400bd37d32Smrg			     ITEM(ambiguous2)->option);
15410bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
15420bd37d32Smrg		result = 0;
15430bd37d32Smrg	    }
15440bd37d32Smrg	}
15450bd37d32Smrg	if (result != 0) {
15460bd37d32Smrg	    TRACE(("...result %s\n", result->option));
15470bd37d32Smrg	    /* expand abbreviations */
15480bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
15490bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
15500bd37d32Smrg		    argv[*num] = x_strdup(result->option);
15510bd37d32Smrg		}
15520bd37d32Smrg	    }
15530bd37d32Smrg
15540bd37d32Smrg	    /* adjust (*num) to skip option value */
15550bd37d32Smrg	    (*num) += countArg(result);
15560bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
15570bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
15580bd37d32Smrg		*valuep = argv[*num];
15590bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
15600bd37d32Smrg	    }
15610bd37d32Smrg	}
15620bd37d32Smrg    }
15630bd37d32Smrg#undef ITEM
15640bd37d32Smrg    return result;
1565d522f475Smrg}
1566d522f475Smrg
1567d522f475Smrgstatic void
1568d522f475SmrgSyntax(char *badOption)
1569d522f475Smrg{
1570d522f475Smrg    OptionHelp *opt;
1571d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1572d522f475Smrg    int col;
1573d522f475Smrg
15740bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
15750bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1576d522f475Smrg
1577d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1578956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1579d522f475Smrg    for (opt = list; opt->opt; opt++) {
1580956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1581d522f475Smrg	if (col + len > 79) {
1582d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1583d522f475Smrg	    col = 3;
1584d522f475Smrg	}
1585d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1586d522f475Smrg	col += len;
1587d522f475Smrg    }
1588d522f475Smrg
1589d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1590d522f475Smrg	    ProgramName);
1591d522f475Smrg    exit(1);
1592d522f475Smrg}
1593d522f475Smrg
1594d522f475Smrgstatic void
1595d522f475SmrgVersion(void)
1596d522f475Smrg{
1597d522f475Smrg    printf("%s\n", xtermVersion());
1598d522f475Smrg    fflush(stdout);
1599d522f475Smrg}
1600d522f475Smrg
1601d522f475Smrgstatic void
1602d522f475SmrgHelp(void)
1603d522f475Smrg{
1604d522f475Smrg    OptionHelp *opt;
1605d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
160620d2c4d2Smrg    const char **cpp;
1607d522f475Smrg
1608d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1609d522f475Smrg	   xtermVersion(), ProgramName);
1610d522f475Smrg    printf("where options include:\n");
1611d522f475Smrg    for (opt = list; opt->opt; opt++) {
1612d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1613d522f475Smrg    }
1614d522f475Smrg
1615d522f475Smrg    putchar('\n');
1616d522f475Smrg    for (cpp = message; *cpp; cpp++)
1617d522f475Smrg	puts(*cpp);
1618d522f475Smrg    putchar('\n');
1619d522f475Smrg    fflush(stdout);
1620d522f475Smrg}
1621d522f475Smrg
1622d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1623d522f475Smrg/* ARGSUSED */
1624d522f475Smrgstatic Boolean
1625d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1626d522f475Smrg			Atom * selection GCC_UNUSED,
1627d522f475Smrg			Atom * target GCC_UNUSED,
1628d522f475Smrg			Atom * type GCC_UNUSED,
1629d522f475Smrg			XtPointer *value GCC_UNUSED,
1630d522f475Smrg			unsigned long *length GCC_UNUSED,
1631d522f475Smrg			int *format GCC_UNUSED)
1632d522f475Smrg{
1633d522f475Smrg    /* we don't save console output, so can't offer it */
1634d522f475Smrg    return False;
1635d522f475Smrg}
1636d522f475Smrg#endif /* TIOCCONS */
1637d522f475Smrg
1638d522f475Smrg/*
1639d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1640d522f475Smrg */
1641d522f475Smrg/* ARGSUSED */
1642d522f475Smrgstatic void
1643d522f475SmrgDeleteWindow(Widget w,
1644d522f475Smrg	     XEvent * event GCC_UNUSED,
1645e0a2b6dfSmrg	     String *params GCC_UNUSED,
1646d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1647d522f475Smrg{
1648d522f475Smrg#if OPT_TEK4014
1649d522f475Smrg    if (w == toplevel) {
1650d522f475Smrg	if (TEK4014_SHOWN(term))
1651d522f475Smrg	    hide_vt_window();
1652d522f475Smrg	else
1653d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
165420d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1655d522f475Smrg	hide_tek_window();
1656d522f475Smrg    else
1657d522f475Smrg#endif
1658d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1659d522f475Smrg}
1660d522f475Smrg
1661d522f475Smrg/* ARGSUSED */
1662d522f475Smrgstatic void
1663d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1664d522f475Smrg		XEvent * event,
1665e0a2b6dfSmrg		String *params GCC_UNUSED,
1666d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1667d522f475Smrg{
1668d522f475Smrg    switch (event->type) {
1669d522f475Smrg    case MappingNotify:
1670d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1671d522f475Smrg	break;
1672d522f475Smrg    }
1673d522f475Smrg}
1674d522f475Smrg
1675d522f475Smrgstatic XtActionsRec actionProcs[] =
1676d522f475Smrg{
1677d522f475Smrg    {"DeleteWindow", DeleteWindow},
1678d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1679d522f475Smrg};
1680d522f475Smrg
1681d522f475Smrg/*
1682d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1683d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1684d522f475Smrg * utmp.
1685d522f475Smrg */
1686d522f475Smrgstatic char *
1687d522f475Smrgmy_pty_name(char *device)
1688d522f475Smrg{
1689d522f475Smrg    size_t len = strlen(device);
1690d522f475Smrg    Bool name = False;
1691d522f475Smrg
1692d522f475Smrg    while (len != 0) {
1693d522f475Smrg	int ch = device[len - 1];
1694d522f475Smrg	if (isdigit(ch)) {
1695d522f475Smrg	    len--;
1696d522f475Smrg	} else if (ch == '/') {
1697d522f475Smrg	    if (name)
1698d522f475Smrg		break;
1699d522f475Smrg	    len--;
1700d522f475Smrg	} else if (isalpha(ch)) {
1701d522f475Smrg	    name = True;
1702d522f475Smrg	    len--;
1703d522f475Smrg	} else {
1704d522f475Smrg	    break;
1705d522f475Smrg	}
1706d522f475Smrg    }
1707d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1708d522f475Smrg    return device + len;
1709d522f475Smrg}
1710d522f475Smrg
1711d522f475Smrg/*
1712d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1713d522f475Smrg * last few characters for a utmp identifier.
1714d522f475Smrg */
1715d522f475Smrgstatic char *
1716d522f475Smrgmy_pty_id(char *device)
1717d522f475Smrg{
1718d522f475Smrg    char *name = my_pty_name(device);
1719d522f475Smrg    char *leaf = x_basename(name);
1720d522f475Smrg
1721d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1722956cc18dSsnj	int len = (int) strlen(leaf);
1723d522f475Smrg	if (PTYCHARLEN < len)
1724d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1725d522f475Smrg    }
1726d522f475Smrg    TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
1727d522f475Smrg    return leaf;
1728d522f475Smrg}
1729d522f475Smrg
1730d522f475Smrg/*
1731d522f475Smrg * Set the tty/pty identifier
1732d522f475Smrg */
1733d522f475Smrgstatic void
1734d522f475Smrgset_pty_id(char *device, char *id)
1735d522f475Smrg{
1736d522f475Smrg    char *name = my_pty_name(device);
1737d522f475Smrg    char *leaf = x_basename(name);
1738d522f475Smrg
1739d522f475Smrg    if (name == leaf) {
1740d522f475Smrg	strcpy(my_pty_id(device), id);
1741d522f475Smrg    } else {
1742d522f475Smrg	strcpy(leaf, id);
1743d522f475Smrg    }
1744d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
1745d522f475Smrg}
1746d522f475Smrg
1747d522f475Smrg/*
1748d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
1749d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
1750d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
1751d522f475Smrg * not, fall-thru to the original logic.
1752d522f475Smrg */
1753d522f475Smrgstatic Bool
1754d522f475SmrgParseSccn(char *option)
1755d522f475Smrg{
1756d522f475Smrg    char *leaf = x_basename(option);
1757d522f475Smrg    Bool code = False;
1758d522f475Smrg
1759d522f475Smrg    if (leaf != option) {
1760d522f475Smrg	if (leaf - option > 0
1761d522f475Smrg	    && isdigit(CharOf(*leaf))
1762d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
1763956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
1764d522f475Smrg	    /*
1765d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
1766d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
1767d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
1768d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
1769d522f475Smrg	     */
1770d522f475Smrg	    strncpy(passedPty, option, len);
1771d522f475Smrg	    passedPty[len] = 0;
1772d522f475Smrg	    code = True;
1773d522f475Smrg	}
1774d522f475Smrg    } else {
1775d522f475Smrg	code = (sscanf(option, "%c%c%d",
1776d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
1777d522f475Smrg    }
1778d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
1779d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
1780d522f475Smrg    return code;
1781d522f475Smrg}
1782d522f475Smrg
1783d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
1784d522f475Smrg/*
1785d522f475Smrg * From "man utmp":
1786d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
1787d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
1788d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
1789d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
1790d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
1791d522f475Smrg * ut_time, ut_user and ut_host as well.
1792d522f475Smrg *
1793d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
1794d522f475Smrg * pty implementation allows more than 3 digits.
1795d522f475Smrg */
1796d522f475Smrgstatic char *
1797d522f475Smrgmy_utmp_id(char *device)
1798d522f475Smrg{
1799d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
1800d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
1801d522f475Smrg    static char result[UTIDSIZE + 1];
1802d522f475Smrg
1803d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
1804d522f475Smrg    /*
1805d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
1806d522f475Smrg     * issues, and can use the available space in ut_id differently from the
1807d522f475Smrg     * default convention.
1808d522f475Smrg     *
1809d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
1810d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
1811d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
1812d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
1813d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
1814d522f475Smrg     * last three digits of the device name, regardless of the format of the
1815d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
1816d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
1817d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
1818d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
1819d522f475Smrg     */
1820d522f475Smrg    int len, n;
1821d522f475Smrg
1822d522f475Smrg    len = strlen(device);
1823d522f475Smrg    n = UTIDSIZE;
1824d522f475Smrg    result[n] = '\0';
1825d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
1826d522f475Smrg	result[--n] = device[--len];
1827d522f475Smrg    while (n > 0)
1828d522f475Smrg	result[--n] = '0';
1829d522f475Smrg    result[0] = 'x';
1830d522f475Smrg#else
1831d522f475Smrg    char *name = my_pty_name(device);
1832d522f475Smrg    char *leaf = x_basename(name);
1833d522f475Smrg    size_t len = strlen(leaf);
1834d522f475Smrg
1835d522f475Smrg    if ((UTIDSIZE - 1) < len)
1836d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
1837d522f475Smrg    sprintf(result, "p%s", leaf);
1838d522f475Smrg#endif
1839d522f475Smrg
1840d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
1841d522f475Smrg    return result;
1842d522f475Smrg}
1843d522f475Smrg#endif /* USE_SYSV_UTMP */
1844d522f475Smrg
1845d522f475Smrg#ifdef USE_POSIX_SIGNALS
1846d522f475Smrg
1847d522f475Smrgtypedef void (*sigfunc) (int);
1848d522f475Smrg
1849d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
1850d522f475Smrg   has just been stopped and not actually killed */
1851d522f475Smrg
1852d522f475Smrgstatic sigfunc
1853d522f475Smrgposix_signal(int signo, sigfunc func)
1854d522f475Smrg{
1855d522f475Smrg    struct sigaction act, oact;
1856d522f475Smrg
1857d522f475Smrg    act.sa_handler = func;
1858d522f475Smrg    sigemptyset(&act.sa_mask);
1859d522f475Smrg#ifdef SA_RESTART
1860d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
1861d522f475Smrg#else
1862d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
1863d522f475Smrg#endif
1864d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
1865d522f475Smrg	return (SIG_ERR);
1866d522f475Smrg    return (oact.sa_handler);
1867d522f475Smrg}
1868d522f475Smrg
18690bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
1870d522f475Smrg
1871d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
1872d522f475Smrgstatic void
1873d522f475SmrgdisableSetUid(void)
1874d522f475Smrg{
1875d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
1876d522f475Smrg    if (setuid(save_ruid) == -1) {
18770bd37d32Smrg	xtermWarning("unable to reset uid\n");
1878d522f475Smrg	exit(1);
1879d522f475Smrg    }
1880d522f475Smrg    TRACE_IDS;
1881d522f475Smrg}
1882d522f475Smrg#else
1883d522f475Smrg#define disableSetUid()		/* nothing */
1884d522f475Smrg#endif /* DISABLE_SETUID */
1885d522f475Smrg
1886d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
1887d522f475Smrgstatic void
1888d522f475SmrgdisableSetGid(void)
1889d522f475Smrg{
1890d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
1891d522f475Smrg    if (setegid(save_rgid) == -1) {
18920bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
1893d522f475Smrg	exit(1);
1894d522f475Smrg    }
1895d522f475Smrg    TRACE_IDS;
1896d522f475Smrg}
1897d522f475Smrg#else
1898d522f475Smrg#define disableSetGid()		/* nothing */
1899d522f475Smrg#endif /* DISABLE_SETGID */
1900d522f475Smrg
1901d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
1902d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
1903d522f475Smrgstatic void
1904d522f475SmrgsetEffectiveGroup(gid_t group)
1905d522f475Smrg{
1906d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
1907d522f475Smrg    if (setegid(group) == -1) {
1908d522f475Smrg#ifdef __MVS__
1909d522f475Smrg	if (!(errno == EMVSERR))	/* could happen if _BPX_SHAREAS=REUSE */
1910d522f475Smrg#endif
1911d522f475Smrg	{
19120bd37d32Smrg	    xtermPerror("setegid(%d)", (int) group);
1913d522f475Smrg	}
1914d522f475Smrg    }
1915d522f475Smrg    TRACE_IDS;
1916d522f475Smrg}
1917d522f475Smrg#endif
1918d522f475Smrg
1919d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
1920d522f475Smrgstatic void
1921d522f475SmrgsetEffectiveUser(uid_t user)
1922d522f475Smrg{
1923d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
1924d522f475Smrg    if (seteuid(user) == -1) {
1925d522f475Smrg#ifdef __MVS__
1926d522f475Smrg	if (!(errno == EMVSERR))
1927d522f475Smrg#endif
1928d522f475Smrg	{
19290bd37d32Smrg	    xtermPerror("seteuid(%d)", (int) user);
1930d522f475Smrg	}
1931d522f475Smrg    }
1932d522f475Smrg    TRACE_IDS;
1933d522f475Smrg}
1934d522f475Smrg#endif
1935d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
1936d522f475Smrg
1937d522f475Smrgint
1938d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
1939d522f475Smrg{
1940a1f3da82Smrg#if OPT_MAXIMIZE
1941a1f3da82Smrg#define DATA(name) { #name, es##name }
1942a1f3da82Smrg    static FlagList tblFullscreen[] =
1943a1f3da82Smrg    {
1944a1f3da82Smrg	DATA(Always),
1945a1f3da82Smrg	DATA(Never)
1946a1f3da82Smrg    };
1947a1f3da82Smrg#undef DATA
1948a1f3da82Smrg#endif
1949a1f3da82Smrg
1950d522f475Smrg    Widget form_top, menu_top;
1951d522f475Smrg    Dimension menu_high;
1952d522f475Smrg    TScreen *screen;
1953d522f475Smrg    int mode;
1954e0a2b6dfSmrg    char *my_class = x_strdup(DEFCLASS);
1955d522f475Smrg    Window winToEmbedInto = None;
1956d522f475Smrg
1957d522f475Smrg    ProgramName = argv[0];
1958d522f475Smrg
1959d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
1960d522f475Smrg    save_euid = geteuid();
1961d522f475Smrg    save_egid = getegid();
1962d522f475Smrg#endif
1963d522f475Smrg
1964d522f475Smrg    save_ruid = getuid();
1965d522f475Smrg    save_rgid = getgid();
1966d522f475Smrg
1967d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
1968d522f475Smrg#if defined(DISABLE_SETUID)
1969d522f475Smrg    disableSetUid();
1970d522f475Smrg#endif
1971d522f475Smrg#if defined(DISABLE_SETGID)
1972d522f475Smrg    disableSetGid();
1973d522f475Smrg#endif
1974d522f475Smrg    TRACE_IDS;
1975d522f475Smrg#endif
1976d522f475Smrg
1977d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
1978d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
1979d522f475Smrg#ifdef USE_PTY_DEVICE
1980d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
1981d522f475Smrg    if (!ttydev || !ptydev)
1982d522f475Smrg#else
1983d522f475Smrg    if (!ttydev)
1984d522f475Smrg#endif
1985d522f475Smrg    {
19860bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
1987d522f475Smrg	exit(1);
1988d522f475Smrg    }
1989d522f475Smrg    strcpy(ttydev, TTYDEV);
1990d522f475Smrg#ifdef USE_PTY_DEVICE
1991d522f475Smrg    strcpy(ptydev, PTYDEV);
1992d522f475Smrg#endif
1993d522f475Smrg
1994d522f475Smrg#if defined(USE_UTMP_SETGID)
1995d522f475Smrg    get_pty(NULL, NULL);
1996d522f475Smrg    disableSetUid();
1997d522f475Smrg    disableSetGid();
1998d522f475Smrg    TRACE_IDS;
1999d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
2000d522f475Smrg#endif
2001d522f475Smrg
2002d522f475Smrg    /* Do these first, since we may not be able to open the display */
2003d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
2004d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
2005d522f475Smrg    if (argc > 1) {
20060bd37d32Smrg	XrmOptionDescRec *option_ptr;
20070bd37d32Smrg	char *option_value;
2008d522f475Smrg	int n;
2009e39b573cSmrg	Bool quit = False;
2010d522f475Smrg
2011d522f475Smrg	for (n = 1; n < argc; n++) {
20120bd37d32Smrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
20130bd37d32Smrg		if (argv[n] == 0) {
20140bd37d32Smrg		    break;
20150bd37d32Smrg		} else if (isOption(argv[n])) {
20160bd37d32Smrg		    Syntax(argv[n]);
20170bd37d32Smrg		} else if (explicit_shname != 0) {
20180bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
20190bd37d32Smrg		    Syntax(argv[n]);
20200bd37d32Smrg		}
20210bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
20220bd37d32Smrg		if (explicit_shname == 0)
20230bd37d32Smrg		    exit(0);
20240bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
20250bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
20260bd37d32Smrg		command_to_exec = (argv + n + 1);
20270bd37d32Smrg		if (!command_to_exec[0])
20280bd37d32Smrg		    Syntax(argv[n]);
20290bd37d32Smrg		break;
20300bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2031d522f475Smrg		Version();
2032e39b573cSmrg		quit = True;
20330bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2034d522f475Smrg		Help();
2035e39b573cSmrg		quit = True;
20360bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
2037e0a2b6dfSmrg		free(my_class);
20380bd37d32Smrg		if ((my_class = x_strdup(option_value)) == 0) {
2039d522f475Smrg		    Help();
2040e39b573cSmrg		    quit = True;
2041d522f475Smrg		}
20420bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
20430bd37d32Smrg		char *endPtr;
20440bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
2045d522f475Smrg	    }
2046d522f475Smrg	}
2047d522f475Smrg	if (quit)
2048d522f475Smrg	    exit(0);
20490bd37d32Smrg	/*
20500bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
20510bd37d32Smrg	 * then give up.
20520bd37d32Smrg	 */
20530bd37d32Smrg	if (n < argc && !command_to_exec) {
20540bd37d32Smrg	    Syntax(argv[n]);
20550bd37d32Smrg	}
2056d522f475Smrg    }
2057d522f475Smrg
20580bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2059d522f475Smrg#if OPT_I18N_SUPPORT
2060d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2061d522f475Smrg#endif
2062d522f475Smrg
2063d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2064d522f475Smrg    /* Initialization is done here rather than above in order
2065d522f475Smrg     * to prevent any assumptions about the order of the contents
2066d522f475Smrg     * of the various terminal structures (which may change from
2067d522f475Smrg     * implementation to implementation).
2068d522f475Smrg     */
2069d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2070d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2071d522f475Smrg#ifdef TAB3
2072d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR | TAB3;
2073d522f475Smrg#else
2074d522f475Smrg#ifdef ONLCR
2075d522f475Smrg    d_tio.c_oflag = OPOST | ONLCR;
2076d522f475Smrg#else
2077d522f475Smrg    d_tio.c_oflag = OPOST;
2078d522f475Smrg#endif
2079d522f475Smrg#endif
2080d522f475Smrg    {
2081d522f475Smrg	Cardinal nn;
2082d522f475Smrg
2083d522f475Smrg	/* fill in default-values */
2084d522f475Smrg	for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2085d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2086d522f475Smrg		d_tio.c_cc[known_ttyChars[nn].sysMode] =
20870bd37d32Smrg		    (cc_t) known_ttyChars[nn].myDefault;
2088d522f475Smrg	    }
2089d522f475Smrg	}
2090d522f475Smrg    }
2091d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
2092d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2093d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2094d522f475Smrg#ifdef ECHOKE
2095d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2096d522f475Smrg#endif
2097d522f475Smrg#ifdef ECHOCTL
2098d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2099d522f475Smrg#endif
2100d522f475Smrg#ifndef USE_TERMIOS		/* { */
2101d522f475Smrg    d_tio.c_line = 0;
2102d522f475Smrg#endif /* } */
2103d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2104d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2105d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2106d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2107d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2108d522f475Smrg    d_ltc.t_werasc = CWERASE;
2109d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2110d522f475Smrg#endif /* } HAS_LTCHARS */
2111d522f475Smrg#ifdef TIOCLSET			/* { */
2112d522f475Smrg    d_lmode = 0;
2113d522f475Smrg#endif /* } TIOCLSET */
2114d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2115d522f475Smrg#ifndef USE_POSIX_TERMIOS
2116d522f475Smrg#ifdef BAUD_0			/* { */
2117d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2118d522f475Smrg#else /* }{ !BAUD_0 */
2119d522f475Smrg    d_tio.c_cflag = VAL_LINE_SPEED | CS8 | CREAD | PARENB | HUPCL;
2120d522f475Smrg#endif /* } !BAUD_0 */
2121d522f475Smrg#else /* USE_POSIX_TERMIOS */
2122d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2123d522f475Smrg    cfsetispeed(&d_tio, VAL_LINE_SPEED);
2124d522f475Smrg    cfsetospeed(&d_tio, VAL_LINE_SPEED);
2125d522f475Smrg#endif
2126d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2127d522f475Smrg#ifdef ECHOKE
2128d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2129d522f475Smrg#endif
2130d522f475Smrg#ifdef ECHOCTL
2131d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2132d522f475Smrg#endif
2133d522f475Smrg#ifndef USE_POSIX_TERMIOS
2134d522f475Smrg#ifdef NTTYDISC
2135d522f475Smrg    d_tio.c_line = NTTYDISC;
2136d522f475Smrg#else
2137d522f475Smrg    d_tio.c_line = 0;
2138d522f475Smrg#endif
2139d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2140d522f475Smrg#ifdef __sgi
2141d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2142d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2143d522f475Smrg#endif
2144d522f475Smrg#ifdef __MVS__
2145d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2146d522f475Smrg#endif
2147d522f475Smrg    {
2148d522f475Smrg	Cardinal nn;
2149d522f475Smrg	int i;
2150d522f475Smrg
2151d522f475Smrg	/* try to inherit tty settings */
2152d522f475Smrg	for (i = 0; i <= 2; i++) {
2153d522f475Smrg	    TERMIO_STRUCT deftio;
2154d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2155d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
2156d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2157d522f475Smrg			d_tio.c_cc[known_ttyChars[nn].sysMode] =
2158d522f475Smrg			    deftio.c_cc[known_ttyChars[nn].sysMode];
2159d522f475Smrg		    }
2160d522f475Smrg		}
2161d522f475Smrg		break;
2162d522f475Smrg	    }
2163d522f475Smrg	}
2164d522f475Smrg    }
2165d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2166d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2167d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2168d522f475Smrg#endif /* } */
2169d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2170d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2171d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2172d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2173d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2174d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2175d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2176d522f475Smrg#endif /* } HAS_LTCHARS */
2177d522f475Smrg
2178d522f475Smrg#ifdef TIOCLSET			/* { */
2179d522f475Smrg    d_lmode = 0;
2180d522f475Smrg#endif /* } TIOCLSET */
2181d522f475Smrg#endif /* } macII, ATT, CRAY */
2182d522f475Smrg#endif /* } TERMIO_STRUCT */
2183d522f475Smrg
2184d522f475Smrg    /* Init the Toolkit. */
2185d522f475Smrg    {
2186d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2187d522f475Smrg	setEffectiveGroup(save_rgid);
2188d522f475Smrg	setEffectiveUser(save_ruid);
2189d522f475Smrg	TRACE_IDS;
2190d522f475Smrg#endif
2191e0a2b6dfSmrg	init_colored_cursor();
2192d522f475Smrg
21930bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
21940bd37d32Smrg					my_class,
21950bd37d32Smrg					optionDescList,
21960bd37d32Smrg					XtNumber(optionDescList),
21970bd37d32Smrg					&argc, (String *) argv,
21980bd37d32Smrg					fallback_resources,
21990bd37d32Smrg					sessionShellWidgetClass,
22000bd37d32Smrg					NULL, 0);
2201d522f475Smrg
2202d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2203d522f475Smrg				  application_resources,
2204d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2205d522f475Smrg	TRACE_XRES();
2206a1f3da82Smrg#if OPT_MAXIMIZE
2207a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2208a1f3da82Smrg					      tblFullscreen,
2209a1f3da82Smrg					      XtNumber(tblFullscreen));
2210a1f3da82Smrg#endif
2211e39b573cSmrg	VTInitTranslations();
2212d522f475Smrg#if OPT_PTY_HANDSHAKE
2213d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2214d522f475Smrg#endif
2215d522f475Smrg
2216d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2217d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2218d522f475Smrg#if !defined(DISABLE_SETUID)
2219d522f475Smrg	setEffectiveUser(save_euid);
2220d522f475Smrg#endif
2221d522f475Smrg#if !defined(DISABLE_SETGID)
2222d522f475Smrg	setEffectiveGroup(save_egid);
2223d522f475Smrg#endif
2224d522f475Smrg	TRACE_IDS;
2225d522f475Smrg#endif
2226d522f475Smrg#endif
2227d522f475Smrg    }
2228d522f475Smrg
2229d522f475Smrg    /*
2230d522f475Smrg     * ICCCM delete_window.
2231d522f475Smrg     */
2232d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2233d522f475Smrg
2234d522f475Smrg    /*
2235d522f475Smrg     * fill in terminal modes
2236d522f475Smrg     */
2237d522f475Smrg    if (resource.tty_modes) {
2238d522f475Smrg	int n = parse_tty_modes(resource.tty_modes, ttymodelist);
2239d522f475Smrg	if (n < 0) {
22400bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2241d522f475Smrg	} else if (n > 0) {
2242d522f475Smrg	    override_tty_modes = True;
2243d522f475Smrg	}
2244d522f475Smrg    }
22450bd37d32Smrg    initZIconBeep();
2246d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2247d522f475Smrg    if (resource.icon_geometry != NULL) {
2248d522f475Smrg	int scr, junk;
2249d522f475Smrg	int ix, iy;
2250d522f475Smrg	Arg args[2];
2251d522f475Smrg
2252d522f475Smrg	for (scr = 0;		/* yyuucchh */
2253d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2254d522f475Smrg	     scr++) ;
2255d522f475Smrg
2256d522f475Smrg	args[0].name = XtNiconX;
2257d522f475Smrg	args[1].name = XtNiconY;
2258d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2259d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2260d522f475Smrg	args[0].value = (XtArgVal) ix;
2261d522f475Smrg	args[1].value = (XtArgVal) iy;
2262d522f475Smrg	XtSetValues(toplevel, args, 2);
2263d522f475Smrg    }
2264d522f475Smrg
2265d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2266d522f475Smrg		number_ourTopLevelShellArgs);
2267d522f475Smrg
2268d522f475Smrg#if OPT_WIDE_CHARS
2269d522f475Smrg    /* seems as good a place as any */
2270d522f475Smrg    init_classtab();
2271d522f475Smrg#endif
2272d522f475Smrg
2273d522f475Smrg    /* Parse the rest of the command line */
2274d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2275d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
22760bd37d32Smrg	if (!isOption(*argv)) {
2277d522f475Smrg#ifdef VMS
2278d522f475Smrg	    Syntax(*argv);
2279d522f475Smrg#else
2280d522f475Smrg	    if (argc > 1)
2281d522f475Smrg		Syntax(*argv);
2282d522f475Smrg	    continue;
2283d522f475Smrg#endif
22840bd37d32Smrg	}
2285d522f475Smrg
2286d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2287d522f475Smrg	switch (argv[0][1]) {
2288d522f475Smrg	case 'C':
2289d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2290d522f475Smrg#ifndef __sgi
2291d522f475Smrg	    {
2292d522f475Smrg		struct stat sbuf;
2293d522f475Smrg
2294d522f475Smrg		/* Must be owner and have read/write permission.
2295d522f475Smrg		   xdm cooperates to give the console the right user. */
2296d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2297d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2298d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2299d522f475Smrg		    Console = True;
2300d522f475Smrg		} else
2301d522f475Smrg		    Console = False;
2302d522f475Smrg	    }
2303d522f475Smrg#else /* __sgi */
2304d522f475Smrg	    Console = True;
2305d522f475Smrg#endif /* __sgi */
2306d522f475Smrg#endif /* TIOCCONS */
2307d522f475Smrg	    continue;
2308d522f475Smrg	case 'S':
2309d522f475Smrg	    if (!ParseSccn(*argv + 2))
2310d522f475Smrg		Syntax(*argv);
2311d522f475Smrg	    continue;
2312d522f475Smrg#ifdef DEBUG
2313d522f475Smrg	case 'D':
2314d522f475Smrg	    debug = True;
2315d522f475Smrg	    continue;
2316d522f475Smrg#endif /* DEBUG */
23170bd37d32Smrg	case 'c':
23180bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2319d522f475Smrg		Syntax(*argv);
23200bd37d32Smrg	    argc--, argv++;
2321d522f475Smrg	    continue;
2322d522f475Smrg	case 'e':
23230bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2324d522f475Smrg		Syntax(*argv);
23250bd37d32Smrg	    command_to_exec = (argv + 1);
2326d522f475Smrg	    break;
2327d522f475Smrg	case 'i':
23280bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2329d522f475Smrg		Syntax(*argv);
23300bd37d32Smrg	    argc--, argv++;
2331d522f475Smrg	    continue;
2332d522f475Smrg
2333d522f475Smrg	default:
2334d522f475Smrg	    Syntax(*argv);
2335d522f475Smrg	}
2336d522f475Smrg	break;
2337d522f475Smrg    }
2338d522f475Smrg
2339d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2340d522f475Smrg
2341d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2342d522f475Smrg						 form_top,
2343d522f475Smrg#if OPT_TOOLBAR
2344d522f475Smrg						 XtNmenuBar, menu_top,
2345d522f475Smrg						 XtNresizable, True,
2346d522f475Smrg						 XtNfromVert, menu_top,
2347d522f475Smrg						 XtNleft, XawChainLeft,
2348d522f475Smrg						 XtNright, XawChainRight,
2349d522f475Smrg						 XtNtop, XawChainTop,
2350d522f475Smrg						 XtNbottom, XawChainBottom,
2351d522f475Smrg						 XtNmenuHeight, menu_high,
2352d522f475Smrg#endif
2353d522f475Smrg						 (XtPointer) 0);
2354d522f475Smrg    decode_keyboard_type(term, &resource);
2355d522f475Smrg
2356d522f475Smrg    screen = TScreenOf(term);
2357d522f475Smrg    screen->inhibit = 0;
2358d522f475Smrg
2359d522f475Smrg#ifdef ALLOWLOGGING
2360d522f475Smrg    if (term->misc.logInhibit)
2361d522f475Smrg	screen->inhibit |= I_LOG;
2362d522f475Smrg#endif
2363d522f475Smrg    if (term->misc.signalInhibit)
2364d522f475Smrg	screen->inhibit |= I_SIGNAL;
2365d522f475Smrg#if OPT_TEK4014
2366d522f475Smrg    if (term->misc.tekInhibit)
2367d522f475Smrg	screen->inhibit |= I_TEK;
2368d522f475Smrg#endif
2369d522f475Smrg
2370d522f475Smrg    /*
2371d522f475Smrg     * We might start by showing the tek4014 window.
2372d522f475Smrg     */
2373d522f475Smrg#if OPT_TEK4014
2374d522f475Smrg    if (screen->inhibit & I_TEK)
2375d522f475Smrg	TEK4014_ACTIVE(term) = False;
2376d522f475Smrg
2377d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2378d522f475Smrg	SysError(ERROR_INIT);
2379d522f475Smrg#endif
2380d522f475Smrg
2381d522f475Smrg    /*
2382d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2383d522f475Smrg     */
2384d522f475Smrg#if OPT_TOOLBAR
2385d522f475Smrg    ShowToolbar(resource.toolBar);
2386d522f475Smrg#endif
2387d522f475Smrg
23880bd37d32Smrg    xtermOpenSession();
2389d522f475Smrg
2390d522f475Smrg    /*
2391d522f475Smrg     * Set title and icon name if not specified
2392d522f475Smrg     */
2393d522f475Smrg    if (command_to_exec) {
2394d522f475Smrg	Arg args[2];
2395d522f475Smrg
2396d522f475Smrg	if (!resource.title) {
2397d522f475Smrg	    if (command_to_exec) {
2398d522f475Smrg		resource.title = x_basename(command_to_exec[0]);
2399d522f475Smrg	    }			/* else not reached */
2400d522f475Smrg	}
2401d522f475Smrg
2402d522f475Smrg	if (!resource.icon_name)
2403d522f475Smrg	    resource.icon_name = resource.title;
2404d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2405d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2406d522f475Smrg
24070bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2408d522f475Smrg	       resource.title,
2409d522f475Smrg	       resource.icon_name,
24100bd37d32Smrg	       NonNull(resource.icon_hint),
2411d522f475Smrg	       *command_to_exec));
2412d522f475Smrg
2413d522f475Smrg	XtSetValues(toplevel, args, 2);
2414d522f475Smrg    }
2415d522f475Smrg#if OPT_LUIT_PROG
2416d522f475Smrg    if (term->misc.callfilter) {
24170bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
24180bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
24190bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
24200bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
24210bd37d32Smrg
24220bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
24230bd37d32Smrg						  (count_split
24240bd37d32Smrg						   + count_exec
24250bd37d32Smrg						   + count_using
24260bd37d32Smrg						   + 8));
24270bd37d32Smrg	if (command_to_exec_with_luit == NULL)
24280bd37d32Smrg	    SysError(ERROR_LUMALLOC);
24290bd37d32Smrg
24300bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
24310bd37d32Smrg	if (count_using) {
24320bd37d32Smrg	    char *encoding_opt[4];
24330bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
24340bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
24350bd37d32Smrg	    encoding_opt[2] = 0;
24360bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
24370bd37d32Smrg	}
24380bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
24390bd37d32Smrg	if (count_exec) {
24400bd37d32Smrg	    char *delimiter[2];
24410bd37d32Smrg	    delimiter[0] = x_strdup("--");
24420bd37d32Smrg	    delimiter[1] = 0;
24430bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
24440bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2445d522f475Smrg	}
24460bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
24470bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2448d522f475Smrg    }
2449d522f475Smrg#endif
2450d522f475Smrg
24510bd37d32Smrg    if_DEBUG({
2452d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2453d522f475Smrg	   done securely by a privileged xterm process (although we try),
2454d522f475Smrg	   so the debug feature is disabled by default. */
2455e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2456d522f475Smrg	int i = -1;
24570bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
24580bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
24590bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2460d522f475Smrg	}
2461d522f475Smrg	if (i >= 0) {
2462d522f475Smrg	    dup2(i, 2);
2463d522f475Smrg
2464d522f475Smrg	    /* mark this file as close on exec */
2465d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2466d522f475Smrg	}
24670bd37d32Smrg    });
2468d522f475Smrg
2469d522f475Smrg    spawnXTerm(term);
2470d522f475Smrg
2471d522f475Smrg#ifndef VMS
2472d522f475Smrg    /* Child process is out there, let's catch its termination */
2473d522f475Smrg
2474d522f475Smrg#ifdef USE_POSIX_SIGNALS
2475d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2476d522f475Smrg#else
2477d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2478d522f475Smrg#endif
2479d522f475Smrg    /* Realize procs have now been executed */
2480d522f475Smrg
2481d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2482d522f475Smrg	char buf[80];
2483d522f475Smrg
2484d522f475Smrg	buf[0] = '\0';
2485d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
248620d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2487d522f475Smrg    }
2488d522f475Smrg#ifdef AIXV3
2489d522f475Smrg#if (OSMAJORVERSION < 4)
2490d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2491d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2492d522f475Smrg     * to the slave-pty process when xterm exits.
2493d522f475Smrg     */
2494d522f475Smrg
2495d522f475Smrg    {
2496d522f475Smrg	TERMIO_STRUCT tio;
2497d522f475Smrg
2498d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
2499d522f475Smrg	    SysError(ERROR_TIOCGETP);
2500d522f475Smrg
2501d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
2502d522f475Smrg
2503d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
2504d522f475Smrg	    SysError(ERROR_TIOCSETP);
2505d522f475Smrg    }
2506d522f475Smrg#endif
2507d522f475Smrg#endif
2508d522f475Smrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__)
2509d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
2510d522f475Smrg	SysError(ERROR_F_GETFL);
2511d522f475Smrg#ifdef O_NDELAY
2512d522f475Smrg    mode |= O_NDELAY;
2513d522f475Smrg#else
2514d522f475Smrg    mode |= O_NONBLOCK;
2515d522f475Smrg#endif /* O_NDELAY */
2516d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
2517d522f475Smrg	SysError(ERROR_F_SETFL);
2518d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
2519d522f475Smrg    mode = 1;
2520d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
2521d522f475Smrg	SysError(ERROR_FIONBIO);
2522d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
2523d522f475Smrg
2524d522f475Smrg    /* The erase character is used to delete the current completion */
2525d522f475Smrg#if OPT_DABBREV
2526d522f475Smrg#ifdef TERMIO_STRUCT
2527d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
2528d522f475Smrg#else
2529d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
2530d522f475Smrg#endif
2531d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
2532d522f475Smrg#endif
2533d522f475Smrg
2534d522f475Smrg    FD_ZERO(&pty_mask);
2535d522f475Smrg    FD_ZERO(&X_mask);
2536d522f475Smrg    FD_ZERO(&Select_mask);
2537d522f475Smrg    FD_SET(screen->respond, &pty_mask);
2538d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
2539d522f475Smrg    FD_SET(screen->respond, &Select_mask);
2540d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
2541d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
2542d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
2543d522f475Smrg		 : (1 + screen->respond));
2544d522f475Smrg
2545d522f475Smrg#endif /* !VMS */
25460bd37d32Smrg    if_DEBUG({
25470bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
25480bd37d32Smrg    });
2549d522f475Smrg    XSetErrorHandler(xerror);
2550d522f475Smrg    XSetIOErrorHandler(xioerror);
2551e39b573cSmrg    IceSetIOErrorHandler(ice_error);
2552d522f475Smrg
2553d522f475Smrg    initPtyData(&VTbuffer);
2554d522f475Smrg#ifdef ALLOWLOGGING
2555d522f475Smrg    if (term->misc.log_on) {
255620d2c4d2Smrg	StartLog(term);
2557d522f475Smrg    }
2558d522f475Smrg#endif
2559d522f475Smrg
25600bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
2561d522f475Smrg#if OPT_COLOR_RES
2562a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
2563a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
256420d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
256520d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2566d522f475Smrg
2567a1f3da82Smrg    if (term->misc.re_verse0) {
2568a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
2569a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
2570a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
2571a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
2572a1f3da82Smrg	} else {
2573a1f3da82Smrg	    ReverseVideo(term);
2574a1f3da82Smrg	}
2575a1f3da82Smrg	term->misc.re_verse = True;
2576a1f3da82Smrg	update_reversevideo();
2577a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
2578a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
2579a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
2580a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2581a1f3da82Smrg    }
2582d522f475Smrg#endif /* OPT_COLOR_RES */
2583d522f475Smrg
2584956cc18dSsnj#if OPT_MAXIMIZE
2585956cc18dSsnj    if (resource.maximized)
2586956cc18dSsnj	RequestMaximize(term, True);
2587956cc18dSsnj#endif
2588d522f475Smrg    for (;;) {
2589d522f475Smrg#if OPT_TEK4014
2590d522f475Smrg	if (TEK4014_ACTIVE(term))
2591d522f475Smrg	    TekRun();
2592d522f475Smrg	else
2593d522f475Smrg#endif
2594956cc18dSsnj	    VTRun(term);
2595d522f475Smrg    }
2596d522f475Smrg}
2597d522f475Smrg
2598956cc18dSsnj#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2599d522f475Smrg#define USE_OPENPTY 1
2600d522f475Smrgstatic int opened_tty = -1;
2601d522f475Smrg#endif
2602d522f475Smrg
2603d522f475Smrg/*
2604d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
2605d522f475Smrg *
2606d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
2607d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
2608d522f475Smrg * so that if a pty master is found and later, we find that the slave
2609d522f475Smrg * has problems, we can re-enter this function and get another one.
2610d522f475Smrg */
2611d522f475Smrgstatic int
2612d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
2613d522f475Smrg{
2614d522f475Smrg    int result = 1;
2615d522f475Smrg
26160bd37d32Smrg#if defined(USE_OPENPTY)
26170bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
26180bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
26190bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
26200bd37d32Smrg	char *name = ptsname(*pty);
26210bd37d32Smrg	if (name != 0) {
26220bd37d32Smrg	    strcpy(ttydev, name);
26230bd37d32Smrg	    result = 0;
26240bd37d32Smrg	}
26250bd37d32Smrg    }
26260bd37d32Smrg#ifdef USE_PTY_SEARCH
26270bd37d32Smrg    if (result) {
26280bd37d32Smrg	result = pty_search(pty);
26290bd37d32Smrg    }
26300bd37d32Smrg#endif
26310bd37d32Smrg#elif defined(PUCC_PTYD)
2632d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
2633d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
2634d522f475Smrg			       save_ruid, from)) < 0);
2635d522f475Smrg#elif defined(__QNXNTO__)
2636d522f475Smrg    result = pty_search(pty);
2637d522f475Smrg#else
2638d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
2639d522f475Smrg#ifdef __GLIBC__		/* if __GLIBC__ and USE_USG_PTYS, we know glibc >= 2.1 */
2640d522f475Smrg    /* GNU libc 2 allows us to abstract away from having to know the
2641d522f475Smrg       master pty device name. */
2642d522f475Smrg    if ((*pty = getpt()) >= 0) {
2643d522f475Smrg	char *name = ptsname(*pty);
2644d522f475Smrg	if (name != 0) {	/* if filesystem is trashed, this may be null */
2645d522f475Smrg	    strcpy(ttydev, name);
2646d522f475Smrg	    result = 0;
2647d522f475Smrg	}
2648d522f475Smrg    }
2649d522f475Smrg#elif defined(__MVS__)
2650d522f475Smrg    result = pty_search(pty);
2651d522f475Smrg#else
26520bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
2653d522f475Smrg#endif
26540bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
26550bd37d32Smrg    if (!result)
26560bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
2657d522f475Smrg#endif
2658d522f475Smrg
2659d522f475Smrg#elif defined(AIXV3)
2660d522f475Smrg
2661d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
2662d522f475Smrg	strcpy(ttydev, ttyname(*pty));
2663d522f475Smrg	result = 0;
2664d522f475Smrg    }
2665d522f475Smrg#elif defined(__convex__)
2666d522f475Smrg
2667d522f475Smrg    char *pty_name;
2668d522f475Smrg    extern char *getpty(void);
2669d522f475Smrg
2670d522f475Smrg    while ((pty_name = getpty()) != NULL) {
2671d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
2672d522f475Smrg	    strcpy(ptydev, pty_name);
2673d522f475Smrg	    strcpy(ttydev, pty_name);
2674d522f475Smrg	    *x_basename(ttydev) = 't';
2675d522f475Smrg	    result = 0;
2676d522f475Smrg	    break;
2677d522f475Smrg	}
2678d522f475Smrg    }
2679d522f475Smrg
2680d522f475Smrg#elif defined(sequent)
2681d522f475Smrg
2682d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
2683d522f475Smrg
2684d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
2685d522f475Smrg
2686d522f475Smrg    char *tty_name;
2687d522f475Smrg
2688d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
2689d522f475Smrg    if (tty_name != 0) {
2690d522f475Smrg	strcpy(ttydev, tty_name);
2691d522f475Smrg	result = 0;
2692d522f475Smrg    }
2693d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
2694d522f475Smrg
2695d522f475Smrg    struct stat fstat_buf;
2696d522f475Smrg
2697d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
2698d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
2699d522f475Smrg	result = 0;
2700d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
2701d522f475Smrg    }
2702d522f475Smrg#elif defined(__hpux)
2703d522f475Smrg
2704d522f475Smrg    /*
2705d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
2706d522f475Smrg     */
2707d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
2708d522f475Smrg	char *name = ptsname(*pty);
2709d522f475Smrg	if (name != 0) {
2710d522f475Smrg	    strcpy(ttydev, name);
2711d522f475Smrg	    result = 0;
2712d522f475Smrg	} else {		/* permissions, or other unexpected problem */
2713d522f475Smrg	    close(*pty);
2714d522f475Smrg	    *pty = -1;
2715d522f475Smrg	    result = pty_search(pty);
2716d522f475Smrg	}
2717d522f475Smrg    } else {
2718d522f475Smrg	result = pty_search(pty);
2719d522f475Smrg    }
2720d522f475Smrg
2721d522f475Smrg#else
2722d522f475Smrg
2723d522f475Smrg    result = pty_search(pty);
2724d522f475Smrg
2725d522f475Smrg#endif
2726d522f475Smrg#endif
2727d522f475Smrg
2728d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
2729d522f475Smrg	   ttydev != 0 ? ttydev : "?",
2730d522f475Smrg	   ptydev != 0 ? ptydev : "?",
2731d522f475Smrg	   result ? "FAIL" : "OK",
2732d522f475Smrg	   pty != 0 ? *pty : -1));
2733d522f475Smrg    return result;
2734d522f475Smrg}
2735d522f475Smrg
2736d522f475Smrgstatic void
2737e0a2b6dfSmrgset_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
2738d522f475Smrg{
2739d522f475Smrg#ifdef USE_TTY_GROUP
2740d522f475Smrg    struct group *ttygrp;
2741d522f475Smrg
2742d522f475Smrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
2743d522f475Smrg	gid = ttygrp->gr_gid;
2744d522f475Smrg	mode &= 0660U;
2745d522f475Smrg    }
2746d522f475Smrg    endgrent();
2747d522f475Smrg#endif /* USE_TTY_GROUP */
2748d522f475Smrg
2749d522f475Smrg    TRACE_IDS;
2750d522f475Smrg    set_owner(ttydev, uid, gid, mode);
2751d522f475Smrg}
2752d522f475Smrg
2753d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
2754d522f475Smrg#undef get_pty
2755d522f475Smrg/*
2756d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
2757d522f475Smrg * result.
2758d522f475Smrg */
2759d522f475Smrgstatic int
2760d522f475Smrgget_pty(int *pty, char *from)
2761d522f475Smrg{
2762d522f475Smrg    static int m_pty = -1;
2763d522f475Smrg    int result = -1;
2764d522f475Smrg
2765d522f475Smrg    if (pty == NULL) {
2766d522f475Smrg	result = really_get_pty(&m_pty, from);
2767d522f475Smrg
2768d522f475Smrg	seteuid(0);
2769d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
2770d522f475Smrg	seteuid(save_ruid);
2771d522f475Smrg	TRACE_IDS;
2772d522f475Smrg
2773d522f475Smrg#ifdef USE_OPENPTY
2774d522f475Smrg	if (opened_tty >= 0) {
2775d522f475Smrg	    close(opened_tty);
2776d522f475Smrg	    opened_tty = -1;
2777d522f475Smrg	}
2778d522f475Smrg#endif
2779d522f475Smrg    } else if (m_pty != -1) {
2780d522f475Smrg	*pty = m_pty;
2781d522f475Smrg	result = 0;
2782d522f475Smrg    } else {
2783d522f475Smrg	result = -1;
2784d522f475Smrg    }
27850bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
27860bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
27870bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
27880bd37d32Smrg	   result ? "FAIL" : "OK",
27890bd37d32Smrg	   pty != 0 ? *pty : -1));
2790d522f475Smrg    return result;
2791d522f475Smrg}
2792d522f475Smrg#endif
2793d522f475Smrg
2794d522f475Smrg/*
2795d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
2796d522f475Smrg * we might allocate.  Used on those systems that do not have
2797d522f475Smrg * a functional interface for allocating a pty.
2798d522f475Smrg * Returns 0 if found a pty, 1 if fails.
2799d522f475Smrg */
2800d522f475Smrg#ifdef USE_PTY_SEARCH
2801d522f475Smrgstatic int
2802d522f475Smrgpty_search(int *pty)
2803d522f475Smrg{
2804d522f475Smrg    static int devindex = 0, letter = 0;
2805d522f475Smrg
2806d522f475Smrg#if defined(CRAY) || defined(__MVS__)
2807d522f475Smrg    while (devindex < MAXPTTYS) {
2808d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
2809d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
2810d522f475Smrg	devindex++;
2811d522f475Smrg
2812d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2813d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2814d522f475Smrg	    return 0;
2815d522f475Smrg	}
2816d522f475Smrg    }
2817d522f475Smrg#else /* CRAY || __MVS__ */
2818d522f475Smrg    while (PTYCHAR1[letter]) {
2819d522f475Smrg	ttydev[strlen(ttydev) - 2] =
2820d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
2821d522f475Smrg
2822d522f475Smrg	while (PTYCHAR2[devindex]) {
2823d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
2824d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
2825d522f475Smrg	    devindex++;
2826d522f475Smrg
2827d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
2828d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
2829d522f475Smrg#ifdef sun
2830d522f475Smrg		/* Need to check the process group of the pty.
2831d522f475Smrg		 * If it exists, then the slave pty is in use,
2832d522f475Smrg		 * and we need to get another one.
2833d522f475Smrg		 */
2834d522f475Smrg		int pgrp_rtn;
2835d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
2836d522f475Smrg		    close(*pty);
2837d522f475Smrg		    continue;
2838d522f475Smrg		}
2839d522f475Smrg#endif /* sun */
2840d522f475Smrg		return 0;
2841d522f475Smrg	    }
2842d522f475Smrg	}
2843d522f475Smrg	devindex = 0;
2844d522f475Smrg	letter++;
2845d522f475Smrg    }
2846d522f475Smrg#endif /* CRAY else */
2847d522f475Smrg    /*
2848d522f475Smrg     * We were unable to allocate a pty master!  Return an error
2849d522f475Smrg     * condition and let our caller terminate cleanly.
2850d522f475Smrg     */
2851d522f475Smrg    return 1;
2852d522f475Smrg}
2853d522f475Smrg#endif /* USE_PTY_SEARCH */
2854d522f475Smrg
2855d522f475Smrg/*
2856d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
2857d522f475Smrg * the latter has support for switching character sets.  We support the
2858d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
2859d522f475Smrg * choose 4014 over 4015.
2860d522f475Smrg *
2861d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
2862d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
2863d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
2864d522f475Smrg * later Tektronix terminals), and 4 character sizes.
2865d522f475Smrg * All of these are supported by xterm.
2866d522f475Smrg */
2867d522f475Smrg
2868d522f475Smrg#if OPT_TEK4014
286920d2c4d2Smrgstatic const char *tekterm[] =
2870d522f475Smrg{
2871d522f475Smrg    "tek4014",
2872d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
2873d522f475Smrg    "tek4012",			/* 4010 with lower case */
2874d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
2875d522f475Smrg    "tek4010",			/* small screen, upper-case only */
2876d522f475Smrg    "dumb",
2877d522f475Smrg    0
2878d522f475Smrg};
2879d522f475Smrg#endif
2880d522f475Smrg
2881d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
2882d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
2883d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
2884d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
2885d522f475Smrg * The VT420 has up to 48 lines on the screen.
2886d522f475Smrg */
2887d522f475Smrg
288820d2c4d2Smrgstatic const char *vtterm[] =
2889d522f475Smrg{
2890d522f475Smrg#ifdef USE_X11TERM
2891d522f475Smrg    "x11term",			/* for people who want special term name */
2892d522f475Smrg#endif
2893d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
2894d522f475Smrg    "xterm",			/* the prefered name, should be fastest */
2895d522f475Smrg    "vt102",
2896d522f475Smrg    "vt100",
2897d522f475Smrg    "ansi",
2898d522f475Smrg    "dumb",
2899d522f475Smrg    0
2900d522f475Smrg};
2901d522f475Smrg
2902d522f475Smrg/* ARGSUSED */
29030bd37d32Smrgstatic void
2904d522f475Smrghungtty(int i GCC_UNUSED)
2905d522f475Smrg{
29060bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
2907d522f475Smrg    siglongjmp(env, 1);
2908d522f475Smrg}
2909d522f475Smrg
2910d522f475Smrg#if OPT_PTY_HANDSHAKE
2911d522f475Smrg#define NO_FDS {-1, -1}
2912d522f475Smrg
2913d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
2914d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
2915d522f475Smrg
2916d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
2917d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
2918d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
2919d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
2920d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
2921d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
2922d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
2923d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
2924d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
2925d522f475Smrg} status_t;
2926d522f475Smrg
2927d522f475Smrgtypedef struct {
2928d522f475Smrg    status_t status;
2929d522f475Smrg    int error;
2930d522f475Smrg    int fatal_error;
2931d522f475Smrg    int tty_slot;
2932d522f475Smrg    int rows;
2933d522f475Smrg    int cols;
2934d522f475Smrg    char buffer[1024];
2935d522f475Smrg} handshake_t;
2936d522f475Smrg
2937d522f475Smrg#if OPT_TRACE
2938d522f475Smrgstatic void
2939d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
2940d522f475Smrg{
2941d522f475Smrg    const char *status = "?";
2942d522f475Smrg    switch (data->status) {
2943d522f475Smrg    case PTY_BAD:
2944d522f475Smrg	status = "PTY_BAD";
2945d522f475Smrg	break;
2946d522f475Smrg    case PTY_FATALERROR:
2947d522f475Smrg	status = "PTY_FATALERROR";
2948d522f475Smrg	break;
2949d522f475Smrg    case PTY_GOOD:
2950d522f475Smrg	status = "PTY_GOOD";
2951d522f475Smrg	break;
2952d522f475Smrg    case PTY_NEW:
2953d522f475Smrg	status = "PTY_NEW";
2954d522f475Smrg	break;
2955d522f475Smrg    case PTY_NOMORE:
2956d522f475Smrg	status = "PTY_NOMORE";
2957d522f475Smrg	break;
2958d522f475Smrg    case UTMP_ADDED:
2959d522f475Smrg	status = "UTMP_ADDED";
2960d522f475Smrg	break;
2961d522f475Smrg    case UTMP_TTYSLOT:
2962d522f475Smrg	status = "UTMP_TTYSLOT";
2963d522f475Smrg	break;
2964d522f475Smrg    case PTY_EXEC:
2965d522f475Smrg	status = "PTY_EXEC";
2966d522f475Smrg	break;
2967d522f475Smrg    }
2968d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
2969d522f475Smrg	   tag,
2970d522f475Smrg	   status,
2971d522f475Smrg	   data->error,
2972d522f475Smrg	   data->fatal_error,
2973d522f475Smrg	   data->buffer));
2974d522f475Smrg}
2975d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
2976d522f475Smrg#else
2977d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
2978d522f475Smrg#endif
2979d522f475Smrg
2980d522f475Smrg/* HsSysError()
2981d522f475Smrg *
2982d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
2983d522f475Smrg * over the errno and error exit to the master process so that it can
2984d522f475Smrg * display our error message and exit with our exit code so that the
2985d522f475Smrg * user can see it.
2986d522f475Smrg */
2987d522f475Smrg
2988d522f475Smrgstatic void
2989d522f475SmrgHsSysError(int error)
2990d522f475Smrg{
2991d522f475Smrg    handshake_t handshake;
2992d522f475Smrg
2993d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
2994d522f475Smrg    handshake.status = PTY_FATALERROR;
2995d522f475Smrg    handshake.error = errno;
2996d522f475Smrg    handshake.fatal_error = error;
29970bd37d32Smrg    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
2998d522f475Smrg
2999d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
3000d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
3001d522f475Smrg	       handshake.error,
3002d522f475Smrg	       handshake.fatal_error,
3003d522f475Smrg	       handshake.buffer));
3004d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
300520d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
300620d2c4d2Smrg			(const char *) &handshake,
300720d2c4d2Smrg			sizeof(handshake)));
3008d522f475Smrg    } else {
30090bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
30100bd37d32Smrg		     handshake.error,
30110bd37d32Smrg		     handshake.fatal_error,
30120bd37d32Smrg		     handshake.buffer);
3013d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3014d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3015d522f475Smrg    }
3016d522f475Smrg    exit(error);
3017d522f475Smrg}
3018d522f475Smrg
3019d522f475Smrgvoid
3020d522f475Smrgfirst_map_occurred(void)
3021d522f475Smrg{
3022d522f475Smrg    if (resource.wait_for_map) {
3023d522f475Smrg	handshake_t handshake;
3024d522f475Smrg	TScreen *screen = TScreenOf(term);
3025d522f475Smrg
3026d522f475Smrg	memset(&handshake, 0, sizeof(handshake));
3027d522f475Smrg	handshake.status = PTY_EXEC;
3028d522f475Smrg	handshake.rows = screen->max_row;
3029d522f475Smrg	handshake.cols = screen->max_col;
3030d522f475Smrg
3031d522f475Smrg	if (pc_pipe[1] >= 0) {
3032d522f475Smrg	    TRACE(("first_map_occurred: %dx%d\n", handshake.rows, handshake.cols));
3033d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
303420d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
303520d2c4d2Smrg			    (const char *) &handshake,
303620d2c4d2Smrg			    sizeof(handshake)));
3037d522f475Smrg	    close(cp_pipe[0]);
3038d522f475Smrg	    close(pc_pipe[1]);
3039d522f475Smrg	}
3040d522f475Smrg	resource.wait_for_map = False;
3041d522f475Smrg    }
3042d522f475Smrg}
3043d522f475Smrg#else
3044d522f475Smrg/*
3045d522f475Smrg * temporary hack to get xterm working on att ptys
3046d522f475Smrg */
3047d522f475Smrgstatic void
3048d522f475SmrgHsSysError(int error)
3049d522f475Smrg{
30500bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
30510bd37d32Smrg		 error, errno, ttydev);
3052d522f475Smrg    exit(error);
3053d522f475Smrg}
3054d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3055d522f475Smrg
3056d522f475Smrg#ifndef VMS
3057d522f475Smrgstatic void
3058e0a2b6dfSmrgset_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
3059d522f475Smrg{
3060d522f475Smrg    int why;
3061d522f475Smrg
3062d522f475Smrg    TRACE_IDS;
306320d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
30640bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3065d522f475Smrg
3066d522f475Smrg    if (chown(device, uid, gid) < 0) {
3067d522f475Smrg	why = errno;
3068d522f475Smrg	if (why != ENOENT
3069d522f475Smrg	    && save_ruid == 0) {
30700bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
30710bd37d32Smrg			device, (long) uid, (long) gid);
3072d522f475Smrg	}
3073d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3074e39b573cSmrg    } else if (chmod(device, mode) < 0) {
3075d522f475Smrg	why = errno;
3076d522f475Smrg	if (why != ENOENT) {
3077d522f475Smrg	    struct stat sb;
3078d522f475Smrg	    if (stat(device, &sb) < 0) {
30790bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
30800bd37d32Smrg			    device, (unsigned) mode);
3081d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
30820bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
30830bd37d32Smrg			    device,
30840bd37d32Smrg			    (unsigned long) mode,
30850bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3086d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
30870bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3088d522f475Smrg	    }
3089d522f475Smrg	}
3090d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3091d522f475Smrg    }
3092d522f475Smrg}
3093d522f475Smrg
3094d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3095d522f475Smrg/*
3096d522f475Smrg * getutid() only looks at ut_type and ut_id.
3097d522f475Smrg * But we'll also check ut_line in find_utmp().
3098d522f475Smrg */
3099d522f475Smrgstatic void
3100d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3101d522f475Smrg{
3102d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3103d522f475Smrg    tofind->ut_type = type;
3104d522f475Smrg    (void) strncpy(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3105d522f475Smrg    (void) strncpy(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3106d522f475Smrg}
3107d522f475Smrg
3108d522f475Smrg/*
3109d522f475Smrg * We could use getutline() if we didn't support old systems.
3110d522f475Smrg */
3111d522f475Smrgstatic struct UTMP_STR *
3112d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3113d522f475Smrg{
3114d522f475Smrg    struct UTMP_STR *result;
31150bd37d32Smrg    struct UTMP_STR limited;
3116d522f475Smrg    struct UTMP_STR working;
3117d522f475Smrg
3118d522f475Smrg    for (;;) {
3119d522f475Smrg	memset(&working, 0, sizeof(working));
3120d522f475Smrg	working.ut_type = tofind->ut_type;
31210bd37d32Smrg	strncpy(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3122d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3123d522f475Smrg	working.ut_type = 0;
3124d522f475Smrg#endif
3125d522f475Smrg	if ((result = call_getutid(&working)) == 0)
3126d522f475Smrg	    break;
31270bd37d32Smrg	/*
31280bd37d32Smrg	 * ut_line may not be null-terminated, but if it is, there may be
31290bd37d32Smrg	 * garbage after the null.  Use strncpy to ensure that the value
31300bd37d32Smrg	 * we check is null-terminated (if there is enough space in the
31310bd37d32Smrg	 * buffer), and that unused space is nulled.
31320bd37d32Smrg	 */
31330bd37d32Smrg	strncpy(limited.ut_line, result->ut_line, sizeof(result->ut_line));
31340bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3135d522f475Smrg	    break;
3136d522f475Smrg	/*
3137d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3138d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3139d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3140d522f475Smrg	 */
3141d522f475Smrg	memset(result, 0, sizeof(*result));
3142d522f475Smrg    }
3143d522f475Smrg    return result;
3144d522f475Smrg}
3145d522f475Smrg#endif /* HAVE_UTMP... */
3146d522f475Smrg
3147d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3148d522f475Smrg
314920d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
315020d2c4d2Smrg#define USE_NO_DEV_TTY 1
315120d2c4d2Smrg#else
315220d2c4d2Smrg#define USE_NO_DEV_TTY 0
315320d2c4d2Smrg#endif
315420d2c4d2Smrg
3155e0a2b6dfSmrgstatic int
3156e0a2b6dfSmrgsame_leaf(char *a, char *b)
3157e0a2b6dfSmrg{
3158e0a2b6dfSmrg    char *p = x_basename(a);
3159e0a2b6dfSmrg    char *q = x_basename(b);
3160e0a2b6dfSmrg    return !strcmp(p, q);
3161e0a2b6dfSmrg}
3162e0a2b6dfSmrg
3163e0a2b6dfSmrg/*
3164e0a2b6dfSmrg * "good enough" (inode wouldn't port to Cygwin)
3165e0a2b6dfSmrg */
3166e0a2b6dfSmrgstatic int
3167e0a2b6dfSmrgsame_file(const char *a, const char *b)
3168e0a2b6dfSmrg{
3169e0a2b6dfSmrg    struct stat asb;
3170e0a2b6dfSmrg    struct stat bsb;
3171e0a2b6dfSmrg    int result = 0;
3172e0a2b6dfSmrg
3173e0a2b6dfSmrg    if ((stat(a, &asb) == 0)
3174e0a2b6dfSmrg	&& (stat(b, &bsb) == 0)
3175e0a2b6dfSmrg	&& ((asb.st_mode & S_IFMT) == S_IFREG)
3176e0a2b6dfSmrg	&& ((bsb.st_mode & S_IFMT) == S_IFREG)
3177e0a2b6dfSmrg	&& (asb.st_mtime == bsb.st_mtime)
3178e0a2b6dfSmrg	&& (asb.st_size == bsb.st_size)) {
3179e0a2b6dfSmrg	result = 1;
3180e0a2b6dfSmrg    }
3181e0a2b6dfSmrg    return result;
3182e0a2b6dfSmrg}
3183e0a2b6dfSmrg
3184e0a2b6dfSmrg/*
3185e0a2b6dfSmrg * Only set $SHELL for paths found in the standard location.
3186e0a2b6dfSmrg */
3187e0a2b6dfSmrgstatic Boolean
3188e0a2b6dfSmrgvalidShell(const char *pathname)
3189e0a2b6dfSmrg{
3190e0a2b6dfSmrg    Boolean result = False;
3191e0a2b6dfSmrg    const char *ok_shells = "/etc/shells";
3192e0a2b6dfSmrg    char *blob;
3193e0a2b6dfSmrg    struct stat sb;
3194e0a2b6dfSmrg    size_t rc;
3195e0a2b6dfSmrg    FILE *fp;
3196e0a2b6dfSmrg
3197e0a2b6dfSmrg    if (validProgram(pathname)
3198e0a2b6dfSmrg	&& stat(ok_shells, &sb) == 0
3199e0a2b6dfSmrg	&& (sb.st_mode & S_IFMT) == S_IFREG
3200e0a2b6dfSmrg	&& (sb.st_size != 0)
3201e0a2b6dfSmrg	&& (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
3202e0a2b6dfSmrg	if ((fp = fopen(ok_shells, "r")) != 0) {
3203e0a2b6dfSmrg	    rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
3204e0a2b6dfSmrg	    if (rc == (size_t) sb.st_size) {
3205e0a2b6dfSmrg		char *p = blob;
3206e0a2b6dfSmrg		char *q, *r;
3207e0a2b6dfSmrg		blob[rc] = '\0';
3208e0a2b6dfSmrg		while (!result && (q = strtok(p, "\n")) != 0) {
3209e0a2b6dfSmrg		    if ((r = x_strtrim(q)) != 0) {
3210e0a2b6dfSmrg			TRACE(("...test \"%s\"\n", q));
3211e0a2b6dfSmrg			if (!strcmp(q, pathname)) {
3212e0a2b6dfSmrg			    result = True;
3213e0a2b6dfSmrg			} else if (same_leaf(q, (char *) pathname) &&
3214e0a2b6dfSmrg				   same_file(q, pathname)) {
3215e0a2b6dfSmrg			    result = True;
3216e0a2b6dfSmrg			}
3217e0a2b6dfSmrg			free(r);
3218e0a2b6dfSmrg		    }
3219e0a2b6dfSmrg		    p = 0;
3220e0a2b6dfSmrg		}
3221e0a2b6dfSmrg	    }
3222e0a2b6dfSmrg	    fclose(fp);
3223e0a2b6dfSmrg	}
3224e0a2b6dfSmrg	free(blob);
3225e0a2b6dfSmrg    }
3226e0a2b6dfSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3227e0a2b6dfSmrg    return result;
3228e0a2b6dfSmrg}
3229e0a2b6dfSmrg
3230e0a2b6dfSmrgstatic char *
3231e0a2b6dfSmrgresetShell(char *oldPath)
3232e0a2b6dfSmrg{
3233e0a2b6dfSmrg    char *newPath = x_strdup("/bin/sh");
3234e0a2b6dfSmrg    char *envPath = getenv("SHELL");
3235e0a2b6dfSmrg    if (oldPath != 0)
3236e0a2b6dfSmrg	free(oldPath);
3237e0a2b6dfSmrg    if (!IsEmpty(envPath))
3238e0a2b6dfSmrg	xtermSetenv("SHELL", newPath);
3239e0a2b6dfSmrg    return newPath;
3240e0a2b6dfSmrg}
3241e0a2b6dfSmrg
3242d522f475Smrg/*
3243d522f475Smrg *  Inits pty and tty and forks a login process.
3244d522f475Smrg *  Does not close fd Xsocket.
3245d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3246d522f475Smrg */
3247d522f475Smrgstatic int
3248d522f475SmrgspawnXTerm(XtermWidget xw)
3249d522f475Smrg{
3250d522f475Smrg    TScreen *screen = TScreenOf(xw);
3251d522f475Smrg    Cardinal nn;
3252d522f475Smrg#if OPT_PTY_HANDSHAKE
3253d522f475Smrg    Bool got_handshake_size = False;
3254d522f475Smrg    handshake_t handshake;
3255d522f475Smrg    int done;
3256d522f475Smrg#endif
3257d522f475Smrg#if OPT_INITIAL_ERASE
3258d522f475Smrg    int initial_erase = VAL_INITIAL_ERASE;
3259d522f475Smrg    Bool setInitialErase;
3260d522f475Smrg#endif
3261d522f475Smrg    int rc = 0;
3262d522f475Smrg    int ttyfd = -1;
3263d522f475Smrg    Bool ok_termcap;
3264d522f475Smrg    char *newtc;
3265d522f475Smrg
3266d522f475Smrg#ifdef TERMIO_STRUCT
3267d522f475Smrg    TERMIO_STRUCT tio;
3268d522f475Smrg#ifdef __MVS__
3269d522f475Smrg    TERMIO_STRUCT gio;
3270d522f475Smrg#endif /* __MVS__ */
3271d522f475Smrg#ifdef TIOCLSET
3272d522f475Smrg    unsigned lmode;
3273d522f475Smrg#endif /* TIOCLSET */
3274d522f475Smrg#ifdef HAS_LTCHARS
3275d522f475Smrg    struct ltchars ltc;
3276d522f475Smrg#endif /* HAS_LTCHARS */
3277d522f475Smrg#else /* !TERMIO_STRUCT */
3278d522f475Smrg    int ldisc = 0;
3279d522f475Smrg    int discipline;
3280d522f475Smrg    unsigned lmode;
3281d522f475Smrg    struct tchars tc;
3282d522f475Smrg    struct ltchars ltc;
3283d522f475Smrg    struct sgttyb sg;
3284d522f475Smrg#ifdef sony
3285d522f475Smrg    int jmode;
3286d522f475Smrg    struct jtchars jtc;
3287d522f475Smrg#endif /* sony */
3288d522f475Smrg#endif /* TERMIO_STRUCT */
3289d522f475Smrg
32900bd37d32Smrg    char *shell_path = 0;
32910bd37d32Smrg    char *shname, *shname_minus;
329220d2c4d2Smrg    int i;
329320d2c4d2Smrg#if USE_NO_DEV_TTY
329420d2c4d2Smrg    int no_dev_tty = False;
329520d2c4d2Smrg#endif
329620d2c4d2Smrg    const char **envnew;	/* new environment */
3297d522f475Smrg    char buf[64];
3298d522f475Smrg    char *TermName = NULL;
3299d522f475Smrg#ifdef TTYSIZE_STRUCT
3300d522f475Smrg    TTYSIZE_STRUCT ts;
3301d522f475Smrg#endif
33020bd37d32Smrg    struct passwd pw;
3303d522f475Smrg    char *login_name = NULL;
3304d522f475Smrg#ifndef USE_UTEMPTER
3305d522f475Smrg#ifdef HAVE_UTMP
3306d522f475Smrg    struct UTMP_STR utmp;
3307d522f475Smrg#ifdef USE_SYSV_UTMP
3308d522f475Smrg    struct UTMP_STR *utret = NULL;
3309d522f475Smrg#endif
3310d522f475Smrg#ifdef USE_LASTLOG
3311d522f475Smrg    struct lastlog lastlog;
3312d522f475Smrg#endif
3313d522f475Smrg#ifdef USE_LASTLOGX
3314d522f475Smrg    struct lastlogx lastlogx;
3315d522f475Smrg#endif /* USE_LASTLOG */
3316d522f475Smrg#endif /* HAVE_UTMP */
3317d522f475Smrg#endif /* !USE_UTEMPTER */
3318d522f475Smrg
3319e39b573cSmrg#if OPT_TRACE
3320e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
3321e39b573cSmrg#endif
3322e39b573cSmrg
3323d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
3324d522f475Smrg    (void) rc;
3325d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3326d522f475Smrg    (void) utret;
3327d522f475Smrg#endif
3328d522f475Smrg
3329d522f475Smrg    screen->uid = save_ruid;
3330d522f475Smrg    screen->gid = save_rgid;
3331d522f475Smrg
3332d522f475Smrg#ifdef SIGTTOU
3333d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
3334d522f475Smrg    signal(SIGTTOU, SIG_IGN);
3335d522f475Smrg#endif
3336d522f475Smrg
3337d522f475Smrg#if OPT_PTY_HANDSHAKE
3338d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3339d522f475Smrg#endif
3340d522f475Smrg
3341d522f475Smrg    if (am_slave >= 0) {
3342d522f475Smrg	screen->respond = am_slave;
3343d522f475Smrg	set_pty_id(ttydev, passedPty);
3344d522f475Smrg#ifdef USE_PTY_DEVICE
3345d522f475Smrg	set_pty_id(ptydev, passedPty);
3346d522f475Smrg#endif
3347d522f475Smrg	if (xtermResetIds(screen) < 0)
3348d522f475Smrg	    exit(1);
3349d522f475Smrg    } else {
3350d522f475Smrg	Bool tty_got_hung;
3351d522f475Smrg
3352d522f475Smrg	/*
3353d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
3354d522f475Smrg	 * that has gone away).  Simply make up some reasonable
3355d522f475Smrg	 * defaults.
3356d522f475Smrg	 */
3357d522f475Smrg
3358d522f475Smrg	signal(SIGALRM, hungtty);
3359d522f475Smrg	alarm(2);		/* alarm(1) might return too soon */
3360d522f475Smrg	if (!sigsetjmp(env, 1)) {
3361d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
3362d522f475Smrg	    alarm(0);
3363d522f475Smrg	    tty_got_hung = False;
3364d522f475Smrg	} else {
3365d522f475Smrg	    tty_got_hung = True;
3366d522f475Smrg	    ttyfd = -1;
3367d522f475Smrg	    errno = ENXIO;
3368d522f475Smrg	}
33690bd37d32Smrg	memset(&pw, 0, sizeof(pw));
3370d522f475Smrg#if OPT_PTY_HANDSHAKE
3371d522f475Smrg	got_handshake_size = False;
3372d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
3373d522f475Smrg#if OPT_INITIAL_ERASE
3374d522f475Smrg	initial_erase = VAL_INITIAL_ERASE;
3375d522f475Smrg#endif
3376d522f475Smrg	signal(SIGALRM, SIG_DFL);
3377d522f475Smrg
3378d522f475Smrg	/*
3379d522f475Smrg	 * Check results and ignore current control terminal if
3380d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
3381d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
3382d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
33830bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
33840bd37d32Smrg	 * if xterm is run within a jail.
3385d522f475Smrg	 */
338620d2c4d2Smrg#if USE_NO_DEV_TTY
3387d522f475Smrg	no_dev_tty = False;
338820d2c4d2Smrg#endif
3389d522f475Smrg	if (ttyfd < 0) {
3390d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
33910bd37d32Smrg		errno == ENOENT ||
3392d522f475Smrg#ifdef ENODEV
3393d522f475Smrg		errno == ENODEV ||
3394d522f475Smrg#endif
3395d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
339620d2c4d2Smrg#if USE_NO_DEV_TTY
3397d522f475Smrg		no_dev_tty = True;
339820d2c4d2Smrg#endif
3399d522f475Smrg#ifdef HAS_LTCHARS
3400d522f475Smrg		ltc = d_ltc;
3401d522f475Smrg#endif /* HAS_LTCHARS */
3402d522f475Smrg#ifdef TIOCLSET
3403d522f475Smrg		lmode = d_lmode;
3404d522f475Smrg#endif /* TIOCLSET */
3405d522f475Smrg#ifdef TERMIO_STRUCT
3406d522f475Smrg		tio = d_tio;
3407d522f475Smrg#else /* !TERMIO_STRUCT */
3408d522f475Smrg		sg = d_sg;
3409d522f475Smrg		tc = d_tc;
3410d522f475Smrg		discipline = d_disipline;
3411d522f475Smrg#ifdef sony
3412d522f475Smrg		jmode = d_jmode;
3413d522f475Smrg		jtc = d_jtc;
3414d522f475Smrg#endif /* sony */
3415d522f475Smrg#endif /* TERMIO_STRUCT */
3416d522f475Smrg	    } else {
3417d522f475Smrg		SysError(ERROR_OPDEVTTY);
3418d522f475Smrg	    }
3419d522f475Smrg	} else {
3420d522f475Smrg
3421d522f475Smrg	    /* Get a copy of the current terminal's state,
3422d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
3423d522f475Smrg	     * may not have a controlling terminal at this point
3424d522f475Smrg	     * if started directly from xdm or xinit,
3425d522f475Smrg	     * in which case we just use the defaults as above.
3426d522f475Smrg	     */
3427d522f475Smrg#ifdef HAS_LTCHARS
3428d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
3429d522f475Smrg		ltc = d_ltc;
3430d522f475Smrg#endif /* HAS_LTCHARS */
3431d522f475Smrg#ifdef TIOCLSET
3432d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
3433d522f475Smrg		lmode = d_lmode;
3434d522f475Smrg#endif /* TIOCLSET */
3435d522f475Smrg#ifdef TERMIO_STRUCT
343620d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
343720d2c4d2Smrg	    if (rc == -1)
3438d522f475Smrg		tio = d_tio;
3439d522f475Smrg#else /* !TERMIO_STRUCT */
344020d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
344120d2c4d2Smrg	    if (rc == -1)
3442d522f475Smrg		sg = d_sg;
3443d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
3444d522f475Smrg		tc = d_tc;
3445d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
3446d522f475Smrg		discipline = d_disipline;
3447d522f475Smrg#ifdef sony
3448d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
3449d522f475Smrg		jmode = d_jmode;
3450d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
3451d522f475Smrg		jtc = d_jtc;
3452d522f475Smrg#endif /* sony */
3453d522f475Smrg#endif /* TERMIO_STRUCT */
3454d522f475Smrg
3455d522f475Smrg	    /*
3456d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
3457d522f475Smrg	     * erase value.  Just in case that will fail, first get
3458d522f475Smrg	     * the value from /dev/tty, so we will have something
3459d522f475Smrg	     * at least.
3460d522f475Smrg	     */
3461d522f475Smrg#if OPT_INITIAL_ERASE
3462d522f475Smrg	    if (resource.ptyInitialErase) {
3463d522f475Smrg#ifdef TERMIO_STRUCT
3464d522f475Smrg		initial_erase = tio.c_cc[VERASE];
3465d522f475Smrg#else /* !TERMIO_STRUCT */
3466d522f475Smrg		initial_erase = sg.sg_erase;
3467d522f475Smrg#endif /* TERMIO_STRUCT */
3468d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
3469d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
3470d522f475Smrg		       initial_erase));
3471d522f475Smrg	    }
3472d522f475Smrg#endif
3473d522f475Smrg#ifdef __MVS__
3474d522f475Smrg	    if (ttyGetAttr(ttyfd, &gio) == 0) {
3475d522f475Smrg		gio.c_cflag &= ~(HUPCL | PARENB);
3476d522f475Smrg		ttySetAttr(ttyfd, &gio);
3477d522f475Smrg	    }
3478d522f475Smrg#endif /* __MVS__ */
3479d522f475Smrg
3480d522f475Smrg	    close_fd(ttyfd);
3481d522f475Smrg	}
3482d522f475Smrg
3483d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
3484d522f475Smrg	    SysError(ERROR_PTYS);
3485d522f475Smrg	}
34860bd37d32Smrg	TRACE_TTYSIZE(screen->respond, "after get_pty");
3487d522f475Smrg#if OPT_INITIAL_ERASE
3488d522f475Smrg	if (resource.ptyInitialErase) {
3489d522f475Smrg#ifdef TERMIO_STRUCT
3490d522f475Smrg	    TERMIO_STRUCT my_tio;
349120d2c4d2Smrg	    rc = ttyGetAttr(screen->respond, &my_tio);
349220d2c4d2Smrg	    if (rc == 0)
3493d522f475Smrg		initial_erase = my_tio.c_cc[VERASE];
3494d522f475Smrg#else /* !TERMIO_STRUCT */
3495d522f475Smrg	    struct sgttyb my_sg;
349620d2c4d2Smrg	    rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg);
349720d2c4d2Smrg	    if (rc == 0)
3498d522f475Smrg		initial_erase = my_sg.sg_erase;
3499d522f475Smrg#endif /* TERMIO_STRUCT */
3500d522f475Smrg	    TRACE(("%s initial_erase:%d (from pty)\n",
3501d522f475Smrg		   (rc == 0) ? "OK" : "FAIL",
3502d522f475Smrg		   initial_erase));
3503d522f475Smrg	}
3504d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3505d522f475Smrg    }
3506d522f475Smrg
3507d522f475Smrg    /* avoid double MapWindow requests */
3508d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
3509d522f475Smrg
3510d522f475Smrg    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
3511d522f475Smrg				   False);
3512d522f475Smrg
3513d522f475Smrg    if (!TEK4014_ACTIVE(xw))
3514956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
3515d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
3516d522f475Smrg    if (Console) {
3517d522f475Smrg	/*
3518d522f475Smrg	 * Inform any running xconsole program
3519d522f475Smrg	 * that we are going to steal the console.
3520d522f475Smrg	 */
3521d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
3522d522f475Smrg	mit_console = XInternAtom(screen->display, mit_console_name, False);
3523d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
3524d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
3525d522f475Smrg		       mit_console, CurrentTime,
3526d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
3527d522f475Smrg    }
3528d522f475Smrg#endif
3529d522f475Smrg#if OPT_TEK4014
3530d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3531d522f475Smrg	envnew = tekterm;
3532d522f475Smrg    } else
3533d522f475Smrg#endif
3534d522f475Smrg    {
3535d522f475Smrg	envnew = vtterm;
3536d522f475Smrg    }
3537d522f475Smrg
3538d522f475Smrg    /*
3539d522f475Smrg     * This used to exit if no termcap entry was found for the specified
3540d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
3541d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
3542d522f475Smrg     * entry is not found.
3543d522f475Smrg     */
3544d522f475Smrg    ok_termcap = True;
354520d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
354620d2c4d2Smrg	const char *last = NULL;
354720d2c4d2Smrg	char *next;
354820d2c4d2Smrg
354920d2c4d2Smrg	TermName = x_strdup(*envnew);
3550d522f475Smrg	ok_termcap = False;
3551d522f475Smrg	while (*envnew != NULL) {
355220d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
355320d2c4d2Smrg		next = x_strdup(*envnew);
355420d2c4d2Smrg		if (get_termcap(xw, next)) {
355520d2c4d2Smrg		    free(TermName);
355620d2c4d2Smrg		    TermName = next;
35570bd37d32Smrg		    ok_termcap = True + 1;
355820d2c4d2Smrg		    break;
355920d2c4d2Smrg		} else {
356020d2c4d2Smrg		    free(next);
356120d2c4d2Smrg		}
3562d522f475Smrg	    }
3563d522f475Smrg	    last = *envnew;
3564d522f475Smrg	    envnew++;
3565d522f475Smrg	}
3566d522f475Smrg    }
3567d522f475Smrg    if (ok_termcap) {
3568a1f3da82Smrg	resource.term_name = TermName;
356920d2c4d2Smrg	resize_termcap(xw);
3570d522f475Smrg    }
3571d522f475Smrg
3572d522f475Smrg    /*
3573d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
3574d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
3575d522f475Smrg     */
3576d522f475Smrg#if OPT_INITIAL_ERASE
3577d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
3578d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
3579d522f475Smrg    setInitialErase = False;
3580d522f475Smrg    if (override_tty_modes && ttymodelist[XTTYMODE_erase].set) {
3581d522f475Smrg	initial_erase = ttymodelist[XTTYMODE_erase].value;
3582d522f475Smrg	setInitialErase = True;
3583d522f475Smrg    } else if (resource.ptyInitialErase) {
3584a1f3da82Smrg	/* EMPTY */ ;
3585d522f475Smrg    } else if (ok_termcap) {
358620d2c4d2Smrg	char *s = get_tcap_erase(xw);
3587d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
3588d522f475Smrg	if (s != 0) {
358920d2c4d2Smrg	    char *save = s;
3590d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
3591d522f475Smrg	    setInitialErase = True;
359220d2c4d2Smrg	    free(save);
3593d522f475Smrg	}
3594d522f475Smrg    }
3595d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
3596d522f475Smrg
3597d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
3598d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
3599d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
3600d522f475Smrg	if (initial_erase == ANSI_DEL) {
360120d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
3602d522f475Smrg	} else {
3603d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
3604d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
3605d522f475Smrg	}
3606d522f475Smrg	TRACE(("...sets DECBKM %s\n",
3607d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
3608d522f475Smrg    } else {
3609d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
3610d522f475Smrg    }
3611d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3612d522f475Smrg
3613d522f475Smrg#ifdef TTYSIZE_STRUCT
3614d522f475Smrg    /* tell tty how big window is */
3615d522f475Smrg#if OPT_TEK4014
3616d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3617d522f475Smrg	TTYSIZE_ROWS(ts) = 38;
3618d522f475Smrg	TTYSIZE_COLS(ts) = 81;
3619d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
362020d2c4d2Smrg	ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
362120d2c4d2Smrg	ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3622d522f475Smrg#endif
3623d522f475Smrg    } else
3624d522f475Smrg#endif
3625d522f475Smrg    {
362620d2c4d2Smrg	TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
362720d2c4d2Smrg	TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3628d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
362920d2c4d2Smrg	ts.ws_xpixel = (ttySize_t) FullWidth(screen);
363020d2c4d2Smrg	ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3631d522f475Smrg#endif
3632d522f475Smrg    }
363320d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
3634d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
3635d522f475Smrg	   TTYSIZE_ROWS(ts),
3636d522f475Smrg	   TTYSIZE_COLS(ts), i));
3637d522f475Smrg#endif /* TTYSIZE_STRUCT */
3638d522f475Smrg
36390bd37d32Smrg#if !defined(USE_OPENPTY)
36400bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
36410bd37d32Smrg    /*
36420bd37d32Smrg     * utempter checks the ownership of the device; some implementations
36430bd37d32Smrg     * set ownership in grantpt - do this first.
36440bd37d32Smrg     */
36450bd37d32Smrg    grantpt(screen->respond);
36460bd37d32Smrg#endif
36470bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
36480bd37d32Smrg    unlockpt(screen->respond);
36490bd37d32Smrg    TRACE_TTYSIZE(screen->respond, "after unlockpt");
36500bd37d32Smrg#endif
36510bd37d32Smrg#endif /* !USE_OPENPTY */
36520bd37d32Smrg
3653d522f475Smrg    added_utmp_entry = False;
3654d522f475Smrg#if defined(USE_UTEMPTER)
3655d522f475Smrg#undef UTMP
3656d522f475Smrg    if (!resource.utmpInhibit) {
3657d522f475Smrg	struct UTMP_STR dummy;
3658d522f475Smrg
3659d522f475Smrg	/* Note: utempter may trim it anyway */
3660d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
36610bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
36620bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
3663d522f475Smrg	addToUtmp(ttydev, dummy.ut_host, screen->respond);
3664d522f475Smrg	added_utmp_entry = True;
3665d522f475Smrg    }
3666d522f475Smrg#endif
3667d522f475Smrg
3668d522f475Smrg    if (am_slave < 0) {
3669d522f475Smrg#if OPT_PTY_HANDSHAKE
3670d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
3671d522f475Smrg	    SysError(ERROR_FORK);
3672d522f475Smrg#endif
3673d522f475Smrg	TRACE(("Forking...\n"));
3674d522f475Smrg	if ((screen->pid = fork()) == -1)
3675d522f475Smrg	    SysError(ERROR_FORK);
3676d522f475Smrg
3677d522f475Smrg	if (screen->pid == 0) {
3678d522f475Smrg#ifdef USE_USG_PTYS
367920d2c4d2Smrg	    int ptyfd = -1;
3680d522f475Smrg	    char *pty_name;
3681d522f475Smrg#endif
3682d522f475Smrg	    /*
3683d522f475Smrg	     * now in child process
3684d522f475Smrg	     */
3685d522f475Smrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
3686d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
3687d522f475Smrg#else
3688d522f475Smrg	    int pgrp = getpid();
3689d522f475Smrg#endif
3690d522f475Smrg	    TRACE_CHILD
3691d522f475Smrg
3692d522f475Smrg#ifdef USE_USG_PTYS
36930bd37d32Smrg#ifdef HAVE_SETPGID
36940bd37d32Smrg		setpgid(0, 0);
36950bd37d32Smrg#else
3696d522f475Smrg		setpgrp();
36970bd37d32Smrg#endif
36980bd37d32Smrg	    unlockpt(screen->respond);
36990bd37d32Smrg	    TRACE_TTYSIZE(screen->respond, "after unlockpt");
37000bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
37010bd37d32Smrg		SysError(ERROR_PTSNAME);
37020bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
37030bd37d32Smrg		SysError(ERROR_OPPTSNAME);
37040bd37d32Smrg	    }
3705d522f475Smrg#ifdef I_PUSH
37060bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ptem") < 0) {
37070bd37d32Smrg		SysError(ERROR_PTEM);
37080bd37d32Smrg	    }
3709d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
37100bd37d32Smrg	    else if (!x_getenv("CONSEM")
37110bd37d32Smrg		     && ioctl(ptyfd, I_PUSH, "consem") < 0) {
37120bd37d32Smrg		SysError(ERROR_CONSEM);
37130bd37d32Smrg	    }
3714d522f475Smrg#endif /* !SVR4 */
37150bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ldterm") < 0) {
37160bd37d32Smrg		SysError(ERROR_LDTERM);
37170bd37d32Smrg	    }
3718d522f475Smrg#ifdef SVR4			/* from Sony */
37190bd37d32Smrg	    else if (ioctl(ptyfd, I_PUSH, "ttcompat") < 0) {
37200bd37d32Smrg		SysError(ERROR_TTCOMPAT);
37210bd37d32Smrg	    }
3722d522f475Smrg#endif /* SVR4 */
3723d522f475Smrg#endif /* I_PUSH */
37240bd37d32Smrg	    ttyfd = ptyfd;
3725d522f475Smrg#ifndef __MVS__
37260bd37d32Smrg	    close_fd(screen->respond);
3727d522f475Smrg#endif /* __MVS__ */
3728d522f475Smrg
3729d522f475Smrg#ifdef TTYSIZE_STRUCT
37300bd37d32Smrg	    /* tell tty how big window is */
3731d522f475Smrg#if OPT_TEK4014
37320bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
37330bd37d32Smrg		TTYSIZE_ROWS(ts) = 24;
37340bd37d32Smrg		TTYSIZE_COLS(ts) = 80;
3735d522f475Smrg#ifdef USE_STRUCT_WINSIZE
37360bd37d32Smrg		ts.ws_xpixel = TFullWidth(TekScreenOf(tekWidget));
37370bd37d32Smrg		ts.ws_ypixel = TFullHeight(TekScreenOf(tekWidget));
3738d522f475Smrg#endif
37390bd37d32Smrg	    } else
3740d522f475Smrg#endif /* OPT_TEK4014 */
37410bd37d32Smrg	    {
37420bd37d32Smrg		TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
37430bd37d32Smrg		TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
3744d522f475Smrg#ifdef USE_STRUCT_WINSIZE
37450bd37d32Smrg		ts.ws_xpixel = (ttySize_t) FullWidth(screen);
37460bd37d32Smrg		ts.ws_ypixel = (ttySize_t) FullHeight(screen);
3747d522f475Smrg#endif
37480bd37d32Smrg	    }
3749d522f475Smrg#endif /* TTYSIZE_STRUCT */
3750d522f475Smrg
3751d522f475Smrg#endif /* USE_USG_PTYS */
3752d522f475Smrg
37530bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
3754d522f475Smrg
3755d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
37560bd37d32Smrg	    if (resource.ptyHandshake) {
37570bd37d32Smrg		char *ptr;
3758d522f475Smrg
37590bd37d32Smrg		/* close parent's sides of the pipes */
37600bd37d32Smrg		close(cp_pipe[0]);
37610bd37d32Smrg		close(pc_pipe[1]);
37620bd37d32Smrg
37630bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
37640bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
37650bd37d32Smrg		 * or err.
37660bd37d32Smrg		 */
37670bd37d32Smrg		if (cp_pipe[1] <= 2) {
37680bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
37690bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
37700bd37d32Smrg			cp_pipe[1] = i;
3771d522f475Smrg		    }
37720bd37d32Smrg		}
37730bd37d32Smrg		if (pc_pipe[0] <= 2) {
37740bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
37750bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
37760bd37d32Smrg			pc_pipe[0] = i;
3777d522f475Smrg		    }
37780bd37d32Smrg		}
3779d522f475Smrg
37800bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
37810bd37d32Smrg		close(ConnectionNumber(screen->display));
3782d522f475Smrg#ifndef __MVS__
3783e0a2b6dfSmrg		close(screen->respond);
3784d522f475Smrg#endif /* __MVS__ */
3785d522f475Smrg
37860bd37d32Smrg		/* Now is the time to set up our process group and
37870bd37d32Smrg		 * open up the pty slave.
37880bd37d32Smrg		 */
3789d522f475Smrg#ifdef USE_SYSV_PGRP
3790d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
37910bd37d32Smrg		IGNORE_RC(setsid());
3792d522f475Smrg#else
37930bd37d32Smrg		IGNORE_RC(setpgrp());
3794d522f475Smrg#endif
3795d522f475Smrg#endif /* USE_SYSV_PGRP */
3796d522f475Smrg
3797d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
37980bd37d32Smrg		qsetlogin(getlogin(), ttydev);
3799d522f475Smrg#endif
38000bd37d32Smrg		if (ttyfd >= 0) {
3801d522f475Smrg#ifdef __MVS__
38020bd37d32Smrg		    if (ttyGetAttr(ttyfd, &gio) == 0) {
38030bd37d32Smrg			gio.c_cflag &= ~(HUPCL | PARENB);
38040bd37d32Smrg			ttySetAttr(ttyfd, &gio);
38050bd37d32Smrg		    }
3806d522f475Smrg#else /* !__MVS__ */
38070bd37d32Smrg		    close_fd(ttyfd);
3808d522f475Smrg#endif /* __MVS__ */
38090bd37d32Smrg		}
3810d522f475Smrg
38110bd37d32Smrg		for (;;) {
381220d2c4d2Smrg#if USE_NO_DEV_TTY
38130bd37d32Smrg		    if (!no_dev_tty
38140bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
38150bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
38160bd37d32Smrg			close_fd(ttyfd);
38170bd37d32Smrg		    }
381820d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
3819d522f475Smrg#ifdef CSRG_BASED
38200bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
3821d522f475Smrg#endif
38220bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
38230bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after open");
38240bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
38250bd37d32Smrg			TRACE_TTYSIZE(ttyfd, "after fixup");
3826d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
38270bd37d32Smrg			/* make /dev/tty work */
38280bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
3829d522f475Smrg#endif
3830d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
38310bd37d32Smrg			/* make /dev/tty work */
38320bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
3833d522f475Smrg#endif
3834d522f475Smrg#ifdef USE_SYSV_PGRP
38350bd37d32Smrg			/* We need to make sure that we are actually
38360bd37d32Smrg			 * the process group leader for the pty.  If
38370bd37d32Smrg			 * we are, then we should now be able to open
38380bd37d32Smrg			 * /dev/tty.
38390bd37d32Smrg			 */
38400bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
38410bd37d32Smrg			    /* success! */
38420bd37d32Smrg			    close(i);
3843d522f475Smrg			    break;
3844d522f475Smrg			}
38450bd37d32Smrg#else /* USE_SYSV_PGRP */
38460bd37d32Smrg			break;
38470bd37d32Smrg#endif /* USE_SYSV_PGRP */
38480bd37d32Smrg		    }
38490bd37d32Smrg		    perror("open ttydev");
3850d522f475Smrg#ifdef TIOCSCTTY
38510bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
3852d522f475Smrg#endif
38530bd37d32Smrg		    /* let our master know that the open failed */
38540bd37d32Smrg		    handshake.status = PTY_BAD;
38550bd37d32Smrg		    handshake.error = errno;
38560bd37d32Smrg		    strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
38570bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
38580bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
38590bd37d32Smrg				    (const char *) &handshake,
38600bd37d32Smrg				    sizeof(handshake)));
3861d522f475Smrg
38620bd37d32Smrg		    /* get reply from parent */
38630bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
38640bd37d32Smrg				   sizeof(handshake));
38650bd37d32Smrg		    if (i <= 0) {
38660bd37d32Smrg			/* parent terminated */
38670bd37d32Smrg			exit(1);
3868d522f475Smrg		    }
3869d522f475Smrg
38700bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
38710bd37d32Smrg			/* No more ptys, let's shutdown. */
38720bd37d32Smrg			exit(1);
3873d522f475Smrg		    }
38740bd37d32Smrg
38750bd37d32Smrg		    /* We have a new pty to try */
38760bd37d32Smrg		    if (ttyfd >= 0)
38770bd37d32Smrg			close(ttyfd);
38780bd37d32Smrg		    free(ttydev);
38790bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
3880d522f475Smrg		}
3881d522f475Smrg
38820bd37d32Smrg		/* use the same tty name that everyone else will use
38830bd37d32Smrg		 * (from ttyname)
38840bd37d32Smrg		 */
38850bd37d32Smrg		if ((ptr = ttyname(ttyfd)) != 0) {
38860bd37d32Smrg		    free(ttydev);
38870bd37d32Smrg		    ttydev = x_strdup(ptr);
38880bd37d32Smrg		}
38890bd37d32Smrg	    }
38900bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
3891d522f475Smrg
3892d522f475Smrg	    set_pty_permissions(screen->uid,
3893d522f475Smrg				screen->gid,
3894d522f475Smrg				(resource.messages
3895d522f475Smrg				 ? 0622U
3896d522f475Smrg				 : 0600U));
3897d522f475Smrg
3898d522f475Smrg	    /*
3899d522f475Smrg	     * set up the tty modes
3900d522f475Smrg	     */
3901d522f475Smrg	    {
3902d522f475Smrg#ifdef TERMIO_STRUCT
3903d522f475Smrg#if defined(umips) || defined(CRAY) || defined(linux)
3904d522f475Smrg		/* If the control tty had its modes screwed around with,
3905d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
3906d522f475Smrg		   will have bad values.  Let's just get termio from the
3907d522f475Smrg		   new tty and tailor it.  */
3908d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
3909d522f475Smrg		    SysError(ERROR_TIOCGETP);
3910d522f475Smrg		tio.c_lflag |= ECHOE;
3911d522f475Smrg#endif /* umips */
3912d522f475Smrg		/* Now is also the time to change the modes of the
3913d522f475Smrg		 * child pty.
3914d522f475Smrg		 */
3915d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
391620d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
3917d522f475Smrg		tio.c_iflag |= ICRNL;
39180bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
3919d522f475Smrg#if OPT_LUIT_PROG
3920d522f475Smrg		if (command_to_exec_with_luit == 0)
3921d522f475Smrg#endif
3922d522f475Smrg		    if (screen->utf8_mode)
3923d522f475Smrg			tio.c_iflag |= IUTF8;
3924d522f475Smrg#endif
3925d522f475Smrg		/* ouput: cr->cr, nl is not return, no delays, ln->cr/nl */
3926d522f475Smrg#ifndef USE_POSIX_TERMIOS
392720d2c4d2Smrg		UIntClr(tio.c_oflag,
392820d2c4d2Smrg			(OCRNL
392920d2c4d2Smrg			 | ONLRET
393020d2c4d2Smrg			 | NLDLY
393120d2c4d2Smrg			 | CRDLY
393220d2c4d2Smrg			 | TABDLY
393320d2c4d2Smrg			 | BSDLY
393420d2c4d2Smrg			 | VTDLY
393520d2c4d2Smrg			 | FFDLY));
3936d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3937d522f475Smrg#ifdef ONLCR
3938d522f475Smrg		tio.c_oflag |= ONLCR;
3939d522f475Smrg#endif /* ONLCR */
3940d522f475Smrg#ifdef OPOST
3941d522f475Smrg		tio.c_oflag |= OPOST;
3942d522f475Smrg#endif /* OPOST */
3943d522f475Smrg#ifndef USE_POSIX_TERMIOS
3944d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
3945d522f475Smrg#  define CBAUD V_CBAUD
3946d522f475Smrg# endif
394720d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
3948d522f475Smrg#ifdef BAUD_0
3949d522f475Smrg		/* baud rate is 0 (don't care) */
3950d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
3951d522f475Smrg		tio.c_ispeed = tio.c_ospeed = VAL_LINE_SPEED;
3952d522f475Smrg#else /* !BAUD_0 */
3953d522f475Smrg		tio.c_cflag |= VAL_LINE_SPEED;
3954d522f475Smrg#endif /* !BAUD_0 */
3955d522f475Smrg#else /* USE_POSIX_TERMIOS */
3956d522f475Smrg		cfsetispeed(&tio, VAL_LINE_SPEED);
3957d522f475Smrg		cfsetospeed(&tio, VAL_LINE_SPEED);
3958d522f475Smrg#ifdef __MVS__
3959d522f475Smrg		/* turn off bits that can't be set from the slave side */
3960d522f475Smrg		tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
3961d522f475Smrg#endif /* __MVS__ */
3962d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
3963d522f475Smrg		   when the xterm ends */
3964d522f475Smrg		tio.c_cflag &= ~CLOCAL;
3965d522f475Smrg#endif /* USE_POSIX_TERMIOS */
3966d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
3967d522f475Smrg		 * echo
3968d522f475Smrg		 */
3969d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
3970d522f475Smrg#ifdef ECHOKE
3971d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
3972d522f475Smrg#endif
3973d522f475Smrg#ifdef ECHOCTL
3974d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
3975d522f475Smrg#endif
3976d522f475Smrg		for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
3977d522f475Smrg		    if (validTtyChar(tio, nn)) {
3978d522f475Smrg			int sysMode = known_ttyChars[nn].sysMode;
3979d522f475Smrg#ifdef __MVS__
3980d522f475Smrg			if (tio.c_cc[sysMode] != 0) {
3981d522f475Smrg			    switch (sysMode) {
3982d522f475Smrg			    case VEOL:
3983d522f475Smrg			    case VEOF:
3984d522f475Smrg				continue;
3985d522f475Smrg			    }
3986d522f475Smrg			}
3987d522f475Smrg#endif
39880bd37d32Smrg			tio.c_cc[sysMode] = (cc_t) known_ttyChars[nn].myDefault;
3989d522f475Smrg		    }
3990d522f475Smrg		}
3991d522f475Smrg
3992d522f475Smrg		if (override_tty_modes) {
3993d522f475Smrg		    for (nn = 0; nn < XtNumber(known_ttyChars); ++nn) {
3994d522f475Smrg			if (validTtyChar(tio, nn)) {
3995d522f475Smrg			    TMODE(known_ttyChars[nn].myMode,
3996d522f475Smrg				  tio.c_cc[known_ttyChars[nn].sysMode]);
3997d522f475Smrg			}
3998d522f475Smrg		    }
3999d522f475Smrg#ifdef HAS_LTCHARS
4000d522f475Smrg		    /* both SYSV and BSD have ltchars */
4001d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4002d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4003d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4004d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4005d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4006d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4007d522f475Smrg#endif
4008d522f475Smrg		}
4009d522f475Smrg#ifdef HAS_LTCHARS
4010d522f475Smrg#ifdef __hpux
4011d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
4012d522f475Smrg		 * are not set to _POSIX_VDISABLE */
4013d522f475Smrg		ltc.t_rprntc = ltc.t_rprntc = ltc.t_flushc =
4014d522f475Smrg		    ltc.t_werasc = ltc.t_lnextc = _POSIX_VDISABLE;
4015d522f475Smrg#endif /* __hpux */
4016d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
4017d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4018d522f475Smrg#endif /* HAS_LTCHARS */
4019d522f475Smrg#ifdef TIOCLSET
4020d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4021d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4022d522f475Smrg#endif /* TIOCLSET */
4023d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
4024d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4025d522f475Smrg
4026d522f475Smrg		/* ignore errors here - some platforms don't work */
402720d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
4028d522f475Smrg		if (screen->input_eight_bits)
4029d522f475Smrg		    tio.c_cflag |= CS8;
4030d522f475Smrg		else
4031d522f475Smrg		    tio.c_cflag |= CS7;
4032d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
4033d522f475Smrg
4034d522f475Smrg#else /* !TERMIO_STRUCT */
4035d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
4036d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
4037d522f475Smrg		/* make sure speed is set on pty so that editors work right */
4038d522f475Smrg		sg.sg_ispeed = VAL_LINE_SPEED;
4039d522f475Smrg		sg.sg_ospeed = VAL_LINE_SPEED;
4040d522f475Smrg		/* reset t_brkc to default value */
4041d522f475Smrg		tc.t_brkc = -1;
4042d522f475Smrg#ifdef LPASS8
4043d522f475Smrg		if (screen->input_eight_bits)
4044d522f475Smrg		    lmode |= LPASS8;
4045d522f475Smrg		else
4046d522f475Smrg		    lmode &= ~(LPASS8);
4047d522f475Smrg#endif
4048d522f475Smrg#ifdef sony
4049d522f475Smrg		jmode &= ~KM_KANJI;
4050d522f475Smrg#endif /* sony */
4051d522f475Smrg
4052d522f475Smrg		ltc = d_ltc;
4053d522f475Smrg
4054d522f475Smrg		if (override_tty_modes) {
4055d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
4056d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
4057d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
4058d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
4059d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
4060d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
4061d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
4062d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
4063d522f475Smrg		    /* both SYSV and BSD have ltchars */
4064d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4065d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4066d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4067d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4068d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4069d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4070d522f475Smrg		}
4071d522f475Smrg
4072d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
4073d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4074d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
4075d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4076d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
4077d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
4078d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
4079d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
4080d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4081d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4082d522f475Smrg#ifdef sony
4083d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
4084d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
4085d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
4086d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
4087d522f475Smrg#endif /* sony */
4088d522f475Smrg#endif /* TERMIO_STRUCT */
4089d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4090d522f475Smrg		if (Console) {
4091d522f475Smrg#ifdef TIOCCONS
4092d522f475Smrg		    int on = 1;
4093d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
40940bd37d32Smrg			xtermPerror("cannot open console");
4095d522f475Smrg#endif
4096d522f475Smrg#ifdef SRIOCSREDIR
4097d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4098d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
40990bd37d32Smrg			xtermPerror("cannot open console");
410020d2c4d2Smrg		    IGNORE_RC(close(fd));
4101d522f475Smrg#endif
4102d522f475Smrg		}
4103d522f475Smrg#endif /* TIOCCONS */
4104d522f475Smrg	    }
4105d522f475Smrg
4106d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4107d522f475Smrg#ifdef USE_SYSV_SIGHUP
4108d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4109d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4110d522f475Smrg#else
4111d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4112d522f475Smrg#endif
4113d522f475Smrg	    /* restore various signals to their defaults */
4114d522f475Smrg	    signal(SIGINT, SIG_DFL);
4115d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4116d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4117d522f475Smrg
4118d522f475Smrg	    /*
4119d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4120d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4121d522f475Smrg	     * the terminal's erase mode from our best guess.
4122d522f475Smrg	     */
4123d522f475Smrg#if OPT_INITIAL_ERASE
4124d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4125d522f475Smrg		   initial_erase,
4126d522f475Smrg		   setInitialErase ? "YES" : "NO",
4127d522f475Smrg		   resource.ptyInitialErase,
4128d522f475Smrg		   override_tty_modes,
4129d522f475Smrg		   ttymodelist[XTTYMODE_erase].set));
4130d522f475Smrg	    if (setInitialErase) {
4131d522f475Smrg#if OPT_TRACE
4132d522f475Smrg		int old_erase;
4133d522f475Smrg#endif
4134d522f475Smrg#ifdef TERMIO_STRUCT
4135d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4136d522f475Smrg		    tio = d_tio;
4137d522f475Smrg#if OPT_TRACE
4138d522f475Smrg		old_erase = tio.c_cc[VERASE];
4139d522f475Smrg#endif
41400bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
414120d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4142d522f475Smrg#else /* !TERMIO_STRUCT */
4143d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4144d522f475Smrg		    sg = d_sg;
4145d522f475Smrg#if OPT_TRACE
4146d522f475Smrg		old_erase = sg.sg_erase;
4147d522f475Smrg#endif
4148d522f475Smrg		sg.sg_erase = initial_erase;
4149d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4150d522f475Smrg#endif /* TERMIO_STRUCT */
4151d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4152d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4153d522f475Smrg	    }
4154d522f475Smrg#endif
4155d522f475Smrg
4156d522f475Smrg	    xtermCopyEnv(environ);
4157d522f475Smrg
41580bd37d32Smrg	    /*
41590bd37d32Smrg	     * standards.freedesktop.org/startup-notification-spec/
41600bd37d32Smrg	     * notes that this variable is used when a "reliable" mechanism is
41610bd37d32Smrg	     * not available; in practice it must be unset to avoid confusing
41620bd37d32Smrg	     * GTK applications.
41630bd37d32Smrg	     */
41640bd37d32Smrg	    xtermUnsetenv("DESKTOP_STARTUP_ID");
4165e0a2b6dfSmrg	    /*
4166e0a2b6dfSmrg	     * We set this temporarily to work around poor design of Xcursor.
4167e0a2b6dfSmrg	     * Unset it here to avoid confusion.
4168e0a2b6dfSmrg	     */
4169e0a2b6dfSmrg	    xtermUnsetenv("XCURSOR_PATH");
41700bd37d32Smrg
4171a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4172a1f3da82Smrg	    if (!resource.term_name)
417320d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4174d522f475Smrg
4175d522f475Smrg	    sprintf(buf, "%lu",
4176d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4177d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4178d522f475Smrg
4179d522f475Smrg	    /* put the display into the environment of the shell */
4180d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4181d522f475Smrg
4182d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4183d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4184d522f475Smrg
4185e39b573cSmrg	    /*
4186e39b573cSmrg	     * For debugging only, add environment variables that can be used
4187e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4188e39b573cSmrg	     * processes.
4189e39b573cSmrg	     */
4190e39b573cSmrg#if OPT_TRACE
4191e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4192e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4193e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4194e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4195e39b573cSmrg#endif
4196e39b573cSmrg
4197d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4198d522f475Smrg
4199d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4200d522f475Smrg	     */
4201d522f475Smrg	    {
4202d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4203d522f475Smrg		close_fd(ttyfd);
4204d522f475Smrg
420520d2c4d2Smrg		IGNORE_RC(close(0));
4206d522f475Smrg
4207d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4208d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4209d522f475Smrg		}
421020d2c4d2Smrg		IGNORE_RC(close(1));
421120d2c4d2Smrg		IGNORE_RC(close(2));
4212d522f475Smrg		dup(0);
4213d522f475Smrg		dup(0);
4214d522f475Smrg#else
4215d522f475Smrg		/* dup the tty */
4216d522f475Smrg		for (i = 0; i <= 2; i++)
4217d522f475Smrg		    if (i != ttyfd) {
421820d2c4d2Smrg			IGNORE_RC(close(i));
421920d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4220d522f475Smrg		    }
4221d522f475Smrg#ifndef ATT
4222d522f475Smrg		/* and close the tty */
4223d522f475Smrg		if (ttyfd > 2)
4224d522f475Smrg		    close_fd(ttyfd);
4225d522f475Smrg#endif
4226d522f475Smrg#endif /* CRAY */
4227d522f475Smrg	    }
4228d522f475Smrg
4229d522f475Smrg#if !defined(USE_SYSV_PGRP)
4230d522f475Smrg#ifdef TIOCSCTTY
4231d522f475Smrg	    setsid();
4232d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4233d522f475Smrg#endif
4234d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4235d522f475Smrg	    setpgrp(0, 0);
4236d522f475Smrg	    close(open(ttydev, O_WRONLY));
4237d522f475Smrg	    setpgrp(0, pgrp);
4238d522f475Smrg#if defined(__QNX__)
4239d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4240d522f475Smrg#endif
4241d522f475Smrg#endif /* !USE_SYSV_PGRP */
4242d522f475Smrg
4243d522f475Smrg#ifdef Lynx
4244d522f475Smrg	    {
4245d522f475Smrg		TERMIO_STRUCT t;
4246d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4247d522f475Smrg		    /* this gets lost somewhere on our way... */
4248d522f475Smrg		    t.c_oflag |= OPOST;
4249d522f475Smrg		    ttySetAttr(0, &t);
4250d522f475Smrg		}
4251d522f475Smrg	    }
4252d522f475Smrg#endif
4253d522f475Smrg
4254d522f475Smrg#ifdef HAVE_UTMP
4255d522f475Smrg	    login_name = NULL;
42560bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
42570bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4258d522f475Smrg	    }
4259d522f475Smrg	    if (login_name != NULL) {
4260d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4261d522f475Smrg	    }
4262d522f475Smrg#ifndef USE_UTEMPTER
4263d522f475Smrg#ifdef USE_UTMP_SETGID
4264d522f475Smrg	    setEffectiveGroup(save_egid);
4265d522f475Smrg	    TRACE_IDS;
4266d522f475Smrg#endif
4267d522f475Smrg#ifdef USE_SYSV_UTMP
4268d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4269d522f475Smrg	     * for the following reasons:
4270d522f475Smrg	     *   - It needs to have our correct process id (for
4271d522f475Smrg	     *     login).
4272d522f475Smrg	     *   - If our parent was to set it after the fork(),
4273d522f475Smrg	     *     it might make it out before we need it.
4274d522f475Smrg	     *   - We need to do it before we go and change our
4275d522f475Smrg	     *     user and group id's.
4276d522f475Smrg	     */
4277d522f475Smrg	    (void) call_setutent();
4278d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4279d522f475Smrg
4280d522f475Smrg	    /* position to entry in utmp file */
4281d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
428220d2c4d2Smrg	    utret = find_utmp(&utmp);
428320d2c4d2Smrg	    if (utret == 0) {
4284d522f475Smrg		(void) call_setutent();
4285d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
428620d2c4d2Smrg		utret = find_utmp(&utmp);
428720d2c4d2Smrg		if (utret == 0) {
4288d522f475Smrg		    (void) call_setutent();
4289d522f475Smrg		}
4290d522f475Smrg	    }
4291d522f475Smrg#if OPT_TRACE
4292d522f475Smrg	    if (!utret)
4293d522f475Smrg		TRACE(("getutid: NULL\n"));
4294d522f475Smrg	    else
42950bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
429620d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
42970bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
42980bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4299d522f475Smrg#endif
4300d522f475Smrg
4301d522f475Smrg	    /* set up the new entry */
4302d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4303d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4304d522f475Smrg	    utmp.ut_xstatus = 2;
4305d522f475Smrg#endif
4306d522f475Smrg	    (void) strncpy(utmp.ut_user,
4307d522f475Smrg			   (login_name != NULL) ? login_name : "????",
4308d522f475Smrg			   sizeof(utmp.ut_user));
4309d522f475Smrg	    /* why are we copying this string again?  (see above) */
4310d522f475Smrg	    (void) strncpy(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4311d522f475Smrg	    (void) strncpy(utmp.ut_line,
4312d522f475Smrg			   my_pty_name(ttydev), sizeof(utmp.ut_line));
4313d522f475Smrg
4314d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4315d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4316d522f475Smrg#endif
4317d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4318d522f475Smrg	    SetUtmpSysLen(utmp);
4319d522f475Smrg#endif
4320d522f475Smrg
4321d522f475Smrg	    (void) strncpy(utmp.ut_name,
4322d522f475Smrg			   (login_name) ? login_name : "????",
4323d522f475Smrg			   sizeof(utmp.ut_name));
4324d522f475Smrg
4325d522f475Smrg	    utmp.ut_pid = getpid();
4326d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4327d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4328d522f475Smrg	    utmp.ut_session = getsid(0);
4329d522f475Smrg#endif
4330d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
4331d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
4332d522f475Smrg#else
4333d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
4334d522f475Smrg#endif
4335d522f475Smrg
4336d522f475Smrg	    /* write out the entry */
4337d522f475Smrg	    if (!resource.utmpInhibit) {
4338d522f475Smrg		errno = 0;
4339d522f475Smrg		call_pututline(&utmp);
43400bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
43410bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
43420bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
4343d522f475Smrg		       (long) utmp.ut_pid,
4344d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
4345d522f475Smrg	    }
4346d522f475Smrg#ifdef WTMP
4347d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
4348d522f475Smrg	    if (xw->misc.login_shell)
4349d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
4350d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4351d522f475Smrg	    if (xw->misc.login_shell)
4352d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
4353d522f475Smrg#else
4354d522f475Smrg	    if (xw->misc.login_shell &&
4355d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
43560bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4357d522f475Smrg		close(i);
4358d522f475Smrg	    }
4359d522f475Smrg#endif
4360d522f475Smrg#endif
4361d522f475Smrg	    /* close the file */
4362d522f475Smrg	    (void) call_endutent();
4363d522f475Smrg
4364d522f475Smrg#else /* USE_SYSV_UTMP */
4365d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
4366d522f475Smrg	     * utmp entry.
4367d522f475Smrg	     */
4368d522f475Smrg	    tslot = ttyslot();
4369d522f475Smrg	    added_utmp_entry = False;
4370d522f475Smrg	    {
43710bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
4372d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
4373956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
4374d522f475Smrg		    (void) strncpy(utmp.ut_line,
4375d522f475Smrg				   my_pty_name(ttydev),
4376d522f475Smrg				   sizeof(utmp.ut_line));
4377d522f475Smrg		    (void) strncpy(utmp.ut_name, login_name,
4378d522f475Smrg				   sizeof(utmp.ut_name));
4379d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4380d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
4381d522f475Smrg#endif
4382d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4383d522f475Smrg		    SetUtmpSysLen(utmp);
4384d522f475Smrg#endif
4385d522f475Smrg
4386d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
4387d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
43880bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4389d522f475Smrg		    close(i);
4390d522f475Smrg		    added_utmp_entry = True;
4391d522f475Smrg#if defined(WTMP)
4392d522f475Smrg		    if (xw->misc.login_shell &&
4393d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4394d522f475Smrg			int status;
4395d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
4396d522f475Smrg			status = close(i);
4397d522f475Smrg		    }
4398d522f475Smrg#elif defined(MNX_LASTLOG)
4399d522f475Smrg		    if (xw->misc.login_shell &&
4400d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
4401d522f475Smrg			lseek(i, (long) (screen->uid *
4402d522f475Smrg					 sizeof(utmp)), 0);
44030bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4404d522f475Smrg			close(i);
4405d522f475Smrg		    }
4406d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
4407d522f475Smrg		} else
4408d522f475Smrg		    tslot = -tslot;
4409d522f475Smrg	    }
4410d522f475Smrg
4411d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
4412d522f475Smrg	     * clean up after us.
4413d522f475Smrg	     */
4414d522f475Smrg#if OPT_PTY_HANDSHAKE
4415d522f475Smrg	    if (resource.ptyHandshake) {
4416d522f475Smrg		handshake.tty_slot = tslot;
4417d522f475Smrg	    }
4418d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4419d522f475Smrg#endif /* USE_SYSV_UTMP */
4420d522f475Smrg
4421d522f475Smrg#ifdef USE_LASTLOGX
4422d522f475Smrg	    if (xw->misc.login_shell) {
4423956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
4424d522f475Smrg		(void) strncpy(lastlogx.ll_line,
4425d522f475Smrg			       my_pty_name(ttydev),
4426d522f475Smrg			       sizeof(lastlogx.ll_line));
4427d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
4428d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
4429d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
4430d522f475Smrg	    }
4431d522f475Smrg#endif
4432d522f475Smrg
4433d522f475Smrg#ifdef USE_LASTLOG
4434d522f475Smrg	    if (xw->misc.login_shell &&
4435d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
4436d522f475Smrg		size_t size = sizeof(struct lastlog);
44370bd37d32Smrg		off_t offset = (off_t) (screen->uid * size);
4438d522f475Smrg
4439956cc18dSsnj		memset(&lastlog, 0, size);
4440d522f475Smrg		(void) strncpy(lastlog.ll_line,
4441d522f475Smrg			       my_pty_name(ttydev),
4442d522f475Smrg			       sizeof(lastlog.ll_line));
4443d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
4444d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
4445d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
44460bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
4447d522f475Smrg		}
4448d522f475Smrg		close(i);
4449d522f475Smrg	    }
4450d522f475Smrg#endif /* USE_LASTLOG */
4451d522f475Smrg
4452d522f475Smrg#if defined(USE_UTMP_SETGID)
4453d522f475Smrg	    disableSetGid();
4454d522f475Smrg	    TRACE_IDS;
4455d522f475Smrg#endif
4456d522f475Smrg
4457d522f475Smrg#if OPT_PTY_HANDSHAKE
4458d522f475Smrg	    /* Let our parent know that we set up our utmp entry
4459d522f475Smrg	     * so that it can clean up after us.
4460d522f475Smrg	     */
4461d522f475Smrg	    if (resource.ptyHandshake) {
4462d522f475Smrg		handshake.status = UTMP_ADDED;
4463d522f475Smrg		handshake.error = 0;
44640bd37d32Smrg		strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4465d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
446620d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
4467d522f475Smrg	    }
4468d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4469d522f475Smrg#endif /* USE_UTEMPTER */
4470d522f475Smrg#endif /* HAVE_UTMP */
4471d522f475Smrg
447220d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
4473d522f475Smrg	    TRACE_IDS;
4474e0a2b6dfSmrg#ifdef HAVE_INITGROUPS
44750bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
44760bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
4477d522f475Smrg		    perror("initgroups failed");
4478d522f475Smrg		    SysError(ERROR_INIGROUPS);
4479d522f475Smrg		}
4480d522f475Smrg	    }
4481d522f475Smrg#endif
4482d522f475Smrg	    if (setuid(screen->uid)) {
4483d522f475Smrg		SysError(ERROR_SETUID);
4484d522f475Smrg	    }
4485d522f475Smrg	    TRACE_IDS;
4486d522f475Smrg#if OPT_PTY_HANDSHAKE
4487d522f475Smrg	    if (resource.ptyHandshake) {
4488d522f475Smrg		/* mark the pipes as close on exec */
44890bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
44900bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
4491d522f475Smrg
4492d522f475Smrg		/* We are at the point where we are going to
4493d522f475Smrg		 * exec our shell (or whatever).  Let our parent
4494d522f475Smrg		 * know we arrived safely.
4495d522f475Smrg		 */
4496d522f475Smrg		handshake.status = PTY_GOOD;
4497d522f475Smrg		handshake.error = 0;
44980bd37d32Smrg		(void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4499d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
450020d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
450120d2c4d2Smrg				(const char *) &handshake,
450220d2c4d2Smrg				sizeof(handshake)));
4503d522f475Smrg
4504d522f475Smrg		if (resource.wait_for_map) {
450520d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
450620d2c4d2Smrg				   sizeof(handshake));
4507d522f475Smrg		    if (i != sizeof(handshake) ||
4508d522f475Smrg			handshake.status != PTY_EXEC) {
4509d522f475Smrg			/* some very bad problem occurred */
4510d522f475Smrg			exit(ERROR_PTY_EXEC);
4511d522f475Smrg		    }
4512d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
4513d522f475Smrg			TRACE(("handshake ttysize: %dx%d\n",
4514d522f475Smrg			       handshake.rows, handshake.cols));
4515d522f475Smrg			set_max_row(screen, handshake.rows);
4516d522f475Smrg			set_max_col(screen, handshake.cols);
4517d522f475Smrg#ifdef TTYSIZE_STRUCT
4518d522f475Smrg			got_handshake_size = True;
451920d2c4d2Smrg			TTYSIZE_ROWS(ts) = (ttySize_t) MaxRows(screen);
452020d2c4d2Smrg			TTYSIZE_COLS(ts) = (ttySize_t) MaxCols(screen);
4521d522f475Smrg#if defined(USE_STRUCT_WINSIZE)
452220d2c4d2Smrg			ts.ws_xpixel = (ttySize_t) FullWidth(screen);
452320d2c4d2Smrg			ts.ws_ypixel = (ttySize_t) FullHeight(screen);
4524d522f475Smrg#endif
4525d522f475Smrg#endif /* TTYSIZE_STRUCT */
4526d522f475Smrg		    }
4527d522f475Smrg		}
4528d522f475Smrg	    }
4529d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4530d522f475Smrg
4531d522f475Smrg#ifdef USE_SYSV_ENVVARS
4532d522f475Smrg	    {
4533d522f475Smrg		char numbuf[12];
4534d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
4535d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
4536d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
4537d522f475Smrg		xtermSetenv("LINES", numbuf);
4538d522f475Smrg	    }
4539d522f475Smrg#ifdef HAVE_UTMP
45400bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
4541d522f475Smrg		if (!x_getenv("HOME"))
45420bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
4543d522f475Smrg		if (!x_getenv("SHELL"))
45440bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
4545d522f475Smrg	    }
4546d522f475Smrg#endif /* HAVE_UTMP */
4547d522f475Smrg#ifdef OWN_TERMINFO_DIR
4548d522f475Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
4549d522f475Smrg#endif
4550d522f475Smrg#else /* USE_SYSV_ENVVARS */
455120d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
455220d2c4d2Smrg		resize_termcap(xw);
455320d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
455420d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
455520d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
455620d2c4d2Smrg		}
455720d2c4d2Smrg		/*
455820d2c4d2Smrg		 * work around broken termcap entries */
455920d2c4d2Smrg		if (resource.useInsertMode) {
456020d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
456120d2c4d2Smrg		    /* don't get duplicates */
456220d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
456320d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
456420d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
456520d2c4d2Smrg		    if (*newtc)
456620d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
456720d2c4d2Smrg		}
456820d2c4d2Smrg		if (*newtc) {
4569d522f475Smrg#if OPT_INITIAL_ERASE
457020d2c4d2Smrg		    unsigned len;
457120d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
457220d2c4d2Smrg		    len = (unsigned) strlen(newtc);
457320d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
457420d2c4d2Smrg			len--;
457520d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
457620d2c4d2Smrg			    TERMCAP_ERASE,
457720d2c4d2Smrg			    CharOf(initial_erase));
457820d2c4d2Smrg#endif
457920d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
458020d2c4d2Smrg		}
4581d522f475Smrg	    }
4582d522f475Smrg#endif /* USE_SYSV_ENVVARS */
4583d522f475Smrg
4584d522f475Smrg#if OPT_PTY_HANDSHAKE
4585d522f475Smrg	    /*
4586d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
4587d522f475Smrg	     *
4588d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
4589d522f475Smrg	     * use that to prevent races.
4590d522f475Smrg	     */
4591d522f475Smrg	    if (resource.ptyHandshake
4592d522f475Smrg		&& resource.ptySttySize
4593d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
4594d522f475Smrg#ifdef TTYSIZE_STRUCT
459520d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
4596d522f475Smrg		TRACE(("ptyHandshake SET_TTYSIZE %dx%d return %d\n",
4597d522f475Smrg		       TTYSIZE_ROWS(ts),
4598d522f475Smrg		       TTYSIZE_COLS(ts), i));
4599d522f475Smrg#endif /* TTYSIZE_STRUCT */
4600d522f475Smrg	    }
4601d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4602d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4603d522f475Smrg
46040bd37d32Smrg	    /*
4605e0a2b6dfSmrg	     * If we have an explicit shell to run, make that set $SHELL.
4606e0a2b6dfSmrg	     * Next, allow an existing setting of $SHELL, for absolute paths.
46070bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
46080bd37d32Smrg	     * password information, if possible.
46090bd37d32Smrg	     *
46100bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
46110bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
46120bd37d32Smrg	     */
4613e0a2b6dfSmrg	    if (validShell(explicit_shname)) {
4614e0a2b6dfSmrg		xtermSetenv("SHELL", explicit_shname);
4615e0a2b6dfSmrg	    } else if (validProgram(shell_path = x_getenv("SHELL"))) {
4616e0a2b6dfSmrg		if (!validShell(shell_path)) {
4617e0a2b6dfSmrg		    xtermUnsetenv("SHELL");
4618d522f475Smrg		}
4619e0a2b6dfSmrg	    } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
4620e0a2b6dfSmrg		       || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
4621e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4622e0a2b6dfSmrg	    } else if (validShell(shell_path)) {
4623e0a2b6dfSmrg		xtermSetenv("SHELL", shell_path);
4624d522f475Smrg	    } else {
4625e0a2b6dfSmrg		shell_path = resetShell(shell_path);
4626d522f475Smrg	    }
4627e0a2b6dfSmrg
4628e0a2b6dfSmrg	    /*
4629e0a2b6dfSmrg	     * Set $XTERM_SHELL, which is not necessarily a valid shell, but
4630e0a2b6dfSmrg	     * is executable.
4631e0a2b6dfSmrg	     */
4632e0a2b6dfSmrg	    if (validProgram(explicit_shname)) {
4633e0a2b6dfSmrg		shell_path = explicit_shname;
4634e0a2b6dfSmrg	    } else if (shell_path == 0) {
4635e0a2b6dfSmrg		/* this could happen if the explicit shname lost a race */
4636e0a2b6dfSmrg		shell_path = resetShell(shell_path);
46370bd37d32Smrg	    }
46380bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
4639d522f475Smrg
46400bd37d32Smrg	    shname = x_basename(shell_path);
46410bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
4642d522f475Smrg
4643d522f475Smrg#if OPT_LUIT_PROG
4644d522f475Smrg	    /*
4645d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
4646d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
4647d522f475Smrg	     * to command that the user gave anyway.
4648d522f475Smrg	     */
46492eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
46500bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
46510bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
46520bd37d32Smrg		free(myShell);
46530bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
4654d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
46550bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
46560bd37d32Smrg		xtermWarning("cannot support your locale.\n");
4657d522f475Smrg	    }
4658d522f475Smrg#endif
4659d522f475Smrg	    if (command_to_exec) {
46600bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
46610bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
46620bd37d32Smrg		free(myShell);
46630bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
4664d522f475Smrg		execvp(*command_to_exec, command_to_exec);
4665d522f475Smrg		if (command_to_exec[1] == 0)
46660bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
46670bd37d32Smrg			   (void *) 0);
46680bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
4669d522f475Smrg	    }
4670d522f475Smrg#ifdef USE_SYSV_SIGHUP
4671d522f475Smrg	    /* fix pts sh hanging around */
4672d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4673d522f475Smrg#endif
4674d522f475Smrg
4675d522f475Smrg	    shname_minus = CastMallocN(char, strlen(shname) + 2);
4676d522f475Smrg	    (void) strcpy(shname_minus, "-");
4677d522f475Smrg	    (void) strcat(shname_minus, shname);
4678d522f475Smrg#ifndef TERMIO_STRUCT
46790bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
46800bd37d32Smrg		     ? NTTYDISC
46810bd37d32Smrg		     : 0);
4682d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
4683d522f475Smrg#endif /* !TERMIO_STRUCT */
4684d522f475Smrg
4685d522f475Smrg#ifdef USE_LOGIN_DASH_P
46860bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
4687d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
4688d522f475Smrg#endif
46892eaa94a1Schristos
46902eaa94a1Schristos#if OPT_LUIT_PROG
46912eaa94a1Schristos	    if (command_to_exec_with_luit) {
46922eaa94a1Schristos		if (xw->misc.login_shell) {
46930bd37d32Smrg		    char *params[4];
46940bd37d32Smrg		    params[0] = x_strdup("-argv0");
46950bd37d32Smrg		    params[1] = shname_minus;
46960bd37d32Smrg		    params[2] = NULL;
46970bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
46980bd37d32Smrg				 + command_length_with_luit,
46990bd37d32Smrg				 params);
47002eaa94a1Schristos		}
47010bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
47022eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
47032eaa94a1Schristos		/* Exec failed. */
47040bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
47052eaa94a1Schristos	    }
47062eaa94a1Schristos#endif
47070bd37d32Smrg	    execlp(shell_path,
4708d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
4709d522f475Smrg		   (void *) 0);
4710d522f475Smrg
4711d522f475Smrg	    /* Exec failed. */
47120bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
471320d2c4d2Smrg	    IGNORE_RC(sleep(5));
47140bd37d32Smrg	    free(shell_path);
4715d522f475Smrg	    exit(ERROR_EXEC);
4716d522f475Smrg	}
4717d522f475Smrg	/* end if in child after fork */
4718d522f475Smrg#if OPT_PTY_HANDSHAKE
4719d522f475Smrg	if (resource.ptyHandshake) {
4720d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
4721d522f475Smrg	     * child process.
4722d522f475Smrg	     */
4723d522f475Smrg
4724d522f475Smrg	    /* close childs's sides of the pipes */
4725d522f475Smrg	    close(cp_pipe[1]);
4726d522f475Smrg	    close(pc_pipe[0]);
4727d522f475Smrg
4728d522f475Smrg	    for (done = 0; !done;) {
4729d522f475Smrg		if (read(cp_pipe[0],
4730d522f475Smrg			 (char *) &handshake,
4731d522f475Smrg			 sizeof(handshake)) <= 0) {
4732d522f475Smrg		    /* Our child is done talking to us.  If it terminated
4733d522f475Smrg		     * due to an error, we will catch the death of child
4734d522f475Smrg		     * and clean up.
4735d522f475Smrg		     */
4736d522f475Smrg		    break;
4737d522f475Smrg		}
4738d522f475Smrg
4739d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
4740d522f475Smrg		switch (handshake.status) {
4741d522f475Smrg		case PTY_GOOD:
4742d522f475Smrg		    /* Success!  Let's free up resources and
4743d522f475Smrg		     * continue.
4744d522f475Smrg		     */
4745d522f475Smrg		    done = 1;
4746d522f475Smrg		    break;
4747d522f475Smrg
4748d522f475Smrg		case PTY_BAD:
4749d522f475Smrg		    /* The open of the pty failed!  Let's get
4750d522f475Smrg		     * another one.
4751d522f475Smrg		     */
475220d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
4753d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
4754d522f475Smrg			/* no more ptys! */
47550bd37d32Smrg			xtermPerror("child process can find no available ptys");
4756d522f475Smrg			handshake.status = PTY_NOMORE;
4757d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
475820d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
475920d2c4d2Smrg					(const char *) &handshake,
476020d2c4d2Smrg					sizeof(handshake)));
4761d522f475Smrg			exit(ERROR_PTYS);
4762d522f475Smrg		    }
4763d522f475Smrg		    handshake.status = PTY_NEW;
47640bd37d32Smrg		    (void) strncpy(handshake.buffer, ttydev, sizeof(handshake.buffer));
4765d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
476620d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
476720d2c4d2Smrg				    (const char *) &handshake,
476820d2c4d2Smrg				    sizeof(handshake)));
4769d522f475Smrg		    break;
4770d522f475Smrg
4771d522f475Smrg		case PTY_FATALERROR:
4772d522f475Smrg		    errno = handshake.error;
4773d522f475Smrg		    close(cp_pipe[0]);
4774d522f475Smrg		    close(pc_pipe[1]);
4775d522f475Smrg		    SysError(handshake.fatal_error);
4776d522f475Smrg		    /*NOTREACHED */
4777d522f475Smrg
4778d522f475Smrg		case UTMP_ADDED:
4779d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
4780d522f475Smrg		     * this so that we can reset it later.
4781d522f475Smrg		     */
4782d522f475Smrg		    added_utmp_entry = True;
4783d522f475Smrg#ifndef	USE_SYSV_UTMP
4784d522f475Smrg		    tslot = handshake.tty_slot;
4785d522f475Smrg#endif /* USE_SYSV_UTMP */
4786d522f475Smrg		    free(ttydev);
4787d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
4788d522f475Smrg		    break;
4789d522f475Smrg		case PTY_NEW:
4790d522f475Smrg		case PTY_NOMORE:
4791d522f475Smrg		case UTMP_TTYSLOT:
4792d522f475Smrg		case PTY_EXEC:
4793d522f475Smrg		default:
47940bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
47950bd37d32Smrg				 (int) handshake.status);
4796d522f475Smrg		}
4797d522f475Smrg	    }
4798d522f475Smrg	    /* close our sides of the pipes */
4799d522f475Smrg	    if (!resource.wait_for_map) {
4800d522f475Smrg		close(cp_pipe[0]);
4801d522f475Smrg		close(pc_pipe[1]);
4802d522f475Smrg	    }
4803d522f475Smrg	}
4804d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4805d522f475Smrg    }
4806d522f475Smrg
4807d522f475Smrg    /* end if no slave */
4808d522f475Smrg    /*
4809d522f475Smrg     * still in parent (xterm process)
4810d522f475Smrg     */
4811d522f475Smrg#ifdef USE_SYSV_SIGHUP
4812d522f475Smrg    /* hung sh problem? */
4813d522f475Smrg    signal(SIGHUP, SIG_DFL);
4814d522f475Smrg#else
4815d522f475Smrg    signal(SIGHUP, SIG_IGN);
4816d522f475Smrg#endif
4817d522f475Smrg
4818d522f475Smrg/*
4819d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
4820d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
4821d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
4822d522f475Smrg * don't ignore the signals.  This is annoying.
4823d522f475Smrg */
4824d522f475Smrg
4825d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
4826d522f475Smrg    signal(SIGINT, SIG_IGN);
4827d522f475Smrg
4828d522f475Smrg#ifndef SYSV
4829d522f475Smrg    /* hung shell problem */
4830d522f475Smrg    signal(SIGQUIT, SIG_IGN);
4831d522f475Smrg#endif
4832d522f475Smrg    signal(SIGTERM, SIG_IGN);
4833d522f475Smrg#elif defined(SYSV) || defined(__osf__)
4834d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
4835d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
4836d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
4837d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
4838d522f475Smrg     * tank on everything.
4839d522f475Smrg     */
4840d522f475Smrg    if (getpid() == getpgrp()) {
4841d522f475Smrg	(void) signal(SIGINT, Exit);
4842d522f475Smrg	(void) signal(SIGQUIT, Exit);
4843d522f475Smrg	(void) signal(SIGTERM, Exit);
4844d522f475Smrg    } else {
4845d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
4846d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
4847d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
4848d522f475Smrg    }
4849d522f475Smrg    (void) signal(SIGPIPE, Exit);
4850d522f475Smrg#else /* SYSV */
4851d522f475Smrg    signal(SIGINT, Exit);
4852d522f475Smrg    signal(SIGQUIT, Exit);
4853d522f475Smrg    signal(SIGTERM, Exit);
4854d522f475Smrg    signal(SIGPIPE, Exit);
4855d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
48560bd37d32Smrg#ifdef NO_LEAKS
48570bd37d32Smrg    if (ok_termcap != True)
48580bd37d32Smrg	free(TermName);
48590bd37d32Smrg#endif
4860d522f475Smrg
4861d522f475Smrg    return 0;
4862d522f475Smrg}				/* end spawnXTerm */
4863d522f475Smrg
48640bd37d32Smrgvoid
4865d522f475SmrgExit(int n)
4866d522f475Smrg{
486720d2c4d2Smrg    XtermWidget xw = term;
486820d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
4869d522f475Smrg
4870d522f475Smrg#ifdef USE_UTEMPTER
48710bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
48720bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
48730bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
4874d522f475Smrg	removeFromUtmp();
48750bd37d32Smrg    }
4876d522f475Smrg#elif defined(HAVE_UTMP)
4877d522f475Smrg#ifdef USE_SYSV_UTMP
4878d522f475Smrg    struct UTMP_STR utmp;
4879d522f475Smrg    struct UTMP_STR *utptr;
4880d522f475Smrg
48810bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
4882d522f475Smrg    /* don't do this more than once */
48830bd37d32Smrg    if (xterm_exiting) {
48840bd37d32Smrg	exit(n);
48850bd37d32Smrg    }
4886d522f475Smrg    xterm_exiting = True;
4887d522f475Smrg
4888d522f475Smrg#ifdef PUCC_PTYD
4889d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
4890d522f475Smrg#endif /* PUCC_PTYD */
4891d522f475Smrg
4892d522f475Smrg    /* cleanup the utmp entry we forged earlier */
4893d522f475Smrg    if (!resource.utmpInhibit
4894d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
4895d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
4896d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4897d522f475Smrg	) {
4898d522f475Smrg#if defined(USE_UTMP_SETGID)
4899d522f475Smrg	setEffectiveGroup(save_egid);
4900d522f475Smrg	TRACE_IDS;
4901d522f475Smrg#endif
4902d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
4903d522f475Smrg	(void) call_setutent();
4904d522f475Smrg
4905d522f475Smrg	/*
4906d522f475Smrg	 * We could use getutline() if we didn't support old systems.
4907d522f475Smrg	 */
4908d522f475Smrg	while ((utptr = find_utmp(&utmp)) != 0) {
4909d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
4910d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
4911d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4912d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4913d522f475Smrg		utptr->ut_session = getsid(0);
4914d522f475Smrg#endif
4915d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
4916d522f475Smrg		utptr->ut_tv.tv_usec = 0;
4917d522f475Smrg#else
4918d522f475Smrg		*utptr->ut_user = 0;
4919d522f475Smrg		utptr->ut_time = time((time_t *) 0);
4920d522f475Smrg#endif
4921d522f475Smrg		(void) call_pututline(utptr);
4922d522f475Smrg#ifdef WTMP
4923d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
492420d2c4d2Smrg		if (xw->misc.login_shell)
4925d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
4926d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4927d522f475Smrg		strncpy(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
492820d2c4d2Smrg		if (xw->misc.login_shell)
4929d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
4930d522f475Smrg#else
4931d522f475Smrg		/* set wtmp entry if wtmp file exists */
493220d2c4d2Smrg		if (xw->misc.login_shell) {
4933d522f475Smrg		    int fd;
4934d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
49350bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
4936d522f475Smrg			close(fd);
4937d522f475Smrg		    }
4938d522f475Smrg		}
4939d522f475Smrg#endif
4940d522f475Smrg#endif
4941d522f475Smrg		break;
4942d522f475Smrg	    }
4943d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
4944d522f475Smrg	}
4945d522f475Smrg	(void) call_endutent();
4946d522f475Smrg#ifdef USE_UTMP_SETGID
4947d522f475Smrg	disableSetGid();
4948d522f475Smrg	TRACE_IDS;
4949d522f475Smrg#endif
4950d522f475Smrg    }
4951d522f475Smrg#else /* not USE_SYSV_UTMP */
4952d522f475Smrg    int wfd;
4953d522f475Smrg    struct utmp utmp;
4954d522f475Smrg
49550bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
4956d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
4957d522f475Smrg	(am_slave < 0 && tslot > 0)) {
4958d522f475Smrg#if defined(USE_UTMP_SETGID)
4959d522f475Smrg	setEffectiveGroup(save_egid);
4960d522f475Smrg	TRACE_IDS;
4961d522f475Smrg#endif
4962d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
4963956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
4964d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
49650bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
4966d522f475Smrg	    close(wfd);
4967d522f475Smrg	}
4968d522f475Smrg#ifdef WTMP
496920d2c4d2Smrg	if (xw->misc.login_shell &&
4970d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4971d522f475Smrg	    (void) strncpy(utmp.ut_line,
4972d522f475Smrg			   my_pty_name(ttydev),
4973d522f475Smrg			   sizeof(utmp.ut_line));
4974d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
49750bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
4976d522f475Smrg	    close(wfd);
4977d522f475Smrg	}
4978d522f475Smrg#endif /* WTMP */
4979d522f475Smrg#ifdef USE_UTMP_SETGID
4980d522f475Smrg	disableSetGid();
4981d522f475Smrg	TRACE_IDS;
4982d522f475Smrg#endif
4983d522f475Smrg    }
4984d522f475Smrg#endif /* USE_SYSV_UTMP */
4985d522f475Smrg#endif /* HAVE_UTMP */
4986d522f475Smrg
4987e0a2b6dfSmrg    cleanup_colored_cursor();
4988e0a2b6dfSmrg
4989d522f475Smrg    /*
4990d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
4991d522f475Smrg     * in the middle of the data.
4992d522f475Smrg     */
4993d522f475Smrg    ttyFlush(screen->respond);
4994d522f475Smrg
4995e39b573cSmrg#ifdef USE_PTY_SEARCH
4996d522f475Smrg    if (am_slave < 0) {
4997d522f475Smrg	TRACE_IDS;
4998d522f475Smrg	/* restore ownership of tty and pty */
4999d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
5000d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
5001d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
5002d522f475Smrg#endif
5003d522f475Smrg    }
5004e39b573cSmrg#endif
5005d522f475Smrg
5006d522f475Smrg    /*
50070bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
5008d522f475Smrg     * grabbing it, and *then* having us release ownership....
5009d522f475Smrg     */
5010d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
5011d522f475Smrg#ifdef ALLOWLOGGING
5012d522f475Smrg    if (screen->logging)
501320d2c4d2Smrg	CloseLog(xw);
5014d522f475Smrg#endif
5015d522f475Smrg
5016e39b573cSmrg    xtermPrintOnXError(xw, n);
5017e39b573cSmrg
5018d522f475Smrg#ifdef NO_LEAKS
5019d522f475Smrg    if (n == 0) {
50200bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
50210bd37d32Smrg
5022d522f475Smrg	TRACE(("Freeing memory leaks\n"));
5023d522f475Smrg
50240bd37d32Smrg	if (toplevel) {
50250bd37d32Smrg	    XtDestroyWidget(toplevel);
50260bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
50270bd37d32Smrg	}
50280bd37d32Smrg	sortedOpts(0, 0, 0);
50290bd37d32Smrg	noleaks_charproc();
50300bd37d32Smrg	noleaks_ptydata();
5031d522f475Smrg#if OPT_WIDE_CHARS
50320bd37d32Smrg	noleaks_CharacterClass();
5033d522f475Smrg#endif
50340bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
50350bd37d32Smrg	XtCloseDisplay(dpy);
50360bd37d32Smrg	XtDestroyApplicationContext(app_con);
50370bd37d32Smrg	xtermCloseSession();
50380bd37d32Smrg	TRACE(("closed display\n"));
50390bd37d32Smrg
504020d2c4d2Smrg	TRACE_CLOSE();
5041d522f475Smrg    }
5042d522f475Smrg#endif
5043d522f475Smrg
5044d522f475Smrg    exit(n);
5045d522f475Smrg}
5046d522f475Smrg
5047d522f475Smrg/* ARGSUSED */
5048d522f475Smrgstatic void
504920d2c4d2Smrgresize_termcap(XtermWidget xw)
5050d522f475Smrg{
505120d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
505220d2c4d2Smrg
5053d522f475Smrg#ifndef USE_SYSV_ENVVARS
5054d522f475Smrg    if (!TEK4014_ACTIVE(xw) && *newtc) {
5055d522f475Smrg	TScreen *screen = TScreenOf(xw);
5056d522f475Smrg	char *ptr1, *ptr2;
5057d522f475Smrg	size_t i;
5058d522f475Smrg	int li_first = 0;
5059d522f475Smrg	char *temp;
5060d522f475Smrg	char oldtc[TERMCAP_SIZE];
5061d522f475Smrg
5062d522f475Smrg	strcpy(oldtc, newtc);
5063d522f475Smrg	TRACE(("resize %s\n", oldtc));
5064d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
5065d522f475Smrg	    strcat(oldtc, "co#80:");
5066d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
5067d522f475Smrg	}
5068d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
5069d522f475Smrg	    strcat(oldtc, "li#24:");
5070d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
5071d522f475Smrg	}
5072d522f475Smrg	if (ptr1 > ptr2) {
5073d522f475Smrg	    li_first++;
5074d522f475Smrg	    temp = ptr1;
5075d522f475Smrg	    ptr1 = ptr2;
5076d522f475Smrg	    ptr2 = temp;
5077d522f475Smrg	}
5078d522f475Smrg	ptr1 += 3;
5079d522f475Smrg	ptr2 += 3;
5080956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
5081d522f475Smrg	temp = newtc + i;
5082d522f475Smrg	sprintf(temp, "%d", (li_first
5083d522f475Smrg			     ? MaxRows(screen)
5084d522f475Smrg			     : MaxCols(screen)));
5085d522f475Smrg	temp += strlen(temp);
50860bd37d32Smrg	if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) {
50870bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
50880bd37d32Smrg	    temp += i;
50890bd37d32Smrg	    sprintf(temp, "%d", (li_first
50900bd37d32Smrg				 ? MaxCols(screen)
50910bd37d32Smrg				 : MaxRows(screen)));
50920bd37d32Smrg	    if ((ptr2 = strchr(ptr2, ':')) != 0) {
50930bd37d32Smrg		strcat(temp, ptr2);
50940bd37d32Smrg	    }
50950bd37d32Smrg	}
5096d522f475Smrg	TRACE(("   ==> %s\n", newtc));
5097d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
5098d522f475Smrg    }
5099d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5100d522f475Smrg}
5101d522f475Smrg
5102d522f475Smrg#endif /* ! VMS */
5103d522f475Smrg
5104d522f475Smrg/*
5105d522f475Smrg * Does a non-blocking wait for a child process.  If the system
5106d522f475Smrg * doesn't support non-blocking wait, do nothing.
5107d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
5108d522f475Smrg */
5109d522f475Smrgint
5110d522f475Smrgnonblocking_wait(void)
5111d522f475Smrg{
5112d522f475Smrg#ifdef USE_POSIX_WAIT
5113d522f475Smrg    pid_t pid;
5114d522f475Smrg
5115d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5116d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5117d522f475Smrg    /* cannot do non-blocking wait */
5118d522f475Smrg    int pid = 0;
5119d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5120d522f475Smrg#if defined(Lynx)
5121d522f475Smrg    int status;
5122d522f475Smrg#else
5123d522f475Smrg    union wait status;
5124d522f475Smrg#endif
5125d522f475Smrg    int pid;
5126d522f475Smrg
5127d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5128d522f475Smrg#endif /* USE_POSIX_WAIT else */
5129d522f475Smrg    return pid;
5130d522f475Smrg}
5131d522f475Smrg
5132d522f475Smrg#ifndef VMS
5133d522f475Smrg
5134d522f475Smrg/* ARGSUSED */
51350bd37d32Smrgstatic void
5136d522f475Smrgreapchild(int n GCC_UNUSED)
5137d522f475Smrg{
5138d522f475Smrg    int olderrno = errno;
5139d522f475Smrg    int pid;
5140d522f475Smrg
51410bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
51420bd37d32Smrg
5143d522f475Smrg    pid = wait(NULL);
5144d522f475Smrg
5145d522f475Smrg#ifdef USE_SYSV_SIGNALS
5146d522f475Smrg    /* cannot re-enable signal before waiting for child
5147d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5148d522f475Smrg     */
5149d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5150d522f475Smrg#endif
5151d522f475Smrg
5152d522f475Smrg    do {
515320d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
51540bd37d32Smrg	    DEBUG_MSG("Exiting\n");
5155d522f475Smrg	    if (!hold_screen)
5156d522f475Smrg		need_cleanup = True;
5157d522f475Smrg	}
5158d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5159d522f475Smrg
5160d522f475Smrg    errno = olderrno;
5161d522f475Smrg}
5162d522f475Smrg#endif /* !VMS */
5163d522f475Smrg
5164d522f475Smrgstatic void
516520d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5166d522f475Smrg{
5167d522f475Smrg    char *base = buf;
5168d522f475Smrg    char *first = base;
5169d522f475Smrg    int count = 0;
5170d522f475Smrg    size_t len = strlen(str);
5171d522f475Smrg
5172d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5173d522f475Smrg
5174d522f475Smrg    while (*buf != 0) {
5175d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5176d522f475Smrg	    while (*buf != 0) {
5177d522f475Smrg		if (*buf == '\\')
5178d522f475Smrg		    buf++;
5179d522f475Smrg		else if (*buf == ':')
5180d522f475Smrg		    break;
5181d522f475Smrg		if (*buf != 0)
5182d522f475Smrg		    buf++;
5183d522f475Smrg	    }
51840bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
51850bd37d32Smrg		;
51860bd37d32Smrg	    }
5187d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5188d522f475Smrg	    return;
5189d522f475Smrg	} else if (*buf == '\\') {
5190d522f475Smrg	    buf++;
5191d522f475Smrg	} else if (*buf == ':') {
5192d522f475Smrg	    first = buf;
5193d522f475Smrg	    count = 0;
5194d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5195d522f475Smrg	    count++;
5196d522f475Smrg	}
5197d522f475Smrg	if (*buf != 0)
5198d522f475Smrg	    buf++;
5199d522f475Smrg    }
5200d522f475Smrg    TRACE(("...cannot remove\n"));
5201d522f475Smrg}
5202d522f475Smrg
5203d522f475Smrg/*
5204d522f475Smrg * parse_tty_modes accepts lines of the following form:
5205d522f475Smrg *
5206d522f475Smrg *         [SETTING] ...
5207d522f475Smrg *
5208d522f475Smrg * where setting consists of the words in the modelist followed by a character
5209d522f475Smrg * or ^char.
5210d522f475Smrg */
5211d522f475Smrgstatic int
5212d522f475Smrgparse_tty_modes(char *s, struct _xttymodes *modelist)
5213d522f475Smrg{
5214d522f475Smrg    struct _xttymodes *mp;
5215d522f475Smrg    int c;
5216d522f475Smrg    int count = 0;
5217d522f475Smrg
5218d522f475Smrg    TRACE(("parse_tty_modes\n"));
5219a1f3da82Smrg    for (;;) {
5220d522f475Smrg	size_t len;
5221d522f475Smrg
5222d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5223d522f475Smrg	    s++;
5224d522f475Smrg	if (!*s)
5225d522f475Smrg	    return count;
5226d522f475Smrg
5227d522f475Smrg	for (len = 0; isalnum(CharOf(s[len])); ++len) ;
5228d522f475Smrg	for (mp = modelist; mp->name; mp++) {
5229d522f475Smrg	    if (len == mp->len
5230d522f475Smrg		&& strncmp(s, mp->name, mp->len) == 0)
5231d522f475Smrg		break;
5232d522f475Smrg	}
5233d522f475Smrg	if (!mp->name)
5234d522f475Smrg	    return -1;
5235d522f475Smrg
5236d522f475Smrg	s += mp->len;
5237d522f475Smrg	while (*s && isascii(CharOf(*s)) && isspace(CharOf(*s)))
5238d522f475Smrg	    s++;
5239d522f475Smrg	if (!*s)
5240d522f475Smrg	    return -1;
5241d522f475Smrg
5242d522f475Smrg	if ((c = decode_keyvalue(&s, False)) != -1) {
5243d522f475Smrg	    mp->value = c;
5244d522f475Smrg	    mp->set = 1;
5245d522f475Smrg	    count++;
5246d522f475Smrg	    TRACE(("...parsed #%d: %s=%#x\n", count, mp->name, c));
5247d522f475Smrg	}
5248d522f475Smrg    }
5249d522f475Smrg}
5250d522f475Smrg
5251d522f475Smrg#ifndef VMS			/* don't use pipes on OpenVMS */
5252d522f475Smrgint
5253d522f475SmrgGetBytesAvailable(int fd)
5254d522f475Smrg{
5255d522f475Smrg#if defined(FIONREAD)
5256d522f475Smrg    int arg;
5257d522f475Smrg    ioctl(fd, FIONREAD, (char *) &arg);
5258d522f475Smrg    return (int) arg;
5259d522f475Smrg#elif defined(__CYGWIN__)
5260d522f475Smrg    fd_set set;
526120d2c4d2Smrg    struct timeval select_timeout =
5262d522f475Smrg    {0, 0};
5263d522f475Smrg
5264d522f475Smrg    FD_ZERO(&set);
5265d522f475Smrg    FD_SET(fd, &set);
526620d2c4d2Smrg    if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0)
5267d522f475Smrg	return 1;
5268d522f475Smrg    else
5269d522f475Smrg	return 0;
5270d522f475Smrg#elif defined(FIORDCK)
5271d522f475Smrg    return (ioctl(fd, FIORDCHK, NULL));
5272d522f475Smrg#else /* !FIORDCK */
5273d522f475Smrg    struct pollfd pollfds[1];
5274d522f475Smrg
5275d522f475Smrg    pollfds[0].fd = fd;
5276d522f475Smrg    pollfds[0].events = POLLIN;
5277d522f475Smrg    return poll(pollfds, 1, 0);
5278d522f475Smrg#endif
5279d522f475Smrg}
5280d522f475Smrg#endif /* !VMS */
5281d522f475Smrg
5282d522f475Smrg/* Utility function to try to hide system differences from
5283d522f475Smrg   everybody who used to call killpg() */
5284d522f475Smrg
5285d522f475Smrgint
5286d522f475Smrgkill_process_group(int pid, int sig)
5287d522f475Smrg{
5288d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5289d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5290d522f475Smrg    return kill(-pid, sig);
5291d522f475Smrg#else
5292d522f475Smrg    return killpg(pid, sig);
5293d522f475Smrg#endif
5294d522f475Smrg}
5295d522f475Smrg
5296d522f475Smrg#if OPT_EBCDIC
5297d522f475Smrgint
5298d522f475SmrgA2E(int x)
5299d522f475Smrg{
5300d522f475Smrg    char c;
5301d522f475Smrg    c = x;
5302d522f475Smrg    __atoe_l(&c, 1);
5303d522f475Smrg    return c;
5304d522f475Smrg}
5305d522f475Smrg
5306d522f475Smrgint
5307d522f475SmrgE2A(int x)
5308d522f475Smrg{
5309d522f475Smrg    char c;
5310d522f475Smrg    c = x;
5311d522f475Smrg    __etoa_l(&c, 1);
5312d522f475Smrg    return c;
5313d522f475Smrg}
5314d522f475Smrg#endif
5315d522f475Smrg
5316d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
5317d522f475Smrg#include <sys/types.h>
5318d522f475Smrg#include <sys/proc_msg.h>
5319d522f475Smrg#include <sys/kernel.h>
5320d522f475Smrg#include <string.h>
5321d522f475Smrg#include <errno.h>
5322d522f475Smrg
5323d522f475Smrgstruct _proc_session ps;
5324d522f475Smrgstruct _proc_session_reply rps;
5325d522f475Smrg
5326d522f475Smrgint
5327d522f475Smrgqsetlogin(char *login, char *ttyname)
5328d522f475Smrg{
5329d522f475Smrg    int v = getsid(getpid());
5330d522f475Smrg
5331d522f475Smrg    memset(&ps, 0, sizeof(ps));
5332d522f475Smrg    memset(&rps, 0, sizeof(rps));
5333d522f475Smrg
5334d522f475Smrg    ps.type = _PROC_SESSION;
5335d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
5336d522f475Smrg    ps.sid = v;
5337d522f475Smrg    strcpy(ps.name, login);
5338d522f475Smrg
5339d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5340d522f475Smrg
5341d522f475Smrg    if (rps.status < 0)
5342d522f475Smrg	return (rps.status);
5343d522f475Smrg
5344d522f475Smrg    ps.type = _PROC_SESSION;
5345d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
5346d522f475Smrg    ps.sid = v;
5347d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
5348d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5349d522f475Smrg
5350d522f475Smrg    return (rps.status);
5351d522f475Smrg}
5352d522f475Smrg#endif
5353