main.c revision a5ae21e4
1a5ae21e4Smrg/* $XTermId: main.c,v 1.882 2021/09/16 19:49:13 tom Exp $ */
20bd37d32Smrg
30bd37d32Smrg/*
4f2e35a3aSmrg * Copyright 2002-2020,2021 by Thomas E. Dickey
50bd37d32Smrg *
60bd37d32Smrg *                         All Rights Reserved
70bd37d32Smrg *
80bd37d32Smrg * Permission is hereby granted, free of charge, to any person obtaining a
90bd37d32Smrg * copy of this software and associated documentation files (the
100bd37d32Smrg * "Software"), to deal in the Software without restriction, including
110bd37d32Smrg * without limitation the rights to use, copy, modify, merge, publish,
120bd37d32Smrg * distribute, sublicense, and/or sell copies of the Software, and to
130bd37d32Smrg * permit persons to whom the Software is furnished to do so, subject to
140bd37d32Smrg * the following conditions:
150bd37d32Smrg *
160bd37d32Smrg * The above copyright notice and this permission notice shall be included
170bd37d32Smrg * in all copies or substantial portions of the Software.
180bd37d32Smrg *
190bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
200bd37d32Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
210bd37d32Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
220bd37d32Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
230bd37d32Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
240bd37d32Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
250bd37d32Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
260bd37d32Smrg *
270bd37d32Smrg * Except as contained in this notice, the name(s) of the above copyright
280bd37d32Smrg * holders shall not be used in advertising or otherwise to promote the
290bd37d32Smrg * sale, use or other dealings in this Software without prior written
300bd37d32Smrg * authorization.
310bd37d32Smrg *
32f2e35a3aSmrg * Copyright 1987, 1988  X Consortium
330bd37d32Smrg *
340bd37d32Smrg * Permission to use, copy, modify, distribute, and sell this software and its
350bd37d32Smrg * documentation for any purpose is hereby granted without fee, provided that
360bd37d32Smrg * the above copyright notice appear in all copies and that both that
370bd37d32Smrg * copyright notice and this permission notice appear in supporting
380bd37d32Smrg * documentation.
390bd37d32Smrg *
400bd37d32Smrg * The above copyright notice and this permission notice shall be included in
410bd37d32Smrg * all copies or substantial portions of the Software.
420bd37d32Smrg *
430bd37d32Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
440bd37d32Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
450bd37d32Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
460bd37d32Smrg * OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
470bd37d32Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
480bd37d32Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
490bd37d32Smrg *
50f2e35a3aSmrg * Except as contained in this notice, the name of the X Consortium shall not be
510bd37d32Smrg * used in advertising or otherwise to promote the sale, use or other dealings
52f2e35a3aSmrg * in this Software without prior written authorization from the X Consortium.
530bd37d32Smrg *
540bd37d32Smrg * Copyright 1987, 1988 by Digital Equipment Corporation, Maynard.
550bd37d32Smrg *
560bd37d32Smrg *                         All Rights Reserved
570bd37d32Smrg *
580bd37d32Smrg * Permission to use, copy, modify, and distribute this software and its
590bd37d32Smrg * documentation for any purpose and without fee is hereby granted,
600bd37d32Smrg * provided that the above copyright notice appear in all copies and that
610bd37d32Smrg * both that copyright notice and this permission notice appear in
620bd37d32Smrg * supporting documentation, and that the name of Digital not be used in
630bd37d32Smrg * advertising or publicity pertaining to distribution of the software
640bd37d32Smrg * without specific, written prior permission.
650bd37d32Smrg *
660bd37d32Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
670bd37d32Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
680bd37d32Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
690bd37d32Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
700bd37d32Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
710bd37d32Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
720bd37d32Smrg * SOFTWARE.
730bd37d32Smrg */
74d522f475Smrg
75d522f475Smrg/*
76d522f475Smrg *				 W A R N I N G
77d522f475Smrg *
78d522f475Smrg * If you think you know what all of this code is doing, you are
79d522f475Smrg * probably very mistaken.  There be serious and nasty dragons here.
80d522f475Smrg *
81d522f475Smrg * This client is *not* to be taken as an example of how to write X
82d522f475Smrg * Toolkit applications.  It is in need of a substantial rewrite,
83d522f475Smrg * ideally to create a generic tty widget with several different parsing
84d522f475Smrg * widgets so that you can plug 'em together any way you want.  Don't
85d522f475Smrg * hold your breath, though....
86d522f475Smrg */
87d522f475Smrg
88d522f475Smrg/* main.c */
89d522f475Smrg
90d522f475Smrg#define RES_OFFSET(field)	XtOffsetOf(XTERM_RESOURCE, field)
91d522f475Smrg
92d522f475Smrg#include <xterm.h>
930bd37d32Smrg#include <version.h>
94894e0ac8Smrg#include <graphics.h>
95d522f475Smrg
96d522f475Smrg#if OPT_TOOLBAR
97d522f475Smrg
98d522f475Smrg#if defined(HAVE_LIB_XAW)
99d522f475Smrg#include <X11/Xaw/Form.h>
100d522f475Smrg#elif defined(HAVE_LIB_XAW3D)
101d522f475Smrg#include <X11/Xaw3d/Form.h>
10201037d57Smrg#elif defined(HAVE_LIB_XAW3DXFT)
10301037d57Smrg#include <X11/Xaw3dxft/Form.h>
104f2e35a3aSmrg#include <X11/Xaw3dxft/Xaw3dXft.h>
105d522f475Smrg#elif defined(HAVE_LIB_NEXTAW)
106d522f475Smrg#include <X11/neXtaw/Form.h>
107d522f475Smrg#elif defined(HAVE_LIB_XAWPLUS)
108d522f475Smrg#include <X11/XawPlus/Form.h>
109d522f475Smrg#endif
110d522f475Smrg
111f2e35a3aSmrg#else
112f2e35a3aSmrg
113f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
114f2e35a3aSmrg#include <X11/Xaw3dxft/Xaw3dXft.h>
115f2e35a3aSmrg#endif
116f2e35a3aSmrg
117d522f475Smrg#endif /* OPT_TOOLBAR */
118d522f475Smrg
119d522f475Smrg#include <pwd.h>
120d522f475Smrg#include <ctype.h>
121d522f475Smrg
122d522f475Smrg#include <data.h>
123d522f475Smrg#include <error.h>
124d522f475Smrg#include <menu.h>
125d522f475Smrg#include <main.h>
126d522f475Smrg#include <xstrings.h>
127d522f475Smrg#include <xtermcap.h>
128d522f475Smrg#include <xterm_io.h>
129d522f475Smrg
130d522f475Smrg#if OPT_WIDE_CHARS
131d522f475Smrg#include <charclass.h>
132d522f475Smrg#endif
133d522f475Smrg
134d522f475Smrg#ifdef __osf__
135d522f475Smrg#define USE_SYSV_SIGNALS
136d522f475Smrg#define WTMP
137d522f475Smrg#include <pty.h>		/* openpty() */
138d522f475Smrg#endif
139d522f475Smrg
140d522f475Smrg#ifdef __sgi
141d522f475Smrg#include <grp.h>		/* initgroups() */
142d522f475Smrg#endif
143d522f475Smrg
144ad37e533Smrgstatic GCC_NORETURN void hungtty(int);
145ad37e533Smrgstatic GCC_NORETURN void Syntax(char *);
146ad37e533Smrgstatic GCC_NORETURN void HsSysError(int);
147d522f475Smrg
1482e4f8982Smrg#if defined(__SCO__) || defined(SVR4) || defined(_POSIX_SOURCE) || ( defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 1) )
149d522f475Smrg#define USE_POSIX_SIGNALS
150d522f475Smrg#endif
151d522f475Smrg
152d522f475Smrg#if defined(SYSV) && !defined(SVR4) && !defined(ISC22) && !defined(ISC30)
153d522f475Smrg/* older SYSV systems cannot ignore SIGHUP.
154d522f475Smrg   Shell hangs, or you get extra shells, or something like that */
155d522f475Smrg#define USE_SYSV_SIGHUP
156d522f475Smrg#endif
157d522f475Smrg
158d522f475Smrg#if defined(sony) && defined(bsd43) && !defined(KANJI)
159d522f475Smrg#define KANJI
160d522f475Smrg#endif
161d522f475Smrg
162d522f475Smrg#ifdef linux
163d522f475Smrg#define USE_SYSV_PGRP
164d522f475Smrg#define USE_SYSV_SIGNALS
165d522f475Smrg#define WTMP
166d522f475Smrg#ifdef __GLIBC__
167d522f475Smrg#if (__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1))
168d522f475Smrg#include <pty.h>
169d522f475Smrg#endif
170d522f475Smrg#endif
171d522f475Smrg#endif
172d522f475Smrg
173d522f475Smrg#ifdef __MVS__
174d522f475Smrg#define USE_SYSV_PGRP
175d522f475Smrg#define USE_SYSV_SIGNALS
176d522f475Smrg#endif
177d522f475Smrg
178d522f475Smrg#ifdef __CYGWIN__
179d522f475Smrg#define WTMP
180d522f475Smrg#endif
181d522f475Smrg
182d522f475Smrg#ifdef __SCO__
183d522f475Smrg#ifndef _SVID3
184d522f475Smrg#define _SVID3
185d522f475Smrg#endif
186d522f475Smrg#endif
187d522f475Smrg
188d522f475Smrg#if defined(__GLIBC__) && !defined(linux)
189d522f475Smrg#define USE_SYSV_PGRP
190d522f475Smrg#define WTMP
191d522f475Smrg#endif
192d522f475Smrg
193f2e35a3aSmrg#if defined(USE_TTY_GROUP) || defined(USE_UTMP_SETGID) || defined(HAVE_INITGROUPS)
194d522f475Smrg#include <grp.h>
195d522f475Smrg#endif
196d522f475Smrg
197d522f475Smrg#ifndef TTY_GROUP_NAME
198d522f475Smrg#define TTY_GROUP_NAME "tty"
199d522f475Smrg#endif
200d522f475Smrg
201d522f475Smrg#include <sys/stat.h>
202d522f475Smrg
203d522f475Smrg#ifdef Lynx
204d522f475Smrg#ifndef BSDLY
205d522f475Smrg#define BSDLY	0
206d522f475Smrg#endif
207d522f475Smrg#ifndef VTDLY
208d522f475Smrg#define VTDLY	0
209d522f475Smrg#endif
210d522f475Smrg#ifndef FFDLY
211d522f475Smrg#define FFDLY	0
212d522f475Smrg#endif
213d522f475Smrg#endif
214d522f475Smrg
215d522f475Smrg#ifdef SYSV			/* { */
216d522f475Smrg
217d522f475Smrg#ifdef USE_USG_PTYS		/* AT&T SYSV has no ptyio.h */
218d522f475Smrg#include <sys/stropts.h>	/* for I_PUSH */
219d522f475Smrg#include <poll.h>		/* for POLLIN */
220d522f475Smrg#endif /* USE_USG_PTYS */
221d522f475Smrg
222d522f475Smrg#define USE_SYSV_SIGNALS
223d522f475Smrg#define	USE_SYSV_PGRP
224d522f475Smrg
225d522f475Smrg#if !defined(TIOCSWINSZ) || defined(__SCO__) || defined(__UNIXWARE__)
226d522f475Smrg#define USE_SYSV_ENVVARS	/* COLUMNS/LINES vs. TERMCAP */
227d522f475Smrg#endif
228d522f475Smrg
229d522f475Smrg/*
230d522f475Smrg * now get system-specific includes
231d522f475Smrg */
232d522f475Smrg#ifdef macII
233d522f475Smrg#include <sys/ttychars.h>
234d522f475Smrg#undef USE_SYSV_ENVVARS
235d522f475Smrg#undef FIOCLEX
236d522f475Smrg#undef FIONCLEX
237d522f475Smrg#define setpgrp2 setpgrp
238d522f475Smrg#include <sgtty.h>
239d522f475Smrg#include <sys/resource.h>
240d522f475Smrg#endif
241d522f475Smrg
242d522f475Smrg#ifdef __hpux
243d522f475Smrg#include <sys/ptyio.h>
244d522f475Smrg#endif /* __hpux */
245d522f475Smrg
246d522f475Smrg#ifdef __osf__
247d522f475Smrg#undef  USE_SYSV_PGRP
248d522f475Smrg#define setpgrp setpgid
249d522f475Smrg#endif
250d522f475Smrg
251d522f475Smrg#ifdef __sgi
252d522f475Smrg#include <sys/sysmacros.h>
253d522f475Smrg#endif /* __sgi */
254d522f475Smrg
255d522f475Smrg#ifdef sun
256d522f475Smrg#include <sys/strredir.h>
257d522f475Smrg#endif
258d522f475Smrg
259e39b573cSmrg#else /* } !SYSV { */ /* BSD systems */
260d522f475Smrg
261d522f475Smrg#ifdef __QNX__
262d522f475Smrg
263d522f475Smrg#ifndef __QNXNTO__
264d522f475Smrg#define ttyslot() 1
265d522f475Smrg#else
266d522f475Smrg#define USE_SYSV_PGRP
267d522f475Smrgextern __inline__
268d522f475Smrgint
269d522f475Smrgttyslot(void)
270d522f475Smrg{
271d522f475Smrg    return 1;			/* yuk */
272d522f475Smrg}
273d522f475Smrg#endif
274d522f475Smrg
275d522f475Smrg#else
276d522f475Smrg
277d522f475Smrg#if defined(__INTERIX) || defined(__APPLE__)
278d522f475Smrg#define setpgrp setpgid
279d522f475Smrg#endif
280d522f475Smrg
281d522f475Smrg#ifndef linux
282d522f475Smrg#ifndef VMS
283d522f475Smrg#ifndef USE_POSIX_TERMIOS
284d522f475Smrg#ifndef USE_ANY_SYSV_TERMIO
285d522f475Smrg#include <sgtty.h>
286d522f475Smrg#endif
287d522f475Smrg#endif /* USE_POSIX_TERMIOS */
288d522f475Smrg#ifdef Lynx
289d522f475Smrg#include <resource.h>
290d522f475Smrg#else
291d522f475Smrg#include <sys/resource.h>
292d522f475Smrg#endif
293d522f475Smrg#endif /* !VMS */
294d522f475Smrg#endif /* !linux */
295d522f475Smrg
296d522f475Smrg#endif /* __QNX__ */
297d522f475Smrg
298d522f475Smrg#endif /* } !SYSV */
299d522f475Smrg
300d522f475Smrg/* Xpoll.h and <sys/param.h> on glibc 2.1 systems have colliding NBBY's */
301d522f475Smrg#if defined(__GLIBC__) && ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 1)))
302d522f475Smrg#ifndef NOFILE
303d522f475Smrg#define NOFILE OPEN_MAX
304d522f475Smrg#endif
305d522f475Smrg#elif !(defined(VMS) || defined(WIN32) || defined(Lynx) || defined(__GNU__) || defined(__MVS__))
306d522f475Smrg#include <sys/param.h>		/* for NOFILE */
307d522f475Smrg#endif
308d522f475Smrg
309d522f475Smrg#if defined(BSD) && (BSD >= 199103)
310d522f475Smrg#define WTMP
311d522f475Smrg#endif
312d522f475Smrg
313d522f475Smrg#include <stdio.h>
314d522f475Smrg
315d522f475Smrg#ifdef __hpux
316d522f475Smrg#include <sys/utsname.h>
317d522f475Smrg#endif /* __hpux */
318d522f475Smrg
319d522f475Smrg#if defined(apollo) && (OSMAJORVERSION == 10) && (OSMINORVERSION < 4)
320d522f475Smrg#define ttyslot() 1
321d522f475Smrg#endif /* apollo */
322d522f475Smrg
323d522f475Smrg#if defined(UTMPX_FOR_UTMP)
324d522f475Smrg#define UTMP_STR utmpx
325d522f475Smrg#else
326d522f475Smrg#define UTMP_STR utmp
327d522f475Smrg#endif
328d522f475Smrg
329d522f475Smrg#if defined(USE_UTEMPTER)
330d522f475Smrg#include <utempter.h>
331f2e35a3aSmrg#if 1
332f2e35a3aSmrg#define UTEMPTER_ADD(pty,hostname,master_fd) utempter_add_record(master_fd, hostname)
333f2e35a3aSmrg#define UTEMPTER_DEL()                       utempter_remove_added_record ()
334f2e35a3aSmrg#else
335f2e35a3aSmrg#define UTEMPTER_ADD(pty,hostname,master_fd) addToUtmp(pty, hostname, master_fd)
336f2e35a3aSmrg#define UTEMPTER_DEL()                       removeFromUtmp()
337f2e35a3aSmrg#endif
338d522f475Smrg#endif
339d522f475Smrg
3402e4f8982Smrg#if defined(I_FIND) && defined(I_PUSH)
3412e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_FIND, name) == 0 \
3422e4f8982Smrg			 && ioctl(fd, I_PUSH, name) < 0
3432e4f8982Smrg#else
3442e4f8982Smrg#define PUSH_FAILS(fd,name) ioctl(fd, I_PUSH, name) < 0
3452e4f8982Smrg#endif
3462e4f8982Smrg
347d522f475Smrg#if defined(UTMPX_FOR_UTMP)
348d522f475Smrg
349d522f475Smrg#include <utmpx.h>
350d522f475Smrg
351d522f475Smrg#define call_endutent  endutxent
352d522f475Smrg#define call_getutid   getutxid
353d522f475Smrg#define call_pututline pututxline
354d522f475Smrg#define call_setutent  setutxent
355d522f475Smrg#define call_updwtmp   updwtmpx
356d522f475Smrg
357d522f475Smrg#elif defined(HAVE_UTMP)
358d522f475Smrg
359d522f475Smrg#include <utmp.h>
360d522f475Smrg
361d522f475Smrg#if defined(_CRAY) && (OSMAJORVERSION < 8)
362d522f475Smrgextern struct utmp *getutid __((struct utmp * _Id));
363d522f475Smrg#endif
364d522f475Smrg
365d522f475Smrg#define call_endutent  endutent
366d522f475Smrg#define call_getutid   getutid
367d522f475Smrg#define call_pututline pututline
368d522f475Smrg#define call_setutent  setutent
369d522f475Smrg#define call_updwtmp   updwtmp
370d522f475Smrg
371d522f475Smrg#endif
372d522f475Smrg
373d522f475Smrg#if defined(USE_LASTLOG) && defined(HAVE_LASTLOG_H)
374d522f475Smrg#include <lastlog.h>		/* caution: glibc includes utmp.h here */
375d522f475Smrg#endif
376d522f475Smrg
377d522f475Smrg#ifndef USE_LASTLOGX
378d522f475Smrg#if defined(_NETBSD_SOURCE) && defined(_PATH_LASTLOGX)
379d522f475Smrg#define USE_LASTLOGX 1
380d522f475Smrg#endif
381d522f475Smrg#endif
382d522f475Smrg
383d522f475Smrg#ifdef  PUCC_PTYD
384d522f475Smrg#include <local/openpty.h>
385d522f475Smrg#endif /* PUCC_PTYD */
386d522f475Smrg
387d522f475Smrg#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
388d522f475Smrg#include <util.h>		/* openpty() */
389d522f475Smrg#endif
390d522f475Smrg
391956cc18dSsnj#if defined(__FreeBSD__) || defined(__DragonFly__)
392d522f475Smrg#include <libutil.h>		/* openpty() */
393d522f475Smrg#endif
394d522f475Smrg
395d522f475Smrg#if !defined(UTMP_FILENAME)
396d522f475Smrg#if defined(UTMP_FILE)
397d522f475Smrg#define UTMP_FILENAME UTMP_FILE
398d522f475Smrg#elif defined(_PATH_UTMP)
399d522f475Smrg#define UTMP_FILENAME _PATH_UTMP
400d522f475Smrg#else
401d522f475Smrg#define UTMP_FILENAME "/etc/utmp"
402d522f475Smrg#endif
403d522f475Smrg#endif
404d522f475Smrg
405d522f475Smrg#ifndef LASTLOG_FILENAME
406d522f475Smrg#ifdef _PATH_LASTLOG
407d522f475Smrg#define LASTLOG_FILENAME _PATH_LASTLOG
408d522f475Smrg#else
409d522f475Smrg#define LASTLOG_FILENAME "/usr/adm/lastlog"	/* only on BSD systems */
410d522f475Smrg#endif
411d522f475Smrg#endif
412d522f475Smrg
413d522f475Smrg#if !defined(WTMP_FILENAME)
414d522f475Smrg#if defined(WTMP_FILE)
415d522f475Smrg#define WTMP_FILENAME WTMP_FILE
416d522f475Smrg#elif defined(_PATH_WTMP)
417d522f475Smrg#define WTMP_FILENAME _PATH_WTMP
418d522f475Smrg#elif defined(SYSV)
419d522f475Smrg#define WTMP_FILENAME "/etc/wtmp"
420d522f475Smrg#else
421d522f475Smrg#define WTMP_FILENAME "/usr/adm/wtmp"
422d522f475Smrg#endif
423d522f475Smrg#endif
424d522f475Smrg
425d522f475Smrg#include <signal.h>
426d522f475Smrg
427d522f475Smrg#if defined(__SCO__) || (defined(ISC) && !defined(_POSIX_SOURCE))
428d522f475Smrg#undef SIGTSTP			/* defined, but not the BSD way */
429d522f475Smrg#endif
430d522f475Smrg
431d522f475Smrg#ifdef SIGTSTP
432d522f475Smrg#include <sys/wait.h>
433d522f475Smrg#endif
434d522f475Smrg
435d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
436d522f475Smrg#undef ECHOKE
437d522f475Smrg#undef ECHOCTL
438d522f475Smrg#endif
439d522f475Smrg
440d522f475Smrg#if defined(HAVE_SYS_TTYDEFAULTS_H) && !defined(CEOF)
441d522f475Smrg#include <sys/ttydefaults.h>
442d522f475Smrg#endif
443d522f475Smrg
444d522f475Smrg#ifdef X_NOT_POSIX
445d522f475Smrgextern long lseek();
446d522f475Smrg#if defined(USG) || defined(SVR4)
447d522f475Smrgextern unsigned sleep();
448d522f475Smrg#else
449d522f475Smrgextern void sleep();
450d522f475Smrg#endif
451d522f475Smrgextern char *ttyname();
452d522f475Smrg#endif
453d522f475Smrg
454d522f475Smrg#if defined(SYSV) && defined(DECL_PTSNAME)
455d522f475Smrgextern char *ptsname(int);
456d522f475Smrg#endif
457d522f475Smrg
458d522f475Smrg#ifndef VMS
4590bd37d32Smrgstatic void reapchild(int /* n */ );
4602e4f8982Smrgstatic int spawnXTerm(XtermWidget	/* xw */
4612e4f8982Smrg		      ,unsigned /* line_speed */ );
46220d2c4d2Smrgstatic void remove_termcap_entry(char *, const char *);
463d522f475Smrg#ifdef USE_PTY_SEARCH
46420d2c4d2Smrgstatic int pty_search(int * /* pty */ );
465d522f475Smrg#endif
466d522f475Smrg#endif /* ! VMS */
467d522f475Smrg
468d522f475Smrgstatic int get_pty(int *pty, char *from);
46920d2c4d2Smrgstatic void resize_termcap(XtermWidget xw);
470e0a2b6dfSmrgstatic void set_owner(char *device, unsigned uid, unsigned gid, unsigned mode);
471d522f475Smrg
472d522f475Smrgstatic Bool added_utmp_entry = False;
473d522f475Smrg
474d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
475d522f475Smrgstatic uid_t save_euid;
476d522f475Smrgstatic gid_t save_egid;
477d522f475Smrg#endif
478d522f475Smrg
479d522f475Smrgstatic uid_t save_ruid;
480d522f475Smrgstatic gid_t save_rgid;
481d522f475Smrg
482d522f475Smrg#if defined(USE_UTMP_SETGID)
483d522f475Smrgstatic int really_get_pty(int *pty, char *from);
484d522f475Smrg#endif
485d522f475Smrg
486d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
487d522f475Smrgstatic Bool xterm_exiting = False;
488d522f475Smrg#endif
489d522f475Smrg
490d522f475Smrgstatic char *explicit_shname = NULL;
491d522f475Smrg
492d522f475Smrg/*
493d522f475Smrg** Ordinarily it should be okay to omit the assignment in the following
494d522f475Smrg** statement. Apparently the c89 compiler on AIX 4.1.3 has a bug, or does
495d522f475Smrg** it? Without the assignment though the compiler will init command_to_exec
496d522f475Smrg** to 0xffffffff instead of NULL; and subsequent usage, e.g. in spawnXTerm() to
497d522f475Smrg** SEGV.
498d522f475Smrg*/
499d522f475Smrgstatic char **command_to_exec = NULL;
500d522f475Smrg
501d522f475Smrg#if OPT_LUIT_PROG
502d522f475Smrgstatic char **command_to_exec_with_luit = NULL;
5030bd37d32Smrgstatic unsigned command_length_with_luit = 0;
504d522f475Smrg#endif
505d522f475Smrg
506d522f475Smrg#define TERMCAP_ERASE "kb"
507d522f475Smrg#define VAL_INITIAL_ERASE A2E(8)
508d522f475Smrg
509d522f475Smrg/* choose a nice default value for speed - if we make it too low, users who
510d522f475Smrg * mistakenly use $TERM set to vt100 will get padding delays.  Setting it to a
511d522f475Smrg * higher value is not useful since legacy applications (termcap) that care
512d522f475Smrg * about padding generally store the code in a short, which does not have
513d522f475Smrg * enough bits for the extended values.
514d522f475Smrg */
515d522f475Smrg#ifdef B38400			/* everyone should define this */
516d522f475Smrg#define VAL_LINE_SPEED B38400
517d522f475Smrg#else /* ...but xterm's used this for a long time */
518d522f475Smrg#define VAL_LINE_SPEED B9600
519d522f475Smrg#endif
520d522f475Smrg
521d522f475Smrg/*
522d522f475Smrg * Allow use of system default characters if defined and reasonable.
523d522f475Smrg * These are based on the BSD ttydefaults.h
524d522f475Smrg */
525d522f475Smrg#ifndef CBRK
526d522f475Smrg#define CBRK     0xff		/* was 0 */
527d522f475Smrg#endif
528d522f475Smrg#ifndef CDISCARD
529d522f475Smrg#define CDISCARD CONTROL('O')
530d522f475Smrg#endif
531d522f475Smrg#ifndef CDSUSP
532d522f475Smrg#define CDSUSP   CONTROL('Y')
533d522f475Smrg#endif
534d522f475Smrg#ifndef CEOF
535d522f475Smrg#define CEOF     CONTROL('D')
536d522f475Smrg#endif
537d522f475Smrg#ifndef CEOL
538d522f475Smrg#define CEOL	 0xff		/* was 0 */
539d522f475Smrg#endif
540d522f475Smrg#ifndef CERASE
541d522f475Smrg#define CERASE   0177
542d522f475Smrg#endif
543d522f475Smrg#ifndef CERASE2
544d522f475Smrg#define	CERASE2  CONTROL('H')
545d522f475Smrg#endif
546d522f475Smrg#ifndef CFLUSH
547d522f475Smrg#define CFLUSH   CONTROL('O')
548d522f475Smrg#endif
549d522f475Smrg#ifndef CINTR
550d522f475Smrg#define CINTR    CONTROL('C')
551d522f475Smrg#endif
552d522f475Smrg#ifndef CKILL
553d522f475Smrg#define CKILL	 CONTROL('U')	/* was '@' */
554d522f475Smrg#endif
555d522f475Smrg#ifndef CLNEXT
556d522f475Smrg#define CLNEXT   CONTROL('V')
557d522f475Smrg#endif
558d522f475Smrg#ifndef CNUL
559d522f475Smrg#define CNUL     0
560d522f475Smrg#endif
561d522f475Smrg#ifndef CQUIT
562d522f475Smrg#define CQUIT    CONTROL('\\')
563d522f475Smrg#endif
564d522f475Smrg#ifndef CRPRNT
565d522f475Smrg#define CRPRNT   CONTROL('R')
566d522f475Smrg#endif
567d522f475Smrg#ifndef CREPRINT
568d522f475Smrg#define CREPRINT CRPRNT
569d522f475Smrg#endif
570d522f475Smrg#ifndef CSTART
571d522f475Smrg#define CSTART   CONTROL('Q')
572d522f475Smrg#endif
573d522f475Smrg#ifndef CSTATUS
574d522f475Smrg#define	CSTATUS  CONTROL('T')
575d522f475Smrg#endif
576d522f475Smrg#ifndef CSTOP
577d522f475Smrg#define CSTOP    CONTROL('S')
578d522f475Smrg#endif
579d522f475Smrg#ifndef CSUSP
580d522f475Smrg#define CSUSP    CONTROL('Z')
581d522f475Smrg#endif
582d522f475Smrg#ifndef CSWTCH
583d522f475Smrg#define CSWTCH   0
584d522f475Smrg#endif
585d522f475Smrg#ifndef CWERASE
586d522f475Smrg#define CWERASE  CONTROL('W')
587d522f475Smrg#endif
588d522f475Smrg
589d522f475Smrg#ifdef USE_ANY_SYSV_TERMIO
590d522f475Smrg#define TERMIO_STRUCT struct termio
591d522f475Smrg#define ttySetAttr(fd, datap) ioctl(fd, TCSETA, datap)
592d522f475Smrg#define ttyGetAttr(fd, datap) ioctl(fd, TCGETA, datap)
593d522f475Smrg#define ttyFlush(fd)          ioctl(fd, TCFLSH, 1)
594d522f475Smrg#elif defined(USE_POSIX_TERMIOS)
595d522f475Smrg#define TERMIO_STRUCT struct termios
596d522f475Smrg#define ttySetAttr(fd, datap) tcsetattr(fd, TCSANOW, datap)
597d522f475Smrg#define ttyGetAttr(fd, datap) tcgetattr(fd, datap)
598d522f475Smrg#define ttyFlush(fd)          tcflush(fd, TCOFLUSH)
599d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO */
600d522f475Smrg
601d522f475Smrg#ifndef VMS
602d522f475Smrg#ifdef TERMIO_STRUCT
603d522f475Smrg/* The following structures are initialized in main() in order
604d522f475Smrg** to eliminate any assumptions about the internal order of their
605d522f475Smrg** contents.
606d522f475Smrg*/
607d522f475Smrgstatic TERMIO_STRUCT d_tio;
608d522f475Smrg
609f2e35a3aSmrg#ifndef ONLCR
610f2e35a3aSmrg#define ONLCR 0
611f2e35a3aSmrg#endif
612f2e35a3aSmrg
613f2e35a3aSmrg#ifndef OPOST
614f2e35a3aSmrg#define OPOST 0
615f2e35a3aSmrg#endif
616f2e35a3aSmrg
617f2e35a3aSmrg#define D_TIO_FLAGS (OPOST | ONLCR)
618f2e35a3aSmrg
619d522f475Smrg#ifdef HAS_LTCHARS
620d522f475Smrgstatic struct ltchars d_ltc;
621d522f475Smrg#endif /* HAS_LTCHARS */
622d522f475Smrg
623d522f475Smrg#ifdef TIOCLSET
624d522f475Smrgstatic unsigned int d_lmode;
625d522f475Smrg#endif /* TIOCLSET */
626d522f475Smrg
627d522f475Smrg#else /* !TERMIO_STRUCT */
628f2e35a3aSmrg
629f2e35a3aSmrg#define D_SG_FLAGS (EVENP | ODDP | ECHO | CRMOD)
630f2e35a3aSmrg
631d522f475Smrgstatic struct sgttyb d_sg =
632d522f475Smrg{
633f2e35a3aSmrg    0, 0, 0177, CKILL, (D_SG_FLAGS | XTABS)
634d522f475Smrg};
635d522f475Smrgstatic struct tchars d_tc =
636d522f475Smrg{
637d522f475Smrg    CINTR, CQUIT, CSTART,
638d522f475Smrg    CSTOP, CEOF, CBRK
639d522f475Smrg};
640d522f475Smrgstatic struct ltchars d_ltc =
641d522f475Smrg{
642d522f475Smrg    CSUSP, CDSUSP, CRPRNT,
643d522f475Smrg    CFLUSH, CWERASE, CLNEXT
644d522f475Smrg};
645d522f475Smrgstatic int d_disipline = NTTYDISC;
646d522f475Smrgstatic long int d_lmode = LCRTBS | LCRTERA | LCRTKIL | LCTLECH;
647d522f475Smrg#ifdef sony
648d522f475Smrgstatic long int d_jmode = KM_SYSSJIS | KM_ASCII;
649d522f475Smrgstatic struct jtchars d_jtc =
650d522f475Smrg{
651d522f475Smrg    'J', 'B'
652d522f475Smrg};
653d522f475Smrg#endif /* sony */
654d522f475Smrg#endif /* TERMIO_STRUCT */
655d522f475Smrg#endif /* ! VMS */
656d522f475Smrg
657d522f475Smrg/*
658d522f475Smrg * SYSV has the termio.c_cc[V] and ltchars; BSD has tchars and ltchars;
659d522f475Smrg * SVR4 has only termio.c_cc, but it includes everything from ltchars.
660d522f475Smrg * POSIX termios has termios.c_cc, which is similar to SVR4.
661d522f475Smrg */
662d522f475Smrg#define TTYMODE(name) { name, sizeof(name)-1, 0, 0 }
663d522f475Smrgstatic Boolean override_tty_modes = False;
664d522f475Smrg/* *INDENT-OFF* */
665f2e35a3aSmrgstatic struct {
66620d2c4d2Smrg    const char *name;
667d522f475Smrg    size_t len;
668d522f475Smrg    int set;
669d522f475Smrg    int value;
670f2e35a3aSmrg} ttyModes[] = {
671d522f475Smrg    TTYMODE("intr"),		/* tchars.t_intrc ; VINTR */
672d522f475Smrg#define XTTYMODE_intr	0
673d522f475Smrg    TTYMODE("quit"),		/* tchars.t_quitc ; VQUIT */
674d522f475Smrg#define XTTYMODE_quit	1
675d522f475Smrg    TTYMODE("erase"),		/* sgttyb.sg_erase ; VERASE */
676d522f475Smrg#define XTTYMODE_erase	2
677d522f475Smrg    TTYMODE("kill"),		/* sgttyb.sg_kill ; VKILL */
678d522f475Smrg#define XTTYMODE_kill	3
679d522f475Smrg    TTYMODE("eof"),		/* tchars.t_eofc ; VEOF */
680d522f475Smrg#define XTTYMODE_eof	4
681d522f475Smrg    TTYMODE("eol"),		/* VEOL */
682d522f475Smrg#define XTTYMODE_eol	5
683d522f475Smrg    TTYMODE("swtch"),		/* VSWTCH */
684d522f475Smrg#define XTTYMODE_swtch	6
685d522f475Smrg    TTYMODE("start"),		/* tchars.t_startc ; VSTART */
686d522f475Smrg#define XTTYMODE_start	7
687d522f475Smrg    TTYMODE("stop"),		/* tchars.t_stopc ; VSTOP */
688d522f475Smrg#define XTTYMODE_stop	8
689d522f475Smrg    TTYMODE("brk"),		/* tchars.t_brkc */
690d522f475Smrg#define XTTYMODE_brk	9
691d522f475Smrg    TTYMODE("susp"),		/* ltchars.t_suspc ; VSUSP */
692d522f475Smrg#define XTTYMODE_susp	10
693d522f475Smrg    TTYMODE("dsusp"),		/* ltchars.t_dsuspc ; VDSUSP */
694d522f475Smrg#define XTTYMODE_dsusp	11
695d522f475Smrg    TTYMODE("rprnt"),		/* ltchars.t_rprntc ; VREPRINT */
696d522f475Smrg#define XTTYMODE_rprnt	12
697d522f475Smrg    TTYMODE("flush"),		/* ltchars.t_flushc ; VDISCARD */
698d522f475Smrg#define XTTYMODE_flush	13
699d522f475Smrg    TTYMODE("weras"),		/* ltchars.t_werasc ; VWERASE */
700d522f475Smrg#define XTTYMODE_weras	14
701d522f475Smrg    TTYMODE("lnext"),		/* ltchars.t_lnextc ; VLNEXT */
702d522f475Smrg#define XTTYMODE_lnext	15
703d522f475Smrg    TTYMODE("status"),		/* VSTATUS */
704d522f475Smrg#define XTTYMODE_status	16
705d522f475Smrg    TTYMODE("erase2"),		/* VERASE2 */
706d522f475Smrg#define XTTYMODE_erase2	17
707d522f475Smrg    TTYMODE("eol2"),		/* VEOL2 */
708d522f475Smrg#define XTTYMODE_eol2	18
709f2e35a3aSmrg    TTYMODE("tabs"),		/* TAB0 */
710f2e35a3aSmrg#define XTTYMODE_tabs	19
711f2e35a3aSmrg    TTYMODE("-tabs"),		/* TAB3 */
712f2e35a3aSmrg#define XTTYMODE__tabs	20
713d522f475Smrg};
714d522f475Smrg
715f2e35a3aSmrg#ifndef TAB0
716f2e35a3aSmrg#define TAB0 0
717f2e35a3aSmrg#endif
718f2e35a3aSmrg
719f2e35a3aSmrg#ifndef TAB3
720f2e35a3aSmrg#if defined(OXTABS)
721f2e35a3aSmrg#define TAB3 OXTABS
722f2e35a3aSmrg#elif defined(XTABS)
723f2e35a3aSmrg#define TAB3 XTABS
724f2e35a3aSmrg#endif
725f2e35a3aSmrg#endif
726f2e35a3aSmrg
727f2e35a3aSmrg#ifndef TABDLY
728f2e35a3aSmrg#define TABDLY (TAB0|TAB3)
729f2e35a3aSmrg#endif
730f2e35a3aSmrg
731f2e35a3aSmrg#define isTtyMode(p,q) (ttyChars[p].myMode == q && ttyModes[q].set)
732f2e35a3aSmrg
733f2e35a3aSmrg#define isTabMode(n) \
734f2e35a3aSmrg	(isTtyMode(n, XTTYMODE_tabs) || \
735f2e35a3aSmrg	 isTtyMode(n, XTTYMODE__tabs))
736f2e35a3aSmrg
737f2e35a3aSmrg#define TMODE(ind,var) \
738f2e35a3aSmrg	if (ttyModes[ind].set) \
739f2e35a3aSmrg	    var = (cc_t) ttyModes[ind].value
740f2e35a3aSmrg
741d522f475Smrg#define validTtyChar(data, n) \
742f2e35a3aSmrg	    (ttyChars[n].sysMode >= 0 && \
743f2e35a3aSmrg	     ttyChars[n].sysMode < (int) XtNumber(data.c_cc))
744d522f475Smrg
745d522f475Smrgstatic const struct {
746d522f475Smrg    int sysMode;
747d522f475Smrg    int myMode;
748d522f475Smrg    int myDefault;
749f2e35a3aSmrg} ttyChars[] = {
750d522f475Smrg#ifdef VINTR
751d522f475Smrg    { VINTR,    XTTYMODE_intr,   CINTR },
752d522f475Smrg#endif
753d522f475Smrg#ifdef VQUIT
754d522f475Smrg    { VQUIT,    XTTYMODE_quit,   CQUIT },
755d522f475Smrg#endif
756d522f475Smrg#ifdef VERASE
757d522f475Smrg    { VERASE,   XTTYMODE_erase,  CERASE },
758d522f475Smrg#endif
759d522f475Smrg#ifdef VKILL
760d522f475Smrg    { VKILL,    XTTYMODE_kill,   CKILL },
761d522f475Smrg#endif
762d522f475Smrg#ifdef VEOF
763d522f475Smrg    { VEOF,     XTTYMODE_eof,    CEOF },
764d522f475Smrg#endif
765d522f475Smrg#ifdef VEOL
766d522f475Smrg    { VEOL,     XTTYMODE_eol,    CEOL },
767d522f475Smrg#endif
768d522f475Smrg#ifdef VSWTCH
769d522f475Smrg    { VSWTCH,   XTTYMODE_swtch,  CNUL },
770d522f475Smrg#endif
771d522f475Smrg#ifdef VSTART
772d522f475Smrg    { VSTART,   XTTYMODE_start,  CSTART },
773d522f475Smrg#endif
774d522f475Smrg#ifdef VSTOP
775d522f475Smrg    { VSTOP,    XTTYMODE_stop,   CSTOP },
776d522f475Smrg#endif
777d522f475Smrg#ifdef VSUSP
778d522f475Smrg    { VSUSP,    XTTYMODE_susp,   CSUSP },
779d522f475Smrg#endif
780d522f475Smrg#ifdef VDSUSP
781d522f475Smrg    { VDSUSP,   XTTYMODE_dsusp,  CDSUSP },
782d522f475Smrg#endif
783d522f475Smrg#ifdef VREPRINT
784d522f475Smrg    { VREPRINT, XTTYMODE_rprnt,  CREPRINT },
785d522f475Smrg#endif
786d522f475Smrg#ifdef VDISCARD
787d522f475Smrg    { VDISCARD, XTTYMODE_flush,  CDISCARD },
788d522f475Smrg#endif
789d522f475Smrg#ifdef VWERASE
790d522f475Smrg    { VWERASE,  XTTYMODE_weras,  CWERASE },
791d522f475Smrg#endif
792d522f475Smrg#ifdef VLNEXT
793d522f475Smrg    { VLNEXT,   XTTYMODE_lnext,  CLNEXT },
794d522f475Smrg#endif
795d522f475Smrg#ifdef VSTATUS
796d522f475Smrg    { VSTATUS,  XTTYMODE_status, CSTATUS },
797d522f475Smrg#endif
798d522f475Smrg#ifdef VERASE2
799d522f475Smrg    { VERASE2,  XTTYMODE_erase2, CERASE2 },
800d522f475Smrg#endif
801d522f475Smrg#ifdef VEOL2
802d522f475Smrg    { VEOL2,    XTTYMODE_eol2,   CNUL },
803d522f475Smrg#endif
804f2e35a3aSmrg    { -1,       XTTYMODE_tabs,   TAB0 },
805f2e35a3aSmrg    { -1,       XTTYMODE__tabs,  TAB3 },
806d522f475Smrg};
807d522f475Smrg/* *INDENT-ON* */
808d522f475Smrg
809f2e35a3aSmrgstatic int parse_tty_modes(char *s);
810d522f475Smrg
811d522f475Smrg#ifndef USE_UTEMPTER
812d522f475Smrg#ifdef USE_SYSV_UTMP
813d522f475Smrg#if (defined(AIXV3) && (OSMAJORVERSION < 4)) && !(defined(getutid))
814d522f475Smrgextern struct utmp *getutid();
815d522f475Smrg#endif /* AIXV3 */
816d522f475Smrg
817d522f475Smrg#else /* not USE_SYSV_UTMP */
818d522f475Smrgstatic char etc_utmp[] = UTMP_FILENAME;
819d522f475Smrg#endif /* USE_SYSV_UTMP */
820d522f475Smrg
821d522f475Smrg#if defined(USE_LASTLOG) && defined(USE_STRUCT_LASTLOG)
822d522f475Smrgstatic char etc_lastlog[] = LASTLOG_FILENAME;
823d522f475Smrg#else
824d522f475Smrg#undef USE_LASTLOG
825d522f475Smrg#endif
826d522f475Smrg
827d522f475Smrg#ifdef WTMP
828d522f475Smrgstatic char etc_wtmp[] = WTMP_FILENAME;
829d522f475Smrg#endif
830d522f475Smrg#endif /* !USE_UTEMPTER */
831d522f475Smrg
832d522f475Smrg/*
833d522f475Smrg * Some people with 4.3bsd /bin/login seem to like to use login -p -f user
834d522f475Smrg * to implement xterm -ls.  They can turn on USE_LOGIN_DASH_P and turn off
835d522f475Smrg * WTMP and USE_LASTLOG.
836d522f475Smrg */
837d522f475Smrg#ifdef USE_LOGIN_DASH_P
838d522f475Smrg#ifndef LOGIN_FILENAME
839d522f475Smrg#define LOGIN_FILENAME "/bin/login"
840d522f475Smrg#endif
841d522f475Smrgstatic char bin_login[] = LOGIN_FILENAME;
842d522f475Smrg#endif
843d522f475Smrg
84401037d57Smrgstatic char noPassedPty[2];
84501037d57Smrgstatic char *passedPty = noPassedPty;	/* name if pty if slave */
846d522f475Smrg
847d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
848d522f475Smrgstatic int Console;
849d522f475Smrg#include <X11/Xmu/SysUtil.h>	/* XmuGetHostname */
850d522f475Smrg#define MIT_CONSOLE_LEN	12
851d522f475Smrg#define MIT_CONSOLE "MIT_CONSOLE_"
852d522f475Smrgstatic char mit_console_name[255 + MIT_CONSOLE_LEN + 1] = MIT_CONSOLE;
853d522f475Smrgstatic Atom mit_console;
854d522f475Smrg#endif /* TIOCCONS */
855d522f475Smrg
856d522f475Smrg#ifndef USE_SYSV_UTMP
857d522f475Smrgstatic int tslot;
858d522f475Smrg#endif /* USE_SYSV_UTMP */
859d522f475Smrgstatic sigjmp_buf env;
860d522f475Smrg
861d522f475Smrg#define SetUtmpHost(dst, screen) \
862d522f475Smrg	{ \
863d522f475Smrg	    char host[sizeof(dst) + 1]; \
864f2e35a3aSmrg	    strncpy(host, DisplayString(screen->display), sizeof(host) - 1); \
865f2e35a3aSmrg	    host[sizeof(dst)] = '\0'; \
866d522f475Smrg	    TRACE(("DisplayString(%s)\n", host)); \
867d522f475Smrg	    if (!resource.utmpDisplayId) { \
868d522f475Smrg		char *endptr = strrchr(host, ':'); \
869d522f475Smrg		if (endptr) { \
870d522f475Smrg		    TRACE(("trimming display-id '%s'\n", host)); \
871d522f475Smrg		    *endptr = '\0'; \
872d522f475Smrg		} \
873d522f475Smrg	    } \
874894e0ac8Smrg	    copy_filled(dst, host, sizeof(dst)); \
875d522f475Smrg	}
876d522f475Smrg
877d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
878d522f475Smrg#  define SetUtmpSysLen(utmp) 			   \
879d522f475Smrg	{ \
880d522f475Smrg	    utmp.ut_host[sizeof(utmp.ut_host)-1] = '\0'; \
881f2e35a3aSmrg	    utmp.ut_syslen = (short) ((int) strlen(utmp.ut_host) + 1); \
882d522f475Smrg	}
883d522f475Smrg#endif
884d522f475Smrg
885d522f475Smrg/* used by VT (charproc.c) */
886d522f475Smrg
887d522f475Smrgstatic XtResource application_resources[] =
888d522f475Smrg{
889d522f475Smrg    Sres("iconGeometry", "IconGeometry", icon_geometry, NULL),
890d522f475Smrg    Sres(XtNtitle, XtCTitle, title, NULL),
8910bd37d32Smrg    Sres(XtNiconHint, XtCIconHint, icon_hint, NULL),
892d522f475Smrg    Sres(XtNiconName, XtCIconName, icon_name, NULL),
893d522f475Smrg    Sres("termName", "TermName", term_name, NULL),
894d522f475Smrg    Sres("ttyModes", "TtyModes", tty_modes, NULL),
895f2e35a3aSmrg    Sres("validShells", "ValidShells", valid_shells, NULL),
896d522f475Smrg    Bres("hold", "Hold", hold_screen, False),
897d522f475Smrg    Bres("utmpInhibit", "UtmpInhibit", utmpInhibit, False),
898d522f475Smrg    Bres("utmpDisplayId", "UtmpDisplayId", utmpDisplayId, True),
899d522f475Smrg    Bres("messages", "Messages", messages, True),
900d522f475Smrg    Ires("minBufSize", "MinBufSize", minBufSize, 4096),
901d522f475Smrg    Ires("maxBufSize", "MaxBufSize", maxBufSize, 32768),
90220d2c4d2Smrg    Sres("menuLocale", "MenuLocale", menuLocale, DEF_MENU_LOCALE),
903a1f3da82Smrg    Sres("omitTranslation", "OmitTranslation", omitTranslation, NULL),
904d522f475Smrg    Sres("keyboardType", "KeyboardType", keyboardType, "unknown"),
905ad37e533Smrg#ifdef HAVE_LIB_XCURSOR
906ad37e533Smrg    Sres("cursorTheme", "CursorTheme", cursorTheme, "none"),
907ad37e533Smrg#endif
908e39b573cSmrg#if OPT_PRINT_ON_EXIT
909e39b573cSmrg    Ires("printModeImmediate", "PrintModeImmediate", printModeNow, 0),
910e39b573cSmrg    Ires("printOptsImmediate", "PrintOptsImmediate", printOptsNow, 9),
911e39b573cSmrg    Sres("printFileImmediate", "PrintFileImmediate", printFileNow, NULL),
912e39b573cSmrg    Ires("printModeOnXError", "PrintModeOnXError", printModeOnXError, 0),
913e39b573cSmrg    Ires("printOptsOnXError", "PrintOptsOnXError", printOptsOnXError, 9),
914e39b573cSmrg    Sres("printFileOnXError", "PrintFileOnXError", printFileOnXError, NULL),
915e39b573cSmrg#endif
916d522f475Smrg#if OPT_SUNPC_KBD
917d522f475Smrg    Bres("sunKeyboard", "SunKeyboard", sunKeyboard, False),
918d522f475Smrg#endif
919d522f475Smrg#if OPT_HP_FUNC_KEYS
920d522f475Smrg    Bres("hpFunctionKeys", "HpFunctionKeys", hpFunctionKeys, False),
921d522f475Smrg#endif
922d522f475Smrg#if OPT_SCO_FUNC_KEYS
923d522f475Smrg    Bres("scoFunctionKeys", "ScoFunctionKeys", scoFunctionKeys, False),
924d522f475Smrg#endif
925d522f475Smrg#if OPT_SUN_FUNC_KEYS
926d522f475Smrg    Bres("sunFunctionKeys", "SunFunctionKeys", sunFunctionKeys, False),
927d522f475Smrg#endif
928d522f475Smrg#if OPT_TCAP_FKEYS
929d522f475Smrg    Bres("tcapFunctionKeys", "TcapFunctionKeys", termcapKeys, False),
930d522f475Smrg#endif
931d522f475Smrg#if OPT_INITIAL_ERASE
932d522f475Smrg    Bres("ptyInitialErase", "PtyInitialErase", ptyInitialErase, DEF_INITIAL_ERASE),
933d522f475Smrg    Bres("backarrowKeyIsErase", "BackarrowKeyIsErase", backarrow_is_erase, DEF_BACKARO_ERASE),
934d522f475Smrg#endif
935d522f475Smrg    Bres("useInsertMode", "UseInsertMode", useInsertMode, False),
936d522f475Smrg#if OPT_ZICONBEEP
937d522f475Smrg    Ires("zIconBeep", "ZIconBeep", zIconBeep, 0),
9380bd37d32Smrg    Sres("zIconTitleFormat", "ZIconTitleFormat", zIconFormat, "*** %s"),
939d522f475Smrg#endif
940d522f475Smrg#if OPT_PTY_HANDSHAKE
941d522f475Smrg    Bres("waitForMap", "WaitForMap", wait_for_map, False),
942d522f475Smrg    Bres("ptyHandshake", "PtyHandshake", ptyHandshake, True),
943d522f475Smrg    Bres("ptySttySize", "PtySttySize", ptySttySize, DEF_PTY_STTY_SIZE),
944d522f475Smrg#endif
945913cc679Smrg#if OPT_REPORT_CCLASS
946913cc679Smrg    Bres("reportCClass", "ReportCClass", reportCClass, False),
947913cc679Smrg#endif
948e0a2b6dfSmrg#if OPT_REPORT_COLORS
949e0a2b6dfSmrg    Bres("reportColors", "ReportColors", reportColors, False),
950e0a2b6dfSmrg#endif
951e0a2b6dfSmrg#if OPT_REPORT_FONTS
952e0a2b6dfSmrg    Bres("reportFonts", "ReportFonts", reportFonts, False),
953e0a2b6dfSmrg#endif
954f2e35a3aSmrg#if OPT_REPORT_ICONS
955f2e35a3aSmrg    Bres("reportIcons", "ReportIcons", reportIcons, False),
956f2e35a3aSmrg#endif
957f2e35a3aSmrg#if OPT_XRES_QUERY
958f2e35a3aSmrg    Bres("reportXRes", "ReportXRes", reportXRes, False),
959f2e35a3aSmrg#endif
960d522f475Smrg#if OPT_SAME_NAME
961d522f475Smrg    Bres("sameName", "SameName", sameName, True),
962d522f475Smrg#endif
963d522f475Smrg#if OPT_SESSION_MGT
964d522f475Smrg    Bres("sessionMgt", "SessionMgt", sessionMgt, True),
965d522f475Smrg#endif
966d522f475Smrg#if OPT_TOOLBAR
967d522f475Smrg    Bres(XtNtoolBar, XtCToolBar, toolBar, True),
968d522f475Smrg#endif
969956cc18dSsnj#if OPT_MAXIMIZE
970956cc18dSsnj    Bres(XtNmaximized, XtCMaximized, maximized, False),
971a1f3da82Smrg    Sres(XtNfullscreen, XtCFullscreen, fullscreen_s, "off"),
972956cc18dSsnj#endif
973f2e35a3aSmrg#if USE_DOUBLE_BUFFER
974f2e35a3aSmrg    Bres(XtNbuffered, XtCBuffered, buffered, DEF_DOUBLE_BUFFER),
975f2e35a3aSmrg    Ires(XtNbufferedFPS, XtCBufferedFPS, buffered_fps, 40),
976f2e35a3aSmrg#endif
977d522f475Smrg};
978d522f475Smrg
97920d2c4d2Smrgstatic String fallback_resources[] =
980d522f475Smrg{
981e39b573cSmrg#if OPT_TOOLBAR
982e39b573cSmrg    "*toolBar: false",
983e39b573cSmrg#endif
984d522f475Smrg    "*SimpleMenu*menuLabel.vertSpace: 100",
985d522f475Smrg    "*SimpleMenu*HorizontalMargins: 16",
986d522f475Smrg    "*SimpleMenu*Sme.height: 16",
987d522f475Smrg    "*SimpleMenu*Cursor: left_ptr",
988d522f475Smrg    "*mainMenu.Label:  Main Options (no app-defaults)",
989d522f475Smrg    "*vtMenu.Label:  VT Options (no app-defaults)",
990d522f475Smrg    "*fontMenu.Label:  VT Fonts (no app-defaults)",
991d522f475Smrg#if OPT_TEK4014
992d522f475Smrg    "*tekMenu.Label:  Tek Options (no app-defaults)",
993d522f475Smrg#endif
994d522f475Smrg    NULL
995d522f475Smrg};
996d522f475Smrg
997d522f475Smrg/* Command line options table.  Only resources are entered here...there is a
998d522f475Smrg   pass over the remaining options after XrmParseCommand is let loose. */
999d522f475Smrg/* *INDENT-OFF* */
1000f2e35a3aSmrg#define DATA(option,pattern,type,value) { (char *) option, (char *) pattern, type, (XPointer) value }
1001d522f475Smrgstatic XrmOptionDescRec optionDescList[] = {
1002f2e35a3aSmrgDATA("-geometry",	"*vt100.geometry",XrmoptionSepArg,	NULL),
1003f2e35a3aSmrgDATA("-132",		"*c132",	XrmoptionNoArg,		"on"),
1004f2e35a3aSmrgDATA("+132",		"*c132",	XrmoptionNoArg,		"off"),
1005f2e35a3aSmrgDATA("-ah",		"*alwaysHighlight", XrmoptionNoArg,	"on"),
1006f2e35a3aSmrgDATA("+ah",		"*alwaysHighlight", XrmoptionNoArg,	"off"),
1007f2e35a3aSmrgDATA("-aw",		"*autoWrap",	XrmoptionNoArg,		"on"),
1008f2e35a3aSmrgDATA("+aw",		"*autoWrap",	XrmoptionNoArg,		"off"),
1009d522f475Smrg#ifndef NO_ACTIVE_ICON
1010f2e35a3aSmrgDATA("-ai",		"*activeIcon",	XrmoptionNoArg,		"off"),
1011f2e35a3aSmrgDATA("+ai",		"*activeIcon",	XrmoptionNoArg,		"on"),
1012d522f475Smrg#endif /* NO_ACTIVE_ICON */
1013f2e35a3aSmrgDATA("-b",		"*internalBorder",XrmoptionSepArg,	NULL),
1014f2e35a3aSmrgDATA("-bc",		"*cursorBlink",	XrmoptionNoArg,		"on"),
1015f2e35a3aSmrgDATA("+bc",		"*cursorBlink",	XrmoptionNoArg,		"off"),
1016f2e35a3aSmrgDATA("-bcf",		"*cursorOffTime",XrmoptionSepArg,	NULL),
1017f2e35a3aSmrgDATA("-bcn",		"*cursorOnTime",XrmoptionSepArg,	NULL),
1018f2e35a3aSmrgDATA("-bdc",		"*colorBDMode",	XrmoptionNoArg,		"off"),
1019f2e35a3aSmrgDATA("+bdc",		"*colorBDMode",	XrmoptionNoArg,		"on"),
1020f2e35a3aSmrgDATA("-cb",		"*cutToBeginningOfLine", XrmoptionNoArg, "off"),
1021f2e35a3aSmrgDATA("+cb",		"*cutToBeginningOfLine", XrmoptionNoArg, "on"),
1022f2e35a3aSmrgDATA("-cc",		"*charClass",	XrmoptionSepArg,	NULL),
1023f2e35a3aSmrgDATA("-cm",		"*colorMode",	XrmoptionNoArg,		"off"),
1024f2e35a3aSmrgDATA("+cm",		"*colorMode",	XrmoptionNoArg,		"on"),
1025f2e35a3aSmrgDATA("-cn",		"*cutNewline",	XrmoptionNoArg,		"off"),
1026f2e35a3aSmrgDATA("+cn",		"*cutNewline",	XrmoptionNoArg,		"on"),
1027f2e35a3aSmrgDATA("-cr",		"*cursorColor",	XrmoptionSepArg,	NULL),
1028f2e35a3aSmrgDATA("-cu",		"*curses",	XrmoptionNoArg,		"on"),
1029f2e35a3aSmrgDATA("+cu",		"*curses",	XrmoptionNoArg,		"off"),
1030f2e35a3aSmrgDATA("-dc",		"*dynamicColors",XrmoptionNoArg,	"off"),
1031f2e35a3aSmrgDATA("+dc",		"*dynamicColors",XrmoptionNoArg,	"on"),
1032f2e35a3aSmrgDATA("-fb",		"*boldFont",	XrmoptionSepArg,	NULL),
1033f2e35a3aSmrgDATA("-fbb",		"*freeBoldBox", XrmoptionNoArg,		"off"),
1034f2e35a3aSmrgDATA("+fbb",		"*freeBoldBox", XrmoptionNoArg,		"on"),
1035f2e35a3aSmrgDATA("-fbx",		"*forceBoxChars", XrmoptionNoArg,	"off"),
1036f2e35a3aSmrgDATA("+fbx",		"*forceBoxChars", XrmoptionNoArg,	"on"),
1037f2e35a3aSmrgDATA("-fc",		"*initialFont",	XrmoptionSepArg,	NULL),
1038d522f475Smrg#ifndef NO_ACTIVE_ICON
1039f2e35a3aSmrgDATA("-fi",		"*iconFont",	XrmoptionSepArg,	NULL),
1040d522f475Smrg#endif /* NO_ACTIVE_ICON */
1041d522f475Smrg#if OPT_RENDERFONT
1042f2e35a3aSmrgDATA("-fa",		"*faceName",	XrmoptionSepArg,	NULL),
1043f2e35a3aSmrgDATA("-fd",		"*faceNameDoublesize", XrmoptionSepArg,	NULL),
1044f2e35a3aSmrgDATA("-fs",		"*faceSize",	XrmoptionSepArg,	NULL),
1045d522f475Smrg#endif
104601037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
1047f2e35a3aSmrgDATA("-itc",		"*colorITMode",	XrmoptionNoArg,		"off"),
1048f2e35a3aSmrgDATA("+itc",		"*colorITMode",	XrmoptionNoArg,		"on"),
104901037d57Smrg#endif
1050d522f475Smrg#if OPT_WIDE_CHARS
1051f2e35a3aSmrgDATA("-fw",		"*wideFont",	XrmoptionSepArg,	NULL),
1052f2e35a3aSmrgDATA("-fwb",		"*wideBoldFont", XrmoptionSepArg,	NULL),
1053d522f475Smrg#endif
1054d522f475Smrg#if OPT_INPUT_METHOD
1055f2e35a3aSmrgDATA("-fx",		"*ximFont",	XrmoptionSepArg,	NULL),
1056d522f475Smrg#endif
1057d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1058f2e35a3aSmrgDATA("-hc",		"*highlightColor", XrmoptionSepArg,	NULL),
1059f2e35a3aSmrgDATA("-hm",		"*highlightColorMode", XrmoptionNoArg,	"on"),
1060f2e35a3aSmrgDATA("+hm",		"*highlightColorMode", XrmoptionNoArg,	"off"),
1061f2e35a3aSmrgDATA("-selfg",		"*highlightTextColor", XrmoptionSepArg,	NULL),
1062f2e35a3aSmrgDATA("-selbg",		"*highlightColor", XrmoptionSepArg,	NULL),
1063d522f475Smrg#endif
1064d522f475Smrg#if OPT_HP_FUNC_KEYS
1065f2e35a3aSmrgDATA("-hf",		"*hpFunctionKeys",XrmoptionNoArg,	"on"),
1066f2e35a3aSmrgDATA("+hf",		"*hpFunctionKeys",XrmoptionNoArg,	"off"),
1067d522f475Smrg#endif
1068f2e35a3aSmrgDATA("-hold",		"*hold",	XrmoptionNoArg,		"on"),
1069f2e35a3aSmrgDATA("+hold",		"*hold",	XrmoptionNoArg,		"off"),
1070d522f475Smrg#if OPT_INITIAL_ERASE
1071f2e35a3aSmrgDATA("-ie",		"*ptyInitialErase", XrmoptionNoArg,	"on"),
1072f2e35a3aSmrgDATA("+ie",		"*ptyInitialErase", XrmoptionNoArg,	"off"),
1073d522f475Smrg#endif
1074f2e35a3aSmrgDATA("-j",		"*jumpScroll",	XrmoptionNoArg,		"on"),
1075f2e35a3aSmrgDATA("+j",		"*jumpScroll",	XrmoptionNoArg,		"off"),
1076d522f475Smrg#if OPT_C1_PRINT
1077f2e35a3aSmrgDATA("-k8",		"*allowC1Printable", XrmoptionNoArg,	"on"),
1078f2e35a3aSmrgDATA("+k8",		"*allowC1Printable", XrmoptionNoArg,	"off"),
1079d522f475Smrg#endif
1080f2e35a3aSmrgDATA("-kt",		"*keyboardType", XrmoptionSepArg,	NULL),
1081d522f475Smrg/* parse logging options anyway for compatibility */
1082f2e35a3aSmrgDATA("-l",		"*logging",	XrmoptionNoArg,		"on"),
1083f2e35a3aSmrgDATA("+l",		"*logging",	XrmoptionNoArg,		"off"),
1084f2e35a3aSmrgDATA("-lf",		"*logFile",	XrmoptionSepArg,	NULL),
1085f2e35a3aSmrgDATA("-ls",		"*loginShell",	XrmoptionNoArg,		"on"),
1086f2e35a3aSmrgDATA("+ls",		"*loginShell",	XrmoptionNoArg,		"off"),
1087f2e35a3aSmrgDATA("-mb",		"*marginBell",	XrmoptionNoArg,		"on"),
1088f2e35a3aSmrgDATA("+mb",		"*marginBell",	XrmoptionNoArg,		"off"),
1089f2e35a3aSmrgDATA("-mc",		"*multiClickTime", XrmoptionSepArg,	NULL),
1090f2e35a3aSmrgDATA("-mesg",		"*messages",	XrmoptionNoArg,		"off"),
1091f2e35a3aSmrgDATA("+mesg",		"*messages",	XrmoptionNoArg,		"on"),
1092f2e35a3aSmrgDATA("-ms",		"*pointerColor",XrmoptionSepArg,	NULL),
1093f2e35a3aSmrgDATA("-nb",		"*nMarginBell",	XrmoptionSepArg,	NULL),
1094f2e35a3aSmrgDATA("-nul",		"*underLine",	XrmoptionNoArg,		"off"),
1095f2e35a3aSmrgDATA("+nul",		"*underLine",	XrmoptionNoArg,		"on"),
1096f2e35a3aSmrgDATA("-pc",		"*boldColors",	XrmoptionNoArg,		"on"),
1097f2e35a3aSmrgDATA("+pc",		"*boldColors",	XrmoptionNoArg,		"off"),
1098f2e35a3aSmrgDATA("-pf",		"*pointerFont",	XrmoptionSepArg,	NULL),
1099f2e35a3aSmrgDATA("-rw",		"*reverseWrap",	XrmoptionNoArg,		"on"),
1100f2e35a3aSmrgDATA("+rw",		"*reverseWrap",	XrmoptionNoArg,		"off"),
1101f2e35a3aSmrgDATA("-s",		"*multiScroll",	XrmoptionNoArg,		"on"),
1102f2e35a3aSmrgDATA("+s",		"*multiScroll",	XrmoptionNoArg,		"off"),
1103f2e35a3aSmrgDATA("-sb",		"*scrollBar",	XrmoptionNoArg,		"on"),
1104f2e35a3aSmrgDATA("+sb",		"*scrollBar",	XrmoptionNoArg,		"off"),
1105913cc679Smrg#if OPT_REPORT_CCLASS
1106f2e35a3aSmrgDATA("-report-charclass","*reportCClass", XrmoptionNoArg,	"on"),
1107913cc679Smrg#endif
1108e0a2b6dfSmrg#if OPT_REPORT_COLORS
1109f2e35a3aSmrgDATA("-report-colors",	"*reportColors", XrmoptionNoArg,	"on"),
1110f2e35a3aSmrg#endif
1111f2e35a3aSmrg#if OPT_REPORT_ICONS
1112f2e35a3aSmrgDATA("-report-icons",	"*reportIcons",	XrmoptionNoArg,		"on"),
1113e0a2b6dfSmrg#endif
1114e0a2b6dfSmrg#if OPT_REPORT_FONTS
1115f2e35a3aSmrgDATA("-report-fonts",	"*reportFonts", XrmoptionNoArg,		"on"),
1116f2e35a3aSmrg#endif
1117f2e35a3aSmrg#if OPT_XRES_QUERY
1118f2e35a3aSmrgDATA("-report-xres",	"*reportXRes",	XrmoptionNoArg,		"on"),
1119e0a2b6dfSmrg#endif
1120d522f475Smrg#ifdef SCROLLBAR_RIGHT
1121f2e35a3aSmrgDATA("-leftbar",	"*rightScrollBar", XrmoptionNoArg,	"off"),
1122f2e35a3aSmrgDATA("-rightbar",	"*rightScrollBar", XrmoptionNoArg,	"on"),
1123f2e35a3aSmrg#endif
1124f2e35a3aSmrgDATA("-rvc",		"*colorRVMode",	XrmoptionNoArg,		"off"),
1125f2e35a3aSmrgDATA("+rvc",		"*colorRVMode",	XrmoptionNoArg,		"on"),
1126f2e35a3aSmrgDATA("-sf",		"*sunFunctionKeys", XrmoptionNoArg,	"on"),
1127f2e35a3aSmrgDATA("+sf",		"*sunFunctionKeys", XrmoptionNoArg,	"off"),
1128f2e35a3aSmrgDATA("-sh",		"*scaleHeight", XrmoptionSepArg,	NULL),
1129f2e35a3aSmrgDATA("-si",		"*scrollTtyOutput", XrmoptionNoArg,	"off"),
1130f2e35a3aSmrgDATA("+si",		"*scrollTtyOutput", XrmoptionNoArg,	"on"),
1131f2e35a3aSmrgDATA("-sk",		"*scrollKey",	XrmoptionNoArg,		"on"),
1132f2e35a3aSmrgDATA("+sk",		"*scrollKey",	XrmoptionNoArg,		"off"),
1133f2e35a3aSmrgDATA("-sl",		"*saveLines",	XrmoptionSepArg,	NULL),
1134d522f475Smrg#if OPT_SUNPC_KBD
1135f2e35a3aSmrgDATA("-sp",		"*sunKeyboard", XrmoptionNoArg,		"on"),
1136f2e35a3aSmrgDATA("+sp",		"*sunKeyboard", XrmoptionNoArg,		"off"),
1137d522f475Smrg#endif
1138d522f475Smrg#if OPT_TEK4014
1139f2e35a3aSmrgDATA("-t",		"*tekStartup",	XrmoptionNoArg,		"on"),
1140f2e35a3aSmrgDATA("+t",		"*tekStartup",	XrmoptionNoArg,		"off"),
1141d522f475Smrg#endif
1142f2e35a3aSmrgDATA("-ti",		"*decTerminalID",XrmoptionSepArg,	NULL),
1143f2e35a3aSmrgDATA("-tm",		"*ttyModes",	XrmoptionSepArg,	NULL),
1144f2e35a3aSmrgDATA("-tn",		"*termName",	XrmoptionSepArg,	NULL),
1145d522f475Smrg#if OPT_WIDE_CHARS
1146f2e35a3aSmrgDATA("-u8",		"*utf8",	XrmoptionNoArg,		"2"),
1147f2e35a3aSmrgDATA("+u8",		"*utf8",	XrmoptionNoArg,		"0"),
1148d522f475Smrg#endif
1149d522f475Smrg#if OPT_LUIT_PROG
1150f2e35a3aSmrgDATA("-lc",		"*locale",	XrmoptionNoArg,		"on"),
1151f2e35a3aSmrgDATA("+lc",		"*locale",	XrmoptionNoArg,		"off"),
1152f2e35a3aSmrgDATA("-lcc",		"*localeFilter",XrmoptionSepArg,	NULL),
1153f2e35a3aSmrgDATA("-en",		"*locale",	XrmoptionSepArg,	NULL),
1154f2e35a3aSmrg#endif
1155f2e35a3aSmrgDATA("-uc",		"*cursorUnderLine", XrmoptionNoArg,	"on"),
1156f2e35a3aSmrgDATA("+uc",		"*cursorUnderLine", XrmoptionNoArg,	"off"),
1157f2e35a3aSmrgDATA("-ulc",		"*colorULMode",	XrmoptionNoArg,		"off"),
1158f2e35a3aSmrgDATA("+ulc",		"*colorULMode",	XrmoptionNoArg,		"on"),
1159f2e35a3aSmrgDATA("-ulit",       	"*italicULMode", XrmoptionNoArg,        "off"),
1160f2e35a3aSmrgDATA("+ulit",       	"*italicULMode", XrmoptionNoArg,        "on"),
1161f2e35a3aSmrgDATA("-ut",		"*utmpInhibit",	XrmoptionNoArg,		"on"),
1162f2e35a3aSmrgDATA("+ut",		"*utmpInhibit",	XrmoptionNoArg,		"off"),
1163f2e35a3aSmrgDATA("-im",		"*useInsertMode", XrmoptionNoArg,	"on"),
1164f2e35a3aSmrgDATA("+im",		"*useInsertMode", XrmoptionNoArg,	"off"),
1165f2e35a3aSmrgDATA("-vb",		"*visualBell",	XrmoptionNoArg,		"on"),
1166f2e35a3aSmrgDATA("+vb",		"*visualBell",	XrmoptionNoArg,		"off"),
1167f2e35a3aSmrgDATA("-pob",		"*popOnBell",	XrmoptionNoArg,		"on"),
1168f2e35a3aSmrgDATA("+pob",		"*popOnBell",	XrmoptionNoArg,		"off"),
1169d522f475Smrg#if OPT_WIDE_CHARS
1170f2e35a3aSmrgDATA("-wc",		"*wideChars",	XrmoptionNoArg,		"on"),
1171f2e35a3aSmrgDATA("+wc",		"*wideChars",	XrmoptionNoArg,		"off"),
1172f2e35a3aSmrgDATA("-mk_width",	"*mkWidth",	XrmoptionNoArg,		"on"),
1173f2e35a3aSmrgDATA("+mk_width",	"*mkWidth",	XrmoptionNoArg,		"off"),
1174f2e35a3aSmrgDATA("-cjk_width",	"*cjkWidth",	XrmoptionNoArg,		"on"),
1175f2e35a3aSmrgDATA("+cjk_width",	"*cjkWidth",	XrmoptionNoArg,		"off"),
1176f2e35a3aSmrg#endif
1177f2e35a3aSmrgDATA("-wf",		"*waitForMap",	XrmoptionNoArg,		"on"),
1178f2e35a3aSmrgDATA("+wf",		"*waitForMap",	XrmoptionNoArg,		"off"),
1179d522f475Smrg#if OPT_ZICONBEEP
1180f2e35a3aSmrgDATA("-ziconbeep",	"*zIconBeep",	XrmoptionSepArg,	NULL),
1181d522f475Smrg#endif
1182d522f475Smrg#if OPT_SAME_NAME
1183f2e35a3aSmrgDATA("-samename",	"*sameName",	XrmoptionNoArg,		"on"),
1184f2e35a3aSmrgDATA("+samename",	"*sameName",	XrmoptionNoArg,		"off"),
1185d522f475Smrg#endif
1186d522f475Smrg#if OPT_SESSION_MGT
1187f2e35a3aSmrgDATA("-sm",		"*sessionMgt",	XrmoptionNoArg,		"on"),
1188f2e35a3aSmrgDATA("+sm",		"*sessionMgt",	XrmoptionNoArg,		"off"),
1189d522f475Smrg#endif
1190d522f475Smrg#if OPT_TOOLBAR
1191f2e35a3aSmrgDATA("-tb",		"*"XtNtoolBar,	XrmoptionNoArg,		"on"),
1192f2e35a3aSmrgDATA("+tb",		"*"XtNtoolBar,	XrmoptionNoArg,		"off"),
1193d522f475Smrg#endif
1194956cc18dSsnj#if OPT_MAXIMIZE
1195f2e35a3aSmrgDATA("-maximized",	"*maximized",	XrmoptionNoArg,		"on"),
1196f2e35a3aSmrgDATA("+maximized",	"*maximized",	XrmoptionNoArg,		"off"),
1197f2e35a3aSmrgDATA("-fullscreen",	"*fullscreen",	XrmoptionNoArg,		"on"),
1198f2e35a3aSmrgDATA("+fullscreen",	"*fullscreen",	XrmoptionNoArg,		"off"),
1199956cc18dSsnj#endif
1200d522f475Smrg/* options that we process ourselves */
1201f2e35a3aSmrgDATA("-help",		NULL,		XrmoptionSkipNArgs,	NULL),
1202f2e35a3aSmrgDATA("-version",	NULL,		XrmoptionSkipNArgs,	NULL),
1203f2e35a3aSmrgDATA("-baudrate",	NULL,		XrmoptionSkipArg,	NULL),
1204f2e35a3aSmrgDATA("-class",		NULL,		XrmoptionSkipArg,	NULL),
1205f2e35a3aSmrgDATA("-e",		NULL,		XrmoptionSkipLine,	NULL),
1206f2e35a3aSmrgDATA("-into",		NULL,		XrmoptionSkipArg,	NULL),
1207d522f475Smrg/* bogus old compatibility stuff for which there are
1208d522f475Smrg   standard XtOpenApplication options now */
1209f2e35a3aSmrgDATA("%",		"*tekGeometry",	XrmoptionStickyArg,	NULL),
1210f2e35a3aSmrgDATA("#",		".iconGeometry",XrmoptionStickyArg,	NULL),
1211f2e35a3aSmrgDATA("-T",		".title",	XrmoptionSepArg,	NULL),
1212f2e35a3aSmrgDATA("-n",		"*iconName",	XrmoptionSepArg,	NULL),
1213f2e35a3aSmrgDATA("-r",		"*reverseVideo",XrmoptionNoArg,		"on"),
1214f2e35a3aSmrgDATA("+r",		"*reverseVideo",XrmoptionNoArg,		"off"),
1215f2e35a3aSmrgDATA("-rv",		"*reverseVideo",XrmoptionNoArg,		"on"),
1216f2e35a3aSmrgDATA("+rv",		"*reverseVideo",XrmoptionNoArg,		"off"),
1217f2e35a3aSmrgDATA("-w",		".borderWidth", XrmoptionSepArg,	NULL),
1218f2e35a3aSmrg#undef DATA
1219d522f475Smrg};
1220d522f475Smrg
1221d522f475Smrgstatic OptionHelp xtermOptions[] = {
1222d522f475Smrg{ "-version",              "print the version number" },
1223d522f475Smrg{ "-help",                 "print out this message" },
1224d522f475Smrg{ "-display displayname",  "X server to contact" },
1225d522f475Smrg{ "-geometry geom",        "size (in characters) and position" },
1226d522f475Smrg{ "-/+rv",                 "turn on/off reverse video" },
1227d522f475Smrg{ "-bg color",             "background color" },
1228d522f475Smrg{ "-fg color",             "foreground color" },
1229d522f475Smrg{ "-bd color",             "border color" },
1230d522f475Smrg{ "-bw number",            "border width in pixels" },
1231d522f475Smrg{ "-fn fontname",          "normal text font" },
1232d522f475Smrg{ "-fb fontname",          "bold text font" },
1233f2e35a3aSmrg{ "-fc fontmenu",          "start with named fontmenu choice" },
1234d522f475Smrg{ "-/+fbb",                "turn on/off normal/bold font comparison inhibit"},
1235d522f475Smrg{ "-/+fbx",                "turn off/on linedrawing characters"},
1236d522f475Smrg#if OPT_RENDERFONT
1237d522f475Smrg{ "-fa pattern",           "FreeType font-selection pattern" },
1238d522f475Smrg{ "-fd pattern",           "FreeType Doublesize font-selection pattern" },
1239d522f475Smrg{ "-fs size",              "FreeType font-size" },
1240d522f475Smrg#endif
1241d522f475Smrg#if OPT_WIDE_CHARS
1242d522f475Smrg{ "-fw fontname",          "doublewidth text font" },
1243d522f475Smrg{ "-fwb fontname",         "doublewidth bold text font" },
1244d522f475Smrg#endif
1245d522f475Smrg#if OPT_INPUT_METHOD
1246d522f475Smrg{ "-fx fontname",          "XIM fontset" },
1247d522f475Smrg#endif
1248d522f475Smrg{ "-iconic",               "start iconic" },
1249d522f475Smrg{ "-name string",          "client instance, icon, and title strings" },
12502e4f8982Smrg{ "-baudrate rate",        "set line-speed (default 38400)" },
1251d522f475Smrg{ "-class string",         "class string (XTerm)" },
1252d522f475Smrg{ "-title string",         "title string" },
1253d522f475Smrg{ "-xrm resourcestring",   "additional resource specifications" },
1254d522f475Smrg{ "-/+132",                "turn on/off 80/132 column switching" },
1255d522f475Smrg{ "-/+ah",                 "turn on/off always highlight" },
1256d522f475Smrg#ifndef NO_ACTIVE_ICON
1257d522f475Smrg{ "-/+ai",                 "turn off/on active icon" },
1258d522f475Smrg{ "-fi fontname",          "icon font for active icon" },
1259d522f475Smrg#endif /* NO_ACTIVE_ICON */
1260d522f475Smrg{ "-b number",             "internal border in pixels" },
1261d522f475Smrg{ "-/+bc",                 "turn on/off text cursor blinking" },
1262d522f475Smrg{ "-bcf milliseconds",     "time text cursor is off when blinking"},
1263d522f475Smrg{ "-bcn milliseconds",     "time text cursor is on when blinking"},
1264d522f475Smrg{ "-/+bdc",                "turn off/on display of bold as color"},
1265d522f475Smrg{ "-/+cb",                 "turn on/off cut-to-beginning-of-line inhibit" },
1266d522f475Smrg{ "-cc classrange",        "specify additional character classes" },
1267d522f475Smrg{ "-/+cm",                 "turn off/on ANSI color mode" },
1268d522f475Smrg{ "-/+cn",                 "turn on/off cut newline inhibit" },
1269f2e35a3aSmrg{ "-pf fontname",          "cursor font for text area pointer" },
1270d522f475Smrg{ "-cr color",             "text cursor color" },
1271d522f475Smrg{ "-/+cu",                 "turn on/off curses emulation" },
1272d522f475Smrg{ "-/+dc",                 "turn off/on dynamic color selection" },
1273d522f475Smrg#if OPT_HIGHLIGHT_COLOR
1274d522f475Smrg{ "-/+hm",                 "turn on/off selection-color override" },
1275d522f475Smrg{ "-selbg color",          "selection background color" },
1276d522f475Smrg{ "-selfg color",          "selection foreground color" },
12770bd37d32Smrg/* -hc is deprecated, not shown in help message */
1278d522f475Smrg#endif
1279d522f475Smrg#if OPT_HP_FUNC_KEYS
1280d522f475Smrg{ "-/+hf",                 "turn on/off HP Function Key escape codes" },
1281d522f475Smrg#endif
1282d522f475Smrg{ "-/+hold",               "turn on/off logic that retains window after exit" },
1283d522f475Smrg#if OPT_INITIAL_ERASE
1284d522f475Smrg{ "-/+ie",                 "turn on/off initialization of 'erase' from pty" },
1285d522f475Smrg#endif
1286d522f475Smrg{ "-/+im",                 "use insert mode for TERMCAP" },
1287d522f475Smrg{ "-/+j",                  "turn on/off jump scroll" },
1288d522f475Smrg#if OPT_C1_PRINT
1289d522f475Smrg{ "-/+k8",                 "turn on/off C1-printable classification"},
1290d522f475Smrg#endif
1291d522f475Smrg{ "-kt keyboardtype",      "set keyboard type:" KEYBOARD_TYPES },
1292d522f475Smrg#ifdef ALLOWLOGGING
1293d522f475Smrg{ "-/+l",                  "turn on/off logging" },
1294f2e35a3aSmrg{ "-lf filename",          "logging filename (use '-' for standard out)" },
1295d522f475Smrg#else
1296d522f475Smrg{ "-/+l",                  "turn on/off logging (not supported)" },
1297d522f475Smrg{ "-lf filename",          "logging filename (not supported)" },
1298d522f475Smrg#endif
1299d522f475Smrg{ "-/+ls",                 "turn on/off login shell" },
1300d522f475Smrg{ "-/+mb",                 "turn on/off margin bell" },
1301d522f475Smrg{ "-mc milliseconds",      "multiclick time in milliseconds" },
1302d522f475Smrg{ "-/+mesg",               "forbid/allow messages" },
1303d522f475Smrg{ "-ms color",             "pointer color" },
1304d522f475Smrg{ "-nb number",            "margin bell in characters from right end" },
1305d522f475Smrg{ "-/+nul",                "turn off/on display of underlining" },
1306d522f475Smrg{ "-/+aw",                 "turn on/off auto wraparound" },
1307d522f475Smrg{ "-/+pc",                 "turn on/off PC-style bold colors" },
1308d522f475Smrg{ "-/+rw",                 "turn on/off reverse wraparound" },
1309d522f475Smrg{ "-/+s",                  "turn on/off multiscroll" },
1310d522f475Smrg{ "-/+sb",                 "turn on/off scrollbar" },
1311913cc679Smrg#if OPT_REPORT_CCLASS
1312913cc679Smrg{"-report-charclass",      "report \"charClass\" after initialization"},
1313913cc679Smrg#endif
1314e0a2b6dfSmrg#if OPT_REPORT_COLORS
1315e0a2b6dfSmrg{ "-report-colors",        "report colors as they are allocated" },
1316e0a2b6dfSmrg#endif
1317e0a2b6dfSmrg#if OPT_REPORT_FONTS
1318e0a2b6dfSmrg{ "-report-fonts",         "report fonts as loaded to stdout" },
1319e0a2b6dfSmrg#endif
1320f2e35a3aSmrg#if OPT_REPORT_ICONS
1321f2e35a3aSmrg{ "-report-icons",	   "report title/icon updates" },
1322f2e35a3aSmrg#endif
1323f2e35a3aSmrg#if OPT_XRES_QUERY
1324f2e35a3aSmrg{ "-report-xres",          "report X resources for VT100 widget" },
1325f2e35a3aSmrg#endif
1326d522f475Smrg#ifdef SCROLLBAR_RIGHT
1327d522f475Smrg{ "-rightbar",             "force scrollbar right (default left)" },
1328d522f475Smrg{ "-leftbar",              "force scrollbar left" },
1329d522f475Smrg#endif
1330d522f475Smrg{ "-/+rvc",                "turn off/on display of reverse as color" },
1331d522f475Smrg{ "-/+sf",                 "turn on/off Sun Function Key escape codes" },
1332894e0ac8Smrg{ "-sh number",            "scale line-height values by the given number" },
1333d522f475Smrg{ "-/+si",                 "turn on/off scroll-on-tty-output inhibit" },
1334d522f475Smrg{ "-/+sk",                 "turn on/off scroll-on-keypress" },
1335d522f475Smrg{ "-sl number",            "number of scrolled lines to save" },
1336d522f475Smrg#if OPT_SUNPC_KBD
1337d522f475Smrg{ "-/+sp",                 "turn on/off Sun/PC Function/Keypad mapping" },
1338d522f475Smrg#endif
1339d522f475Smrg#if OPT_TEK4014
1340d522f475Smrg{ "-/+t",                  "turn on/off Tek emulation window" },
1341d522f475Smrg#endif
1342d522f475Smrg#if OPT_TOOLBAR
1343d522f475Smrg{ "-/+tb",                 "turn on/off toolbar" },
1344d522f475Smrg#endif
1345d522f475Smrg{ "-ti termid",            "terminal identifier" },
1346d522f475Smrg{ "-tm string",            "terminal mode keywords and characters" },
1347d522f475Smrg{ "-tn name",              "TERM environment variable name" },
1348d522f475Smrg#if OPT_WIDE_CHARS
1349d522f475Smrg{ "-/+u8",                 "turn on/off UTF-8 mode (implies wide-characters)" },
1350d522f475Smrg#endif
1351d522f475Smrg#if OPT_LUIT_PROG
1352d522f475Smrg{ "-/+lc",                 "turn on/off locale mode using luit" },
1353d522f475Smrg{ "-lcc path",             "filename of locale converter (" DEFLOCALEFILTER ")" },
13540bd37d32Smrg/* -en is deprecated, not shown in help message */
1355d522f475Smrg#endif
13562eaa94a1Schristos{ "-/+uc",                 "turn on/off underline cursor" },
1357d522f475Smrg{ "-/+ulc",                "turn off/on display of underline as color" },
1358d522f475Smrg{ "-/+ulit",               "turn off/on display of underline as italics" },
1359d522f475Smrg#ifdef HAVE_UTMP
1360d522f475Smrg{ "-/+ut",                 "turn on/off utmp support" },
1361d522f475Smrg#else
1362d522f475Smrg{ "-/+ut",                 "turn on/off utmp support (not available)" },
1363d522f475Smrg#endif
1364d522f475Smrg{ "-/+vb",                 "turn on/off visual bell" },
1365d522f475Smrg{ "-/+pob",                "turn on/off pop on bell" },
136601037d57Smrg#if OPT_WIDE_ATTRS && OPT_ISO_COLORS
136701037d57Smrg{ "-/+itc",                "turn off/on display of italic as color"},
136801037d57Smrg#endif
1369d522f475Smrg#if OPT_WIDE_CHARS
1370d522f475Smrg{ "-/+wc",                 "turn on/off wide-character mode" },
1371d522f475Smrg{ "-/+mk_width",           "turn on/off simple width convention" },
1372d522f475Smrg{ "-/+cjk_width",          "turn on/off legacy CJK width convention" },
1373d522f475Smrg#endif
1374d522f475Smrg{ "-/+wf",                 "turn on/off wait for map before command exec" },
1375d522f475Smrg{ "-e command args ...",   "command to execute" },
1376d522f475Smrg#if OPT_TEK4014
1377d522f475Smrg{ "%geom",                 "Tek window geometry" },
1378d522f475Smrg#endif
1379d522f475Smrg{ "#geom",                 "icon window geometry" },
1380d522f475Smrg{ "-T string",             "title name for window" },
1381d522f475Smrg{ "-n string",             "icon name for window" },
1382d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1383d522f475Smrg{ "-C",                    "intercept console messages" },
1384d522f475Smrg#else
1385d522f475Smrg{ "-C",                    "intercept console messages (not supported)" },
1386d522f475Smrg#endif
1387d522f475Smrg{ "-Sccn",                 "slave mode on \"ttycc\", file descriptor \"n\"" },
1388d522f475Smrg{ "-into windowId",        "use the window id given to -into as the parent window rather than the default root window" },
1389d522f475Smrg#if OPT_ZICONBEEP
1390d522f475Smrg{ "-ziconbeep percent",    "beep and flag icon of window having hidden output" },
1391d522f475Smrg#endif
1392d522f475Smrg#if OPT_SAME_NAME
1393d522f475Smrg{ "-/+samename",           "turn on/off the no-flicker option for title and icon name" },
1394d522f475Smrg#endif
1395d522f475Smrg#if OPT_SESSION_MGT
1396d522f475Smrg{ "-/+sm",                 "turn on/off the session-management support" },
1397d522f475Smrg#endif
1398956cc18dSsnj#if OPT_MAXIMIZE
1399ad37e533Smrg{"-/+maximized",           "turn on/off maximize on startup" },
1400a1f3da82Smrg{"-/+fullscreen",          "turn on/off fullscreen on startup" },
1401956cc18dSsnj#endif
1402d522f475Smrg{ NULL, NULL }};
1403d522f475Smrg/* *INDENT-ON* */
1404d522f475Smrg
140501037d57Smrgstatic const char *const message[] =
1406d522f475Smrg{
1407d522f475Smrg    "Fonts should be fixed width and, if both normal and bold are specified, should",
1408d522f475Smrg    "have the same size.  If only a normal font is specified, it will be used for",
1409d522f475Smrg    "both normal and bold text (by doing overstriking).  The -e option, if given,",
1410d522f475Smrg    "must appear at the end of the command line, otherwise the user's default shell",
1411d522f475Smrg    "will be started.  Options that start with a plus sign (+) restore the default.",
1412d522f475Smrg    NULL};
1413d522f475Smrg
1414d522f475Smrg/*
1415d522f475Smrg * Decode a key-definition.  This combines the termcap and ttyModes, for
1416d522f475Smrg * comparison.  Note that octal escapes in ttyModes are done by the normal
1417d522f475Smrg * resource translation.  Also, ttyModes allows '^-' as a synonym for disabled.
1418d522f475Smrg */
1419d522f475Smrgstatic int
1420d522f475Smrgdecode_keyvalue(char **ptr, int termcap)
1421d522f475Smrg{
1422d522f475Smrg    char *string = *ptr;
1423d522f475Smrg    int value = -1;
1424d522f475Smrg
142520d2c4d2Smrg    TRACE(("decode_keyvalue '%s'\n", string));
1426d522f475Smrg    if (*string == '^') {
1427d522f475Smrg	switch (*++string) {
1428d522f475Smrg	case '?':
1429d522f475Smrg	    value = A2E(ANSI_DEL);
1430d522f475Smrg	    break;
1431d522f475Smrg	case '-':
1432d522f475Smrg	    if (!termcap) {
1433d522f475Smrg		errno = 0;
1434d522f475Smrg#if defined(_POSIX_VDISABLE) && defined(HAVE_UNISTD_H)
1435d522f475Smrg		value = _POSIX_VDISABLE;
1436d522f475Smrg#endif
1437d522f475Smrg#if defined(_PC_VDISABLE)
1438d522f475Smrg		if (value == -1) {
143920d2c4d2Smrg		    value = (int) fpathconf(0, _PC_VDISABLE);
1440d522f475Smrg		    if (value == -1) {
1441d522f475Smrg			if (errno != 0)
1442d522f475Smrg			    break;	/* skip this (error) */
1443d522f475Smrg			value = 0377;
1444d522f475Smrg		    }
1445d522f475Smrg		}
1446d522f475Smrg#elif defined(VDISABLE)
1447d522f475Smrg		if (value == -1)
1448d522f475Smrg		    value = VDISABLE;
1449d522f475Smrg#endif
1450d522f475Smrg		break;
1451d522f475Smrg	    }
1452d522f475Smrg	    /* FALLTHRU */
1453d522f475Smrg	default:
1454d522f475Smrg	    value = CONTROL(*string);
1455d522f475Smrg	    break;
1456d522f475Smrg	}
1457d522f475Smrg	++string;
1458d522f475Smrg    } else if (termcap && (*string == '\\')) {
14592e4f8982Smrg	char *s = (string + 1);
1460d522f475Smrg	char *d;
14612e4f8982Smrg	int temp = (int) strtol(s, &d, 8);
14622e4f8982Smrg	if (PartS2L(s, d) && temp > 0) {
1463d522f475Smrg	    value = temp;
1464d522f475Smrg	    string = d;
1465d522f475Smrg	}
1466d522f475Smrg    } else {
1467d522f475Smrg	value = CharOf(*string);
1468d522f475Smrg	++string;
1469d522f475Smrg    }
1470d522f475Smrg    *ptr = string;
147120d2c4d2Smrg    TRACE(("...decode_keyvalue %#x\n", value));
1472d522f475Smrg    return value;
1473d522f475Smrg}
1474d522f475Smrg
1475d522f475Smrgstatic int
14760bd37d32SmrgmatchArg(XrmOptionDescRec * table, const char *param)
14770bd37d32Smrg{
14780bd37d32Smrg    int result = -1;
14790bd37d32Smrg    int n;
14800bd37d32Smrg    int ch;
14810bd37d32Smrg
14820bd37d32Smrg    for (n = 0; (ch = table->option[n]) != '\0'; ++n) {
14830bd37d32Smrg	if (param[n] == ch) {
14840bd37d32Smrg	    result = n;
14850bd37d32Smrg	} else {
14860bd37d32Smrg	    if (param[n] != '\0')
14870bd37d32Smrg		result = -1;
14880bd37d32Smrg	    break;
14890bd37d32Smrg	}
14900bd37d32Smrg    }
14910bd37d32Smrg
14920bd37d32Smrg    return result;
14930bd37d32Smrg}
14940bd37d32Smrg
14950bd37d32Smrg/* return the number of argv[] entries which constitute arguments of option */
14960bd37d32Smrgstatic int
14970bd37d32SmrgcountArg(XrmOptionDescRec * item)
1498d522f475Smrg{
14990bd37d32Smrg    int result = 0;
15000bd37d32Smrg
15010bd37d32Smrg    switch (item->argKind) {
15020bd37d32Smrg    case XrmoptionNoArg:
15030bd37d32Smrg	/* FALLTHRU */
15040bd37d32Smrg    case XrmoptionIsArg:
15050bd37d32Smrg	/* FALLTHRU */
15060bd37d32Smrg    case XrmoptionStickyArg:
15070bd37d32Smrg	break;
15080bd37d32Smrg    case XrmoptionSepArg:
15090bd37d32Smrg	/* FALLTHRU */
15100bd37d32Smrg    case XrmoptionResArg:
15110bd37d32Smrg	/* FALLTHRU */
15120bd37d32Smrg    case XrmoptionSkipArg:
15130bd37d32Smrg	result = 1;
15140bd37d32Smrg	break;
15150bd37d32Smrg    case XrmoptionSkipLine:
15160bd37d32Smrg	break;
15170bd37d32Smrg    case XrmoptionSkipNArgs:
15180bd37d32Smrg	result = (int) (long) (item->value);
15190bd37d32Smrg	break;
15200bd37d32Smrg    }
15210bd37d32Smrg    return result;
15220bd37d32Smrg}
15230bd37d32Smrg
15240bd37d32Smrg#define isOption(string) (Boolean)((string)[0] == '-' || (string)[0] == '+')
15250bd37d32Smrg
15260bd37d32Smrg/*
15270bd37d32Smrg * Parse the argument list, more/less as XtInitialize, etc., would do, so we
15280bd37d32Smrg * can find our own "-help" and "-version" options reliably.  Improve on just
15290bd37d32Smrg * doing that, by detecting ambiguous options (things that happen to match the
15300bd37d32Smrg * abbreviated option we are examining), and making it smart enough to handle
15310bd37d32Smrg * "-d" as an abbreviation for "-display".  Doing this requires checking the
15320bd37d32Smrg * standard table (something that the X libraries should do).
15330bd37d32Smrg */
15340bd37d32Smrgstatic XrmOptionDescRec *
15350bd37d32SmrgparseArg(int *num, char **argv, char **valuep)
15360bd37d32Smrg{
15370bd37d32Smrg    /* table adapted from XtInitialize, used here to improve abbreviations */
15380bd37d32Smrg    /* *INDENT-OFF* */
1539f2e35a3aSmrg#define DATA(option,kind) { (char *) option, NULL, kind, (XtPointer) NULL }
15400bd37d32Smrg    static XrmOptionDescRec opTable[] = {
15410bd37d32Smrg	DATA("+synchronous",	   XrmoptionNoArg),
15420bd37d32Smrg	DATA("-background",	   XrmoptionSepArg),
15430bd37d32Smrg	DATA("-bd",		   XrmoptionSepArg),
15440bd37d32Smrg	DATA("-bg",		   XrmoptionSepArg),
15450bd37d32Smrg	DATA("-bordercolor",	   XrmoptionSepArg),
15460bd37d32Smrg	DATA("-borderwidth",	   XrmoptionSepArg),
15470bd37d32Smrg	DATA("-bw",		   XrmoptionSepArg),
15480bd37d32Smrg	DATA("-display",	   XrmoptionSepArg),
15490bd37d32Smrg	DATA("-fg",		   XrmoptionSepArg),
15500bd37d32Smrg	DATA("-fn",		   XrmoptionSepArg),
15510bd37d32Smrg	DATA("-font",		   XrmoptionSepArg),
15520bd37d32Smrg	DATA("-foreground",	   XrmoptionSepArg),
15530bd37d32Smrg	DATA("-iconic",		   XrmoptionNoArg),
15540bd37d32Smrg	DATA("-name",		   XrmoptionSepArg),
15550bd37d32Smrg	DATA("-reverse",	   XrmoptionNoArg),
15560bd37d32Smrg	DATA("-selectionTimeout",  XrmoptionSepArg),
15570bd37d32Smrg	DATA("-synchronous",	   XrmoptionNoArg),
15580bd37d32Smrg	DATA("-title",		   XrmoptionSepArg),
15590bd37d32Smrg	DATA("-xnllanguage",	   XrmoptionSepArg),
15600bd37d32Smrg	DATA("-xrm",		   XrmoptionResArg),
15610bd37d32Smrg	DATA("-xtsessionID",	   XrmoptionSepArg),
15620bd37d32Smrg	/* These xterm options are processed after XtOpenApplication */
15630bd37d32Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
15640bd37d32Smrg	DATA("-C",		   XrmoptionNoArg),
15650bd37d32Smrg#endif /* TIOCCONS */
15660bd37d32Smrg	DATA("-S",		   XrmoptionStickyArg),
15670bd37d32Smrg	DATA("-D",		   XrmoptionNoArg),
15680bd37d32Smrg    };
15690bd37d32Smrg#undef DATA
15700bd37d32Smrg    /* *INDENT-ON* */
15710bd37d32Smrg    XrmOptionDescRec *result = 0;
15720bd37d32Smrg    Cardinal inlist;
15730bd37d32Smrg    Cardinal limit = XtNumber(optionDescList) + XtNumber(opTable);
15740bd37d32Smrg    int atbest = -1;
15750bd37d32Smrg    int best = -1;
15760bd37d32Smrg    int test;
15770bd37d32Smrg    Boolean exact = False;
15780bd37d32Smrg    int ambiguous1 = -1;
15790bd37d32Smrg    int ambiguous2 = -1;
15800bd37d32Smrg    char *option;
15810bd37d32Smrg    char *value;
15820bd37d32Smrg
15830bd37d32Smrg#define ITEM(n) ((Cardinal)(n) < XtNumber(optionDescList) \
15840bd37d32Smrg		 ? &optionDescList[n] \
15850bd37d32Smrg		 : &opTable[(Cardinal)(n) - XtNumber(optionDescList)])
15860bd37d32Smrg
15870bd37d32Smrg    if ((option = argv[*num]) != 0) {
15880bd37d32Smrg	Boolean need_value;
15890bd37d32Smrg	Boolean have_value = False;
15900bd37d32Smrg
15910bd37d32Smrg	TRACE(("parseArg %s\n", option));
15920bd37d32Smrg	if ((value = argv[(*num) + 1]) != 0) {
1593e0a2b6dfSmrg	    have_value = (Boolean) !isOption(value);
15940bd37d32Smrg	}
15950bd37d32Smrg	for (inlist = 0; inlist < limit; ++inlist) {
15960bd37d32Smrg	    XrmOptionDescRec *check = ITEM(inlist);
15970bd37d32Smrg
15980bd37d32Smrg	    test = matchArg(check, option);
15990bd37d32Smrg	    if (test < 0)
16000bd37d32Smrg		continue;
16010bd37d32Smrg
16020bd37d32Smrg	    /* check for exact match */
16030bd37d32Smrg	    if ((test + 1) == (int) strlen(check->option)) {
16040bd37d32Smrg		if (check->argKind == XrmoptionStickyArg) {
16050bd37d32Smrg		    if (strlen(option) > strlen(check->option)) {
16060bd37d32Smrg			exact = True;
16070bd37d32Smrg			atbest = (int) inlist;
16080bd37d32Smrg			break;
16090bd37d32Smrg		    }
16100bd37d32Smrg		} else if ((test + 1) == (int) strlen(option)) {
16110bd37d32Smrg		    exact = True;
16120bd37d32Smrg		    atbest = (int) inlist;
16130bd37d32Smrg		    break;
16140bd37d32Smrg		}
16150bd37d32Smrg	    }
16160bd37d32Smrg
16170bd37d32Smrg	    need_value = (Boolean) (test > 0 && countArg(check) > 0);
16180bd37d32Smrg
16190bd37d32Smrg	    if (need_value && value != 0) {
16200bd37d32Smrg		;
16210bd37d32Smrg	    } else if (need_value ^ have_value) {
16220bd37d32Smrg		TRACE(("...skipping, need %d vs have %d\n", need_value, have_value));
16230bd37d32Smrg		continue;
16240bd37d32Smrg	    }
16250bd37d32Smrg
16260bd37d32Smrg	    /* special-case for our own options - always allow abbreviation */
16270bd37d32Smrg	    if (test > 0
16280bd37d32Smrg		&& ITEM(inlist)->argKind >= XrmoptionSkipArg) {
16290bd37d32Smrg		atbest = (int) inlist;
1630e0a2b6dfSmrg		if (ITEM(inlist)->argKind == XrmoptionSkipNArgs) {
1631e0a2b6dfSmrg		    /* in particular, silence a warning about ambiguity */
1632e0a2b6dfSmrg		    exact = 1;
1633e0a2b6dfSmrg		}
16340bd37d32Smrg		break;
16350bd37d32Smrg	    }
16360bd37d32Smrg	    if (test > best) {
16370bd37d32Smrg		best = test;
16380bd37d32Smrg		atbest = (int) inlist;
16390bd37d32Smrg	    } else if (test == best) {
16400bd37d32Smrg		if (atbest >= 0) {
16410bd37d32Smrg		    if (atbest > 0) {
16420bd37d32Smrg			ambiguous1 = (int) inlist;
16430bd37d32Smrg			ambiguous2 = (int) atbest;
16440bd37d32Smrg		    }
16450bd37d32Smrg		    atbest = -1;
16460bd37d32Smrg		}
16470bd37d32Smrg	    }
16480bd37d32Smrg	}
16490bd37d32Smrg    }
16500bd37d32Smrg
16510bd37d32Smrg    *valuep = 0;
16520bd37d32Smrg    if (atbest >= 0) {
16530bd37d32Smrg	result = ITEM(atbest);
16540bd37d32Smrg	if (!exact) {
16550bd37d32Smrg	    if (ambiguous1 >= 0 && ambiguous2 >= 0) {
16560bd37d32Smrg		xtermWarning("ambiguous option \"%s\" vs \"%s\"\n",
16570bd37d32Smrg			     ITEM(ambiguous1)->option,
16580bd37d32Smrg			     ITEM(ambiguous2)->option);
16590bd37d32Smrg	    } else if (strlen(option) > strlen(result->option)) {
16600bd37d32Smrg		result = 0;
16610bd37d32Smrg	    }
16620bd37d32Smrg	}
16630bd37d32Smrg	if (result != 0) {
16640bd37d32Smrg	    TRACE(("...result %s\n", result->option));
16650bd37d32Smrg	    /* expand abbreviations */
16660bd37d32Smrg	    if (result->argKind != XrmoptionStickyArg) {
16670bd37d32Smrg		if (strcmp(argv[*num], result->option)) {
16680bd37d32Smrg		    argv[*num] = x_strdup(result->option);
16690bd37d32Smrg		}
16700bd37d32Smrg	    }
16710bd37d32Smrg
16720bd37d32Smrg	    /* adjust (*num) to skip option value */
16730bd37d32Smrg	    (*num) += countArg(result);
16740bd37d32Smrg	    TRACE(("...next %s\n", NonNull(argv[*num])));
16750bd37d32Smrg	    if (result->argKind == XrmoptionSkipArg) {
16760bd37d32Smrg		*valuep = argv[*num];
16770bd37d32Smrg		TRACE(("...parameter %s\n", NonNull(*valuep)));
16780bd37d32Smrg	    }
16790bd37d32Smrg	}
16800bd37d32Smrg    }
16810bd37d32Smrg#undef ITEM
16820bd37d32Smrg    return result;
1683d522f475Smrg}
1684d522f475Smrg
1685d522f475Smrgstatic void
1686d522f475SmrgSyntax(char *badOption)
1687d522f475Smrg{
1688d522f475Smrg    OptionHelp *opt;
1689d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
1690d522f475Smrg    int col;
1691d522f475Smrg
16920bd37d32Smrg    TRACE(("Syntax error at %s\n", badOption));
16930bd37d32Smrg    xtermWarning("bad command line option \"%s\"\r\n\n", badOption);
1694d522f475Smrg
1695d522f475Smrg    fprintf(stderr, "usage:  %s", ProgramName);
1696956cc18dSsnj    col = 8 + (int) strlen(ProgramName);
1697d522f475Smrg    for (opt = list; opt->opt; opt++) {
1698956cc18dSsnj	int len = 3 + (int) strlen(opt->opt);	/* space [ string ] */
1699d522f475Smrg	if (col + len > 79) {
1700d522f475Smrg	    fprintf(stderr, "\r\n   ");		/* 3 spaces */
1701d522f475Smrg	    col = 3;
1702d522f475Smrg	}
1703d522f475Smrg	fprintf(stderr, " [%s]", opt->opt);
1704d522f475Smrg	col += len;
1705d522f475Smrg    }
1706d522f475Smrg
1707d522f475Smrg    fprintf(stderr, "\r\n\nType %s -help for a full description.\r\n\n",
1708d522f475Smrg	    ProgramName);
1709d522f475Smrg    exit(1);
1710d522f475Smrg}
1711d522f475Smrg
1712d522f475Smrgstatic void
1713d522f475SmrgVersion(void)
1714d522f475Smrg{
1715d522f475Smrg    printf("%s\n", xtermVersion());
1716d522f475Smrg    fflush(stdout);
1717d522f475Smrg}
1718d522f475Smrg
1719d522f475Smrgstatic void
1720d522f475SmrgHelp(void)
1721d522f475Smrg{
1722d522f475Smrg    OptionHelp *opt;
1723d522f475Smrg    OptionHelp *list = sortedOpts(xtermOptions, optionDescList, XtNumber(optionDescList));
172401037d57Smrg    const char *const *cpp;
1725d522f475Smrg
1726d522f475Smrg    printf("%s usage:\n    %s [-options ...] [-e command args]\n\n",
1727d522f475Smrg	   xtermVersion(), ProgramName);
1728d522f475Smrg    printf("where options include:\n");
1729d522f475Smrg    for (opt = list; opt->opt; opt++) {
1730d522f475Smrg	printf("    %-28s %s\n", opt->opt, opt->desc);
1731d522f475Smrg    }
1732d522f475Smrg
1733d522f475Smrg    putchar('\n');
1734d522f475Smrg    for (cpp = message; *cpp; cpp++)
1735d522f475Smrg	puts(*cpp);
1736d522f475Smrg    putchar('\n');
1737d522f475Smrg    fflush(stdout);
1738d522f475Smrg}
1739d522f475Smrg
1740f2e35a3aSmrgstatic void
1741f2e35a3aSmrgNeedParam(XrmOptionDescRec * option_ptr, const char *option_val)
1742f2e35a3aSmrg{
1743f2e35a3aSmrg    if (IsEmpty(option_val)) {
1744f2e35a3aSmrg	xtermWarning("option %s requires a value\n", option_ptr->option);
1745f2e35a3aSmrg	exit(1);
1746f2e35a3aSmrg    }
1747f2e35a3aSmrg}
1748f2e35a3aSmrg
1749d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
1750d522f475Smrg/* ARGSUSED */
1751d522f475Smrgstatic Boolean
1752d522f475SmrgConvertConsoleSelection(Widget w GCC_UNUSED,
1753894e0ac8Smrg			Atom *selection GCC_UNUSED,
1754894e0ac8Smrg			Atom *target GCC_UNUSED,
1755894e0ac8Smrg			Atom *type GCC_UNUSED,
1756d522f475Smrg			XtPointer *value GCC_UNUSED,
1757d522f475Smrg			unsigned long *length GCC_UNUSED,
1758d522f475Smrg			int *format GCC_UNUSED)
1759d522f475Smrg{
1760d522f475Smrg    /* we don't save console output, so can't offer it */
1761d522f475Smrg    return False;
1762d522f475Smrg}
1763d522f475Smrg#endif /* TIOCCONS */
1764d522f475Smrg
1765d522f475Smrg/*
1766d522f475Smrg * DeleteWindow(): Action proc to implement ICCCM delete_window.
1767d522f475Smrg */
1768d522f475Smrg/* ARGSUSED */
1769d522f475Smrgstatic void
1770d522f475SmrgDeleteWindow(Widget w,
1771894e0ac8Smrg	     XEvent *event GCC_UNUSED,
1772e0a2b6dfSmrg	     String *params GCC_UNUSED,
1773d522f475Smrg	     Cardinal *num_params GCC_UNUSED)
1774d522f475Smrg{
1775d522f475Smrg#if OPT_TEK4014
1776d522f475Smrg    if (w == toplevel) {
1777d522f475Smrg	if (TEK4014_SHOWN(term))
1778d522f475Smrg	    hide_vt_window();
1779d522f475Smrg	else
1780d522f475Smrg	    do_hangup(w, (XtPointer) 0, (XtPointer) 0);
178120d2c4d2Smrg    } else if (TScreenOf(term)->Vshow)
1782d522f475Smrg	hide_tek_window();
1783d522f475Smrg    else
1784d522f475Smrg#endif
1785d522f475Smrg	do_hangup(w, (XtPointer) 0, (XtPointer) 0);
1786d522f475Smrg}
1787d522f475Smrg
1788d522f475Smrg/* ARGSUSED */
1789d522f475Smrgstatic void
1790d522f475SmrgKeyboardMapping(Widget w GCC_UNUSED,
1791894e0ac8Smrg		XEvent *event,
1792e0a2b6dfSmrg		String *params GCC_UNUSED,
1793d522f475Smrg		Cardinal *num_params GCC_UNUSED)
1794d522f475Smrg{
1795d522f475Smrg    switch (event->type) {
1796d522f475Smrg    case MappingNotify:
1797d522f475Smrg	XRefreshKeyboardMapping(&event->xmapping);
1798d522f475Smrg	break;
1799d522f475Smrg    }
1800d522f475Smrg}
1801d522f475Smrg
1802d522f475Smrgstatic XtActionsRec actionProcs[] =
1803d522f475Smrg{
1804d522f475Smrg    {"DeleteWindow", DeleteWindow},
1805d522f475Smrg    {"KeyboardMapping", KeyboardMapping},
1806d522f475Smrg};
1807d522f475Smrg
1808d522f475Smrg/*
1809d522f475Smrg * Some platforms use names such as /dev/tty01, others /dev/pts/1.  Parse off
1810d522f475Smrg * the "tty01" or "pts/1" portion, and return that for use as an identifier for
1811d522f475Smrg * utmp.
1812d522f475Smrg */
1813d522f475Smrgstatic char *
1814d522f475Smrgmy_pty_name(char *device)
1815d522f475Smrg{
1816d522f475Smrg    size_t len = strlen(device);
1817d522f475Smrg    Bool name = False;
1818d522f475Smrg
1819d522f475Smrg    while (len != 0) {
1820d522f475Smrg	int ch = device[len - 1];
1821d522f475Smrg	if (isdigit(ch)) {
1822d522f475Smrg	    len--;
1823d522f475Smrg	} else if (ch == '/') {
1824d522f475Smrg	    if (name)
1825d522f475Smrg		break;
1826d522f475Smrg	    len--;
1827d522f475Smrg	} else if (isalpha(ch)) {
1828d522f475Smrg	    name = True;
1829d522f475Smrg	    len--;
1830d522f475Smrg	} else {
1831d522f475Smrg	    break;
1832d522f475Smrg	}
1833d522f475Smrg    }
1834d522f475Smrg    TRACE(("my_pty_name(%s) -> '%s'\n", device, device + len));
1835d522f475Smrg    return device + len;
1836d522f475Smrg}
1837d522f475Smrg
1838d522f475Smrg/*
1839d522f475Smrg * If the name contains a '/', it is a "pts/1" case.  Otherwise, return the
1840d522f475Smrg * last few characters for a utmp identifier.
1841d522f475Smrg */
1842d522f475Smrgstatic char *
1843d522f475Smrgmy_pty_id(char *device)
1844d522f475Smrg{
1845d522f475Smrg    char *name = my_pty_name(device);
1846d522f475Smrg    char *leaf = x_basename(name);
1847d522f475Smrg
1848d522f475Smrg    if (name == leaf) {		/* no '/' in the name */
1849956cc18dSsnj	int len = (int) strlen(leaf);
1850d522f475Smrg	if (PTYCHARLEN < len)
1851d522f475Smrg	    leaf = leaf + (len - PTYCHARLEN);
1852d522f475Smrg    }
1853d522f475Smrg    TRACE(("my_pty_id  (%s) -> '%s'\n", device, leaf));
1854d522f475Smrg    return leaf;
1855d522f475Smrg}
1856d522f475Smrg
1857d522f475Smrg/*
1858d522f475Smrg * Set the tty/pty identifier
1859d522f475Smrg */
1860d522f475Smrgstatic void
1861d522f475Smrgset_pty_id(char *device, char *id)
1862d522f475Smrg{
1863d522f475Smrg    char *name = my_pty_name(device);
1864d522f475Smrg    char *leaf = x_basename(name);
1865d522f475Smrg
1866d522f475Smrg    if (name == leaf) {
1867d522f475Smrg	strcpy(my_pty_id(device), id);
1868d522f475Smrg    } else {
1869d522f475Smrg	strcpy(leaf, id);
1870d522f475Smrg    }
1871d522f475Smrg    TRACE(("set_pty_id(%s) -> '%s'\n", id, device));
1872d522f475Smrg}
1873d522f475Smrg
1874d522f475Smrg/*
1875d522f475Smrg * The original -S option accepts two characters to identify the pty, and a
1876d522f475Smrg * file-descriptor (assumed to be nonzero).  That is not general enough, so we
1877d522f475Smrg * check first if the option contains a '/' to delimit the two fields, and if
1878d522f475Smrg * not, fall-thru to the original logic.
1879d522f475Smrg */
1880d522f475Smrgstatic Bool
1881d522f475SmrgParseSccn(char *option)
1882d522f475Smrg{
1883d522f475Smrg    char *leaf = x_basename(option);
1884d522f475Smrg    Bool code = False;
1885d522f475Smrg
188601037d57Smrg    passedPty = x_strdup(option);
1887d522f475Smrg    if (leaf != option) {
1888d522f475Smrg	if (leaf - option > 0
1889d522f475Smrg	    && isdigit(CharOf(*leaf))
1890d522f475Smrg	    && sscanf(leaf, "%d", &am_slave) == 1) {
1891956cc18dSsnj	    size_t len = (size_t) (leaf - option - 1);
1892d522f475Smrg	    /*
1893d522f475Smrg	     * If we have a slash, we only care about the part after the slash,
1894d522f475Smrg	     * which is a file-descriptor.  The part before the slash can be
1895d522f475Smrg	     * the /dev/pts/XXX value, but since we do not need to reopen it,
1896d522f475Smrg	     * it is useful mainly for display in a "ps -ef".
1897d522f475Smrg	     */
1898d522f475Smrg	    passedPty[len] = 0;
1899d522f475Smrg	    code = True;
1900d522f475Smrg	}
1901d522f475Smrg    } else {
1902d522f475Smrg	code = (sscanf(option, "%c%c%d",
1903d522f475Smrg		       passedPty, passedPty + 1, &am_slave) == 3);
190401037d57Smrg	passedPty[2] = '\0';
1905d522f475Smrg    }
1906d522f475Smrg    TRACE(("ParseSccn(%s) = '%s' %d (%s)\n", option,
1907d522f475Smrg	   passedPty, am_slave, code ? "OK" : "ERR"));
1908d522f475Smrg    return code;
1909d522f475Smrg}
1910d522f475Smrg
1911d522f475Smrg#if defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
1912d522f475Smrg/*
1913d522f475Smrg * From "man utmp":
1914d522f475Smrg * xterm and other terminal emulators directly create a USER_PROCESS record
1915d522f475Smrg * and generate the ut_id by using the last two letters of /dev/ttyp%c or by
1916d522f475Smrg * using p%d for /dev/pts/%d.  If they find a DEAD_PROCESS for this id, they
1917d522f475Smrg * recycle it, otherwise they create a new entry.  If they can, they will mark
1918d522f475Smrg * it as DEAD_PROCESS on exiting and it is advised that they null ut_line,
1919d522f475Smrg * ut_time, ut_user and ut_host as well.
1920d522f475Smrg *
1921d522f475Smrg * Generally ut_id allows no more than 3 characters (plus null), even if the
1922d522f475Smrg * pty implementation allows more than 3 digits.
1923d522f475Smrg */
1924d522f475Smrgstatic char *
1925d522f475Smrgmy_utmp_id(char *device)
1926d522f475Smrg{
1927d522f475Smrg    typedef struct UTMP_STR UTMP_STRUCT;
1928d522f475Smrg#define	UTIDSIZE	(sizeof(((UTMP_STRUCT *)NULL)->ut_id))
1929d522f475Smrg    static char result[UTIDSIZE + 1];
1930d522f475Smrg
1931d522f475Smrg#if defined(__SCO__) || defined(__UNIXWARE__)
1932d522f475Smrg    /*
1933d522f475Smrg     * Legend does not support old-style pty's, has no related compatibility
1934d522f475Smrg     * issues, and can use the available space in ut_id differently from the
1935d522f475Smrg     * default convention.
1936d522f475Smrg     *
1937d522f475Smrg     * This scheme is intended to avoid conflicts both with other users of
1938d522f475Smrg     * utmpx as well as between multiple xterms.  First, Legend uses all of the
1939d522f475Smrg     * characters of ut_id, and adds no terminating NUL is required (the
1940d522f475Smrg     * default scheme may add a trailing NUL).  Second, all xterm entries will
1941d522f475Smrg     * start with the letter 'x' followed by three digits, which will be the
1942d522f475Smrg     * last three digits of the device name, regardless of the format of the
1943d522f475Smrg     * device name, with leading 0's added where necessary.  For instance, an
1944d522f475Smrg     * xterm on /dev/pts/3 will have a ut_id of x003; an xterm on /dev/pts123
1945d522f475Smrg     * will have a ut_id of x123.  Under the other convention, /dev/pts/3 would
1946d522f475Smrg     * have a ut_id of p3 and /dev/pts123 would have a ut_id of p123.
1947d522f475Smrg     */
1948d522f475Smrg    int len, n;
1949d522f475Smrg
1950d522f475Smrg    len = strlen(device);
1951d522f475Smrg    n = UTIDSIZE;
1952d522f475Smrg    result[n] = '\0';
1953d522f475Smrg    while ((n > 0) && (len > 0) && isdigit(device[len - 1]))
1954d522f475Smrg	result[--n] = device[--len];
1955d522f475Smrg    while (n > 0)
1956d522f475Smrg	result[--n] = '0';
1957d522f475Smrg    result[0] = 'x';
1958d522f475Smrg#else
1959d522f475Smrg    char *name = my_pty_name(device);
1960d522f475Smrg    char *leaf = x_basename(name);
1961d522f475Smrg    size_t len = strlen(leaf);
1962d522f475Smrg
1963d522f475Smrg    if ((UTIDSIZE - 1) < len)
1964d522f475Smrg	leaf = leaf + (len - (UTIDSIZE - 1));
1965d522f475Smrg    sprintf(result, "p%s", leaf);
1966d522f475Smrg#endif
1967d522f475Smrg
1968d522f475Smrg    TRACE(("my_utmp_id (%s) -> '%s'\n", device, result));
1969d522f475Smrg    return result;
1970d522f475Smrg}
1971d522f475Smrg#endif /* USE_SYSV_UTMP */
1972d522f475Smrg
1973d522f475Smrg#ifdef USE_POSIX_SIGNALS
1974d522f475Smrg
1975d522f475Smrgtypedef void (*sigfunc) (int);
1976d522f475Smrg
1977d522f475Smrg/* make sure we sure we ignore SIGCHLD for the cases parent
1978d522f475Smrg   has just been stopped and not actually killed */
1979d522f475Smrg
1980d522f475Smrgstatic sigfunc
1981d522f475Smrgposix_signal(int signo, sigfunc func)
1982d522f475Smrg{
1983d522f475Smrg    struct sigaction act, oact;
1984d522f475Smrg
1985d522f475Smrg    act.sa_handler = func;
1986d522f475Smrg    sigemptyset(&act.sa_mask);
1987d522f475Smrg#ifdef SA_RESTART
1988d522f475Smrg    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
1989d522f475Smrg#else
1990d522f475Smrg    act.sa_flags = SA_NOCLDSTOP;
1991d522f475Smrg#endif
1992d522f475Smrg    if (sigaction(signo, &act, &oact) < 0)
1993d522f475Smrg	return (SIG_ERR);
1994d522f475Smrg    return (oact.sa_handler);
1995d522f475Smrg}
1996d522f475Smrg
19970bd37d32Smrg#endif /* USE_POSIX_SIGNALS */
1998d522f475Smrg
1999d522f475Smrg#if defined(DISABLE_SETUID) || defined(USE_UTMP_SETGID)
2000d522f475Smrgstatic void
2001d522f475SmrgdisableSetUid(void)
2002d522f475Smrg{
2003d522f475Smrg    TRACE(("process %d disableSetUid\n", (int) getpid()));
2004d522f475Smrg    if (setuid(save_ruid) == -1) {
20050bd37d32Smrg	xtermWarning("unable to reset uid\n");
2006d522f475Smrg	exit(1);
2007d522f475Smrg    }
2008d522f475Smrg    TRACE_IDS;
2009d522f475Smrg}
2010d522f475Smrg#else
2011d522f475Smrg#define disableSetUid()		/* nothing */
2012d522f475Smrg#endif /* DISABLE_SETUID */
2013d522f475Smrg
2014d522f475Smrg#if defined(DISABLE_SETGID) || defined(USE_UTMP_SETGID)
2015d522f475Smrgstatic void
2016d522f475SmrgdisableSetGid(void)
2017d522f475Smrg{
2018d522f475Smrg    TRACE(("process %d disableSetGid\n", (int) getpid()));
2019d522f475Smrg    if (setegid(save_rgid) == -1) {
20200bd37d32Smrg	xtermWarning("unable to reset effective gid\n");
2021d522f475Smrg	exit(1);
2022d522f475Smrg    }
2023d522f475Smrg    TRACE_IDS;
2024d522f475Smrg}
2025d522f475Smrg#else
2026d522f475Smrg#define disableSetGid()		/* nothing */
2027d522f475Smrg#endif /* DISABLE_SETGID */
2028d522f475Smrg
2029d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS)
2030d522f475Smrg#if (!defined(USE_UTEMPTER) || !defined(DISABLE_SETGID))
2031d522f475Smrgstatic void
2032d522f475SmrgsetEffectiveGroup(gid_t group)
2033d522f475Smrg{
2034d522f475Smrg    TRACE(("process %d setEffectiveGroup(%d)\n", (int) getpid(), (int) group));
2035d522f475Smrg    if (setegid(group) == -1) {
2036d522f475Smrg#ifdef __MVS__
2037d522f475Smrg	if (!(errno == EMVSERR))	/* could happen if _BPX_SHAREAS=REUSE */
2038d522f475Smrg#endif
2039d522f475Smrg	{
20400bd37d32Smrg	    xtermPerror("setegid(%d)", (int) group);
2041d522f475Smrg	}
2042d522f475Smrg    }
2043d522f475Smrg    TRACE_IDS;
2044d522f475Smrg}
2045d522f475Smrg#endif
2046d522f475Smrg
2047d522f475Smrg#if !defined(USE_UTMP_SETGID) && (!defined(USE_UTEMPTER) || !defined(DISABLE_SETUID))
2048d522f475Smrgstatic void
2049d522f475SmrgsetEffectiveUser(uid_t user)
2050d522f475Smrg{
2051d522f475Smrg    TRACE(("process %d setEffectiveUser(%d)\n", (int) getpid(), (int) user));
2052d522f475Smrg    if (seteuid(user) == -1) {
2053d522f475Smrg#ifdef __MVS__
2054d522f475Smrg	if (!(errno == EMVSERR))
2055d522f475Smrg#endif
2056d522f475Smrg	{
20570bd37d32Smrg	    xtermPerror("seteuid(%d)", (int) user);
2058d522f475Smrg	}
2059d522f475Smrg    }
2060d522f475Smrg    TRACE_IDS;
2061d522f475Smrg}
2062d522f475Smrg#endif
2063d522f475Smrg#endif /* HAVE_POSIX_SAVED_IDS */
2064d522f475Smrg
20652e4f8982Smrg#if OPT_LUIT_PROG
20662e4f8982Smrgstatic Boolean
20672e4f8982Smrgcomplex_command(char **args)
20682e4f8982Smrg{
20692e4f8982Smrg    Boolean result = False;
20702e4f8982Smrg    if (x_countargv(args) == 1) {
20712e4f8982Smrg	char *check = xtermFindShell(args[0], False);
20722e4f8982Smrg	if (check == 0) {
20732e4f8982Smrg	    result = True;
20742e4f8982Smrg	} else {
20752e4f8982Smrg	    free(check);
20762e4f8982Smrg	}
20772e4f8982Smrg    }
20782e4f8982Smrg    return result;
20792e4f8982Smrg}
20802e4f8982Smrg#endif
20812e4f8982Smrg
20822e4f8982Smrgstatic unsigned
20832e4f8982Smrglookup_baudrate(const char *value)
20842e4f8982Smrg{
20852e4f8982Smrg    struct speed {
20862e4f8982Smrg	unsigned given_speed;	/* values for 'ospeed' */
20872e4f8982Smrg	unsigned actual_speed;	/* the actual speed */
20882e4f8982Smrg    };
20892e4f8982Smrg
20902e4f8982Smrg#define DATA(number) { B##number, number }
20912e4f8982Smrg
20922e4f8982Smrg    static struct speed const speeds[] =
20932e4f8982Smrg    {
20942e4f8982Smrg	DATA(0),
20952e4f8982Smrg	DATA(50),
20962e4f8982Smrg	DATA(75),
20972e4f8982Smrg	DATA(110),
20982e4f8982Smrg	DATA(134),
20992e4f8982Smrg	DATA(150),
21002e4f8982Smrg	DATA(200),
21012e4f8982Smrg	DATA(300),
21022e4f8982Smrg	DATA(600),
21032e4f8982Smrg	DATA(1200),
21042e4f8982Smrg	DATA(1800),
21052e4f8982Smrg	DATA(2400),
21062e4f8982Smrg	DATA(4800),
21072e4f8982Smrg	DATA(9600),
21082e4f8982Smrg#ifdef B19200
21092e4f8982Smrg	DATA(19200),
21102e4f8982Smrg#elif defined(EXTA)
21112e4f8982Smrg	{EXTA, 19200},
21122e4f8982Smrg#endif
21132e4f8982Smrg#ifdef B28800
21142e4f8982Smrg	DATA(28800),
21152e4f8982Smrg#endif
21162e4f8982Smrg#ifdef B38400
21172e4f8982Smrg	DATA(38400),
21182e4f8982Smrg#elif defined(EXTB)
21192e4f8982Smrg	{EXTB, 38400},
21202e4f8982Smrg#endif
21212e4f8982Smrg#ifdef B57600
21222e4f8982Smrg	DATA(57600),
21232e4f8982Smrg#endif
21242e4f8982Smrg#ifdef B76800
21252e4f8982Smrg	DATA(76800),
21262e4f8982Smrg#endif
21272e4f8982Smrg#ifdef B115200
21282e4f8982Smrg	DATA(115200),
21292e4f8982Smrg#endif
21302e4f8982Smrg#ifdef B153600
21312e4f8982Smrg	DATA(153600),
21322e4f8982Smrg#endif
21332e4f8982Smrg#ifdef B230400
21342e4f8982Smrg	DATA(230400),
21352e4f8982Smrg#endif
21362e4f8982Smrg#ifdef B307200
21372e4f8982Smrg	DATA(307200),
21382e4f8982Smrg#endif
21392e4f8982Smrg#ifdef B460800
21402e4f8982Smrg	DATA(460800),
21412e4f8982Smrg#endif
21422e4f8982Smrg#ifdef B500000
21432e4f8982Smrg	DATA(500000),
21442e4f8982Smrg#endif
21452e4f8982Smrg#ifdef B576000
21462e4f8982Smrg	DATA(576000),
21472e4f8982Smrg#endif
21482e4f8982Smrg#ifdef B921600
21492e4f8982Smrg	DATA(921600),
21502e4f8982Smrg#endif
21512e4f8982Smrg#ifdef B1000000
21522e4f8982Smrg	DATA(1000000),
21532e4f8982Smrg#endif
21542e4f8982Smrg#ifdef B1152000
21552e4f8982Smrg	DATA(1152000),
21562e4f8982Smrg#endif
21572e4f8982Smrg#ifdef B1500000
21582e4f8982Smrg	DATA(1500000),
21592e4f8982Smrg#endif
21602e4f8982Smrg#ifdef B2000000
21612e4f8982Smrg	DATA(2000000),
21622e4f8982Smrg#endif
21632e4f8982Smrg#ifdef B2500000
21642e4f8982Smrg	DATA(2500000),
21652e4f8982Smrg#endif
21662e4f8982Smrg#ifdef B3000000
21672e4f8982Smrg	DATA(3000000),
21682e4f8982Smrg#endif
21692e4f8982Smrg#ifdef B3500000
21702e4f8982Smrg	DATA(3500000),
21712e4f8982Smrg#endif
21722e4f8982Smrg#ifdef B4000000
21732e4f8982Smrg	DATA(4000000),
21742e4f8982Smrg#endif
21752e4f8982Smrg    };
21762e4f8982Smrg#undef DATA
21772e4f8982Smrg    unsigned result = 0;
21782e4f8982Smrg    long check;
21792e4f8982Smrg    char *next;
21802e4f8982Smrg    if (x_toupper(*value) == 'B')
21812e4f8982Smrg	value++;
21822e4f8982Smrg    if (isdigit(CharOf(*value))) {
21832e4f8982Smrg	check = strtol(value, &next, 10);
21842e4f8982Smrg	if (FullS2L(value, next) && (check > 0)) {
21852e4f8982Smrg	    Cardinal n;
21862e4f8982Smrg	    for (n = 0; n < XtNumber(speeds); ++n) {
21872e4f8982Smrg		if (speeds[n].actual_speed == (unsigned) check) {
21882e4f8982Smrg		    result = speeds[n].given_speed;
21892e4f8982Smrg		    break;
21902e4f8982Smrg		}
21912e4f8982Smrg	    }
21922e4f8982Smrg	}
21932e4f8982Smrg    }
21942e4f8982Smrg    if (result == 0) {
21952e4f8982Smrg	fprintf(stderr, "unsupported value for baudrate: %s\n", value);
21962e4f8982Smrg    }
21972e4f8982Smrg    return result;
21982e4f8982Smrg}
21992e4f8982Smrg
2200d522f475Smrgint
2201d522f475Smrgmain(int argc, char *argv[]ENVP_ARG)
2202d522f475Smrg{
2203a1f3da82Smrg#if OPT_MAXIMIZE
2204a1f3da82Smrg#define DATA(name) { #name, es##name }
220501037d57Smrg    static const FlagList tblFullscreen[] =
2206a1f3da82Smrg    {
2207a1f3da82Smrg	DATA(Always),
2208a1f3da82Smrg	DATA(Never)
2209a1f3da82Smrg    };
2210a1f3da82Smrg#undef DATA
2211a1f3da82Smrg#endif
2212a1f3da82Smrg
2213d522f475Smrg    Widget form_top, menu_top;
2214d522f475Smrg    Dimension menu_high;
2215d522f475Smrg    TScreen *screen;
2216d522f475Smrg    int mode;
2217e0a2b6dfSmrg    char *my_class = x_strdup(DEFCLASS);
22182e4f8982Smrg    unsigned line_speed = VAL_LINE_SPEED;
2219d522f475Smrg    Window winToEmbedInto = None;
2220f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
2221f2e35a3aSmrg    Xaw3dXftData *xaw3dxft_data;
2222f2e35a3aSmrg#endif
2223d522f475Smrg
2224ae137402Smrg    ProgramName = x_strdup(x_basename(argv[0]));
2225ae137402Smrg    ProgramPath = xtermFindShell(argv[0], True);
2226ae137402Smrg    if (ProgramPath != NULL)
2227ae137402Smrg	argv[0] = ProgramPath;
2228d522f475Smrg
2229d522f475Smrg#ifdef HAVE_POSIX_SAVED_IDS
2230d522f475Smrg    save_euid = geteuid();
2231d522f475Smrg    save_egid = getegid();
2232d522f475Smrg#endif
2233d522f475Smrg
2234d522f475Smrg    save_ruid = getuid();
2235d522f475Smrg    save_rgid = getgid();
2236d522f475Smrg
2237d522f475Smrg#if defined(DISABLE_SETUID) || defined(DISABLE_SETGID)
2238d522f475Smrg#if defined(DISABLE_SETUID)
2239d522f475Smrg    disableSetUid();
2240d522f475Smrg#endif
2241d522f475Smrg#if defined(DISABLE_SETGID)
2242d522f475Smrg    disableSetGid();
2243d522f475Smrg#endif
2244d522f475Smrg    TRACE_IDS;
2245d522f475Smrg#endif
2246d522f475Smrg
2247d522f475Smrg    /* extra length in case longer tty name like /dev/ttyq255 */
2248d522f475Smrg    ttydev = TypeMallocN(char, sizeof(TTYDEV) + 80);
2249d522f475Smrg#ifdef USE_PTY_DEVICE
2250d522f475Smrg    ptydev = TypeMallocN(char, sizeof(PTYDEV) + 80);
2251d522f475Smrg    if (!ttydev || !ptydev)
2252d522f475Smrg#else
2253d522f475Smrg    if (!ttydev)
2254d522f475Smrg#endif
2255d522f475Smrg    {
22560bd37d32Smrg	xtermWarning("unable to allocate memory for ttydev or ptydev\n");
2257d522f475Smrg	exit(1);
2258d522f475Smrg    }
2259d522f475Smrg    strcpy(ttydev, TTYDEV);
2260d522f475Smrg#ifdef USE_PTY_DEVICE
2261d522f475Smrg    strcpy(ptydev, PTYDEV);
2262d522f475Smrg#endif
2263d522f475Smrg
2264d522f475Smrg#if defined(USE_UTMP_SETGID)
2265d522f475Smrg    get_pty(NULL, NULL);
2266d522f475Smrg    disableSetUid();
2267d522f475Smrg    disableSetGid();
2268d522f475Smrg    TRACE_IDS;
2269d522f475Smrg#define get_pty(pty, from) really_get_pty(pty, from)
2270d522f475Smrg#endif
2271d522f475Smrg
2272d522f475Smrg    /* Do these first, since we may not be able to open the display */
2273d522f475Smrg    TRACE_OPTS(xtermOptions, optionDescList, XtNumber(optionDescList));
2274d522f475Smrg    TRACE_ARGV("Before XtOpenApplication", argv);
2275ae137402Smrg    restart_params = 0;
2276d522f475Smrg    if (argc > 1) {
22770bd37d32Smrg	XrmOptionDescRec *option_ptr;
22780bd37d32Smrg	char *option_value;
2279d522f475Smrg	int n;
2280e39b573cSmrg	Bool quit = False;
2281d522f475Smrg
2282d522f475Smrg	for (n = 1; n < argc; n++) {
22830bd37d32Smrg	    if ((option_ptr = parseArg(&n, argv, &option_value)) == 0) {
22840bd37d32Smrg		if (argv[n] == 0) {
22850bd37d32Smrg		    break;
22860bd37d32Smrg		} else if (isOption(argv[n])) {
22870bd37d32Smrg		    Syntax(argv[n]);
22880bd37d32Smrg		} else if (explicit_shname != 0) {
22890bd37d32Smrg		    xtermWarning("Explicit shell already was %s\n", explicit_shname);
22900bd37d32Smrg		    Syntax(argv[n]);
22910bd37d32Smrg		}
22920bd37d32Smrg		explicit_shname = xtermFindShell(argv[n], True);
22930bd37d32Smrg		if (explicit_shname == 0)
22940bd37d32Smrg		    exit(0);
22950bd37d32Smrg		TRACE(("...explicit shell %s\n", explicit_shname));
2296ae137402Smrg		restart_params = (argc - n);
22970bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-e")) {
22980bd37d32Smrg		command_to_exec = (argv + n + 1);
22990bd37d32Smrg		if (!command_to_exec[0])
23000bd37d32Smrg		    Syntax(argv[n]);
2301ae137402Smrg		restart_params = (argc - n);
23020bd37d32Smrg		break;
23030bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-version")) {
2304d522f475Smrg		Version();
2305e39b573cSmrg		quit = True;
23060bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-help")) {
2307d522f475Smrg		Help();
2308e39b573cSmrg		quit = True;
23092e4f8982Smrg	    } else if (!strcmp(option_ptr->option, "-baudrate")) {
2310f2e35a3aSmrg		NeedParam(option_ptr, option_value);
23112e4f8982Smrg		if ((line_speed = lookup_baudrate(option_value)) == 0) {
23122e4f8982Smrg		    Help();
23132e4f8982Smrg		    quit = True;
23142e4f8982Smrg		}
23150bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-class")) {
2316f2e35a3aSmrg		NeedParam(option_ptr, option_value);
2317e0a2b6dfSmrg		free(my_class);
23180bd37d32Smrg		if ((my_class = x_strdup(option_value)) == 0) {
2319d522f475Smrg		    Help();
2320e39b573cSmrg		    quit = True;
2321d522f475Smrg		}
23220bd37d32Smrg	    } else if (!strcmp(option_ptr->option, "-into")) {
23230bd37d32Smrg		char *endPtr;
2324f2e35a3aSmrg		NeedParam(option_ptr, option_value);
23250bd37d32Smrg		winToEmbedInto = (Window) strtol(option_value, &endPtr, 0);
23262e4f8982Smrg		if (!FullS2L(option_value, endPtr)) {
23272e4f8982Smrg		    Help();
23282e4f8982Smrg		    quit = True;
23292e4f8982Smrg		}
2330d522f475Smrg	    }
2331d522f475Smrg	}
2332d522f475Smrg	if (quit)
2333d522f475Smrg	    exit(0);
23340bd37d32Smrg	/*
23350bd37d32Smrg	 * If there is anything left unparsed, and we're not using "-e",
23360bd37d32Smrg	 * then give up.
23370bd37d32Smrg	 */
23380bd37d32Smrg	if (n < argc && !command_to_exec) {
23390bd37d32Smrg	    Syntax(argv[n]);
23400bd37d32Smrg	}
2341d522f475Smrg    }
2342d522f475Smrg
23430bd37d32Smrg    /* This dumped core on HP-UX 9.05 with X11R5 */
2344d522f475Smrg#if OPT_I18N_SUPPORT
2345d522f475Smrg    XtSetLanguageProc(NULL, NULL, NULL);
2346d522f475Smrg#endif
2347d522f475Smrg
2348f2e35a3aSmrg    /* enable Xft support in Xaw3DXft */
2349f2e35a3aSmrg#if defined(HAVE_LIB_XAW3DXFT)
2350f2e35a3aSmrg    GET_XAW3DXFT_DATA(xaw3dxft_data);
2351f2e35a3aSmrg    xaw3dxft_data->encoding = -1;
2352f2e35a3aSmrg#endif
2353f2e35a3aSmrg
2354d522f475Smrg#ifdef TERMIO_STRUCT		/* { */
2355d522f475Smrg    /* Initialization is done here rather than above in order
2356d522f475Smrg     * to prevent any assumptions about the order of the contents
2357d522f475Smrg     * of the various terminal structures (which may change from
2358d522f475Smrg     * implementation to implementation).
2359d522f475Smrg     */
2360d522f475Smrg    memset(&d_tio, 0, sizeof(d_tio));
2361d522f475Smrg    d_tio.c_iflag = ICRNL | IXON;
2362f2e35a3aSmrg    d_tio.c_oflag = TAB3 | D_TIO_FLAGS;
2363d522f475Smrg    {
2364d522f475Smrg	Cardinal nn;
2365d522f475Smrg
2366d522f475Smrg	/* fill in default-values */
2367f2e35a3aSmrg	for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
2368d522f475Smrg	    if (validTtyChar(d_tio, nn)) {
2369f2e35a3aSmrg		d_tio.c_cc[ttyChars[nn].sysMode] =
2370f2e35a3aSmrg		    (cc_t) ttyChars[nn].myDefault;
2371d522f475Smrg	    }
2372d522f475Smrg	}
2373d522f475Smrg    }
2374d522f475Smrg#if defined(macII) || defined(ATT) || defined(CRAY)	/* { */
23752e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2376d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2377d522f475Smrg#ifdef ECHOKE
2378d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2379d522f475Smrg#endif
2380d522f475Smrg#ifdef ECHOCTL
2381d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2382d522f475Smrg#endif
2383d522f475Smrg#ifndef USE_TERMIOS		/* { */
2384d522f475Smrg    d_tio.c_line = 0;
2385d522f475Smrg#endif /* } */
2386d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2387d522f475Smrg    d_ltc.t_suspc = CSUSP;	/* t_suspc */
2388d522f475Smrg    d_ltc.t_dsuspc = CDSUSP;	/* t_dsuspc */
2389d522f475Smrg    d_ltc.t_rprntc = CRPRNT;
2390d522f475Smrg    d_ltc.t_flushc = CFLUSH;
2391d522f475Smrg    d_ltc.t_werasc = CWERASE;
2392d522f475Smrg    d_ltc.t_lnextc = CLNEXT;
2393d522f475Smrg#endif /* } HAS_LTCHARS */
2394d522f475Smrg#ifdef TIOCLSET			/* { */
2395d522f475Smrg    d_lmode = 0;
2396d522f475Smrg#endif /* } TIOCLSET */
2397d522f475Smrg#else /* }{ else !macII, ATT, CRAY */
2398d522f475Smrg#ifndef USE_POSIX_TERMIOS
2399d522f475Smrg#ifdef BAUD_0			/* { */
2400d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
2401d522f475Smrg#else /* }{ !BAUD_0 */
24022e4f8982Smrg    d_tio.c_cflag = line_speed | CS8 | CREAD | PARENB | HUPCL;
2403d522f475Smrg#endif /* } !BAUD_0 */
2404d522f475Smrg#else /* USE_POSIX_TERMIOS */
2405d522f475Smrg    d_tio.c_cflag = CS8 | CREAD | PARENB | HUPCL;
24062e4f8982Smrg    cfsetispeed(&d_tio, line_speed);
24072e4f8982Smrg    cfsetospeed(&d_tio, line_speed);
2408d522f475Smrg#endif
2409d522f475Smrg    d_tio.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;
2410d522f475Smrg#ifdef ECHOKE
2411d522f475Smrg    d_tio.c_lflag |= ECHOKE | IEXTEN;
2412d522f475Smrg#endif
2413d522f475Smrg#ifdef ECHOCTL
2414d522f475Smrg    d_tio.c_lflag |= ECHOCTL | IEXTEN;
2415d522f475Smrg#endif
2416d522f475Smrg#ifndef USE_POSIX_TERMIOS
2417d522f475Smrg#ifdef NTTYDISC
2418d522f475Smrg    d_tio.c_line = NTTYDISC;
2419d522f475Smrg#else
2420d522f475Smrg    d_tio.c_line = 0;
2421d522f475Smrg#endif
2422d522f475Smrg#endif /* USE_POSIX_TERMIOS */
2423d522f475Smrg#ifdef __sgi
2424d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2425d522f475Smrg    d_tio.c_iflag |= BRKINT | ISTRIP | IGNPAR;
2426d522f475Smrg#endif
2427d522f475Smrg#ifdef __MVS__
2428d522f475Smrg    d_tio.c_cflag &= ~(HUPCL | PARENB);
2429d522f475Smrg#endif
2430d522f475Smrg    {
2431d522f475Smrg	Cardinal nn;
2432d522f475Smrg	int i;
2433d522f475Smrg
2434d522f475Smrg	/* try to inherit tty settings */
2435d522f475Smrg	for (i = 0; i <= 2; i++) {
2436d522f475Smrg	    TERMIO_STRUCT deftio;
2437d522f475Smrg	    if (ttyGetAttr(i, &deftio) == 0) {
2438f2e35a3aSmrg		for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
2439d522f475Smrg		    if (validTtyChar(d_tio, nn)) {
2440f2e35a3aSmrg			d_tio.c_cc[ttyChars[nn].sysMode] =
2441f2e35a3aSmrg			    deftio.c_cc[ttyChars[nn].sysMode];
2442d522f475Smrg		    }
2443d522f475Smrg		}
2444d522f475Smrg		break;
2445d522f475Smrg	    }
2446d522f475Smrg	}
2447d522f475Smrg    }
2448d522f475Smrg#if defined(USE_TERMIOS) || defined(USE_POSIX_TERMIOS)	/* { */
2449d522f475Smrg    d_tio.c_cc[VMIN] = 1;
2450d522f475Smrg    d_tio.c_cc[VTIME] = 0;
2451d522f475Smrg#endif /* } */
2452d522f475Smrg#ifdef HAS_LTCHARS		/* { */
2453d522f475Smrg    d_ltc.t_suspc = CharOf('\000');	/* t_suspc */
2454d522f475Smrg    d_ltc.t_dsuspc = CharOf('\000');	/* t_dsuspc */
2455d522f475Smrg    d_ltc.t_rprntc = CharOf('\377');	/* reserved... */
2456d522f475Smrg    d_ltc.t_flushc = CharOf('\377');
2457d522f475Smrg    d_ltc.t_werasc = CharOf('\377');
2458d522f475Smrg    d_ltc.t_lnextc = CharOf('\377');
2459d522f475Smrg#endif /* } HAS_LTCHARS */
2460d522f475Smrg
2461d522f475Smrg#ifdef TIOCLSET			/* { */
2462d522f475Smrg    d_lmode = 0;
2463d522f475Smrg#endif /* } TIOCLSET */
2464d522f475Smrg#endif /* } macII, ATT, CRAY */
2465d522f475Smrg#endif /* } TERMIO_STRUCT */
2466d522f475Smrg
2467d522f475Smrg    /* Init the Toolkit. */
2468d522f475Smrg    {
2469d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID) && !defined(USE_UTEMPTER)
2470d522f475Smrg	setEffectiveGroup(save_rgid);
2471d522f475Smrg	setEffectiveUser(save_ruid);
2472d522f475Smrg	TRACE_IDS;
2473d522f475Smrg#endif
24740bd37d32Smrg	toplevel = xtermOpenApplication(&app_con,
24750bd37d32Smrg					my_class,
24760bd37d32Smrg					optionDescList,
24770bd37d32Smrg					XtNumber(optionDescList),
2478f2e35a3aSmrg					&argc, argv,
24790bd37d32Smrg					fallback_resources,
24800bd37d32Smrg					sessionShellWidgetClass,
24810bd37d32Smrg					NULL, 0);
2482ae137402Smrg	TRACE(("created toplevel widget %p, window %#lx\n",
2483ae137402Smrg	       (void *) toplevel, XtWindow(toplevel)));
2484d522f475Smrg
2485d522f475Smrg	XtGetApplicationResources(toplevel, (XtPointer) &resource,
2486d522f475Smrg				  application_resources,
2487d522f475Smrg				  XtNumber(application_resources), NULL, 0);
2488d522f475Smrg	TRACE_XRES();
2489ad37e533Smrg#ifdef HAVE_LIB_XCURSOR
2490ad37e533Smrg	if (!strcmp(resource.cursorTheme, "none")) {
2491ad37e533Smrg	    TRACE(("startup with no cursorTheme\n"));
2492ad37e533Smrg	    init_colored_cursor(XtDisplay(toplevel));
2493ad37e533Smrg	} else {
2494ad37e533Smrg	    const char *theme = resource.cursorTheme;
2495ad37e533Smrg	    if (IsEmpty(theme))
2496ad37e533Smrg		theme = "default";
2497ad37e533Smrg	    TRACE(("startup with \"%s\" cursorTheme\n", theme));
2498ad37e533Smrg	    xtermSetenv("XCURSOR_THEME", theme);
2499ad37e533Smrg	}
2500ad37e533Smrg#endif
2501f2e35a3aSmrg#if USE_DOUBLE_BUFFER
2502f2e35a3aSmrg	if (resource.buffered_fps <= 0)
2503f2e35a3aSmrg	    resource.buffered_fps = DEF_BUFFER_RATE;
2504f2e35a3aSmrg	if (resource.buffered_fps > 100)
2505f2e35a3aSmrg	    resource.buffered_fps = 100;
2506f2e35a3aSmrg#endif
2507a1f3da82Smrg#if OPT_MAXIMIZE
2508a1f3da82Smrg	resource.fullscreen = extendedBoolean(resource.fullscreen_s,
2509a1f3da82Smrg					      tblFullscreen,
2510f2e35a3aSmrg					      esLAST);
2511a1f3da82Smrg#endif
2512e39b573cSmrg	VTInitTranslations();
2513d522f475Smrg#if OPT_PTY_HANDSHAKE
2514d522f475Smrg	resource.wait_for_map0 = resource.wait_for_map;
2515d522f475Smrg#endif
2516d522f475Smrg
2517d522f475Smrg#if defined(HAVE_POSIX_SAVED_IDS) && !defined(USE_UTMP_SETGID)
2518d522f475Smrg#if !defined(DISABLE_SETUID) || !defined(DISABLE_SETGID)
2519d522f475Smrg#if !defined(DISABLE_SETUID)
2520d522f475Smrg	setEffectiveUser(save_euid);
2521d522f475Smrg#endif
2522d522f475Smrg#if !defined(DISABLE_SETGID)
2523d522f475Smrg	setEffectiveGroup(save_egid);
2524d522f475Smrg#endif
2525d522f475Smrg	TRACE_IDS;
2526d522f475Smrg#endif
2527d522f475Smrg#endif
2528d522f475Smrg    }
2529d522f475Smrg
2530d522f475Smrg    /*
2531d522f475Smrg     * ICCCM delete_window.
2532d522f475Smrg     */
2533d522f475Smrg    XtAppAddActions(app_con, actionProcs, XtNumber(actionProcs));
2534d522f475Smrg
2535d522f475Smrg    /*
2536d522f475Smrg     * fill in terminal modes
2537d522f475Smrg     */
2538d522f475Smrg    if (resource.tty_modes) {
2539f2e35a3aSmrg	int n = parse_tty_modes(resource.tty_modes);
2540d522f475Smrg	if (n < 0) {
25410bd37d32Smrg	    xtermWarning("bad tty modes \"%s\"\n", resource.tty_modes);
2542d522f475Smrg	} else if (n > 0) {
2543d522f475Smrg	    override_tty_modes = True;
2544d522f475Smrg	}
2545d522f475Smrg    }
25460bd37d32Smrg    initZIconBeep();
2547d522f475Smrg    hold_screen = resource.hold_screen ? 1 : 0;
2548d522f475Smrg    if (resource.icon_geometry != NULL) {
2549d522f475Smrg	int scr, junk;
2550d522f475Smrg	int ix, iy;
2551d522f475Smrg	Arg args[2];
2552d522f475Smrg
2553d522f475Smrg	for (scr = 0;		/* yyuucchh */
2554d522f475Smrg	     XtScreen(toplevel) != ScreenOfDisplay(XtDisplay(toplevel), scr);
2555d522f475Smrg	     scr++) ;
2556d522f475Smrg
2557d522f475Smrg	args[0].name = XtNiconX;
2558d522f475Smrg	args[1].name = XtNiconY;
2559d522f475Smrg	XGeometry(XtDisplay(toplevel), scr, resource.icon_geometry, "",
2560d522f475Smrg		  0, 0, 0, 0, 0, &ix, &iy, &junk, &junk);
2561d522f475Smrg	args[0].value = (XtArgVal) ix;
2562d522f475Smrg	args[1].value = (XtArgVal) iy;
2563d522f475Smrg	XtSetValues(toplevel, args, 2);
2564d522f475Smrg    }
2565d522f475Smrg
2566d522f475Smrg    XtSetValues(toplevel, ourTopLevelShellArgs,
2567d522f475Smrg		number_ourTopLevelShellArgs);
2568d522f475Smrg
2569d522f475Smrg#if OPT_WIDE_CHARS
2570d522f475Smrg    /* seems as good a place as any */
2571d522f475Smrg    init_classtab();
2572d522f475Smrg#endif
2573d522f475Smrg
2574d522f475Smrg    /* Parse the rest of the command line */
2575d522f475Smrg    TRACE_ARGV("After XtOpenApplication", argv);
2576d522f475Smrg    for (argc--, argv++; argc > 0; argc--, argv++) {
25770bd37d32Smrg	if (!isOption(*argv)) {
2578d522f475Smrg#ifdef VMS
2579d522f475Smrg	    Syntax(*argv);
2580d522f475Smrg#else
2581d522f475Smrg	    if (argc > 1)
2582d522f475Smrg		Syntax(*argv);
2583d522f475Smrg	    continue;
2584d522f475Smrg#endif
25850bd37d32Smrg	}
2586d522f475Smrg
2587d522f475Smrg	TRACE(("parsing %s\n", argv[0]));
2588d522f475Smrg	switch (argv[0][1]) {
2589d522f475Smrg	case 'C':
2590d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
2591d522f475Smrg#ifndef __sgi
2592d522f475Smrg	    {
2593d522f475Smrg		struct stat sbuf;
2594d522f475Smrg
2595d522f475Smrg		/* Must be owner and have read/write permission.
2596d522f475Smrg		   xdm cooperates to give the console the right user. */
2597d522f475Smrg		if (!stat("/dev/console", &sbuf) &&
2598d522f475Smrg		    (sbuf.st_uid == save_ruid) &&
2599d522f475Smrg		    !access("/dev/console", R_OK | W_OK)) {
2600d522f475Smrg		    Console = True;
2601d522f475Smrg		} else
2602d522f475Smrg		    Console = False;
2603d522f475Smrg	    }
2604d522f475Smrg#else /* __sgi */
2605d522f475Smrg	    Console = True;
2606d522f475Smrg#endif /* __sgi */
2607d522f475Smrg#endif /* TIOCCONS */
2608d522f475Smrg	    continue;
2609d522f475Smrg	case 'S':
2610d522f475Smrg	    if (!ParseSccn(*argv + 2))
2611d522f475Smrg		Syntax(*argv);
2612d522f475Smrg	    continue;
2613d522f475Smrg#ifdef DEBUG
2614d522f475Smrg	case 'D':
2615d522f475Smrg	    debug = True;
2616d522f475Smrg	    continue;
2617d522f475Smrg#endif /* DEBUG */
26182e4f8982Smrg	case 'b':
26192e4f8982Smrg	    if (strcmp(argv[0], "-baudrate"))
26202e4f8982Smrg		Syntax(*argv);
2621f2e35a3aSmrg	    argc--;
2622f2e35a3aSmrg	    argv++;
26232e4f8982Smrg	    continue;
26240bd37d32Smrg	case 'c':
26250bd37d32Smrg	    if (strcmp(argv[0], "-class"))
2626d522f475Smrg		Syntax(*argv);
2627f2e35a3aSmrg	    argc--;
2628f2e35a3aSmrg	    argv++;
2629d522f475Smrg	    continue;
2630d522f475Smrg	case 'e':
26310bd37d32Smrg	    if (strcmp(argv[0], "-e"))
2632d522f475Smrg		Syntax(*argv);
26330bd37d32Smrg	    command_to_exec = (argv + 1);
2634d522f475Smrg	    break;
2635d522f475Smrg	case 'i':
26360bd37d32Smrg	    if (strcmp(argv[0], "-into"))
2637d522f475Smrg		Syntax(*argv);
2638f2e35a3aSmrg	    argc--;
2639f2e35a3aSmrg	    argv++;
2640d522f475Smrg	    continue;
2641d522f475Smrg
2642d522f475Smrg	default:
2643d522f475Smrg	    Syntax(*argv);
2644d522f475Smrg	}
2645d522f475Smrg	break;
2646d522f475Smrg    }
2647d522f475Smrg
2648d522f475Smrg    SetupMenus(toplevel, &form_top, &menu_top, &menu_high);
2649d522f475Smrg
2650d522f475Smrg    term = (XtermWidget) XtVaCreateManagedWidget("vt100", xtermWidgetClass,
2651d522f475Smrg						 form_top,
2652d522f475Smrg#if OPT_TOOLBAR
2653d522f475Smrg						 XtNmenuBar, menu_top,
2654d522f475Smrg						 XtNresizable, True,
2655d522f475Smrg						 XtNfromVert, menu_top,
2656d522f475Smrg						 XtNleft, XawChainLeft,
2657d522f475Smrg						 XtNright, XawChainRight,
2658d522f475Smrg						 XtNtop, XawChainTop,
2659d522f475Smrg						 XtNbottom, XawChainBottom,
2660d522f475Smrg						 XtNmenuHeight, menu_high,
2661d522f475Smrg#endif
2662d522f475Smrg						 (XtPointer) 0);
2663ae137402Smrg    TRACE(("created vt100 widget %p, window %#lx\n",
2664ae137402Smrg	   (void *) term, XtWindow(term)));
2665d522f475Smrg    decode_keyboard_type(term, &resource);
2666d522f475Smrg
2667d522f475Smrg    screen = TScreenOf(term);
2668d522f475Smrg    screen->inhibit = 0;
2669d522f475Smrg
2670d522f475Smrg#ifdef ALLOWLOGGING
2671d522f475Smrg    if (term->misc.logInhibit)
2672d522f475Smrg	screen->inhibit |= I_LOG;
2673d522f475Smrg#endif
2674d522f475Smrg    if (term->misc.signalInhibit)
2675d522f475Smrg	screen->inhibit |= I_SIGNAL;
2676d522f475Smrg#if OPT_TEK4014
2677d522f475Smrg    if (term->misc.tekInhibit)
2678d522f475Smrg	screen->inhibit |= I_TEK;
2679d522f475Smrg#endif
2680d522f475Smrg
2681d522f475Smrg    /*
2682d522f475Smrg     * We might start by showing the tek4014 window.
2683d522f475Smrg     */
2684d522f475Smrg#if OPT_TEK4014
2685d522f475Smrg    if (screen->inhibit & I_TEK)
2686d522f475Smrg	TEK4014_ACTIVE(term) = False;
2687d522f475Smrg
2688d522f475Smrg    if (TEK4014_ACTIVE(term) && !TekInit())
2689d522f475Smrg	SysError(ERROR_INIT);
2690d522f475Smrg#endif
2691d522f475Smrg
2692d522f475Smrg    /*
2693d522f475Smrg     * Start the toolbar at this point, after the first window has been setup.
2694d522f475Smrg     */
2695d522f475Smrg#if OPT_TOOLBAR
2696d522f475Smrg    ShowToolbar(resource.toolBar);
2697d522f475Smrg#endif
2698d522f475Smrg
26990bd37d32Smrg    xtermOpenSession();
2700d522f475Smrg
2701d522f475Smrg    /*
2702d522f475Smrg     * Set title and icon name if not specified
2703d522f475Smrg     */
2704d522f475Smrg    if (command_to_exec) {
2705d522f475Smrg	Arg args[2];
2706d522f475Smrg
2707d522f475Smrg	if (!resource.title) {
2708d522f475Smrg	    if (command_to_exec) {
2709d522f475Smrg		resource.title = x_basename(command_to_exec[0]);
2710d522f475Smrg	    }			/* else not reached */
2711d522f475Smrg	}
2712d522f475Smrg
2713d522f475Smrg	if (!resource.icon_name)
2714d522f475Smrg	    resource.icon_name = resource.title;
2715d522f475Smrg	XtSetArg(args[0], XtNtitle, resource.title);
2716d522f475Smrg	XtSetArg(args[1], XtNiconName, resource.icon_name);
2717d522f475Smrg
27180bd37d32Smrg	TRACE(("setting:\n\ttitle \"%s\"\n\ticon \"%s\"\n\thint \"%s\"\n\tbased on command \"%s\"\n",
2719d522f475Smrg	       resource.title,
2720d522f475Smrg	       resource.icon_name,
27210bd37d32Smrg	       NonNull(resource.icon_hint),
2722d522f475Smrg	       *command_to_exec));
2723d522f475Smrg
2724d522f475Smrg	XtSetValues(toplevel, args, 2);
2725d522f475Smrg    }
2726d522f475Smrg#if OPT_LUIT_PROG
2727d522f475Smrg    if (term->misc.callfilter) {
27280bd37d32Smrg	char **split_filter = x_splitargs(term->misc.localefilter);
27290bd37d32Smrg	unsigned count_split = x_countargv(split_filter);
27300bd37d32Smrg	unsigned count_exec = x_countargv(command_to_exec);
27310bd37d32Smrg	unsigned count_using = (unsigned) (term->misc.use_encoding ? 2 : 0);
27320bd37d32Smrg
27330bd37d32Smrg	command_to_exec_with_luit = TypeCallocN(char *,
27340bd37d32Smrg						  (count_split
27350bd37d32Smrg						   + count_exec
27360bd37d32Smrg						   + count_using
27370bd37d32Smrg						   + 8));
27380bd37d32Smrg	if (command_to_exec_with_luit == NULL)
27390bd37d32Smrg	    SysError(ERROR_LUMALLOC);
27400bd37d32Smrg
27410bd37d32Smrg	x_appendargv(command_to_exec_with_luit, split_filter);
27420bd37d32Smrg	if (count_using) {
27430bd37d32Smrg	    char *encoding_opt[4];
27440bd37d32Smrg	    encoding_opt[0] = x_strdup("-encoding");
27450bd37d32Smrg	    encoding_opt[1] = term->misc.locale_str;
27460bd37d32Smrg	    encoding_opt[2] = 0;
27470bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, encoding_opt);
27480bd37d32Smrg	}
27490bd37d32Smrg	command_length_with_luit = x_countargv(command_to_exec_with_luit);
27500bd37d32Smrg	if (count_exec) {
27512e4f8982Smrg	    static char *fixup_shell[] =
2752f2e35a3aSmrg	    {(char *) "sh", (char *) "-c", 0};
27530bd37d32Smrg	    char *delimiter[2];
27540bd37d32Smrg	    delimiter[0] = x_strdup("--");
27550bd37d32Smrg	    delimiter[1] = 0;
27560bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, delimiter);
27572e4f8982Smrg	    if (complex_command(command_to_exec)) {
27582e4f8982Smrg		x_appendargv(command_to_exec_with_luit, fixup_shell);
27592e4f8982Smrg	    }
27600bd37d32Smrg	    x_appendargv(command_to_exec_with_luit, command_to_exec);
2761d522f475Smrg	}
27620bd37d32Smrg	TRACE_ARGV("luit command", command_to_exec_with_luit);
27630bd37d32Smrg	xtermSetenv("XTERM_FILTER", *command_to_exec_with_luit);
2764d522f475Smrg    }
2765d522f475Smrg#endif
2766d522f475Smrg
27670bd37d32Smrg    if_DEBUG({
2768d522f475Smrg	/* Set up stderr properly.  Opening this log file cannot be
2769d522f475Smrg	   done securely by a privileged xterm process (although we try),
2770d522f475Smrg	   so the debug feature is disabled by default. */
2771e39b573cSmrg	char dbglogfile[TIMESTAMP_LEN + 20];
2772d522f475Smrg	int i = -1;
27730bd37d32Smrg	timestamp_filename(dbglogfile, "xterm.debug.log.");
27740bd37d32Smrg	if (creat_as(save_ruid, save_rgid, False, dbglogfile, 0600) > 0) {
27750bd37d32Smrg	    i = open(dbglogfile, O_WRONLY | O_TRUNC);
2776d522f475Smrg	}
2777d522f475Smrg	if (i >= 0) {
2778d522f475Smrg	    dup2(i, 2);
2779d522f475Smrg
2780d522f475Smrg	    /* mark this file as close on exec */
2781d522f475Smrg	    (void) fcntl(i, F_SETFD, 1);
2782d522f475Smrg	}
27830bd37d32Smrg    });
2784d522f475Smrg
27852e4f8982Smrg    spawnXTerm(term, line_speed);
2786d522f475Smrg
2787d522f475Smrg#ifndef VMS
2788d522f475Smrg    /* Child process is out there, let's catch its termination */
2789d522f475Smrg
2790d522f475Smrg#ifdef USE_POSIX_SIGNALS
2791d522f475Smrg    (void) posix_signal(SIGCHLD, reapchild);
2792d522f475Smrg#else
2793d522f475Smrg    (void) signal(SIGCHLD, reapchild);
2794d522f475Smrg#endif
2795d522f475Smrg    /* Realize procs have now been executed */
2796d522f475Smrg
2797d522f475Smrg    if (am_slave >= 0) {	/* Write window id so master end can read and use */
2798d522f475Smrg	char buf[80];
2799d522f475Smrg
2800d522f475Smrg	buf[0] = '\0';
2801d522f475Smrg	sprintf(buf, "%lx\n", XtWindow(SHELL_OF(CURRENT_EMU())));
280220d2c4d2Smrg	IGNORE_RC(write(screen->respond, buf, strlen(buf)));
2803d522f475Smrg    }
2804d522f475Smrg#ifdef AIXV3
2805d522f475Smrg#if (OSMAJORVERSION < 4)
2806d522f475Smrg    /* In AIXV3, xterms started from /dev/console have CLOCAL set.
2807d522f475Smrg     * This means we need to clear CLOCAL so that SIGHUP gets sent
2808d522f475Smrg     * to the slave-pty process when xterm exits.
2809d522f475Smrg     */
2810d522f475Smrg
2811d522f475Smrg    {
2812d522f475Smrg	TERMIO_STRUCT tio;
2813d522f475Smrg
2814d522f475Smrg	if (ttyGetAttr(screen->respond, &tio) == -1)
2815d522f475Smrg	    SysError(ERROR_TIOCGETP);
2816d522f475Smrg
2817d522f475Smrg	tio.c_cflag &= ~(CLOCAL);
2818d522f475Smrg
2819d522f475Smrg	if (ttySetAttr(screen->respond, &tio) == -1)
2820d522f475Smrg	    SysError(ERROR_TIOCSETP);
2821d522f475Smrg    }
2822d522f475Smrg#endif
2823d522f475Smrg#endif
282401037d57Smrg#if defined(USE_ANY_SYSV_TERMIO) || defined(__MVS__) || defined(__minix)
2825d522f475Smrg    if (0 > (mode = fcntl(screen->respond, F_GETFL, 0)))
2826d522f475Smrg	SysError(ERROR_F_GETFL);
2827d522f475Smrg#ifdef O_NDELAY
2828d522f475Smrg    mode |= O_NDELAY;
2829d522f475Smrg#else
2830d522f475Smrg    mode |= O_NONBLOCK;
2831d522f475Smrg#endif /* O_NDELAY */
2832d522f475Smrg    if (fcntl(screen->respond, F_SETFL, mode))
2833d522f475Smrg	SysError(ERROR_F_SETFL);
2834d522f475Smrg#else /* !USE_ANY_SYSV_TERMIO */
2835d522f475Smrg    mode = 1;
2836d522f475Smrg    if (ioctl(screen->respond, FIONBIO, (char *) &mode) == -1)
2837d522f475Smrg	SysError(ERROR_FIONBIO);
2838d522f475Smrg#endif /* USE_ANY_SYSV_TERMIO, etc */
2839d522f475Smrg
2840d522f475Smrg    /* The erase character is used to delete the current completion */
2841d522f475Smrg#if OPT_DABBREV
2842d522f475Smrg#ifdef TERMIO_STRUCT
2843d522f475Smrg    screen->dabbrev_erase_char = d_tio.c_cc[VERASE];
2844d522f475Smrg#else
2845d522f475Smrg    screen->dabbrev_erase_char = d_sg.sg_erase;
2846d522f475Smrg#endif
2847d522f475Smrg    TRACE(("set dabbrev erase_char %#x\n", screen->dabbrev_erase_char));
2848d522f475Smrg#endif
2849d522f475Smrg
2850d522f475Smrg    FD_ZERO(&pty_mask);
2851d522f475Smrg    FD_ZERO(&X_mask);
2852d522f475Smrg    FD_ZERO(&Select_mask);
2853d522f475Smrg    FD_SET(screen->respond, &pty_mask);
2854d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &X_mask);
2855d522f475Smrg    FD_SET(screen->respond, &Select_mask);
2856d522f475Smrg    FD_SET(ConnectionNumber(screen->display), &Select_mask);
2857d522f475Smrg    max_plus1 = ((screen->respond < ConnectionNumber(screen->display))
2858d522f475Smrg		 ? (1 + ConnectionNumber(screen->display))
2859d522f475Smrg		 : (1 + screen->respond));
2860d522f475Smrg
2861d522f475Smrg#endif /* !VMS */
28620bd37d32Smrg    if_DEBUG({
28630bd37d32Smrg	TRACE(("debugging on pid %d\n", (int) getpid()));
28640bd37d32Smrg    });
2865d522f475Smrg    XSetErrorHandler(xerror);
2866d522f475Smrg    XSetIOErrorHandler(xioerror);
286701037d57Smrg#if OPT_SESSION_MGT
2868e39b573cSmrg    IceSetIOErrorHandler(ice_error);
286901037d57Smrg#endif
2870d522f475Smrg
2871d522f475Smrg    initPtyData(&VTbuffer);
2872d522f475Smrg#ifdef ALLOWLOGGING
2873d522f475Smrg    if (term->misc.log_on) {
287420d2c4d2Smrg	StartLog(term);
2875d522f475Smrg    }
2876d522f475Smrg#endif
2877d522f475Smrg
28780bd37d32Smrg    xtermEmbedWindow(winToEmbedInto);
2879a5ae21e4Smrg
2880a1f3da82Smrg    TRACE(("checking reverseVideo before rv %s fg %s, bg %s\n",
2881a1f3da82Smrg	   term->misc.re_verse0 ? "reverse" : "normal",
288220d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
288320d2c4d2Smrg	   NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2884d522f475Smrg
2885a1f3da82Smrg    if (term->misc.re_verse0) {
2886a1f3da82Smrg	if (isDefaultForeground(TScreenOf(term)->Tcolors[TEXT_FG].resource)
2887a1f3da82Smrg	    && isDefaultBackground(TScreenOf(term)->Tcolors[TEXT_BG].resource)) {
2888a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_FG].resource = x_strdup(XtDefaultBackground);
2889a1f3da82Smrg	    TScreenOf(term)->Tcolors[TEXT_BG].resource = x_strdup(XtDefaultForeground);
2890a1f3da82Smrg	} else {
2891a1f3da82Smrg	    ReverseVideo(term);
2892a1f3da82Smrg	}
2893a1f3da82Smrg	term->misc.re_verse = True;
2894a1f3da82Smrg	update_reversevideo();
2895a1f3da82Smrg	TRACE(("updated  reverseVideo after  rv %s fg %s, bg %s\n",
2896a1f3da82Smrg	       term->misc.re_verse ? "reverse" : "normal",
2897a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_FG].resource),
2898a1f3da82Smrg	       NonNull(TScreenOf(term)->Tcolors[TEXT_BG].resource)));
2899a1f3da82Smrg    }
2900d522f475Smrg
2901956cc18dSsnj#if OPT_MAXIMIZE
2902956cc18dSsnj    if (resource.maximized)
2903956cc18dSsnj	RequestMaximize(term, True);
2904956cc18dSsnj#endif
2905d522f475Smrg    for (;;) {
2906d522f475Smrg#if OPT_TEK4014
2907d522f475Smrg	if (TEK4014_ACTIVE(term))
2908d522f475Smrg	    TekRun();
2909d522f475Smrg	else
2910d522f475Smrg#endif
2911956cc18dSsnj	    VTRun(term);
2912d522f475Smrg    }
2913d522f475Smrg}
2914d522f475Smrg
2915956cc18dSsnj#if defined(__osf__) || (defined(__GLIBC__) && !defined(USE_USG_PTYS)) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
2916d522f475Smrg#define USE_OPENPTY 1
2917d522f475Smrgstatic int opened_tty = -1;
2918d522f475Smrg#endif
2919d522f475Smrg
2920d522f475Smrg/*
2921d522f475Smrg * This function opens up a pty master and stuffs its value into pty.
2922d522f475Smrg *
2923d522f475Smrg * If it finds one, it returns a value of 0.  If it does not find one,
2924d522f475Smrg * it returns a value of !0.  This routine is designed to be re-entrant,
2925d522f475Smrg * so that if a pty master is found and later, we find that the slave
2926d522f475Smrg * has problems, we can re-enter this function and get another one.
2927d522f475Smrg */
2928d522f475Smrgstatic int
2929d522f475Smrgget_pty(int *pty, char *from GCC_UNUSED)
2930d522f475Smrg{
2931d522f475Smrg    int result = 1;
2932d522f475Smrg
29330bd37d32Smrg#if defined(USE_OPENPTY)
29340bd37d32Smrg    result = openpty(pty, &opened_tty, ttydev, NULL, NULL);
29352e4f8982Smrg    if (opened_tty >= 0) {
29362e4f8982Smrg	close(opened_tty);
29372e4f8982Smrg	opened_tty = -1;
29382e4f8982Smrg    }
29390bd37d32Smrg#elif defined(HAVE_POSIX_OPENPT) && defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT_PTY_ISATTY)
29400bd37d32Smrg    if ((*pty = posix_openpt(O_RDWR)) >= 0) {
29410bd37d32Smrg	char *name = ptsname(*pty);
29420bd37d32Smrg	if (name != 0) {
29430bd37d32Smrg	    strcpy(ttydev, name);
29440bd37d32Smrg	    result = 0;
29450bd37d32Smrg	}
29460bd37d32Smrg    }
29470bd37d32Smrg#ifdef USE_PTY_SEARCH
29480bd37d32Smrg    if (result) {
29490bd37d32Smrg	result = pty_search(pty);
29500bd37d32Smrg    }
29510bd37d32Smrg#endif
29520bd37d32Smrg#elif defined(PUCC_PTYD)
2953d522f475Smrg    result = ((*pty = openrpty(ttydev, ptydev,
2954d522f475Smrg			       (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN),
2955d522f475Smrg			       save_ruid, from)) < 0);
2956d522f475Smrg#elif defined(__QNXNTO__)
2957d522f475Smrg    result = pty_search(pty);
2958d522f475Smrg#else
2959d522f475Smrg#if defined(USE_USG_PTYS) || defined(__CYGWIN__)
2960f2e35a3aSmrg#if defined(__MVS__)
2961d522f475Smrg    result = pty_search(pty);
2962d522f475Smrg#else
29630bd37d32Smrg    result = ((*pty = open("/dev/ptmx", O_RDWR)) < 0);
2964d522f475Smrg#endif
29650bd37d32Smrg#if defined(SVR4) || defined(__SCO__)
29660bd37d32Smrg    if (!result)
29670bd37d32Smrg	strcpy(ttydev, ptsname(*pty));
2968d522f475Smrg#endif
2969d522f475Smrg
2970d522f475Smrg#elif defined(AIXV3)
2971d522f475Smrg
2972d522f475Smrg    if ((*pty = open("/dev/ptc", O_RDWR)) >= 0) {
2973d522f475Smrg	strcpy(ttydev, ttyname(*pty));
2974d522f475Smrg	result = 0;
2975d522f475Smrg    }
2976d522f475Smrg#elif defined(__convex__)
2977d522f475Smrg
2978d522f475Smrg    char *pty_name;
2979d522f475Smrg    extern char *getpty(void);
2980d522f475Smrg
2981d522f475Smrg    while ((pty_name = getpty()) != NULL) {
2982d522f475Smrg	if ((*pty = open(pty_name, O_RDWR)) >= 0) {
2983d522f475Smrg	    strcpy(ptydev, pty_name);
2984d522f475Smrg	    strcpy(ttydev, pty_name);
2985d522f475Smrg	    *x_basename(ttydev) = 't';
2986d522f475Smrg	    result = 0;
2987d522f475Smrg	    break;
2988d522f475Smrg	}
2989d522f475Smrg    }
2990d522f475Smrg
2991d522f475Smrg#elif defined(sequent)
2992d522f475Smrg
2993d522f475Smrg    result = ((*pty = getpseudotty(&ttydev, &ptydev)) < 0);
2994d522f475Smrg
2995d522f475Smrg#elif defined(__sgi) && (OSMAJORVERSION >= 4)
2996d522f475Smrg
2997d522f475Smrg    char *tty_name;
2998d522f475Smrg
2999d522f475Smrg    tty_name = _getpty(pty, O_RDWR, 0622, 0);
3000d522f475Smrg    if (tty_name != 0) {
3001d522f475Smrg	strcpy(ttydev, tty_name);
3002d522f475Smrg	result = 0;
3003d522f475Smrg    }
3004d522f475Smrg#elif (defined(__sgi) && (OSMAJORVERSION < 4)) || (defined(umips) && defined (SYSTYPE_SYSV))
3005d522f475Smrg
3006d522f475Smrg    struct stat fstat_buf;
3007d522f475Smrg
3008d522f475Smrg    *pty = open("/dev/ptc", O_RDWR);
3009d522f475Smrg    if (*pty >= 0 && (fstat(*pty, &fstat_buf)) >= 0) {
3010d522f475Smrg	result = 0;
3011d522f475Smrg	sprintf(ttydev, "/dev/ttyq%d", minor(fstat_buf.st_rdev));
3012d522f475Smrg    }
3013d522f475Smrg#elif defined(__hpux)
3014d522f475Smrg
3015d522f475Smrg    /*
3016d522f475Smrg     * Use the clone device if it works, otherwise use pty_search logic.
3017d522f475Smrg     */
3018d522f475Smrg    if ((*pty = open("/dev/ptym/clone", O_RDWR)) >= 0) {
3019d522f475Smrg	char *name = ptsname(*pty);
3020d522f475Smrg	if (name != 0) {
3021d522f475Smrg	    strcpy(ttydev, name);
3022d522f475Smrg	    result = 0;
3023d522f475Smrg	} else {		/* permissions, or other unexpected problem */
3024d522f475Smrg	    close(*pty);
3025d522f475Smrg	    *pty = -1;
3026d522f475Smrg	    result = pty_search(pty);
3027d522f475Smrg	}
3028d522f475Smrg    } else {
3029d522f475Smrg	result = pty_search(pty);
3030d522f475Smrg    }
3031d522f475Smrg
3032d522f475Smrg#else
3033d522f475Smrg
3034d522f475Smrg    result = pty_search(pty);
3035d522f475Smrg
3036d522f475Smrg#endif
3037d522f475Smrg#endif
3038d522f475Smrg
3039d522f475Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d\n",
3040d522f475Smrg	   ttydev != 0 ? ttydev : "?",
3041d522f475Smrg	   ptydev != 0 ? ptydev : "?",
3042d522f475Smrg	   result ? "FAIL" : "OK",
3043d522f475Smrg	   pty != 0 ? *pty : -1));
3044d522f475Smrg    return result;
3045d522f475Smrg}
3046d522f475Smrg
3047d522f475Smrgstatic void
3048e0a2b6dfSmrgset_pty_permissions(uid_t uid, unsigned gid, unsigned mode)
3049d522f475Smrg{
3050d522f475Smrg#ifdef USE_TTY_GROUP
3051d522f475Smrg    struct group *ttygrp;
3052d522f475Smrg
3053d522f475Smrg    if ((ttygrp = getgrnam(TTY_GROUP_NAME)) != 0) {
3054913cc679Smrg	gid = (unsigned) ttygrp->gr_gid;
3055d522f475Smrg	mode &= 0660U;
3056d522f475Smrg    }
3057d522f475Smrg    endgrent();
3058d522f475Smrg#endif /* USE_TTY_GROUP */
3059d522f475Smrg
3060d522f475Smrg    TRACE_IDS;
3061913cc679Smrg    set_owner(ttydev, (unsigned) uid, gid, mode);
3062d522f475Smrg}
3063d522f475Smrg
3064d522f475Smrg#ifdef get_pty			/* USE_UTMP_SETGID */
3065d522f475Smrg#undef get_pty
3066d522f475Smrg/*
3067d522f475Smrg * Call the real get_pty() before relinquishing root-setuid, caching the
3068d522f475Smrg * result.
3069d522f475Smrg */
3070d522f475Smrgstatic int
3071d522f475Smrgget_pty(int *pty, char *from)
3072d522f475Smrg{
3073d522f475Smrg    static int m_pty = -1;
3074d522f475Smrg    int result = -1;
3075d522f475Smrg
3076d522f475Smrg    if (pty == NULL) {
3077d522f475Smrg	result = really_get_pty(&m_pty, from);
3078d522f475Smrg
3079d522f475Smrg	seteuid(0);
3080d522f475Smrg	set_pty_permissions(save_ruid, save_rgid, 0600U);
3081d522f475Smrg	seteuid(save_ruid);
3082d522f475Smrg	TRACE_IDS;
3083d522f475Smrg
3084d522f475Smrg    } else if (m_pty != -1) {
3085d522f475Smrg	*pty = m_pty;
3086d522f475Smrg	result = 0;
3087d522f475Smrg    } else {
3088d522f475Smrg	result = -1;
3089d522f475Smrg    }
30900bd37d32Smrg    TRACE(("get_pty(ttydev=%s, ptydev=%s) %s fd=%d (utmp setgid)\n",
30910bd37d32Smrg	   ttydev != 0 ? ttydev : "?",
30920bd37d32Smrg	   ptydev != 0 ? ptydev : "?",
30930bd37d32Smrg	   result ? "FAIL" : "OK",
30940bd37d32Smrg	   pty != 0 ? *pty : -1));
30952e4f8982Smrg#ifdef USE_OPENPTY
30962e4f8982Smrg    if (opened_tty >= 0) {
30972e4f8982Smrg	close(opened_tty);
30982e4f8982Smrg	opened_tty = -1;
30992e4f8982Smrg    }
31002e4f8982Smrg#endif
3101d522f475Smrg    return result;
3102d522f475Smrg}
3103d522f475Smrg#endif
3104d522f475Smrg
3105d522f475Smrg/*
3106d522f475Smrg * Called from get_pty to iterate over likely pseudo terminals
3107d522f475Smrg * we might allocate.  Used on those systems that do not have
3108d522f475Smrg * a functional interface for allocating a pty.
3109d522f475Smrg * Returns 0 if found a pty, 1 if fails.
3110d522f475Smrg */
3111d522f475Smrg#ifdef USE_PTY_SEARCH
3112d522f475Smrgstatic int
3113d522f475Smrgpty_search(int *pty)
3114d522f475Smrg{
3115d522f475Smrg    static int devindex = 0, letter = 0;
3116d522f475Smrg
3117d522f475Smrg#if defined(CRAY) || defined(__MVS__)
3118d522f475Smrg    while (devindex < MAXPTTYS) {
3119d522f475Smrg	sprintf(ttydev, TTYFORMAT, devindex);
3120d522f475Smrg	sprintf(ptydev, PTYFORMAT, devindex);
3121d522f475Smrg	devindex++;
3122d522f475Smrg
3123d522f475Smrg	TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
3124d522f475Smrg	if ((*pty = open(ptydev, O_RDWR)) >= 0) {
3125d522f475Smrg	    return 0;
3126d522f475Smrg	}
3127d522f475Smrg    }
3128d522f475Smrg#else /* CRAY || __MVS__ */
3129d522f475Smrg    while (PTYCHAR1[letter]) {
3130d522f475Smrg	ttydev[strlen(ttydev) - 2] =
3131d522f475Smrg	    ptydev[strlen(ptydev) - 2] = PTYCHAR1[letter];
3132d522f475Smrg
3133d522f475Smrg	while (PTYCHAR2[devindex]) {
3134d522f475Smrg	    ttydev[strlen(ttydev) - 1] =
3135d522f475Smrg		ptydev[strlen(ptydev) - 1] = PTYCHAR2[devindex];
3136d522f475Smrg	    devindex++;
3137d522f475Smrg
3138d522f475Smrg	    TRACE(("pty_search(ttydev=%s, ptydev=%s)\n", ttydev, ptydev));
3139d522f475Smrg	    if ((*pty = open(ptydev, O_RDWR)) >= 0) {
3140d522f475Smrg#ifdef sun
3141d522f475Smrg		/* Need to check the process group of the pty.
3142d522f475Smrg		 * If it exists, then the slave pty is in use,
3143d522f475Smrg		 * and we need to get another one.
3144d522f475Smrg		 */
3145d522f475Smrg		int pgrp_rtn;
3146d522f475Smrg		if (ioctl(*pty, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
3147d522f475Smrg		    close(*pty);
3148d522f475Smrg		    continue;
3149d522f475Smrg		}
3150d522f475Smrg#endif /* sun */
3151d522f475Smrg		return 0;
3152d522f475Smrg	    }
3153d522f475Smrg	}
3154d522f475Smrg	devindex = 0;
3155d522f475Smrg	letter++;
3156d522f475Smrg    }
3157d522f475Smrg#endif /* CRAY else */
3158d522f475Smrg    /*
3159d522f475Smrg     * We were unable to allocate a pty master!  Return an error
3160d522f475Smrg     * condition and let our caller terminate cleanly.
3161d522f475Smrg     */
3162d522f475Smrg    return 1;
3163d522f475Smrg}
3164d522f475Smrg#endif /* USE_PTY_SEARCH */
3165d522f475Smrg
3166d522f475Smrg/*
3167d522f475Smrg * The only difference in /etc/termcap between 4014 and 4015 is that
3168d522f475Smrg * the latter has support for switching character sets.  We support the
3169d522f475Smrg * 4015 protocol, but ignore the character switches.  Therefore, we
3170d522f475Smrg * choose 4014 over 4015.
3171d522f475Smrg *
3172d522f475Smrg * Features of the 4014 over the 4012: larger (19") screen, 12-bit
3173d522f475Smrg * graphics addressing (compatible with 4012 10-bit addressing),
3174d522f475Smrg * special point plot mode, incremental plot mode (not implemented in
3175d522f475Smrg * later Tektronix terminals), and 4 character sizes.
3176d522f475Smrg * All of these are supported by xterm.
3177d522f475Smrg */
3178d522f475Smrg
3179d522f475Smrg#if OPT_TEK4014
318001037d57Smrgstatic const char *const tekterm[] =
3181d522f475Smrg{
3182d522f475Smrg    "tek4014",
3183d522f475Smrg    "tek4015",			/* 4014 with APL character set support */
3184d522f475Smrg    "tek4012",			/* 4010 with lower case */
3185d522f475Smrg    "tek4013",			/* 4012 with APL character set support */
3186d522f475Smrg    "tek4010",			/* small screen, upper-case only */
3187d522f475Smrg    "dumb",
3188d522f475Smrg    0
3189d522f475Smrg};
3190d522f475Smrg#endif
3191d522f475Smrg
3192d522f475Smrg/* The VT102 is a VT100 with the Advanced Video Option included standard.
3193d522f475Smrg * It also adds Escape sequences for insert/delete character/line.
3194d522f475Smrg * The VT220 adds 8-bit character sets, selective erase.
3195d522f475Smrg * The VT320 adds a 25th status line, terminal state interrogation.
3196d522f475Smrg * The VT420 has up to 48 lines on the screen.
3197d522f475Smrg */
3198d522f475Smrg
319901037d57Smrgstatic const char *const vtterm[] =
3200d522f475Smrg{
3201d522f475Smrg#ifdef USE_X11TERM
3202d522f475Smrg    "x11term",			/* for people who want special term name */
3203d522f475Smrg#endif
3204d522f475Smrg    DFT_TERMTYPE,		/* for people who want special term name */
3205f2e35a3aSmrg    "xterm",			/* the preferred name, should be fastest */
3206d522f475Smrg    "vt102",
3207d522f475Smrg    "vt100",
3208d522f475Smrg    "ansi",
3209d522f475Smrg    "dumb",
3210d522f475Smrg    0
3211d522f475Smrg};
3212d522f475Smrg
3213d522f475Smrg/* ARGSUSED */
32140bd37d32Smrgstatic void
3215d522f475Smrghungtty(int i GCC_UNUSED)
3216d522f475Smrg{
32170bd37d32Smrg    DEBUG_MSG("handle:hungtty\n");
3218d522f475Smrg    siglongjmp(env, 1);
3219d522f475Smrg}
3220d522f475Smrg
3221d522f475Smrg#if OPT_PTY_HANDSHAKE
3222d522f475Smrg#define NO_FDS {-1, -1}
3223d522f475Smrg
3224d522f475Smrgstatic int cp_pipe[2] = NO_FDS;	/* this pipe is used for child to parent transfer */
3225d522f475Smrgstatic int pc_pipe[2] = NO_FDS;	/* this pipe is used for parent to child transfer */
3226d522f475Smrg
3227d522f475Smrgtypedef enum {			/* c == child, p == parent                        */
3228d522f475Smrg    PTY_BAD,			/* c->p: can't open pty slave for some reason     */
3229d522f475Smrg    PTY_FATALERROR,		/* c->p: we had a fatal error with the pty        */
3230d522f475Smrg    PTY_GOOD,			/* c->p: we have a good pty, let's go on          */
3231d522f475Smrg    PTY_NEW,			/* p->c: here is a new pty slave, try this        */
3232d522f475Smrg    PTY_NOMORE,			/* p->c; no more pty's, terminate                 */
3233d522f475Smrg    UTMP_ADDED,			/* c->p: utmp entry has been added                */
3234d522f475Smrg    UTMP_TTYSLOT,		/* c->p: here is my ttyslot                       */
3235d522f475Smrg    PTY_EXEC			/* p->c: window has been mapped the first time    */
3236d522f475Smrg} status_t;
3237d522f475Smrg
3238f2e35a3aSmrg#define HANDSHAKE_LEN	1024
3239f2e35a3aSmrg
3240d522f475Smrgtypedef struct {
3241d522f475Smrg    status_t status;
3242d522f475Smrg    int error;
3243d522f475Smrg    int fatal_error;
3244d522f475Smrg    int tty_slot;
3245d522f475Smrg    int rows;
3246d522f475Smrg    int cols;
3247f2e35a3aSmrg    char buffer[HANDSHAKE_LEN];
3248d522f475Smrg} handshake_t;
3249d522f475Smrg
3250f2e35a3aSmrg/* the buffer is large enough that we can always have a trailing null */
3251f2e35a3aSmrg#define copy_handshake(dst, src) \
3252f2e35a3aSmrg	strncpy(dst.buffer, src, (size_t)HANDSHAKE_LEN - 1)[HANDSHAKE_LEN - 1] = '\0'
3253f2e35a3aSmrg
3254d522f475Smrg#if OPT_TRACE
3255d522f475Smrgstatic void
3256d522f475Smrgtrace_handshake(const char *tag, handshake_t * data)
3257d522f475Smrg{
3258d522f475Smrg    const char *status = "?";
3259d522f475Smrg    switch (data->status) {
3260d522f475Smrg    case PTY_BAD:
3261d522f475Smrg	status = "PTY_BAD";
3262d522f475Smrg	break;
3263d522f475Smrg    case PTY_FATALERROR:
3264d522f475Smrg	status = "PTY_FATALERROR";
3265d522f475Smrg	break;
3266d522f475Smrg    case PTY_GOOD:
3267d522f475Smrg	status = "PTY_GOOD";
3268d522f475Smrg	break;
3269d522f475Smrg    case PTY_NEW:
3270d522f475Smrg	status = "PTY_NEW";
3271d522f475Smrg	break;
3272d522f475Smrg    case PTY_NOMORE:
3273d522f475Smrg	status = "PTY_NOMORE";
3274d522f475Smrg	break;
3275d522f475Smrg    case UTMP_ADDED:
3276d522f475Smrg	status = "UTMP_ADDED";
3277d522f475Smrg	break;
3278d522f475Smrg    case UTMP_TTYSLOT:
3279d522f475Smrg	status = "UTMP_TTYSLOT";
3280d522f475Smrg	break;
3281d522f475Smrg    case PTY_EXEC:
3282d522f475Smrg	status = "PTY_EXEC";
3283d522f475Smrg	break;
3284d522f475Smrg    }
3285d522f475Smrg    TRACE(("handshake %s %s errno=%d, error=%d device \"%s\"\n",
3286d522f475Smrg	   tag,
3287d522f475Smrg	   status,
3288d522f475Smrg	   data->error,
3289d522f475Smrg	   data->fatal_error,
3290d522f475Smrg	   data->buffer));
3291d522f475Smrg}
3292d522f475Smrg#define TRACE_HANDSHAKE(tag, data) trace_handshake(tag, data)
3293d522f475Smrg#else
3294d522f475Smrg#define TRACE_HANDSHAKE(tag, data)	/* nothing */
3295d522f475Smrg#endif
3296d522f475Smrg
3297d522f475Smrg/* HsSysError()
3298d522f475Smrg *
3299d522f475Smrg * This routine does the equivalent of a SysError but it handshakes
3300d522f475Smrg * over the errno and error exit to the master process so that it can
3301d522f475Smrg * display our error message and exit with our exit code so that the
3302d522f475Smrg * user can see it.
3303d522f475Smrg */
3304d522f475Smrg
3305d522f475Smrgstatic void
3306d522f475SmrgHsSysError(int error)
3307d522f475Smrg{
3308d522f475Smrg    handshake_t handshake;
3309d522f475Smrg
3310d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3311d522f475Smrg    handshake.status = PTY_FATALERROR;
3312d522f475Smrg    handshake.error = errno;
3313d522f475Smrg    handshake.fatal_error = error;
3314f2e35a3aSmrg    copy_handshake(handshake, ttydev);
3315d522f475Smrg
3316d522f475Smrg    if (resource.ptyHandshake && (cp_pipe[1] >= 0)) {
3317d522f475Smrg	TRACE(("HsSysError errno=%d, error=%d device \"%s\"\n",
3318d522f475Smrg	       handshake.error,
3319d522f475Smrg	       handshake.fatal_error,
3320d522f475Smrg	       handshake.buffer));
3321d522f475Smrg	TRACE_HANDSHAKE("writing", &handshake);
332220d2c4d2Smrg	IGNORE_RC(write(cp_pipe[1],
332320d2c4d2Smrg			(const char *) &handshake,
332420d2c4d2Smrg			sizeof(handshake)));
3325d522f475Smrg    } else {
33260bd37d32Smrg	xtermWarning("fatal pty error errno=%d, error=%d device \"%s\"\n",
33270bd37d32Smrg		     handshake.error,
33280bd37d32Smrg		     handshake.fatal_error,
33290bd37d32Smrg		     handshake.buffer);
3330d522f475Smrg	fprintf(stderr, "%s\n", SysErrorMsg(handshake.error));
3331d522f475Smrg	fprintf(stderr, "Reason: %s\n", SysReasonMsg(handshake.fatal_error));
3332d522f475Smrg    }
3333d522f475Smrg    exit(error);
3334d522f475Smrg}
3335d522f475Smrg
3336d522f475Smrgvoid
3337d522f475Smrgfirst_map_occurred(void)
3338d522f475Smrg{
3339d522f475Smrg    if (resource.wait_for_map) {
3340913cc679Smrg	if (pc_pipe[1] >= 0) {
3341913cc679Smrg	    handshake_t handshake;
3342913cc679Smrg	    TScreen *screen = TScreenOf(term);
3343d522f475Smrg
3344913cc679Smrg	    memset(&handshake, 0, sizeof(handshake));
3345913cc679Smrg	    handshake.status = PTY_EXEC;
3346913cc679Smrg	    handshake.rows = screen->max_row;
3347913cc679Smrg	    handshake.cols = screen->max_col;
3348d522f475Smrg
3349913cc679Smrg	    TRACE(("first_map_occurred: %dx%d\n", MaxRows(screen), MaxCols(screen)));
3350d522f475Smrg	    TRACE_HANDSHAKE("writing", &handshake);
335120d2c4d2Smrg	    IGNORE_RC(write(pc_pipe[1],
335220d2c4d2Smrg			    (const char *) &handshake,
335320d2c4d2Smrg			    sizeof(handshake)));
3354d522f475Smrg	    close(cp_pipe[0]);
3355d522f475Smrg	    close(pc_pipe[1]);
3356d522f475Smrg	}
3357d522f475Smrg	resource.wait_for_map = False;
3358d522f475Smrg    }
3359d522f475Smrg}
3360d522f475Smrg#else
3361d522f475Smrg/*
3362d522f475Smrg * temporary hack to get xterm working on att ptys
3363d522f475Smrg */
3364d522f475Smrgstatic void
3365d522f475SmrgHsSysError(int error)
3366d522f475Smrg{
33670bd37d32Smrg    xtermWarning("fatal pty error %d (errno=%d) on tty %s\n",
33680bd37d32Smrg		 error, errno, ttydev);
3369d522f475Smrg    exit(error);
3370d522f475Smrg}
3371d522f475Smrg#endif /* OPT_PTY_HANDSHAKE else !OPT_PTY_HANDSHAKE */
3372d522f475Smrg
3373d522f475Smrg#ifndef VMS
3374d522f475Smrgstatic void
3375e0a2b6dfSmrgset_owner(char *device, unsigned uid, unsigned gid, unsigned mode)
3376d522f475Smrg{
3377d522f475Smrg    int why;
3378d522f475Smrg
3379d522f475Smrg    TRACE_IDS;
338020d2c4d2Smrg    TRACE(("set_owner(%s, uid=%d, gid=%d, mode=%#o\n",
33810bd37d32Smrg	   device, (int) uid, (int) gid, (unsigned) mode));
3382d522f475Smrg
3383913cc679Smrg    if (chown(device, (uid_t) uid, (gid_t) gid) < 0) {
3384d522f475Smrg	why = errno;
3385d522f475Smrg	if (why != ENOENT
3386d522f475Smrg	    && save_ruid == 0) {
33870bd37d32Smrg	    xtermPerror("Cannot chown %s to %ld,%ld",
33880bd37d32Smrg			device, (long) uid, (long) gid);
3389d522f475Smrg	}
3390d522f475Smrg	TRACE(("...chown failed: %s\n", strerror(why)));
3391913cc679Smrg    } else if (chmod(device, (mode_t) mode) < 0) {
3392d522f475Smrg	why = errno;
3393d522f475Smrg	if (why != ENOENT) {
3394d522f475Smrg	    struct stat sb;
3395d522f475Smrg	    if (stat(device, &sb) < 0) {
33960bd37d32Smrg		xtermPerror("Cannot chmod %s to %03o",
33970bd37d32Smrg			    device, (unsigned) mode);
3398d522f475Smrg	    } else if (mode != (sb.st_mode & 0777U)) {
33990bd37d32Smrg		xtermPerror("Cannot chmod %s to %03lo currently %03lo",
34000bd37d32Smrg			    device,
34010bd37d32Smrg			    (unsigned long) mode,
34020bd37d32Smrg			    (unsigned long) (sb.st_mode & 0777U));
3403d522f475Smrg		TRACE(("...stat uid=%d, gid=%d, mode=%#o\n",
34040bd37d32Smrg		       (int) sb.st_uid, (int) sb.st_gid, (unsigned) sb.st_mode));
3405d522f475Smrg	    }
3406d522f475Smrg	}
3407d522f475Smrg	TRACE(("...chmod failed: %s\n", strerror(why)));
3408d522f475Smrg    }
3409d522f475Smrg}
3410d522f475Smrg
3411894e0ac8Smrg/*
3412894e0ac8Smrg * utmp data may not be null-terminated; even if it is, there may be garbage
3413894e0ac8Smrg * after the null.  This fills the unused part of the result with nulls.
3414894e0ac8Smrg */
3415894e0ac8Smrgstatic void
3416894e0ac8Smrgcopy_filled(char *target, const char *source, size_t len)
3417894e0ac8Smrg{
3418894e0ac8Smrg    size_t used = 0;
3419894e0ac8Smrg    while (used < len) {
3420894e0ac8Smrg	if ((target[used] = source[used]) == 0)
3421894e0ac8Smrg	    break;
3422894e0ac8Smrg	++used;
3423894e0ac8Smrg    }
3424894e0ac8Smrg    while (used < len) {
3425894e0ac8Smrg	target[used++] = '\0';
3426894e0ac8Smrg    }
3427894e0ac8Smrg}
3428894e0ac8Smrg
3429d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3430d522f475Smrg/*
3431d522f475Smrg * getutid() only looks at ut_type and ut_id.
3432d522f475Smrg * But we'll also check ut_line in find_utmp().
3433d522f475Smrg */
3434d522f475Smrgstatic void
3435d522f475Smrginit_utmp(int type, struct UTMP_STR *tofind)
3436d522f475Smrg{
3437d522f475Smrg    memset(tofind, 0, sizeof(*tofind));
3438913cc679Smrg    tofind->ut_type = (short) type;
3439894e0ac8Smrg    copy_filled(tofind->ut_id, my_utmp_id(ttydev), sizeof(tofind->ut_id));
3440894e0ac8Smrg    copy_filled(tofind->ut_line, my_pty_name(ttydev), sizeof(tofind->ut_line));
3441d522f475Smrg}
3442d522f475Smrg
3443d522f475Smrg/*
3444d522f475Smrg * We could use getutline() if we didn't support old systems.
3445d522f475Smrg */
3446d522f475Smrgstatic struct UTMP_STR *
3447d522f475Smrgfind_utmp(struct UTMP_STR *tofind)
3448d522f475Smrg{
3449d522f475Smrg    struct UTMP_STR *result;
34500bd37d32Smrg    struct UTMP_STR limited;
3451d522f475Smrg    struct UTMP_STR working;
3452d522f475Smrg
3453d522f475Smrg    for (;;) {
3454d522f475Smrg	memset(&working, 0, sizeof(working));
3455d522f475Smrg	working.ut_type = tofind->ut_type;
3456894e0ac8Smrg	copy_filled(working.ut_id, tofind->ut_id, sizeof(tofind->ut_id));
3457d522f475Smrg#if defined(__digital__) && defined(__unix__) && (defined(OSMAJORVERSION) && OSMAJORVERSION < 5)
3458d522f475Smrg	working.ut_type = 0;
3459d522f475Smrg#endif
3460d522f475Smrg	if ((result = call_getutid(&working)) == 0)
3461d522f475Smrg	    break;
3462894e0ac8Smrg	copy_filled(limited.ut_line, result->ut_line, sizeof(result->ut_line));
34630bd37d32Smrg	if (!memcmp(limited.ut_line, tofind->ut_line, sizeof(limited.ut_line)))
3464d522f475Smrg	    break;
3465d522f475Smrg	/*
3466d522f475Smrg	 * Solaris, IRIX64 and HPUX manpages say to fill the static area
3467d522f475Smrg	 * pointed to by the return-value to zeros if searching for multiple
3468d522f475Smrg	 * occurrences.  Otherwise it will continue to return the same value.
3469d522f475Smrg	 */
3470d522f475Smrg	memset(result, 0, sizeof(*result));
3471d522f475Smrg    }
3472d522f475Smrg    return result;
3473d522f475Smrg}
3474d522f475Smrg#endif /* HAVE_UTMP... */
3475d522f475Smrg
3476d522f475Smrg#define close_fd(fd) close(fd), fd = -1
3477d522f475Smrg
347820d2c4d2Smrg#if defined(TIOCNOTTY) && (!defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 1)))
347920d2c4d2Smrg#define USE_NO_DEV_TTY 1
348020d2c4d2Smrg#else
348120d2c4d2Smrg#define USE_NO_DEV_TTY 0
348220d2c4d2Smrg#endif
348320d2c4d2Smrg
3484e0a2b6dfSmrgstatic int
3485e0a2b6dfSmrgsame_leaf(char *a, char *b)
3486e0a2b6dfSmrg{
3487e0a2b6dfSmrg    char *p = x_basename(a);
3488e0a2b6dfSmrg    char *q = x_basename(b);
3489e0a2b6dfSmrg    return !strcmp(p, q);
3490e0a2b6dfSmrg}
3491e0a2b6dfSmrg
3492e0a2b6dfSmrg/*
3493e0a2b6dfSmrg * "good enough" (inode wouldn't port to Cygwin)
3494e0a2b6dfSmrg */
3495e0a2b6dfSmrgstatic int
3496e0a2b6dfSmrgsame_file(const char *a, const char *b)
3497e0a2b6dfSmrg{
3498e0a2b6dfSmrg    struct stat asb;
3499e0a2b6dfSmrg    struct stat bsb;
3500e0a2b6dfSmrg    int result = 0;
3501e0a2b6dfSmrg
3502e0a2b6dfSmrg    if ((stat(a, &asb) == 0)
3503e0a2b6dfSmrg	&& (stat(b, &bsb) == 0)
3504e0a2b6dfSmrg	&& ((asb.st_mode & S_IFMT) == S_IFREG)
3505e0a2b6dfSmrg	&& ((bsb.st_mode & S_IFMT) == S_IFREG)
3506e0a2b6dfSmrg	&& (asb.st_mtime == bsb.st_mtime)
3507e0a2b6dfSmrg	&& (asb.st_size == bsb.st_size)) {
3508e0a2b6dfSmrg	result = 1;
3509e0a2b6dfSmrg    }
3510e0a2b6dfSmrg    return result;
3511e0a2b6dfSmrg}
3512e0a2b6dfSmrg
3513f2e35a3aSmrgstatic int
3514f2e35a3aSmrgfindValidShell(const char *haystack, const char *needle)
3515f2e35a3aSmrg{
3516f2e35a3aSmrg    int result = -1;
3517f2e35a3aSmrg    int count = -1;
3518f2e35a3aSmrg    const char *s, *t;
3519f2e35a3aSmrg    size_t have;
3520f2e35a3aSmrg    size_t want = strlen(needle);
3521f2e35a3aSmrg
3522f2e35a3aSmrg    TRACE(("findValidShell:\n%s\n", NonNull(haystack)));
3523f2e35a3aSmrg
3524f2e35a3aSmrg    for (s = haystack; (s != 0) && (*s != '\0'); s = t) {
3525f2e35a3aSmrg	++count;
3526f2e35a3aSmrg	if ((t = strchr(s, '\n')) == 0) {
3527f2e35a3aSmrg	    t = s + strlen(s);
3528f2e35a3aSmrg	}
3529f2e35a3aSmrg	have = (size_t) (t - s);
3530f2e35a3aSmrg
3531f2e35a3aSmrg	if ((have >= want) && (*s != '#')) {
3532f2e35a3aSmrg	    char *p = malloc(have + 1);
3533f2e35a3aSmrg
3534f2e35a3aSmrg	    if (p != 0) {
3535f2e35a3aSmrg		char *q;
3536f2e35a3aSmrg
3537f2e35a3aSmrg		memcpy(p, s, have);
3538f2e35a3aSmrg		p[have] = '\0';
3539f2e35a3aSmrg		if ((q = x_strtrim(p)) != 0) {
3540f2e35a3aSmrg		    TRACE(("...test %s\n", q));
3541f2e35a3aSmrg		    if (!strcmp(q, needle)) {
3542f2e35a3aSmrg			result = count;
3543f2e35a3aSmrg		    } else if (same_leaf(q, (char *) needle) &&
3544f2e35a3aSmrg			       same_file(q, needle)) {
3545f2e35a3aSmrg			result = count;
3546f2e35a3aSmrg		    }
3547f2e35a3aSmrg		    free(q);
3548f2e35a3aSmrg		}
3549f2e35a3aSmrg		free(p);
3550f2e35a3aSmrg	    }
3551f2e35a3aSmrg	    if (result >= 0)
3552f2e35a3aSmrg		break;
3553f2e35a3aSmrg	}
3554f2e35a3aSmrg	while (*t == '\n') {
3555f2e35a3aSmrg	    ++t;
3556f2e35a3aSmrg	}
3557f2e35a3aSmrg    }
3558f2e35a3aSmrg    return result;
3559f2e35a3aSmrg}
3560f2e35a3aSmrg
3561f2e35a3aSmrgstatic int
3562f2e35a3aSmrgourValidShell(const char *pathname)
3563f2e35a3aSmrg{
3564f2e35a3aSmrg    return findValidShell(x_strtrim(resource.valid_shells), pathname);
3565f2e35a3aSmrg}
3566f2e35a3aSmrg
3567f2e35a3aSmrg#if defined(HAVE_GETUSERSHELL) && defined(HAVE_ENDUSERSHELL)
3568f2e35a3aSmrgstatic Boolean
3569f2e35a3aSmrgvalidShell(const char *pathname)
3570f2e35a3aSmrg{
3571f2e35a3aSmrg    int result = -1;
3572f2e35a3aSmrg
3573f2e35a3aSmrg    if (validProgram(pathname)) {
3574f2e35a3aSmrg	char *q;
3575f2e35a3aSmrg	int count = -1;
3576f2e35a3aSmrg
3577f2e35a3aSmrg	TRACE(("validShell:getusershell\n"));
3578f2e35a3aSmrg	while ((q = getusershell()) != 0) {
3579f2e35a3aSmrg	    ++count;
3580f2e35a3aSmrg	    TRACE(("...test \"%s\"\n", q));
3581f2e35a3aSmrg	    if (!strcmp(q, pathname)) {
3582f2e35a3aSmrg		result = count;
3583f2e35a3aSmrg		break;
3584f2e35a3aSmrg	    }
3585f2e35a3aSmrg	}
3586f2e35a3aSmrg	endusershell();
3587f2e35a3aSmrg
3588f2e35a3aSmrg	if (result < 0)
3589f2e35a3aSmrg	    result = ourValidShell(pathname);
3590f2e35a3aSmrg    }
3591f2e35a3aSmrg
3592f2e35a3aSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3593f2e35a3aSmrg    return (result >= 0);
3594f2e35a3aSmrg}
3595f2e35a3aSmrg#else
3596e0a2b6dfSmrg/*
3597e0a2b6dfSmrg * Only set $SHELL for paths found in the standard location.
3598e0a2b6dfSmrg */
3599e0a2b6dfSmrgstatic Boolean
3600e0a2b6dfSmrgvalidShell(const char *pathname)
3601e0a2b6dfSmrg{
3602f2e35a3aSmrg    int result = -1;
3603e0a2b6dfSmrg    const char *ok_shells = "/etc/shells";
3604e0a2b6dfSmrg    char *blob;
3605e0a2b6dfSmrg    struct stat sb;
3606e0a2b6dfSmrg    size_t rc;
3607e0a2b6dfSmrg    FILE *fp;
3608e0a2b6dfSmrg
3609f2e35a3aSmrg    if (validProgram(pathname)) {
3610f2e35a3aSmrg
3611f2e35a3aSmrg	TRACE(("validShell:%s\n", ok_shells));
3612f2e35a3aSmrg
3613f2e35a3aSmrg	if (stat(ok_shells, &sb) == 0
3614f2e35a3aSmrg	    && (sb.st_mode & S_IFMT) == S_IFREG
3615f2e35a3aSmrg	    && ((size_t) sb.st_size > 0)
3616f2e35a3aSmrg	    && ((size_t) sb.st_size < (((size_t) ~0) - 2))
3617f2e35a3aSmrg	    && (blob = calloc((size_t) sb.st_size + 2, sizeof(char))) != 0) {
3618f2e35a3aSmrg
3619f2e35a3aSmrg	    if ((fp = fopen(ok_shells, "r")) != 0) {
3620f2e35a3aSmrg		rc = fread(blob, sizeof(char), (size_t) sb.st_size, fp);
3621f2e35a3aSmrg		fclose(fp);
3622f2e35a3aSmrg
3623f2e35a3aSmrg		if (rc == (size_t) sb.st_size) {
3624f2e35a3aSmrg		    blob[rc] = '\0';
3625f2e35a3aSmrg		    result = findValidShell(blob, pathname);
3626e0a2b6dfSmrg		}
3627e0a2b6dfSmrg	    }
3628f2e35a3aSmrg	    free(blob);
3629e0a2b6dfSmrg	}
3630f2e35a3aSmrg	if (result < 0)
3631f2e35a3aSmrg	    result = ourValidShell(pathname);
3632e0a2b6dfSmrg    }
3633e0a2b6dfSmrg    TRACE(("validShell %s ->%d\n", NonNull(pathname), result));
3634f2e35a3aSmrg    return (result > 0);
3635e0a2b6dfSmrg}
3636f2e35a3aSmrg#endif
3637e0a2b6dfSmrg
3638e0a2b6dfSmrgstatic char *
3639e0a2b6dfSmrgresetShell(char *oldPath)
3640e0a2b6dfSmrg{
3641e0a2b6dfSmrg    char *newPath = x_strdup("/bin/sh");
3642e0a2b6dfSmrg    char *envPath = getenv("SHELL");
3643f2e35a3aSmrg    free(oldPath);
3644e0a2b6dfSmrg    if (!IsEmpty(envPath))
3645e0a2b6dfSmrg	xtermSetenv("SHELL", newPath);
3646e0a2b6dfSmrg    return newPath;
3647e0a2b6dfSmrg}
3648e0a2b6dfSmrg
3649d522f475Smrg/*
3650d522f475Smrg *  Inits pty and tty and forks a login process.
3651d522f475Smrg *  Does not close fd Xsocket.
3652d522f475Smrg *  If slave, the pty named in passedPty is already open for use
3653d522f475Smrg */
3654d522f475Smrgstatic int
36552e4f8982SmrgspawnXTerm(XtermWidget xw, unsigned line_speed)
3656d522f475Smrg{
3657d522f475Smrg    TScreen *screen = TScreenOf(xw);
3658d522f475Smrg    Cardinal nn;
3659d522f475Smrg#if OPT_PTY_HANDSHAKE
3660d522f475Smrg    Bool got_handshake_size = False;
3661d522f475Smrg    handshake_t handshake;
3662d522f475Smrg    int done;
3663d522f475Smrg#endif
3664d522f475Smrg#if OPT_INITIAL_ERASE
3665d522f475Smrg    int initial_erase = VAL_INITIAL_ERASE;
3666d522f475Smrg    Bool setInitialErase;
3667d522f475Smrg#endif
3668d522f475Smrg    int rc = 0;
3669d522f475Smrg    int ttyfd = -1;
3670d522f475Smrg    Bool ok_termcap;
3671d522f475Smrg    char *newtc;
3672d522f475Smrg
3673d522f475Smrg#ifdef TERMIO_STRUCT
3674d522f475Smrg    TERMIO_STRUCT tio;
3675d522f475Smrg#ifdef __MVS__
3676d522f475Smrg    TERMIO_STRUCT gio;
3677d522f475Smrg#endif /* __MVS__ */
3678d522f475Smrg#ifdef TIOCLSET
3679d522f475Smrg    unsigned lmode;
3680d522f475Smrg#endif /* TIOCLSET */
3681d522f475Smrg#ifdef HAS_LTCHARS
3682d522f475Smrg    struct ltchars ltc;
3683d522f475Smrg#endif /* HAS_LTCHARS */
3684d522f475Smrg#else /* !TERMIO_STRUCT */
3685d522f475Smrg    int ldisc = 0;
3686d522f475Smrg    int discipline;
3687d522f475Smrg    unsigned lmode;
3688d522f475Smrg    struct tchars tc;
3689d522f475Smrg    struct ltchars ltc;
3690d522f475Smrg    struct sgttyb sg;
3691d522f475Smrg#ifdef sony
3692d522f475Smrg    int jmode;
3693d522f475Smrg    struct jtchars jtc;
3694d522f475Smrg#endif /* sony */
3695d522f475Smrg#endif /* TERMIO_STRUCT */
3696d522f475Smrg
36970bd37d32Smrg    char *shell_path = 0;
36980bd37d32Smrg    char *shname, *shname_minus;
369920d2c4d2Smrg    int i;
370020d2c4d2Smrg#if USE_NO_DEV_TTY
370120d2c4d2Smrg    int no_dev_tty = False;
370220d2c4d2Smrg#endif
370301037d57Smrg    const char *const *envnew;	/* new environment */
3704d522f475Smrg    char buf[64];
3705d522f475Smrg    char *TermName = NULL;
3706d522f475Smrg#ifdef TTYSIZE_STRUCT
3707d522f475Smrg    TTYSIZE_STRUCT ts;
3708d522f475Smrg#endif
37090bd37d32Smrg    struct passwd pw;
3710d522f475Smrg    char *login_name = NULL;
3711d522f475Smrg#ifndef USE_UTEMPTER
3712d522f475Smrg#ifdef HAVE_UTMP
3713d522f475Smrg    struct UTMP_STR utmp;
3714d522f475Smrg#ifdef USE_SYSV_UTMP
3715d522f475Smrg    struct UTMP_STR *utret = NULL;
3716d522f475Smrg#endif
3717d522f475Smrg#ifdef USE_LASTLOG
3718d522f475Smrg    struct lastlog lastlog;
3719d522f475Smrg#endif
3720d522f475Smrg#ifdef USE_LASTLOGX
3721d522f475Smrg    struct lastlogx lastlogx;
3722d522f475Smrg#endif /* USE_LASTLOG */
3723d522f475Smrg#endif /* HAVE_UTMP */
3724d522f475Smrg#endif /* !USE_UTEMPTER */
3725d522f475Smrg
3726e39b573cSmrg#if OPT_TRACE
3727e39b573cSmrg    unsigned long xterm_parent = (unsigned long) getpid();
3728e39b573cSmrg#endif
3729e39b573cSmrg
3730d522f475Smrg    /* Noisy compilers (suppress some unused-variable warnings) */
3731d522f475Smrg    (void) rc;
3732d522f475Smrg#if defined(HAVE_UTMP) && defined(USE_SYSV_UTMP) && !defined(USE_UTEMPTER)
3733d522f475Smrg    (void) utret;
3734d522f475Smrg#endif
3735d522f475Smrg
3736d522f475Smrg    screen->uid = save_ruid;
3737d522f475Smrg    screen->gid = save_rgid;
3738d522f475Smrg
3739d522f475Smrg#ifdef SIGTTOU
3740d522f475Smrg    /* so that TIOCSWINSZ || TIOCSIZE doesn't block */
3741d522f475Smrg    signal(SIGTTOU, SIG_IGN);
3742d522f475Smrg#endif
3743d522f475Smrg
3744d522f475Smrg#if OPT_PTY_HANDSHAKE
3745d522f475Smrg    memset(&handshake, 0, sizeof(handshake));
3746d522f475Smrg#endif
3747d522f475Smrg
3748d522f475Smrg    if (am_slave >= 0) {
3749d522f475Smrg	screen->respond = am_slave;
3750d522f475Smrg	set_pty_id(ttydev, passedPty);
3751d522f475Smrg#ifdef USE_PTY_DEVICE
3752d522f475Smrg	set_pty_id(ptydev, passedPty);
3753d522f475Smrg#endif
3754d522f475Smrg	if (xtermResetIds(screen) < 0)
3755d522f475Smrg	    exit(1);
3756d522f475Smrg    } else {
3757d522f475Smrg	Bool tty_got_hung;
3758d522f475Smrg
3759d522f475Smrg	/*
3760d522f475Smrg	 * Sometimes /dev/tty hangs on open (as in the case of a pty
3761d522f475Smrg	 * that has gone away).  Simply make up some reasonable
3762d522f475Smrg	 * defaults.
3763d522f475Smrg	 */
3764d522f475Smrg
3765d522f475Smrg	if (!sigsetjmp(env, 1)) {
3766913cc679Smrg	    signal(SIGALRM, hungtty);
3767913cc679Smrg	    alarm(2);		/* alarm(1) might return too soon */
3768d522f475Smrg	    ttyfd = open("/dev/tty", O_RDWR);
3769d522f475Smrg	    alarm(0);
3770d522f475Smrg	    tty_got_hung = False;
3771d522f475Smrg	} else {
3772d522f475Smrg	    tty_got_hung = True;
3773d522f475Smrg	    ttyfd = -1;
3774d522f475Smrg	    errno = ENXIO;
3775d522f475Smrg	}
37762e4f8982Smrg	shell_path = 0;
37770bd37d32Smrg	memset(&pw, 0, sizeof(pw));
3778d522f475Smrg#if OPT_PTY_HANDSHAKE
3779d522f475Smrg	got_handshake_size = False;
3780d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
3781d522f475Smrg#if OPT_INITIAL_ERASE
3782d522f475Smrg	initial_erase = VAL_INITIAL_ERASE;
3783d522f475Smrg#endif
3784d522f475Smrg	signal(SIGALRM, SIG_DFL);
3785d522f475Smrg
3786d522f475Smrg	/*
3787d522f475Smrg	 * Check results and ignore current control terminal if
3788d522f475Smrg	 * necessary.  ENXIO is what is normally returned if there is
3789d522f475Smrg	 * no controlling terminal, but some systems (e.g. SunOS 4.0)
3790d522f475Smrg	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.
37910bd37d32Smrg	 * Cygwin returns ENOENT.  FreeBSD can return ENOENT, especially
37920bd37d32Smrg	 * if xterm is run within a jail.
3793d522f475Smrg	 */
379420d2c4d2Smrg#if USE_NO_DEV_TTY
3795d522f475Smrg	no_dev_tty = False;
379620d2c4d2Smrg#endif
3797d522f475Smrg	if (ttyfd < 0) {
3798d522f475Smrg	    if (tty_got_hung || errno == ENXIO || errno == EIO ||
37990bd37d32Smrg		errno == ENOENT ||
3800d522f475Smrg#ifdef ENODEV
3801d522f475Smrg		errno == ENODEV ||
3802d522f475Smrg#endif
3803d522f475Smrg		errno == EINVAL || errno == ENOTTY || errno == EACCES) {
380420d2c4d2Smrg#if USE_NO_DEV_TTY
3805d522f475Smrg		no_dev_tty = True;
380620d2c4d2Smrg#endif
3807d522f475Smrg#ifdef HAS_LTCHARS
3808d522f475Smrg		ltc = d_ltc;
3809d522f475Smrg#endif /* HAS_LTCHARS */
3810d522f475Smrg#ifdef TIOCLSET
3811d522f475Smrg		lmode = d_lmode;
3812d522f475Smrg#endif /* TIOCLSET */
3813d522f475Smrg#ifdef TERMIO_STRUCT
3814d522f475Smrg		tio = d_tio;
3815d522f475Smrg#else /* !TERMIO_STRUCT */
3816d522f475Smrg		sg = d_sg;
3817d522f475Smrg		tc = d_tc;
3818d522f475Smrg		discipline = d_disipline;
3819d522f475Smrg#ifdef sony
3820d522f475Smrg		jmode = d_jmode;
3821d522f475Smrg		jtc = d_jtc;
3822d522f475Smrg#endif /* sony */
3823d522f475Smrg#endif /* TERMIO_STRUCT */
3824d522f475Smrg	    } else {
3825d522f475Smrg		SysError(ERROR_OPDEVTTY);
3826d522f475Smrg	    }
3827d522f475Smrg	} else {
3828d522f475Smrg
3829d522f475Smrg	    /* Get a copy of the current terminal's state,
3830d522f475Smrg	     * if we can.  Some systems (e.g., SVR4 and MacII)
3831d522f475Smrg	     * may not have a controlling terminal at this point
3832d522f475Smrg	     * if started directly from xdm or xinit,
3833d522f475Smrg	     * in which case we just use the defaults as above.
3834d522f475Smrg	     */
3835d522f475Smrg#ifdef HAS_LTCHARS
3836d522f475Smrg	    if (ioctl(ttyfd, TIOCGLTC, &ltc) == -1)
3837d522f475Smrg		ltc = d_ltc;
3838d522f475Smrg#endif /* HAS_LTCHARS */
3839d522f475Smrg#ifdef TIOCLSET
3840d522f475Smrg	    if (ioctl(ttyfd, TIOCLGET, &lmode) == -1)
3841d522f475Smrg		lmode = d_lmode;
3842d522f475Smrg#endif /* TIOCLSET */
3843d522f475Smrg#ifdef TERMIO_STRUCT
384420d2c4d2Smrg	    rc = ttyGetAttr(ttyfd, &tio);
384520d2c4d2Smrg	    if (rc == -1)
3846d522f475Smrg		tio = d_tio;
3847d522f475Smrg#else /* !TERMIO_STRUCT */
384820d2c4d2Smrg	    rc = ioctl(ttyfd, TIOCGETP, (char *) &sg);
384920d2c4d2Smrg	    if (rc == -1)
3850d522f475Smrg		sg = d_sg;
3851d522f475Smrg	    if (ioctl(ttyfd, TIOCGETC, (char *) &tc) == -1)
3852d522f475Smrg		tc = d_tc;
3853d522f475Smrg	    if (ioctl(ttyfd, TIOCGETD, (char *) &discipline) == -1)
3854d522f475Smrg		discipline = d_disipline;
3855d522f475Smrg#ifdef sony
3856d522f475Smrg	    if (ioctl(ttyfd, TIOCKGET, (char *) &jmode) == -1)
3857d522f475Smrg		jmode = d_jmode;
3858d522f475Smrg	    if (ioctl(ttyfd, TIOCKGETC, (char *) &jtc) == -1)
3859d522f475Smrg		jtc = d_jtc;
3860d522f475Smrg#endif /* sony */
3861d522f475Smrg#endif /* TERMIO_STRUCT */
3862d522f475Smrg
3863d522f475Smrg	    /*
3864d522f475Smrg	     * If ptyInitialErase is set, we want to get the pty's
3865d522f475Smrg	     * erase value.  Just in case that will fail, first get
3866d522f475Smrg	     * the value from /dev/tty, so we will have something
3867d522f475Smrg	     * at least.
3868d522f475Smrg	     */
3869d522f475Smrg#if OPT_INITIAL_ERASE
3870d522f475Smrg	    if (resource.ptyInitialErase) {
3871d522f475Smrg#ifdef TERMIO_STRUCT
3872d522f475Smrg		initial_erase = tio.c_cc[VERASE];
3873d522f475Smrg#else /* !TERMIO_STRUCT */
3874d522f475Smrg		initial_erase = sg.sg_erase;
3875d522f475Smrg#endif /* TERMIO_STRUCT */
3876d522f475Smrg		TRACE(("%s initial_erase:%d (from /dev/tty)\n",
3877d522f475Smrg		       rc == 0 ? "OK" : "FAIL",
3878d522f475Smrg		       initial_erase));
3879d522f475Smrg	    }
3880d522f475Smrg#endif
3881d522f475Smrg#ifdef __MVS__
3882d522f475Smrg	    if (ttyGetAttr(ttyfd, &gio) == 0) {
3883d522f475Smrg		gio.c_cflag &= ~(HUPCL | PARENB);
3884d522f475Smrg		ttySetAttr(ttyfd, &gio);
3885d522f475Smrg	    }
3886d522f475Smrg#endif /* __MVS__ */
3887d522f475Smrg
3888d522f475Smrg	    close_fd(ttyfd);
3889d522f475Smrg	}
3890d522f475Smrg
3891d522f475Smrg	if (get_pty(&screen->respond, XDisplayString(screen->display))) {
3892d522f475Smrg	    SysError(ERROR_PTYS);
3893d522f475Smrg	}
3894913cc679Smrg	TRACE_GET_TTYSIZE(screen->respond, "after get_pty");
3895d522f475Smrg#if OPT_INITIAL_ERASE
3896d522f475Smrg	if (resource.ptyInitialErase) {
3897d522f475Smrg#ifdef TERMIO_STRUCT
3898d522f475Smrg	    TERMIO_STRUCT my_tio;
389920d2c4d2Smrg	    rc = ttyGetAttr(screen->respond, &my_tio);
390020d2c4d2Smrg	    if (rc == 0)
3901d522f475Smrg		initial_erase = my_tio.c_cc[VERASE];
3902d522f475Smrg#else /* !TERMIO_STRUCT */
3903d522f475Smrg	    struct sgttyb my_sg;
390420d2c4d2Smrg	    rc = ioctl(screen->respond, TIOCGETP, (char *) &my_sg);
390520d2c4d2Smrg	    if (rc == 0)
3906d522f475Smrg		initial_erase = my_sg.sg_erase;
3907d522f475Smrg#endif /* TERMIO_STRUCT */
3908d522f475Smrg	    TRACE(("%s initial_erase:%d (from pty)\n",
3909d522f475Smrg		   (rc == 0) ? "OK" : "FAIL",
3910d522f475Smrg		   initial_erase));
3911d522f475Smrg	}
3912d522f475Smrg#endif /* OPT_INITIAL_ERASE */
3913d522f475Smrg    }
3914d522f475Smrg
3915d522f475Smrg    /* avoid double MapWindow requests */
3916d522f475Smrg    XtSetMappedWhenManaged(SHELL_OF(CURRENT_EMU()), False);
3917d522f475Smrg
3918d522f475Smrg    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",
3919d522f475Smrg				   False);
3920d522f475Smrg
3921d522f475Smrg    if (!TEK4014_ACTIVE(xw))
3922956cc18dSsnj	VTInit(xw);		/* realize now so know window size for tty driver */
3923d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
3924d522f475Smrg    if (Console) {
3925d522f475Smrg	/*
3926d522f475Smrg	 * Inform any running xconsole program
3927d522f475Smrg	 * that we are going to steal the console.
3928d522f475Smrg	 */
3929d522f475Smrg	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);
3930d522f475Smrg	mit_console = XInternAtom(screen->display, mit_console_name, False);
3931d522f475Smrg	/* the user told us to be the console, so we can use CurrentTime */
3932d522f475Smrg	XtOwnSelection(SHELL_OF(CURRENT_EMU()),
3933d522f475Smrg		       mit_console, CurrentTime,
3934d522f475Smrg		       ConvertConsoleSelection, NULL, NULL);
3935d522f475Smrg    }
3936d522f475Smrg#endif
3937d522f475Smrg#if OPT_TEK4014
3938d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
3939d522f475Smrg	envnew = tekterm;
3940d522f475Smrg    } else
3941d522f475Smrg#endif
3942d522f475Smrg    {
3943d522f475Smrg	envnew = vtterm;
3944d522f475Smrg    }
3945d522f475Smrg
3946d522f475Smrg    /*
3947d522f475Smrg     * This used to exit if no termcap entry was found for the specified
3948d522f475Smrg     * terminal name.  That's a little unfriendly, so instead we'll allow
3949d522f475Smrg     * the program to proceed (but not to set $TERMCAP) if the termcap
3950d522f475Smrg     * entry is not found.
3951d522f475Smrg     */
3952d522f475Smrg    ok_termcap = True;
395320d2c4d2Smrg    if (!get_termcap(xw, TermName = resource.term_name)) {
395420d2c4d2Smrg	const char *last = NULL;
395520d2c4d2Smrg	char *next;
395620d2c4d2Smrg
395720d2c4d2Smrg	TermName = x_strdup(*envnew);
3958d522f475Smrg	ok_termcap = False;
3959d522f475Smrg	while (*envnew != NULL) {
396020d2c4d2Smrg	    if (last == NULL || strcmp(last, *envnew)) {
396120d2c4d2Smrg		next = x_strdup(*envnew);
396220d2c4d2Smrg		if (get_termcap(xw, next)) {
396320d2c4d2Smrg		    free(TermName);
396420d2c4d2Smrg		    TermName = next;
39650bd37d32Smrg		    ok_termcap = True + 1;
396620d2c4d2Smrg		    break;
396720d2c4d2Smrg		} else {
396820d2c4d2Smrg		    free(next);
396920d2c4d2Smrg		}
3970d522f475Smrg	    }
3971d522f475Smrg	    last = *envnew;
3972d522f475Smrg	    envnew++;
3973d522f475Smrg	}
3974d522f475Smrg    }
3975d522f475Smrg    if (ok_termcap) {
3976f2e35a3aSmrg	resource.term_name = x_strdup(TermName);
397720d2c4d2Smrg	resize_termcap(xw);
3978d522f475Smrg    }
3979d522f475Smrg
3980d522f475Smrg    /*
3981d522f475Smrg     * Check if ptyInitialErase is not set.  If so, we rely on the termcap
3982d522f475Smrg     * (or terminfo) to tell us what the erase mode should be set to.
3983d522f475Smrg     */
3984d522f475Smrg#if OPT_INITIAL_ERASE
3985d522f475Smrg    TRACE(("resource ptyInitialErase is %sset\n",
3986d522f475Smrg	   resource.ptyInitialErase ? "" : "not "));
3987d522f475Smrg    setInitialErase = False;
3988f2e35a3aSmrg    if (override_tty_modes && ttyModes[XTTYMODE_erase].set) {
3989f2e35a3aSmrg	initial_erase = ttyModes[XTTYMODE_erase].value;
3990d522f475Smrg	setInitialErase = True;
3991d522f475Smrg    } else if (resource.ptyInitialErase) {
3992a1f3da82Smrg	/* EMPTY */ ;
3993d522f475Smrg    } else if (ok_termcap) {
399420d2c4d2Smrg	char *s = get_tcap_erase(xw);
3995d522f475Smrg	TRACE(("...extracting initial_erase value from termcap\n"));
3996d522f475Smrg	if (s != 0) {
399720d2c4d2Smrg	    char *save = s;
3998d522f475Smrg	    initial_erase = decode_keyvalue(&s, True);
3999d522f475Smrg	    setInitialErase = True;
400020d2c4d2Smrg	    free(save);
4001d522f475Smrg	}
4002d522f475Smrg    }
4003d522f475Smrg    TRACE(("...initial_erase:%d\n", initial_erase));
4004d522f475Smrg
4005d522f475Smrg    TRACE(("resource backarrowKeyIsErase is %sset\n",
4006d522f475Smrg	   resource.backarrow_is_erase ? "" : "not "));
4007d522f475Smrg    if (resource.backarrow_is_erase) {	/* see input.c */
4008d522f475Smrg	if (initial_erase == ANSI_DEL) {
400920d2c4d2Smrg	    UIntClr(xw->keyboard.flags, MODE_DECBKM);
4010d522f475Smrg	} else {
4011d522f475Smrg	    xw->keyboard.flags |= MODE_DECBKM;
4012d522f475Smrg	    xw->keyboard.reset_DECBKM = 1;
4013d522f475Smrg	}
4014d522f475Smrg	TRACE(("...sets DECBKM %s\n",
4015d522f475Smrg	       (xw->keyboard.flags & MODE_DECBKM) ? "on" : "off"));
4016d522f475Smrg    } else {
4017d522f475Smrg	xw->keyboard.reset_DECBKM = 2;
4018d522f475Smrg    }
4019d522f475Smrg#endif /* OPT_INITIAL_ERASE */
4020d522f475Smrg
4021d522f475Smrg#ifdef TTYSIZE_STRUCT
4022d522f475Smrg    /* tell tty how big window is */
4023d522f475Smrg#if OPT_TEK4014
4024d522f475Smrg    if (TEK4014_ACTIVE(xw)) {
4025913cc679Smrg	setup_winsize(ts, TDefaultRows, TDefaultCols,
4026913cc679Smrg		      TFullHeight(TekScreenOf(tekWidget)),
4027913cc679Smrg		      TFullWidth(TekScreenOf(tekWidget)));
4028d522f475Smrg    } else
4029d522f475Smrg#endif
4030d522f475Smrg    {
4031913cc679Smrg	setup_winsize(ts, MaxRows(screen), MaxCols(screen),
4032913cc679Smrg		      FullHeight(screen), FullWidth(screen));
4033d522f475Smrg    }
403420d2c4d2Smrg    TRACE_RC(i, SET_TTYSIZE(screen->respond, ts));
4035d522f475Smrg    TRACE(("spawn SET_TTYSIZE %dx%d return %d\n",
4036d522f475Smrg	   TTYSIZE_ROWS(ts),
4037d522f475Smrg	   TTYSIZE_COLS(ts), i));
4038d522f475Smrg#endif /* TTYSIZE_STRUCT */
4039d522f475Smrg
40400bd37d32Smrg#if !defined(USE_OPENPTY)
40410bd37d32Smrg#if defined(USE_USG_PTYS) || defined(HAVE_POSIX_OPENPT)
40420bd37d32Smrg    /*
40430bd37d32Smrg     * utempter checks the ownership of the device; some implementations
40440bd37d32Smrg     * set ownership in grantpt - do this first.
40450bd37d32Smrg     */
40460bd37d32Smrg    grantpt(screen->respond);
40470bd37d32Smrg#endif
40480bd37d32Smrg#if !defined(USE_USG_PTYS) && defined(HAVE_POSIX_OPENPT)
40490bd37d32Smrg    unlockpt(screen->respond);
4050913cc679Smrg    TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
40510bd37d32Smrg#endif
40520bd37d32Smrg#endif /* !USE_OPENPTY */
40530bd37d32Smrg
4054d522f475Smrg    added_utmp_entry = False;
4055d522f475Smrg#if defined(USE_UTEMPTER)
4056d522f475Smrg#undef UTMP
40572e4f8982Smrg    if ((xw->misc.login_shell || !command_to_exec) && !resource.utmpInhibit) {
4058d522f475Smrg	struct UTMP_STR dummy;
4059d522f475Smrg
4060d522f475Smrg	/* Note: utempter may trim it anyway */
4061d522f475Smrg	SetUtmpHost(dummy.ut_host, screen);
40620bd37d32Smrg	TRACE(("...calling addToUtmp(pty=%s, hostname=%s, master_fd=%d)\n",
40630bd37d32Smrg	       ttydev, dummy.ut_host, screen->respond));
4064f2e35a3aSmrg	UTEMPTER_ADD(ttydev, dummy.ut_host, screen->respond);
4065d522f475Smrg	added_utmp_entry = True;
4066d522f475Smrg    }
4067d522f475Smrg#endif
4068d522f475Smrg
4069d522f475Smrg    if (am_slave < 0) {
4070d522f475Smrg#if OPT_PTY_HANDSHAKE
4071d522f475Smrg	if (resource.ptyHandshake && (pipe(pc_pipe) || pipe(cp_pipe)))
4072d522f475Smrg	    SysError(ERROR_FORK);
4073d522f475Smrg#endif
4074d522f475Smrg	TRACE(("Forking...\n"));
4075d522f475Smrg	if ((screen->pid = fork()) == -1)
4076d522f475Smrg	    SysError(ERROR_FORK);
4077d522f475Smrg
4078d522f475Smrg	if (screen->pid == 0) {
4079d522f475Smrg#ifdef USE_USG_PTYS
408020d2c4d2Smrg	    int ptyfd = -1;
4081d522f475Smrg	    char *pty_name;
4082d522f475Smrg#endif
4083d522f475Smrg	    /*
4084d522f475Smrg	     * now in child process
4085d522f475Smrg	     */
4086d522f475Smrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__convex__) || defined(__SCO__) || defined(__QNX__)
4087d522f475Smrg	    int pgrp = setsid();	/* variable may not be used... */
4088d522f475Smrg#else
4089d522f475Smrg	    int pgrp = getpid();
4090d522f475Smrg#endif
4091d522f475Smrg	    TRACE_CHILD
4092d522f475Smrg
4093d522f475Smrg#ifdef USE_USG_PTYS
40940bd37d32Smrg#ifdef HAVE_SETPGID
40950bd37d32Smrg		setpgid(0, 0);
40960bd37d32Smrg#else
4097d522f475Smrg		setpgrp();
40980bd37d32Smrg#endif
40990bd37d32Smrg	    unlockpt(screen->respond);
4100913cc679Smrg	    TRACE_GET_TTYSIZE(screen->respond, "after unlockpt");
41010bd37d32Smrg	    if ((pty_name = ptsname(screen->respond)) == 0) {
41020bd37d32Smrg		SysError(ERROR_PTSNAME);
41030bd37d32Smrg	    } else if ((ptyfd = open(pty_name, O_RDWR)) < 0) {
41040bd37d32Smrg		SysError(ERROR_OPPTSNAME);
41050bd37d32Smrg	    }
4106d522f475Smrg#ifdef I_PUSH
41072e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ptem")) {
41080bd37d32Smrg		SysError(ERROR_PTEM);
41090bd37d32Smrg	    }
4110d522f475Smrg#if !defined(SVR4) && !(defined(SYSV) && defined(i386))
41110bd37d32Smrg	    else if (!x_getenv("CONSEM")
41122e4f8982Smrg		     && PUSH_FAILS(ptyfd, "consem")) {
41130bd37d32Smrg		SysError(ERROR_CONSEM);
41140bd37d32Smrg	    }
4115d522f475Smrg#endif /* !SVR4 */
41162e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ldterm")) {
41170bd37d32Smrg		SysError(ERROR_LDTERM);
41180bd37d32Smrg	    }
4119d522f475Smrg#ifdef SVR4			/* from Sony */
41202e4f8982Smrg	    else if (PUSH_FAILS(ptyfd, "ttcompat")) {
41210bd37d32Smrg		SysError(ERROR_TTCOMPAT);
41220bd37d32Smrg	    }
4123d522f475Smrg#endif /* SVR4 */
4124d522f475Smrg#endif /* I_PUSH */
41250bd37d32Smrg	    ttyfd = ptyfd;
4126d522f475Smrg#ifndef __MVS__
41270bd37d32Smrg	    close_fd(screen->respond);
4128d522f475Smrg#endif /* __MVS__ */
4129d522f475Smrg
4130d522f475Smrg#ifdef TTYSIZE_STRUCT
41310bd37d32Smrg	    /* tell tty how big window is */
4132d522f475Smrg#if OPT_TEK4014
41330bd37d32Smrg	    if (TEK4014_ACTIVE(xw)) {
4134913cc679Smrg		setup_winsize(ts, TDefaultRows, TDefaultCols,
4135913cc679Smrg			      TFullHeight(TekScreenOf(tekWidget)),
4136913cc679Smrg			      TFullWidth(TekScreenOf(tekWidget)));
41370bd37d32Smrg	    } else
4138d522f475Smrg#endif /* OPT_TEK4014 */
41390bd37d32Smrg	    {
4140913cc679Smrg		setup_winsize(ts, MaxRows(screen), MaxCols(screen),
4141913cc679Smrg			      FullHeight(screen), FullWidth(screen));
41420bd37d32Smrg	    }
4143913cc679Smrg	    trace_winsize(ts, "initial tty size");
4144d522f475Smrg#endif /* TTYSIZE_STRUCT */
4145d522f475Smrg
4146d522f475Smrg#endif /* USE_USG_PTYS */
4147d522f475Smrg
41480bd37d32Smrg	    (void) pgrp;	/* not all branches use this variable */
4149d522f475Smrg
4150d522f475Smrg#if OPT_PTY_HANDSHAKE		/* warning, goes for a long ways */
41510bd37d32Smrg	    if (resource.ptyHandshake) {
41520bd37d32Smrg		char *ptr;
4153d522f475Smrg
41540bd37d32Smrg		/* close parent's sides of the pipes */
41550bd37d32Smrg		close(cp_pipe[0]);
41560bd37d32Smrg		close(pc_pipe[1]);
41570bd37d32Smrg
41580bd37d32Smrg		/* Make sure that our sides of the pipes are not in the
41590bd37d32Smrg		 * 0, 1, 2 range so that we don't fight with stdin, out
41600bd37d32Smrg		 * or err.
41610bd37d32Smrg		 */
41620bd37d32Smrg		if (cp_pipe[1] <= 2) {
41630bd37d32Smrg		    if ((i = fcntl(cp_pipe[1], F_DUPFD, 3)) >= 0) {
41640bd37d32Smrg			IGNORE_RC(close(cp_pipe[1]));
41650bd37d32Smrg			cp_pipe[1] = i;
4166d522f475Smrg		    }
41670bd37d32Smrg		}
41680bd37d32Smrg		if (pc_pipe[0] <= 2) {
41690bd37d32Smrg		    if ((i = fcntl(pc_pipe[0], F_DUPFD, 3)) >= 0) {
41700bd37d32Smrg			IGNORE_RC(close(pc_pipe[0]));
41710bd37d32Smrg			pc_pipe[0] = i;
4172d522f475Smrg		    }
41730bd37d32Smrg		}
4174d522f475Smrg
41750bd37d32Smrg		/* we don't need the socket, or the pty master anymore */
41760bd37d32Smrg		close(ConnectionNumber(screen->display));
4177d522f475Smrg#ifndef __MVS__
4178894e0ac8Smrg		if (screen->respond >= 0)
4179894e0ac8Smrg		    close(screen->respond);
4180d522f475Smrg#endif /* __MVS__ */
4181d522f475Smrg
41820bd37d32Smrg		/* Now is the time to set up our process group and
41830bd37d32Smrg		 * open up the pty slave.
41840bd37d32Smrg		 */
4185d522f475Smrg#ifdef USE_SYSV_PGRP
4186d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION > 5)
41870bd37d32Smrg		IGNORE_RC(setsid());
4188d522f475Smrg#else
41890bd37d32Smrg		IGNORE_RC(setpgrp());
4190d522f475Smrg#endif
4191d522f475Smrg#endif /* USE_SYSV_PGRP */
4192d522f475Smrg
4193d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
41940bd37d32Smrg		qsetlogin(getlogin(), ttydev);
4195d522f475Smrg#endif
41960bd37d32Smrg		if (ttyfd >= 0) {
4197d522f475Smrg#ifdef __MVS__
41980bd37d32Smrg		    if (ttyGetAttr(ttyfd, &gio) == 0) {
41990bd37d32Smrg			gio.c_cflag &= ~(HUPCL | PARENB);
42000bd37d32Smrg			ttySetAttr(ttyfd, &gio);
42010bd37d32Smrg		    }
4202d522f475Smrg#else /* !__MVS__ */
42030bd37d32Smrg		    close_fd(ttyfd);
4204d522f475Smrg#endif /* __MVS__ */
42050bd37d32Smrg		}
4206d522f475Smrg
42070bd37d32Smrg		for (;;) {
420820d2c4d2Smrg#if USE_NO_DEV_TTY
42090bd37d32Smrg		    if (!no_dev_tty
42100bd37d32Smrg			&& (ttyfd = open("/dev/tty", O_RDWR)) >= 0) {
42110bd37d32Smrg			ioctl(ttyfd, TIOCNOTTY, (char *) NULL);
42120bd37d32Smrg			close_fd(ttyfd);
42130bd37d32Smrg		    }
421420d2c4d2Smrg#endif /* USE_NO_DEV_TTY */
4215d522f475Smrg#ifdef CSRG_BASED
42160bd37d32Smrg		    IGNORE_RC(revoke(ttydev));
4217d522f475Smrg#endif
42180bd37d32Smrg		    if ((ttyfd = open(ttydev, O_RDWR)) >= 0) {
4219913cc679Smrg			TRACE_GET_TTYSIZE(ttyfd, "after open");
42200bd37d32Smrg			TRACE_RC(i, SET_TTYSIZE(ttyfd, ts));
4221913cc679Smrg			TRACE_GET_TTYSIZE(ttyfd, "after SET_TTYSIZE fixup");
4222d522f475Smrg#if defined(CRAY) && defined(TCSETCTTY)
42230bd37d32Smrg			/* make /dev/tty work */
42240bd37d32Smrg			ioctl(ttyfd, TCSETCTTY, 0);
4225d522f475Smrg#endif
4226d522f475Smrg#if ((defined(__GLIBC__) && defined(__FreeBSD_kernel__)) || defined(__GNU__)) && defined(TIOCSCTTY)
42270bd37d32Smrg			/* make /dev/tty work */
42280bd37d32Smrg			ioctl(ttyfd, TIOCSCTTY, 0);
4229d522f475Smrg#endif
4230d522f475Smrg#ifdef USE_SYSV_PGRP
42310bd37d32Smrg			/* We need to make sure that we are actually
42320bd37d32Smrg			 * the process group leader for the pty.  If
42330bd37d32Smrg			 * we are, then we should now be able to open
42340bd37d32Smrg			 * /dev/tty.
42350bd37d32Smrg			 */
42360bd37d32Smrg			if ((i = open("/dev/tty", O_RDWR)) >= 0) {
42370bd37d32Smrg			    /* success! */
42380bd37d32Smrg			    close(i);
4239d522f475Smrg			    break;
4240d522f475Smrg			}
42410bd37d32Smrg#else /* USE_SYSV_PGRP */
42420bd37d32Smrg			break;
42430bd37d32Smrg#endif /* USE_SYSV_PGRP */
42440bd37d32Smrg		    }
42450bd37d32Smrg		    perror("open ttydev");
4246d522f475Smrg#ifdef TIOCSCTTY
42470bd37d32Smrg		    ioctl(ttyfd, TIOCSCTTY, 0);
4248d522f475Smrg#endif
42490bd37d32Smrg		    /* let our master know that the open failed */
42500bd37d32Smrg		    handshake.status = PTY_BAD;
42510bd37d32Smrg		    handshake.error = errno;
4252f2e35a3aSmrg		    copy_handshake(handshake, ttydev);
42530bd37d32Smrg		    TRACE_HANDSHAKE("writing", &handshake);
42540bd37d32Smrg		    IGNORE_RC(write(cp_pipe[1],
42550bd37d32Smrg				    (const char *) &handshake,
42560bd37d32Smrg				    sizeof(handshake)));
4257d522f475Smrg
42580bd37d32Smrg		    /* get reply from parent */
42590bd37d32Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
42600bd37d32Smrg				   sizeof(handshake));
42610bd37d32Smrg		    if (i <= 0) {
42620bd37d32Smrg			/* parent terminated */
42630bd37d32Smrg			exit(1);
4264d522f475Smrg		    }
4265d522f475Smrg
42660bd37d32Smrg		    if (handshake.status == PTY_NOMORE) {
42670bd37d32Smrg			/* No more ptys, let's shutdown. */
42680bd37d32Smrg			exit(1);
4269d522f475Smrg		    }
42700bd37d32Smrg
42710bd37d32Smrg		    /* We have a new pty to try */
42720bd37d32Smrg		    if (ttyfd >= 0)
42730bd37d32Smrg			close(ttyfd);
42740bd37d32Smrg		    free(ttydev);
4275f2e35a3aSmrg		    handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
42760bd37d32Smrg		    ttydev = x_strdup(handshake.buffer);
4277d522f475Smrg		}
4278d522f475Smrg
42790bd37d32Smrg		/* use the same tty name that everyone else will use
42800bd37d32Smrg		 * (from ttyname)
42810bd37d32Smrg		 */
42820bd37d32Smrg		if ((ptr = ttyname(ttyfd)) != 0) {
42830bd37d32Smrg		    free(ttydev);
42840bd37d32Smrg		    ttydev = x_strdup(ptr);
42850bd37d32Smrg		}
42860bd37d32Smrg	    }
42870bd37d32Smrg#endif /* OPT_PTY_HANDSHAKE -- from near fork */
4288d522f475Smrg
4289d522f475Smrg	    set_pty_permissions(screen->uid,
4290913cc679Smrg				(unsigned) screen->gid,
4291d522f475Smrg				(resource.messages
4292d522f475Smrg				 ? 0622U
4293d522f475Smrg				 : 0600U));
4294d522f475Smrg
4295d522f475Smrg	    /*
4296d522f475Smrg	     * set up the tty modes
4297d522f475Smrg	     */
4298d522f475Smrg	    {
4299d522f475Smrg#ifdef TERMIO_STRUCT
4300d522f475Smrg#if defined(umips) || defined(CRAY) || defined(linux)
4301d522f475Smrg		/* If the control tty had its modes screwed around with,
4302d522f475Smrg		   eg. by lineedit in the shell, or emacs, etc. then tio
4303d522f475Smrg		   will have bad values.  Let's just get termio from the
4304d522f475Smrg		   new tty and tailor it.  */
4305d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4306d522f475Smrg		    SysError(ERROR_TIOCGETP);
4307d522f475Smrg		tio.c_lflag |= ECHOE;
4308d522f475Smrg#endif /* umips */
4309d522f475Smrg		/* Now is also the time to change the modes of the
4310d522f475Smrg		 * child pty.
4311d522f475Smrg		 */
4312d522f475Smrg		/* input: nl->nl, don't ignore cr, cr->nl */
431320d2c4d2Smrg		UIntClr(tio.c_iflag, (INLCR | IGNCR));
4314d522f475Smrg		tio.c_iflag |= ICRNL;
43150bd37d32Smrg#if OPT_WIDE_CHARS && defined(IUTF8)
4316d522f475Smrg#if OPT_LUIT_PROG
4317d522f475Smrg		if (command_to_exec_with_luit == 0)
4318d522f475Smrg#endif
4319d522f475Smrg		    if (screen->utf8_mode)
4320d522f475Smrg			tio.c_iflag |= IUTF8;
4321d522f475Smrg#endif
4322f2e35a3aSmrg		/* output: cr->cr, nl is not return, no delays, ln->cr/nl */
4323d522f475Smrg#ifndef USE_POSIX_TERMIOS
432420d2c4d2Smrg		UIntClr(tio.c_oflag,
432520d2c4d2Smrg			(OCRNL
432620d2c4d2Smrg			 | ONLRET
432720d2c4d2Smrg			 | NLDLY
432820d2c4d2Smrg			 | CRDLY
432920d2c4d2Smrg			 | TABDLY
433020d2c4d2Smrg			 | BSDLY
433120d2c4d2Smrg			 | VTDLY
433220d2c4d2Smrg			 | FFDLY));
4333d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4334f2e35a3aSmrg		tio.c_oflag |= D_TIO_FLAGS;
4335d522f475Smrg#ifndef USE_POSIX_TERMIOS
4336d522f475Smrg# if defined(Lynx) && !defined(CBAUD)
4337d522f475Smrg#  define CBAUD V_CBAUD
4338d522f475Smrg# endif
433920d2c4d2Smrg		UIntClr(tio.c_cflag, CBAUD);
4340d522f475Smrg#ifdef BAUD_0
4341d522f475Smrg		/* baud rate is 0 (don't care) */
4342d522f475Smrg#elif defined(HAVE_TERMIO_C_ISPEED)
43432e4f8982Smrg		tio.c_ispeed = tio.c_ospeed = line_speed;
4344d522f475Smrg#else /* !BAUD_0 */
43452e4f8982Smrg		tio.c_cflag |= line_speed;
4346d522f475Smrg#endif /* !BAUD_0 */
4347d522f475Smrg#else /* USE_POSIX_TERMIOS */
43482e4f8982Smrg		cfsetispeed(&tio, line_speed);
43492e4f8982Smrg		cfsetospeed(&tio, line_speed);
4350d522f475Smrg#ifdef __MVS__
4351d522f475Smrg		/* turn off bits that can't be set from the slave side */
4352d522f475Smrg		tio.c_cflag &= ~(PACKET | PKT3270 | PTU3270 | PKTXTND);
4353d522f475Smrg#endif /* __MVS__ */
4354d522f475Smrg		/* Clear CLOCAL so that SIGHUP is sent to us
4355d522f475Smrg		   when the xterm ends */
43562e4f8982Smrg		tio.c_cflag &= (unsigned) ~CLOCAL;
4357d522f475Smrg#endif /* USE_POSIX_TERMIOS */
4358d522f475Smrg		/* enable signals, canonical processing (erase, kill, etc),
4359d522f475Smrg		 * echo
4360d522f475Smrg		 */
4361d522f475Smrg		tio.c_lflag |= ISIG | ICANON | ECHO | ECHOE | ECHOK;
4362d522f475Smrg#ifdef ECHOKE
4363d522f475Smrg		tio.c_lflag |= ECHOKE | IEXTEN;
4364d522f475Smrg#endif
4365d522f475Smrg#ifdef ECHOCTL
4366d522f475Smrg		tio.c_lflag |= ECHOCTL | IEXTEN;
4367d522f475Smrg#endif
4368f2e35a3aSmrg		for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
4369d522f475Smrg		    if (validTtyChar(tio, nn)) {
4370f2e35a3aSmrg			int sysMode = ttyChars[nn].sysMode;
4371d522f475Smrg#ifdef __MVS__
4372d522f475Smrg			if (tio.c_cc[sysMode] != 0) {
4373d522f475Smrg			    switch (sysMode) {
4374d522f475Smrg			    case VEOL:
4375d522f475Smrg			    case VEOF:
4376d522f475Smrg				continue;
4377d522f475Smrg			    }
4378d522f475Smrg			}
4379d522f475Smrg#endif
4380f2e35a3aSmrg			tio.c_cc[sysMode] = (cc_t) ttyChars[nn].myDefault;
4381d522f475Smrg		    }
4382d522f475Smrg		}
4383d522f475Smrg
4384d522f475Smrg		if (override_tty_modes) {
4385f2e35a3aSmrg		    TRACE(("applying termios ttyModes\n"));
4386f2e35a3aSmrg		    for (nn = 0; nn < XtNumber(ttyChars); ++nn) {
4387d522f475Smrg			if (validTtyChar(tio, nn)) {
4388f2e35a3aSmrg			    TMODE(ttyChars[nn].myMode,
4389f2e35a3aSmrg				  tio.c_cc[ttyChars[nn].sysMode]);
4390f2e35a3aSmrg			} else if (isTabMode(nn)) {
4391f2e35a3aSmrg			    unsigned tmp = (unsigned) tio.c_oflag;
4392f2e35a3aSmrg			    tmp = tmp & (unsigned) ~TABDLY;
4393f2e35a3aSmrg			    tmp |= (unsigned) ttyModes[ttyChars[nn].myMode].value;
4394f2e35a3aSmrg			    tio.c_oflag = tmp;
4395d522f475Smrg			}
4396d522f475Smrg		    }
4397d522f475Smrg#ifdef HAS_LTCHARS
4398d522f475Smrg		    /* both SYSV and BSD have ltchars */
4399d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4400d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4401d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4402d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4403d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4404d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4405d522f475Smrg#endif
4406d522f475Smrg		}
4407d522f475Smrg#ifdef HAS_LTCHARS
4408d522f475Smrg#ifdef __hpux
4409d522f475Smrg		/* ioctl chokes when the "reserved" process group controls
4410d522f475Smrg		 * are not set to _POSIX_VDISABLE */
4411913cc679Smrg		ltc.t_rprntc = _POSIX_VDISABLE;
4412913cc679Smrg		ltc.t_rprntc = _POSIX_VDISABLE;
4413913cc679Smrg		ltc.t_flushc = _POSIX_VDISABLE;
4414913cc679Smrg		ltc.t_werasc = _POSIX_VDISABLE;
4415913cc679Smrg		ltc.t_lnextc = _POSIX_VDISABLE;
4416d522f475Smrg#endif /* __hpux */
4417d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, &ltc) == -1)
4418d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4419d522f475Smrg#endif /* HAS_LTCHARS */
4420d522f475Smrg#ifdef TIOCLSET
4421d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4422d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4423d522f475Smrg#endif /* TIOCLSET */
4424d522f475Smrg		if (ttySetAttr(ttyfd, &tio) == -1)
4425d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4426d522f475Smrg
4427d522f475Smrg		/* ignore errors here - some platforms don't work */
442820d2c4d2Smrg		UIntClr(tio.c_cflag, CSIZE);
4429d522f475Smrg		if (screen->input_eight_bits)
4430d522f475Smrg		    tio.c_cflag |= CS8;
4431d522f475Smrg		else
4432d522f475Smrg		    tio.c_cflag |= CS7;
4433d522f475Smrg		(void) ttySetAttr(ttyfd, &tio);
4434d522f475Smrg
4435d522f475Smrg#else /* !TERMIO_STRUCT */
4436d522f475Smrg		sg.sg_flags &= ~(ALLDELAY | XTABS | CBREAK | RAW);
4437d522f475Smrg		sg.sg_flags |= ECHO | CRMOD;
4438d522f475Smrg		/* make sure speed is set on pty so that editors work right */
44392e4f8982Smrg		sg.sg_ispeed = line_speed;
44402e4f8982Smrg		sg.sg_ospeed = line_speed;
4441d522f475Smrg		/* reset t_brkc to default value */
4442d522f475Smrg		tc.t_brkc = -1;
4443d522f475Smrg#ifdef LPASS8
4444d522f475Smrg		if (screen->input_eight_bits)
4445d522f475Smrg		    lmode |= LPASS8;
4446d522f475Smrg		else
4447d522f475Smrg		    lmode &= ~(LPASS8);
4448d522f475Smrg#endif
4449d522f475Smrg#ifdef sony
4450d522f475Smrg		jmode &= ~KM_KANJI;
4451d522f475Smrg#endif /* sony */
4452d522f475Smrg
4453d522f475Smrg		ltc = d_ltc;
4454d522f475Smrg
4455d522f475Smrg		if (override_tty_modes) {
4456f2e35a3aSmrg		    TRACE(("applying sgtty ttyModes\n"));
4457d522f475Smrg		    TMODE(XTTYMODE_intr, tc.t_intrc);
4458d522f475Smrg		    TMODE(XTTYMODE_quit, tc.t_quitc);
4459d522f475Smrg		    TMODE(XTTYMODE_erase, sg.sg_erase);
4460d522f475Smrg		    TMODE(XTTYMODE_kill, sg.sg_kill);
4461d522f475Smrg		    TMODE(XTTYMODE_eof, tc.t_eofc);
4462d522f475Smrg		    TMODE(XTTYMODE_start, tc.t_startc);
4463d522f475Smrg		    TMODE(XTTYMODE_stop, tc.t_stopc);
4464d522f475Smrg		    TMODE(XTTYMODE_brk, tc.t_brkc);
4465d522f475Smrg		    /* both SYSV and BSD have ltchars */
4466d522f475Smrg		    TMODE(XTTYMODE_susp, ltc.t_suspc);
4467d522f475Smrg		    TMODE(XTTYMODE_dsusp, ltc.t_dsuspc);
4468d522f475Smrg		    TMODE(XTTYMODE_rprnt, ltc.t_rprntc);
4469d522f475Smrg		    TMODE(XTTYMODE_flush, ltc.t_flushc);
4470d522f475Smrg		    TMODE(XTTYMODE_weras, ltc.t_werasc);
4471d522f475Smrg		    TMODE(XTTYMODE_lnext, ltc.t_lnextc);
4472f2e35a3aSmrg		    if (ttyModes[XTTYMODE_tabs].set
4473f2e35a3aSmrg			|| ttyModes[XTTYMODE__tabs].set) {
4474f2e35a3aSmrg			sg.sg_flags &= ~XTABS;
4475f2e35a3aSmrg			if (ttyModes[XTTYMODE__tabs].set.set)
4476f2e35a3aSmrg			    sg.sg_flags |= XTABS;
4477f2e35a3aSmrg		    }
4478d522f475Smrg		}
4479d522f475Smrg
4480d522f475Smrg		if (ioctl(ttyfd, TIOCSETP, (char *) &sg) == -1)
4481d522f475Smrg		    HsSysError(ERROR_TIOCSETP);
4482d522f475Smrg		if (ioctl(ttyfd, TIOCSETC, (char *) &tc) == -1)
4483d522f475Smrg		    HsSysError(ERROR_TIOCSETC);
4484d522f475Smrg		if (ioctl(ttyfd, TIOCSETD, (char *) &discipline) == -1)
4485d522f475Smrg		    HsSysError(ERROR_TIOCSETD);
4486d522f475Smrg		if (ioctl(ttyfd, TIOCSLTC, (char *) &ltc) == -1)
4487d522f475Smrg		    HsSysError(ERROR_TIOCSLTC);
4488d522f475Smrg		if (ioctl(ttyfd, TIOCLSET, (char *) &lmode) == -1)
4489d522f475Smrg		    HsSysError(ERROR_TIOCLSET);
4490d522f475Smrg#ifdef sony
4491d522f475Smrg		if (ioctl(ttyfd, TIOCKSET, (char *) &jmode) == -1)
4492d522f475Smrg		    HsSysError(ERROR_TIOCKSET);
4493d522f475Smrg		if (ioctl(ttyfd, TIOCKSETC, (char *) &jtc) == -1)
4494d522f475Smrg		    HsSysError(ERROR_TIOCKSETC);
4495d522f475Smrg#endif /* sony */
4496d522f475Smrg#endif /* TERMIO_STRUCT */
4497d522f475Smrg#if defined(TIOCCONS) || defined(SRIOCSREDIR)
4498d522f475Smrg		if (Console) {
4499d522f475Smrg#ifdef TIOCCONS
4500d522f475Smrg		    int on = 1;
4501d522f475Smrg		    if (ioctl(ttyfd, TIOCCONS, (char *) &on) == -1)
45020bd37d32Smrg			xtermPerror("cannot open console");
4503d522f475Smrg#endif
4504d522f475Smrg#ifdef SRIOCSREDIR
4505d522f475Smrg		    int fd = open("/dev/console", O_RDWR);
4506d522f475Smrg		    if (fd == -1 || ioctl(fd, SRIOCSREDIR, ttyfd) == -1)
45070bd37d32Smrg			xtermPerror("cannot open console");
450820d2c4d2Smrg		    IGNORE_RC(close(fd));
4509d522f475Smrg#endif
4510d522f475Smrg		}
4511d522f475Smrg#endif /* TIOCCONS */
4512d522f475Smrg	    }
4513d522f475Smrg
4514d522f475Smrg	    signal(SIGCHLD, SIG_DFL);
4515d522f475Smrg#ifdef USE_SYSV_SIGHUP
4516d522f475Smrg	    /* watch out for extra shells (I don't understand either) */
4517d522f475Smrg	    signal(SIGHUP, SIG_DFL);
4518d522f475Smrg#else
4519d522f475Smrg	    signal(SIGHUP, SIG_IGN);
4520d522f475Smrg#endif
4521d522f475Smrg	    /* restore various signals to their defaults */
4522d522f475Smrg	    signal(SIGINT, SIG_DFL);
4523d522f475Smrg	    signal(SIGQUIT, SIG_DFL);
4524d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4525d522f475Smrg
4526d522f475Smrg	    /*
4527d522f475Smrg	     * If we're not asked to let the parent process set the terminal's
4528d522f475Smrg	     * erase mode, or if we had the ttyModes erase resource, then set
4529d522f475Smrg	     * the terminal's erase mode from our best guess.
4530d522f475Smrg	     */
4531d522f475Smrg#if OPT_INITIAL_ERASE
4532d522f475Smrg	    TRACE(("check if we should set erase to %d:%s\n\tptyInitialErase:%d,\n\toveride_tty_modes:%d,\n\tXTTYMODE_erase:%d\n",
4533d522f475Smrg		   initial_erase,
4534d522f475Smrg		   setInitialErase ? "YES" : "NO",
4535d522f475Smrg		   resource.ptyInitialErase,
4536d522f475Smrg		   override_tty_modes,
4537f2e35a3aSmrg		   ttyModes[XTTYMODE_erase].set));
4538d522f475Smrg	    if (setInitialErase) {
4539d522f475Smrg#if OPT_TRACE
4540d522f475Smrg		int old_erase;
4541d522f475Smrg#endif
4542d522f475Smrg#ifdef TERMIO_STRUCT
4543d522f475Smrg		if (ttyGetAttr(ttyfd, &tio) == -1)
4544d522f475Smrg		    tio = d_tio;
4545d522f475Smrg#if OPT_TRACE
4546d522f475Smrg		old_erase = tio.c_cc[VERASE];
4547d522f475Smrg#endif
45480bd37d32Smrg		tio.c_cc[VERASE] = (cc_t) initial_erase;
454920d2c4d2Smrg		TRACE_RC(rc, ttySetAttr(ttyfd, &tio));
4550d522f475Smrg#else /* !TERMIO_STRUCT */
4551d522f475Smrg		if (ioctl(ttyfd, TIOCGETP, (char *) &sg) == -1)
4552d522f475Smrg		    sg = d_sg;
4553d522f475Smrg#if OPT_TRACE
4554d522f475Smrg		old_erase = sg.sg_erase;
4555d522f475Smrg#endif
4556d522f475Smrg		sg.sg_erase = initial_erase;
4557d522f475Smrg		rc = ioctl(ttyfd, TIOCSETP, (char *) &sg);
4558d522f475Smrg#endif /* TERMIO_STRUCT */
4559d522f475Smrg		TRACE(("%s setting erase to %d (was %d)\n",
4560d522f475Smrg		       rc ? "FAIL" : "OK", initial_erase, old_erase));
4561d522f475Smrg	    }
4562d522f475Smrg#endif
4563d522f475Smrg
4564d522f475Smrg	    xtermCopyEnv(environ);
4565d522f475Smrg
45660bd37d32Smrg	    /*
45670bd37d32Smrg	     * standards.freedesktop.org/startup-notification-spec/
45680bd37d32Smrg	     * notes that this variable is used when a "reliable" mechanism is
45690bd37d32Smrg	     * not available; in practice it must be unset to avoid confusing
45700bd37d32Smrg	     * GTK applications.
45710bd37d32Smrg	     */
45720bd37d32Smrg	    xtermUnsetenv("DESKTOP_STARTUP_ID");
4573e0a2b6dfSmrg	    /*
4574e0a2b6dfSmrg	     * We set this temporarily to work around poor design of Xcursor.
4575e0a2b6dfSmrg	     * Unset it here to avoid confusion.
4576e0a2b6dfSmrg	     */
4577e0a2b6dfSmrg	    xtermUnsetenv("XCURSOR_PATH");
45780bd37d32Smrg
4579a1f3da82Smrg	    xtermSetenv("TERM", resource.term_name);
4580a1f3da82Smrg	    if (!resource.term_name)
458120d2c4d2Smrg		*get_tcap_buffer(xw) = 0;
4582d522f475Smrg
4583d522f475Smrg	    sprintf(buf, "%lu",
4584d522f475Smrg		    ((unsigned long) XtWindow(SHELL_OF(CURRENT_EMU()))));
4585d522f475Smrg	    xtermSetenv("WINDOWID", buf);
4586d522f475Smrg
4587d522f475Smrg	    /* put the display into the environment of the shell */
4588d522f475Smrg	    xtermSetenv("DISPLAY", XDisplayString(screen->display));
4589d522f475Smrg
4590d522f475Smrg	    xtermSetenv("XTERM_VERSION", xtermVersion());
4591d522f475Smrg	    xtermSetenv("XTERM_LOCALE", xtermEnvLocale());
4592d522f475Smrg
4593e39b573cSmrg	    /*
4594e39b573cSmrg	     * For debugging only, add environment variables that can be used
4595e39b573cSmrg	     * in scripts to selectively kill xterm's parent or child
4596e39b573cSmrg	     * processes.
4597e39b573cSmrg	     */
4598e39b573cSmrg#if OPT_TRACE
4599e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) xterm_parent);
4600e39b573cSmrg	    xtermSetenv("XTERM_PARENT", buf);
4601e39b573cSmrg	    sprintf(buf, "%lu", (unsigned long) getpid());
4602e39b573cSmrg	    xtermSetenv("XTERM_CHILD", buf);
4603e39b573cSmrg#endif
4604e39b573cSmrg
4605d522f475Smrg	    signal(SIGTERM, SIG_DFL);
4606d522f475Smrg
4607d522f475Smrg	    /* this is the time to go and set up stdin, out, and err
4608d522f475Smrg	     */
4609d522f475Smrg	    {
4610d522f475Smrg#if defined(CRAY) && (OSMAJORVERSION >= 6)
4611d522f475Smrg		close_fd(ttyfd);
4612d522f475Smrg
461320d2c4d2Smrg		IGNORE_RC(close(0));
4614d522f475Smrg
4615d522f475Smrg		if (open("/dev/tty", O_RDWR)) {
4616d522f475Smrg		    SysError(ERROR_OPDEVTTY);
4617d522f475Smrg		}
461820d2c4d2Smrg		IGNORE_RC(close(1));
461920d2c4d2Smrg		IGNORE_RC(close(2));
4620d522f475Smrg		dup(0);
4621d522f475Smrg		dup(0);
4622d522f475Smrg#else
4623d522f475Smrg		/* dup the tty */
4624d522f475Smrg		for (i = 0; i <= 2; i++)
4625d522f475Smrg		    if (i != ttyfd) {
462620d2c4d2Smrg			IGNORE_RC(close(i));
462720d2c4d2Smrg			IGNORE_RC(dup(ttyfd));
4628d522f475Smrg		    }
4629d522f475Smrg#ifndef ATT
4630d522f475Smrg		/* and close the tty */
4631d522f475Smrg		if (ttyfd > 2)
4632d522f475Smrg		    close_fd(ttyfd);
4633d522f475Smrg#endif
4634d522f475Smrg#endif /* CRAY */
4635d522f475Smrg	    }
4636d522f475Smrg
4637d522f475Smrg#if !defined(USE_SYSV_PGRP)
4638d522f475Smrg#ifdef TIOCSCTTY
4639d522f475Smrg	    setsid();
4640d522f475Smrg	    ioctl(0, TIOCSCTTY, 0);
4641d522f475Smrg#endif
4642d522f475Smrg	    ioctl(0, TIOCSPGRP, (char *) &pgrp);
4643d522f475Smrg	    setpgrp(0, 0);
4644d522f475Smrg	    close(open(ttydev, O_WRONLY));
4645d522f475Smrg	    setpgrp(0, pgrp);
4646d522f475Smrg#if defined(__QNX__)
4647d522f475Smrg	    tcsetpgrp(0, pgrp /*setsid() */ );
4648d522f475Smrg#endif
4649d522f475Smrg#endif /* !USE_SYSV_PGRP */
4650d522f475Smrg
4651d522f475Smrg#ifdef Lynx
4652d522f475Smrg	    {
4653d522f475Smrg		TERMIO_STRUCT t;
4654d522f475Smrg		if (ttyGetAttr(0, &t) >= 0) {
4655d522f475Smrg		    /* this gets lost somewhere on our way... */
4656d522f475Smrg		    t.c_oflag |= OPOST;
4657d522f475Smrg		    ttySetAttr(0, &t);
4658d522f475Smrg		}
4659d522f475Smrg	    }
4660d522f475Smrg#endif
4661d522f475Smrg
4662d522f475Smrg#ifdef HAVE_UTMP
4663d522f475Smrg	    login_name = NULL;
46640bd37d32Smrg	    if (x_getpwuid(screen->uid, &pw)) {
46650bd37d32Smrg		login_name = x_getlogin(screen->uid, &pw);
4666d522f475Smrg	    }
4667d522f475Smrg	    if (login_name != NULL) {
4668d522f475Smrg		xtermSetenv("LOGNAME", login_name);	/* for POSIX */
4669d522f475Smrg	    }
4670d522f475Smrg#ifndef USE_UTEMPTER
4671d522f475Smrg#ifdef USE_UTMP_SETGID
4672d522f475Smrg	    setEffectiveGroup(save_egid);
4673d522f475Smrg	    TRACE_IDS;
4674d522f475Smrg#endif
4675d522f475Smrg#ifdef USE_SYSV_UTMP
4676d522f475Smrg	    /* Set up our utmp entry now.  We need to do it here
4677d522f475Smrg	     * for the following reasons:
4678d522f475Smrg	     *   - It needs to have our correct process id (for
4679d522f475Smrg	     *     login).
4680d522f475Smrg	     *   - If our parent was to set it after the fork(),
4681d522f475Smrg	     *     it might make it out before we need it.
4682d522f475Smrg	     *   - We need to do it before we go and change our
4683d522f475Smrg	     *     user and group id's.
4684d522f475Smrg	     */
4685d522f475Smrg	    (void) call_setutent();
4686d522f475Smrg	    init_utmp(DEAD_PROCESS, &utmp);
4687d522f475Smrg
4688d522f475Smrg	    /* position to entry in utmp file */
4689d522f475Smrg	    /* Test return value: beware of entries left behind: PSz 9 Mar 00 */
469020d2c4d2Smrg	    utret = find_utmp(&utmp);
469120d2c4d2Smrg	    if (utret == 0) {
4692d522f475Smrg		(void) call_setutent();
4693d522f475Smrg		init_utmp(USER_PROCESS, &utmp);
469420d2c4d2Smrg		utret = find_utmp(&utmp);
469520d2c4d2Smrg		if (utret == 0) {
4696d522f475Smrg		    (void) call_setutent();
4697d522f475Smrg		}
4698d522f475Smrg	    }
4699d522f475Smrg#if OPT_TRACE
4700d522f475Smrg	    if (!utret)
4701d522f475Smrg		TRACE(("getutid: NULL\n"));
4702d522f475Smrg	    else
47030bd37d32Smrg		TRACE(("getutid: pid=%d type=%d user=%s line=%.*s id=%.*s\n",
470420d2c4d2Smrg		       (int) utret->ut_pid, utret->ut_type, utret->ut_user,
47050bd37d32Smrg		       (int) sizeof(utret->ut_line), utret->ut_line,
47060bd37d32Smrg		       (int) sizeof(utret->ut_id), utret->ut_id));
4707d522f475Smrg#endif
4708d522f475Smrg
4709d522f475Smrg	    /* set up the new entry */
4710d522f475Smrg	    utmp.ut_type = USER_PROCESS;
4711d522f475Smrg#ifdef HAVE_UTMP_UT_XSTATUS
4712d522f475Smrg	    utmp.ut_xstatus = 2;
4713d522f475Smrg#endif
4714894e0ac8Smrg	    copy_filled(utmp.ut_user,
4715894e0ac8Smrg			(login_name != NULL) ? login_name : "????",
4716894e0ac8Smrg			sizeof(utmp.ut_user));
4717d522f475Smrg	    /* why are we copying this string again?  (see above) */
4718894e0ac8Smrg	    copy_filled(utmp.ut_id, my_utmp_id(ttydev), sizeof(utmp.ut_id));
4719894e0ac8Smrg	    copy_filled(utmp.ut_line,
4720894e0ac8Smrg			my_pty_name(ttydev), sizeof(utmp.ut_line));
4721d522f475Smrg
4722d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4723d522f475Smrg	    SetUtmpHost(utmp.ut_host, screen);
4724d522f475Smrg#endif
4725d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4726d522f475Smrg	    SetUtmpSysLen(utmp);
4727d522f475Smrg#endif
4728d522f475Smrg
4729894e0ac8Smrg	    copy_filled(utmp.ut_name,
4730894e0ac8Smrg			(login_name) ? login_name : "????",
4731894e0ac8Smrg			sizeof(utmp.ut_name));
4732d522f475Smrg
4733d522f475Smrg	    utmp.ut_pid = getpid();
4734d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
4735d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
4736d522f475Smrg	    utmp.ut_session = getsid(0);
4737d522f475Smrg#endif
4738d522f475Smrg	    utmp.ut_xtime = time((time_t *) 0);
4739d522f475Smrg	    utmp.ut_tv.tv_usec = 0;
4740d522f475Smrg#else
4741d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
4742d522f475Smrg#endif
4743d522f475Smrg
4744d522f475Smrg	    /* write out the entry */
4745d522f475Smrg	    if (!resource.utmpInhibit) {
4746d522f475Smrg		errno = 0;
4747d522f475Smrg		call_pututline(&utmp);
47480bd37d32Smrg		TRACE(("pututline: id %.*s, line %.*s, pid %ld, errno %d %s\n",
47490bd37d32Smrg		       (int) sizeof(utmp.ut_id), utmp.ut_id,
47500bd37d32Smrg		       (int) sizeof(utmp.ut_line), utmp.ut_line,
4751d522f475Smrg		       (long) utmp.ut_pid,
4752d522f475Smrg		       errno, (errno != 0) ? strerror(errno) : ""));
4753d522f475Smrg	    }
4754d522f475Smrg#ifdef WTMP
4755d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
4756d522f475Smrg	    if (xw->misc.login_shell)
4757d522f475Smrg		updwtmpx(WTMPX_FILE, &utmp);
4758d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
4759d522f475Smrg	    if (xw->misc.login_shell)
4760d522f475Smrg		call_updwtmp(etc_wtmp, &utmp);
4761d522f475Smrg#else
4762d522f475Smrg	    if (xw->misc.login_shell &&
4763d522f475Smrg		(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
47640bd37d32Smrg		IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4765d522f475Smrg		close(i);
4766d522f475Smrg	    }
4767d522f475Smrg#endif
4768d522f475Smrg#endif
4769d522f475Smrg	    /* close the file */
4770d522f475Smrg	    (void) call_endutent();
4771d522f475Smrg
4772d522f475Smrg#else /* USE_SYSV_UTMP */
4773d522f475Smrg	    /* We can now get our ttyslot!  We can also set the initial
4774d522f475Smrg	     * utmp entry.
4775d522f475Smrg	     */
4776d522f475Smrg	    tslot = ttyslot();
4777d522f475Smrg	    added_utmp_entry = False;
4778d522f475Smrg	    {
47790bd37d32Smrg		if (tslot > 0 && OkPasswd(&pw) && !resource.utmpInhibit &&
4780d522f475Smrg		    (i = open(etc_utmp, O_WRONLY)) >= 0) {
4781956cc18dSsnj		    memset(&utmp, 0, sizeof(utmp));
4782894e0ac8Smrg		    copy_filled(utmp.ut_line,
4783894e0ac8Smrg				my_pty_name(ttydev),
4784894e0ac8Smrg				sizeof(utmp.ut_line));
4785894e0ac8Smrg		    copy_filled(utmp.ut_name, login_name,
4786894e0ac8Smrg				sizeof(utmp.ut_name));
4787d522f475Smrg#ifdef HAVE_UTMP_UT_HOST
4788d522f475Smrg		    SetUtmpHost(utmp.ut_host, screen);
4789d522f475Smrg#endif
4790d522f475Smrg#ifdef HAVE_UTMP_UT_SYSLEN
4791d522f475Smrg		    SetUtmpSysLen(utmp);
4792d522f475Smrg#endif
4793d522f475Smrg
4794d522f475Smrg		    utmp.ut_time = time((time_t *) 0);
4795d522f475Smrg		    lseek(i, (long) (tslot * sizeof(utmp)), 0);
47960bd37d32Smrg		    IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4797d522f475Smrg		    close(i);
4798d522f475Smrg		    added_utmp_entry = True;
4799d522f475Smrg#if defined(WTMP)
4800d522f475Smrg		    if (xw->misc.login_shell &&
4801d522f475Smrg			(i = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
4802d522f475Smrg			int status;
4803d522f475Smrg			status = write(i, (char *) &utmp, sizeof(utmp));
4804d522f475Smrg			status = close(i);
4805d522f475Smrg		    }
4806d522f475Smrg#elif defined(MNX_LASTLOG)
4807d522f475Smrg		    if (xw->misc.login_shell &&
4808d522f475Smrg			(i = open(_U_LASTLOG, O_WRONLY)) >= 0) {
4809d522f475Smrg			lseek(i, (long) (screen->uid *
4810d522f475Smrg					 sizeof(utmp)), 0);
48110bd37d32Smrg			IGNORE_RC(write(i, (char *) &utmp, sizeof(utmp)));
4812d522f475Smrg			close(i);
4813d522f475Smrg		    }
4814d522f475Smrg#endif /* WTMP or MNX_LASTLOG */
4815d522f475Smrg		} else
4816d522f475Smrg		    tslot = -tslot;
4817d522f475Smrg	    }
4818d522f475Smrg
4819d522f475Smrg	    /* Let's pass our ttyslot to our parent so that it can
4820d522f475Smrg	     * clean up after us.
4821d522f475Smrg	     */
4822d522f475Smrg#if OPT_PTY_HANDSHAKE
4823d522f475Smrg	    if (resource.ptyHandshake) {
4824d522f475Smrg		handshake.tty_slot = tslot;
4825d522f475Smrg	    }
4826d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4827d522f475Smrg#endif /* USE_SYSV_UTMP */
4828d522f475Smrg
4829d522f475Smrg#ifdef USE_LASTLOGX
4830d522f475Smrg	    if (xw->misc.login_shell) {
4831956cc18dSsnj		memset(&lastlogx, 0, sizeof(lastlogx));
4832f2e35a3aSmrg		copy_filled(lastlogx.ll_line,
4833f2e35a3aSmrg			    my_pty_name(ttydev),
4834f2e35a3aSmrg			    sizeof(lastlogx.ll_line));
4835d522f475Smrg		X_GETTIMEOFDAY(&lastlogx.ll_tv);
4836d522f475Smrg		SetUtmpHost(lastlogx.ll_host, screen);
4837d522f475Smrg		updlastlogx(_PATH_LASTLOGX, screen->uid, &lastlogx);
4838d522f475Smrg	    }
4839d522f475Smrg#endif
4840d522f475Smrg
4841d522f475Smrg#ifdef USE_LASTLOG
4842d522f475Smrg	    if (xw->misc.login_shell &&
4843d522f475Smrg		(i = open(etc_lastlog, O_WRONLY)) >= 0) {
4844d522f475Smrg		size_t size = sizeof(struct lastlog);
4845913cc679Smrg		off_t offset = (off_t) ((size_t) screen->uid * size);
4846d522f475Smrg
4847956cc18dSsnj		memset(&lastlog, 0, size);
4848f2e35a3aSmrg		copy_filled(lastlog.ll_line,
4849f2e35a3aSmrg			    my_pty_name(ttydev),
4850f2e35a3aSmrg			    sizeof(lastlog.ll_line));
4851d522f475Smrg		SetUtmpHost(lastlog.ll_host, screen);
4852d522f475Smrg		lastlog.ll_time = time((time_t *) 0);
4853d522f475Smrg		if (lseek(i, offset, 0) != (off_t) (-1)) {
48540bd37d32Smrg		    IGNORE_RC(write(i, (char *) &lastlog, size));
4855d522f475Smrg		}
4856d522f475Smrg		close(i);
4857d522f475Smrg	    }
4858d522f475Smrg#endif /* USE_LASTLOG */
4859d522f475Smrg
4860d522f475Smrg#if defined(USE_UTMP_SETGID)
4861d522f475Smrg	    disableSetGid();
4862d522f475Smrg	    TRACE_IDS;
4863d522f475Smrg#endif
4864d522f475Smrg
4865d522f475Smrg#if OPT_PTY_HANDSHAKE
4866d522f475Smrg	    /* Let our parent know that we set up our utmp entry
4867d522f475Smrg	     * so that it can clean up after us.
4868d522f475Smrg	     */
4869d522f475Smrg	    if (resource.ptyHandshake) {
4870d522f475Smrg		handshake.status = UTMP_ADDED;
4871d522f475Smrg		handshake.error = 0;
4872f2e35a3aSmrg		copy_handshake(handshake, ttydev);
4873d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
487420d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1], (char *) &handshake, sizeof(handshake)));
4875d522f475Smrg	    }
4876d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4877d522f475Smrg#endif /* USE_UTEMPTER */
4878d522f475Smrg#endif /* HAVE_UTMP */
4879d522f475Smrg
488020d2c4d2Smrg	    IGNORE_RC(setgid(screen->gid));
4881d522f475Smrg	    TRACE_IDS;
4882e0a2b6dfSmrg#ifdef HAVE_INITGROUPS
48830bd37d32Smrg	    if (geteuid() == 0 && OkPasswd(&pw)) {
48840bd37d32Smrg		if (initgroups(login_name, pw.pw_gid)) {
4885d522f475Smrg		    perror("initgroups failed");
4886d522f475Smrg		    SysError(ERROR_INIGROUPS);
4887d522f475Smrg		}
4888d522f475Smrg	    }
4889d522f475Smrg#endif
4890d522f475Smrg	    if (setuid(screen->uid)) {
4891d522f475Smrg		SysError(ERROR_SETUID);
4892d522f475Smrg	    }
4893d522f475Smrg	    TRACE_IDS;
4894d522f475Smrg#if OPT_PTY_HANDSHAKE
4895d522f475Smrg	    if (resource.ptyHandshake) {
4896d522f475Smrg		/* mark the pipes as close on exec */
48970bd37d32Smrg		(void) fcntl(cp_pipe[1], F_SETFD, 1);
48980bd37d32Smrg		(void) fcntl(pc_pipe[0], F_SETFD, 1);
4899d522f475Smrg
4900d522f475Smrg		/* We are at the point where we are going to
4901d522f475Smrg		 * exec our shell (or whatever).  Let our parent
4902d522f475Smrg		 * know we arrived safely.
4903d522f475Smrg		 */
4904d522f475Smrg		handshake.status = PTY_GOOD;
4905d522f475Smrg		handshake.error = 0;
4906f2e35a3aSmrg		copy_handshake(handshake, ttydev);
4907d522f475Smrg		TRACE_HANDSHAKE("writing", &handshake);
490820d2c4d2Smrg		IGNORE_RC(write(cp_pipe[1],
490920d2c4d2Smrg				(const char *) &handshake,
491020d2c4d2Smrg				sizeof(handshake)));
4911d522f475Smrg
4912d522f475Smrg		if (resource.wait_for_map) {
491320d2c4d2Smrg		    i = (int) read(pc_pipe[0], (char *) &handshake,
491420d2c4d2Smrg				   sizeof(handshake));
4915d522f475Smrg		    if (i != sizeof(handshake) ||
4916d522f475Smrg			handshake.status != PTY_EXEC) {
4917d522f475Smrg			/* some very bad problem occurred */
4918d522f475Smrg			exit(ERROR_PTY_EXEC);
4919d522f475Smrg		    }
4920d522f475Smrg		    if (handshake.rows > 0 && handshake.cols > 0) {
4921913cc679Smrg			TRACE(("handshake read ttysize: %dx%d\n",
4922d522f475Smrg			       handshake.rows, handshake.cols));
4923d522f475Smrg			set_max_row(screen, handshake.rows);
4924d522f475Smrg			set_max_col(screen, handshake.cols);
4925d522f475Smrg#ifdef TTYSIZE_STRUCT
4926d522f475Smrg			got_handshake_size = True;
4927913cc679Smrg			setup_winsize(ts, MaxRows(screen), MaxCols(screen),
4928913cc679Smrg				      FullHeight(screen), FullWidth(screen));
4929913cc679Smrg			trace_winsize(ts, "got handshake");
4930d522f475Smrg#endif /* TTYSIZE_STRUCT */
4931d522f475Smrg		    }
4932d522f475Smrg		}
4933d522f475Smrg	    }
4934d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
4935d522f475Smrg
4936d522f475Smrg#ifdef USE_SYSV_ENVVARS
4937d522f475Smrg	    {
4938d522f475Smrg		char numbuf[12];
4939d522f475Smrg		sprintf(numbuf, "%d", MaxCols(screen));
4940d522f475Smrg		xtermSetenv("COLUMNS", numbuf);
4941d522f475Smrg		sprintf(numbuf, "%d", MaxRows(screen));
4942d522f475Smrg		xtermSetenv("LINES", numbuf);
4943d522f475Smrg	    }
4944d522f475Smrg#ifdef HAVE_UTMP
49450bd37d32Smrg	    if (OkPasswd(&pw)) {	/* SVR4 doesn't provide these */
4946d522f475Smrg		if (!x_getenv("HOME"))
49470bd37d32Smrg		    xtermSetenv("HOME", pw.pw_dir);
4948d522f475Smrg		if (!x_getenv("SHELL"))
49490bd37d32Smrg		    xtermSetenv("SHELL", pw.pw_shell);
4950d522f475Smrg	    }
4951d522f475Smrg#endif /* HAVE_UTMP */
4952d522f475Smrg#else /* USE_SYSV_ENVVARS */
495320d2c4d2Smrg	    if (*(newtc = get_tcap_buffer(xw)) != '\0') {
495420d2c4d2Smrg		resize_termcap(xw);
495520d2c4d2Smrg		if (xw->misc.titeInhibit && !xw->misc.tiXtraScroll) {
495620d2c4d2Smrg		    remove_termcap_entry(newtc, "ti=");
495720d2c4d2Smrg		    remove_termcap_entry(newtc, "te=");
495820d2c4d2Smrg		}
495920d2c4d2Smrg		/*
496020d2c4d2Smrg		 * work around broken termcap entries */
496120d2c4d2Smrg		if (resource.useInsertMode) {
496220d2c4d2Smrg		    remove_termcap_entry(newtc, "ic=");
496320d2c4d2Smrg		    /* don't get duplicates */
496420d2c4d2Smrg		    remove_termcap_entry(newtc, "im=");
496520d2c4d2Smrg		    remove_termcap_entry(newtc, "ei=");
496620d2c4d2Smrg		    remove_termcap_entry(newtc, "mi");
496720d2c4d2Smrg		    if (*newtc)
496820d2c4d2Smrg			strcat(newtc, ":im=\\E[4h:ei=\\E[4l:mi:");
496920d2c4d2Smrg		}
497020d2c4d2Smrg		if (*newtc) {
4971d522f475Smrg#if OPT_INITIAL_ERASE
497220d2c4d2Smrg		    unsigned len;
497320d2c4d2Smrg		    remove_termcap_entry(newtc, TERMCAP_ERASE "=");
497420d2c4d2Smrg		    len = (unsigned) strlen(newtc);
497520d2c4d2Smrg		    if (len != 0 && newtc[len - 1] == ':')
497620d2c4d2Smrg			len--;
497720d2c4d2Smrg		    sprintf(newtc + len, ":%s=\\%03o:",
497820d2c4d2Smrg			    TERMCAP_ERASE,
497920d2c4d2Smrg			    CharOf(initial_erase));
498020d2c4d2Smrg#endif
498120d2c4d2Smrg		    xtermSetenv("TERMCAP", newtc);
498220d2c4d2Smrg		}
4983d522f475Smrg	    }
4984d522f475Smrg#endif /* USE_SYSV_ENVVARS */
4985913cc679Smrg#ifdef OWN_TERMINFO_ENV
4986913cc679Smrg	    xtermSetenv("TERMINFO", OWN_TERMINFO_DIR);
4987913cc679Smrg#endif
4988d522f475Smrg
4989d522f475Smrg#if OPT_PTY_HANDSHAKE
4990d522f475Smrg	    /*
4991d522f475Smrg	     * Need to reset after all the ioctl bashing we did above.
4992d522f475Smrg	     *
4993d522f475Smrg	     * If we expect the waitForMap logic to set the handshake-size,
4994d522f475Smrg	     * use that to prevent races.
4995d522f475Smrg	     */
4996913cc679Smrg	    TRACE(("should we reset screensize after pty-handshake?\n"));
4997913cc679Smrg	    TRACE(("... ptyHandshake      :%d\n", resource.ptyHandshake));
4998913cc679Smrg	    TRACE(("... ptySttySize       :%d\n", resource.ptySttySize));
4999913cc679Smrg	    TRACE(("... got_handshake_size:%d\n", got_handshake_size));
5000913cc679Smrg	    TRACE(("... wait_for_map0     :%d\n", resource.wait_for_map0));
5001d522f475Smrg	    if (resource.ptyHandshake
5002d522f475Smrg		&& resource.ptySttySize
5003d522f475Smrg		&& (got_handshake_size || !resource.wait_for_map0)) {
5004d522f475Smrg#ifdef TTYSIZE_STRUCT
500520d2c4d2Smrg		TRACE_RC(i, SET_TTYSIZE(0, ts));
5006913cc679Smrg		trace_winsize(ts, "ptyHandshake SET_TTYSIZE");
5007d522f475Smrg#endif /* TTYSIZE_STRUCT */
5008d522f475Smrg	    }
5009d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5010d522f475Smrg	    signal(SIGHUP, SIG_DFL);
5011d522f475Smrg
50120bd37d32Smrg	    /*
5013e0a2b6dfSmrg	     * If we have an explicit shell to run, make that set $SHELL.
5014e0a2b6dfSmrg	     * Next, allow an existing setting of $SHELL, for absolute paths.
50150bd37d32Smrg	     * Otherwise, if $SHELL is not set, determine it from the user's
50160bd37d32Smrg	     * password information, if possible.
50170bd37d32Smrg	     *
50180bd37d32Smrg	     * Incidentally, our setting of $SHELL tells luit to use that
50190bd37d32Smrg	     * program rather than choosing between $SHELL and "/bin/sh".
50200bd37d32Smrg	     */
5021e0a2b6dfSmrg	    if (validShell(explicit_shname)) {
5022e0a2b6dfSmrg		xtermSetenv("SHELL", explicit_shname);
5023e0a2b6dfSmrg	    } else if (validProgram(shell_path = x_getenv("SHELL"))) {
5024e0a2b6dfSmrg		if (!validShell(shell_path)) {
5025e0a2b6dfSmrg		    xtermUnsetenv("SHELL");
5026d522f475Smrg		}
5027e0a2b6dfSmrg	    } else if ((!OkPasswd(&pw) && !x_getpwuid(screen->uid, &pw))
5028e0a2b6dfSmrg		       || *(shell_path = x_strdup(pw.pw_shell)) == 0) {
5029e0a2b6dfSmrg		shell_path = resetShell(shell_path);
5030e0a2b6dfSmrg	    } else if (validShell(shell_path)) {
5031e0a2b6dfSmrg		xtermSetenv("SHELL", shell_path);
5032d522f475Smrg	    } else {
5033e0a2b6dfSmrg		shell_path = resetShell(shell_path);
5034d522f475Smrg	    }
5035e0a2b6dfSmrg
5036e0a2b6dfSmrg	    /*
5037e0a2b6dfSmrg	     * Set $XTERM_SHELL, which is not necessarily a valid shell, but
5038e0a2b6dfSmrg	     * is executable.
5039e0a2b6dfSmrg	     */
5040e0a2b6dfSmrg	    if (validProgram(explicit_shname)) {
5041e0a2b6dfSmrg		shell_path = explicit_shname;
5042e0a2b6dfSmrg	    } else if (shell_path == 0) {
5043e0a2b6dfSmrg		/* this could happen if the explicit shname lost a race */
5044e0a2b6dfSmrg		shell_path = resetShell(shell_path);
50450bd37d32Smrg	    }
50460bd37d32Smrg	    xtermSetenv("XTERM_SHELL", shell_path);
5047d522f475Smrg
50480bd37d32Smrg	    shname = x_basename(shell_path);
50490bd37d32Smrg	    TRACE(("shell path '%s' leaf '%s'\n", shell_path, shname));
5050d522f475Smrg
5051d522f475Smrg#if OPT_LUIT_PROG
5052d522f475Smrg	    /*
5053d522f475Smrg	     * Use two copies of command_to_exec, in case luit is not actually
5054d522f475Smrg	     * there, or refuses to run.  In that case we will fall-through to
5055d522f475Smrg	     * to command that the user gave anyway.
5056d522f475Smrg	     */
50572eaa94a1Schristos	    if (command_to_exec_with_luit && command_to_exec) {
50580bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec_with_luit, False);
50590bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
50600bd37d32Smrg		free(myShell);
50610bd37d32Smrg		TRACE_ARGV("spawning luit command", command_to_exec_with_luit);
5062d522f475Smrg		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
50630bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
50640bd37d32Smrg		xtermWarning("cannot support your locale.\n");
5065d522f475Smrg	    }
5066d522f475Smrg#endif
5067d522f475Smrg	    if (command_to_exec) {
50680bd37d32Smrg		char *myShell = xtermFindShell(*command_to_exec, False);
50690bd37d32Smrg		xtermSetenv("XTERM_SHELL", myShell);
50700bd37d32Smrg		free(myShell);
50710bd37d32Smrg		TRACE_ARGV("spawning command", command_to_exec);
5072d522f475Smrg		execvp(*command_to_exec, command_to_exec);
5073d522f475Smrg		if (command_to_exec[1] == 0)
50740bd37d32Smrg		    execlp(shell_path, shname, "-c", command_to_exec[0],
50750bd37d32Smrg			   (void *) 0);
50760bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec);
5077d522f475Smrg	    }
5078d522f475Smrg#ifdef USE_SYSV_SIGHUP
5079d522f475Smrg	    /* fix pts sh hanging around */
5080d522f475Smrg	    signal(SIGHUP, SIG_DFL);
5081d522f475Smrg#endif
5082d522f475Smrg
5083f2e35a3aSmrg	    if ((shname_minus = malloc(strlen(shname) + 2)) != 0) {
508401037d57Smrg		(void) strcpy(shname_minus, "-");
508501037d57Smrg		(void) strcat(shname_minus, shname);
508601037d57Smrg	    } else {
508701037d57Smrg		static char default_minus[] = "-sh";
508801037d57Smrg		shname_minus = default_minus;
508901037d57Smrg	    }
5090d522f475Smrg#ifndef TERMIO_STRUCT
50910bd37d32Smrg	    ldisc = (!XStrCmp("csh", shname + strlen(shname) - 3)
50920bd37d32Smrg		     ? NTTYDISC
50930bd37d32Smrg		     : 0);
5094d522f475Smrg	    ioctl(0, TIOCSETD, (char *) &ldisc);
5095d522f475Smrg#endif /* !TERMIO_STRUCT */
5096d522f475Smrg
5097d522f475Smrg#ifdef USE_LOGIN_DASH_P
50980bd37d32Smrg	    if (xw->misc.login_shell && OkPasswd(&pw) && added_utmp_entry)
5099d522f475Smrg		execl(bin_login, "login", "-p", "-f", login_name, (void *) 0);
5100d522f475Smrg#endif
51012eaa94a1Schristos
51022eaa94a1Schristos#if OPT_LUIT_PROG
51032eaa94a1Schristos	    if (command_to_exec_with_luit) {
51042eaa94a1Schristos		if (xw->misc.login_shell) {
51050bd37d32Smrg		    char *params[4];
51060bd37d32Smrg		    params[0] = x_strdup("-argv0");
51070bd37d32Smrg		    params[1] = shname_minus;
51080bd37d32Smrg		    params[2] = NULL;
51090bd37d32Smrg		    x_appendargv(command_to_exec_with_luit
51100bd37d32Smrg				 + command_length_with_luit,
51110bd37d32Smrg				 params);
51122eaa94a1Schristos		}
51130bd37d32Smrg		TRACE_ARGV("final luit command", command_to_exec_with_luit);
51142eaa94a1Schristos		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);
51152eaa94a1Schristos		/* Exec failed. */
51160bd37d32Smrg		xtermPerror("Can't execvp %s", *command_to_exec_with_luit);
51172eaa94a1Schristos	    }
51182eaa94a1Schristos#endif
51190bd37d32Smrg	    execlp(shell_path,
5120d522f475Smrg		   (xw->misc.login_shell ? shname_minus : shname),
5121d522f475Smrg		   (void *) 0);
5122d522f475Smrg
5123d522f475Smrg	    /* Exec failed. */
51240bd37d32Smrg	    xtermPerror("Could not exec %s", shell_path);
512520d2c4d2Smrg	    IGNORE_RC(sleep(5));
51260bd37d32Smrg	    free(shell_path);
5127d522f475Smrg	    exit(ERROR_EXEC);
5128d522f475Smrg	}
5129d522f475Smrg	/* end if in child after fork */
5130d522f475Smrg#if OPT_PTY_HANDSHAKE
5131d522f475Smrg	if (resource.ptyHandshake) {
5132d522f475Smrg	    /* Parent process.  Let's handle handshaked requests to our
5133d522f475Smrg	     * child process.
5134d522f475Smrg	     */
5135d522f475Smrg
5136d522f475Smrg	    /* close childs's sides of the pipes */
5137d522f475Smrg	    close(cp_pipe[1]);
5138d522f475Smrg	    close(pc_pipe[0]);
5139d522f475Smrg
5140d522f475Smrg	    for (done = 0; !done;) {
5141d522f475Smrg		if (read(cp_pipe[0],
5142d522f475Smrg			 (char *) &handshake,
5143d522f475Smrg			 sizeof(handshake)) <= 0) {
5144d522f475Smrg		    /* Our child is done talking to us.  If it terminated
5145d522f475Smrg		     * due to an error, we will catch the death of child
5146d522f475Smrg		     * and clean up.
5147d522f475Smrg		     */
5148d522f475Smrg		    break;
5149d522f475Smrg		}
5150d522f475Smrg
5151d522f475Smrg		TRACE_HANDSHAKE("read", &handshake);
5152d522f475Smrg		switch (handshake.status) {
5153d522f475Smrg		case PTY_GOOD:
5154d522f475Smrg		    /* Success!  Let's free up resources and
5155d522f475Smrg		     * continue.
5156d522f475Smrg		     */
5157d522f475Smrg		    done = 1;
5158d522f475Smrg		    break;
5159d522f475Smrg
5160d522f475Smrg		case PTY_BAD:
5161d522f475Smrg		    /* The open of the pty failed!  Let's get
5162d522f475Smrg		     * another one.
5163d522f475Smrg		     */
516420d2c4d2Smrg		    IGNORE_RC(close(screen->respond));
5165d522f475Smrg		    if (get_pty(&screen->respond, XDisplayString(screen->display))) {
5166d522f475Smrg			/* no more ptys! */
51670bd37d32Smrg			xtermPerror("child process can find no available ptys");
5168d522f475Smrg			handshake.status = PTY_NOMORE;
5169d522f475Smrg			TRACE_HANDSHAKE("writing", &handshake);
517020d2c4d2Smrg			IGNORE_RC(write(pc_pipe[1],
517120d2c4d2Smrg					(const char *) &handshake,
517220d2c4d2Smrg					sizeof(handshake)));
5173d522f475Smrg			exit(ERROR_PTYS);
5174d522f475Smrg		    }
5175d522f475Smrg		    handshake.status = PTY_NEW;
5176f2e35a3aSmrg		    copy_handshake(handshake, ttydev);
5177d522f475Smrg		    TRACE_HANDSHAKE("writing", &handshake);
517820d2c4d2Smrg		    IGNORE_RC(write(pc_pipe[1],
517920d2c4d2Smrg				    (const char *) &handshake,
518020d2c4d2Smrg				    sizeof(handshake)));
5181d522f475Smrg		    break;
5182d522f475Smrg
5183d522f475Smrg		case PTY_FATALERROR:
5184d522f475Smrg		    errno = handshake.error;
5185d522f475Smrg		    close(cp_pipe[0]);
5186d522f475Smrg		    close(pc_pipe[1]);
5187d522f475Smrg		    SysError(handshake.fatal_error);
5188d522f475Smrg		    /*NOTREACHED */
5189d522f475Smrg
5190d522f475Smrg		case UTMP_ADDED:
5191d522f475Smrg		    /* The utmp entry was set by our slave.  Remember
5192d522f475Smrg		     * this so that we can reset it later.
5193d522f475Smrg		     */
5194d522f475Smrg		    added_utmp_entry = True;
5195d522f475Smrg#ifndef	USE_SYSV_UTMP
5196d522f475Smrg		    tslot = handshake.tty_slot;
5197d522f475Smrg#endif /* USE_SYSV_UTMP */
5198d522f475Smrg		    free(ttydev);
5199f2e35a3aSmrg		    handshake.buffer[HANDSHAKE_LEN - 1] = '\0';
5200d522f475Smrg		    ttydev = x_strdup(handshake.buffer);
5201d522f475Smrg		    break;
5202d522f475Smrg		case PTY_NEW:
5203d522f475Smrg		case PTY_NOMORE:
5204d522f475Smrg		case UTMP_TTYSLOT:
5205d522f475Smrg		case PTY_EXEC:
5206d522f475Smrg		default:
52070bd37d32Smrg		    xtermWarning("unexpected handshake status %d\n",
52080bd37d32Smrg				 (int) handshake.status);
5209d522f475Smrg		}
5210d522f475Smrg	    }
5211d522f475Smrg	    /* close our sides of the pipes */
5212d522f475Smrg	    if (!resource.wait_for_map) {
5213d522f475Smrg		close(cp_pipe[0]);
5214d522f475Smrg		close(pc_pipe[1]);
5215d522f475Smrg	    }
5216d522f475Smrg	}
5217d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5218d522f475Smrg    }
5219d522f475Smrg
5220d522f475Smrg    /* end if no slave */
5221d522f475Smrg    /*
5222d522f475Smrg     * still in parent (xterm process)
5223d522f475Smrg     */
5224d522f475Smrg#ifdef USE_SYSV_SIGHUP
5225d522f475Smrg    /* hung sh problem? */
5226d522f475Smrg    signal(SIGHUP, SIG_DFL);
5227d522f475Smrg#else
5228d522f475Smrg    signal(SIGHUP, SIG_IGN);
5229d522f475Smrg#endif
5230d522f475Smrg
5231d522f475Smrg/*
5232d522f475Smrg * Unfortunately, System V seems to have trouble divorcing the child process
5233d522f475Smrg * from the process group of xterm.  This is a problem because hitting the
5234d522f475Smrg * INTR or QUIT characters on the keyboard will cause xterm to go away if we
5235d522f475Smrg * don't ignore the signals.  This is annoying.
5236d522f475Smrg */
5237d522f475Smrg
5238d522f475Smrg#if defined(USE_SYSV_SIGNALS) && !defined(SIGTSTP)
5239d522f475Smrg    signal(SIGINT, SIG_IGN);
5240d522f475Smrg
5241d522f475Smrg#ifndef SYSV
5242d522f475Smrg    /* hung shell problem */
5243d522f475Smrg    signal(SIGQUIT, SIG_IGN);
5244d522f475Smrg#endif
5245d522f475Smrg    signal(SIGTERM, SIG_IGN);
5246d522f475Smrg#elif defined(SYSV) || defined(__osf__)
5247d522f475Smrg    /* if we were spawned by a jobcontrol smart shell (like ksh or csh),
5248d522f475Smrg     * then our pgrp and pid will be the same.  If we were spawned by
5249d522f475Smrg     * a jobcontrol dumb shell (like /bin/sh), then we will be in our
5250d522f475Smrg     * parent's pgrp, and we must ignore keyboard signals, or we will
5251d522f475Smrg     * tank on everything.
5252d522f475Smrg     */
5253d522f475Smrg    if (getpid() == getpgrp()) {
5254d522f475Smrg	(void) signal(SIGINT, Exit);
5255d522f475Smrg	(void) signal(SIGQUIT, Exit);
5256d522f475Smrg	(void) signal(SIGTERM, Exit);
5257d522f475Smrg    } else {
5258d522f475Smrg	(void) signal(SIGINT, SIG_IGN);
5259d522f475Smrg	(void) signal(SIGQUIT, SIG_IGN);
5260d522f475Smrg	(void) signal(SIGTERM, SIG_IGN);
5261d522f475Smrg    }
5262d522f475Smrg    (void) signal(SIGPIPE, Exit);
5263d522f475Smrg#else /* SYSV */
5264d522f475Smrg    signal(SIGINT, Exit);
5265d522f475Smrg    signal(SIGQUIT, Exit);
5266d522f475Smrg    signal(SIGTERM, Exit);
5267d522f475Smrg    signal(SIGPIPE, Exit);
5268d522f475Smrg#endif /* USE_SYSV_SIGNALS and not SIGTSTP */
52690bd37d32Smrg#ifdef NO_LEAKS
52700bd37d32Smrg    if (ok_termcap != True)
52710bd37d32Smrg	free(TermName);
52720bd37d32Smrg#endif
5273d522f475Smrg
5274d522f475Smrg    return 0;
5275d522f475Smrg}				/* end spawnXTerm */
5276d522f475Smrg
52770bd37d32Smrgvoid
5278d522f475SmrgExit(int n)
5279d522f475Smrg{
528020d2c4d2Smrg    XtermWidget xw = term;
528120d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
5282d522f475Smrg
5283d522f475Smrg#ifdef USE_UTEMPTER
52840bd37d32Smrg    DEBUG_MSG("handle:Exit USE_UTEMPTER\n");
52850bd37d32Smrg    if (!resource.utmpInhibit && added_utmp_entry) {
52860bd37d32Smrg	TRACE(("...calling removeFromUtmp\n"));
5287f2e35a3aSmrg	UTEMPTER_DEL();
52880bd37d32Smrg    }
5289d522f475Smrg#elif defined(HAVE_UTMP)
5290d522f475Smrg#ifdef USE_SYSV_UTMP
5291d522f475Smrg    struct UTMP_STR utmp;
5292d522f475Smrg    struct UTMP_STR *utptr;
5293d522f475Smrg
52940bd37d32Smrg    DEBUG_MSG("handle:Exit USE_SYSV_UTMP\n");
5295d522f475Smrg    /* don't do this more than once */
52960bd37d32Smrg    if (xterm_exiting) {
52970bd37d32Smrg	exit(n);
52980bd37d32Smrg    }
5299d522f475Smrg    xterm_exiting = True;
5300d522f475Smrg
5301d522f475Smrg#ifdef PUCC_PTYD
5302d522f475Smrg    closepty(ttydev, ptydev, (resource.utmpInhibit ? OPTY_NOP : OPTY_LOGIN), screen->respond);
5303d522f475Smrg#endif /* PUCC_PTYD */
5304d522f475Smrg
5305d522f475Smrg    /* cleanup the utmp entry we forged earlier */
5306d522f475Smrg    if (!resource.utmpInhibit
5307d522f475Smrg#if OPT_PTY_HANDSHAKE		/* without handshake, no way to know */
5308d522f475Smrg	&& (resource.ptyHandshake && added_utmp_entry)
5309d522f475Smrg#endif /* OPT_PTY_HANDSHAKE */
5310d522f475Smrg	) {
5311d522f475Smrg#if defined(USE_UTMP_SETGID)
5312d522f475Smrg	setEffectiveGroup(save_egid);
5313d522f475Smrg	TRACE_IDS;
5314d522f475Smrg#endif
5315d522f475Smrg	init_utmp(USER_PROCESS, &utmp);
5316d522f475Smrg	(void) call_setutent();
5317d522f475Smrg
5318d522f475Smrg	/*
5319d522f475Smrg	 * We could use getutline() if we didn't support old systems.
5320d522f475Smrg	 */
5321d522f475Smrg	while ((utptr = find_utmp(&utmp)) != 0) {
5322d522f475Smrg	    if (utptr->ut_pid == screen->pid) {
5323d522f475Smrg		utptr->ut_type = DEAD_PROCESS;
5324d522f475Smrg#if defined(HAVE_UTMP_UT_XTIME)
5325d522f475Smrg#if defined(HAVE_UTMP_UT_SESSION)
5326d522f475Smrg		utptr->ut_session = getsid(0);
5327d522f475Smrg#endif
5328d522f475Smrg		utptr->ut_xtime = time((time_t *) 0);
5329d522f475Smrg		utptr->ut_tv.tv_usec = 0;
5330d522f475Smrg#else
5331d522f475Smrg		*utptr->ut_user = 0;
5332d522f475Smrg		utptr->ut_time = time((time_t *) 0);
5333d522f475Smrg#endif
5334d522f475Smrg		(void) call_pututline(utptr);
5335d522f475Smrg#ifdef WTMP
5336d522f475Smrg#if defined(WTMPX_FILE) && (defined(SVR4) || defined(__SCO__))
533720d2c4d2Smrg		if (xw->misc.login_shell)
5338d522f475Smrg		    updwtmpx(WTMPX_FILE, utptr);
5339d522f475Smrg#elif defined(linux) && defined(__GLIBC__) && (__GLIBC__ >= 2) && !(defined(__powerpc__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0))
5340894e0ac8Smrg		copy_filled(utmp.ut_line, utptr->ut_line, sizeof(utmp.ut_line));
534120d2c4d2Smrg		if (xw->misc.login_shell)
5342d522f475Smrg		    call_updwtmp(etc_wtmp, utptr);
5343d522f475Smrg#else
5344d522f475Smrg		/* set wtmp entry if wtmp file exists */
534520d2c4d2Smrg		if (xw->misc.login_shell) {
5346d522f475Smrg		    int fd;
5347d522f475Smrg		    if ((fd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
53480bd37d32Smrg			IGNORE_RC(write(fd, utptr, sizeof(*utptr)));
5349d522f475Smrg			close(fd);
5350d522f475Smrg		    }
5351d522f475Smrg		}
5352d522f475Smrg#endif
5353d522f475Smrg#endif
5354d522f475Smrg		break;
5355d522f475Smrg	    }
5356d522f475Smrg	    memset(utptr, 0, sizeof(*utptr));	/* keep searching */
5357d522f475Smrg	}
5358d522f475Smrg	(void) call_endutent();
5359d522f475Smrg#ifdef USE_UTMP_SETGID
5360d522f475Smrg	disableSetGid();
5361d522f475Smrg	TRACE_IDS;
5362d522f475Smrg#endif
5363d522f475Smrg    }
5364d522f475Smrg#else /* not USE_SYSV_UTMP */
5365d522f475Smrg    int wfd;
5366d522f475Smrg    struct utmp utmp;
5367d522f475Smrg
53680bd37d32Smrg    DEBUG_MSG("handle:Exit !USE_SYSV_UTMP\n");
5369d522f475Smrg    if (!resource.utmpInhibit && added_utmp_entry &&
5370d522f475Smrg	(am_slave < 0 && tslot > 0)) {
5371d522f475Smrg#if defined(USE_UTMP_SETGID)
5372d522f475Smrg	setEffectiveGroup(save_egid);
5373d522f475Smrg	TRACE_IDS;
5374d522f475Smrg#endif
5375d522f475Smrg	if ((wfd = open(etc_utmp, O_WRONLY)) >= 0) {
5376956cc18dSsnj	    memset(&utmp, 0, sizeof(utmp));
5377d522f475Smrg	    lseek(wfd, (long) (tslot * sizeof(utmp)), 0);
53780bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5379d522f475Smrg	    close(wfd);
5380d522f475Smrg	}
5381d522f475Smrg#ifdef WTMP
538220d2c4d2Smrg	if (xw->misc.login_shell &&
5383d522f475Smrg	    (wfd = open(etc_wtmp, O_WRONLY | O_APPEND)) >= 0) {
5384894e0ac8Smrg	    copy_filled(utmp.ut_line,
5385894e0ac8Smrg			my_pty_name(ttydev),
5386894e0ac8Smrg			sizeof(utmp.ut_line));
5387d522f475Smrg	    utmp.ut_time = time((time_t *) 0);
53880bd37d32Smrg	    IGNORE_RC(write(wfd, (char *) &utmp, sizeof(utmp)));
5389d522f475Smrg	    close(wfd);
5390d522f475Smrg	}
5391d522f475Smrg#endif /* WTMP */
5392d522f475Smrg#ifdef USE_UTMP_SETGID
5393d522f475Smrg	disableSetGid();
5394d522f475Smrg	TRACE_IDS;
5395d522f475Smrg#endif
5396d522f475Smrg    }
5397d522f475Smrg#endif /* USE_SYSV_UTMP */
5398d522f475Smrg#endif /* HAVE_UTMP */
5399d522f475Smrg
5400e0a2b6dfSmrg    cleanup_colored_cursor();
5401e0a2b6dfSmrg
5402d522f475Smrg    /*
5403d522f475Smrg     * Flush pending data before releasing ownership, so nobody else can write
5404d522f475Smrg     * in the middle of the data.
5405d522f475Smrg     */
5406d522f475Smrg    ttyFlush(screen->respond);
5407d522f475Smrg
5408e39b573cSmrg#ifdef USE_PTY_SEARCH
5409d522f475Smrg    if (am_slave < 0) {
5410d522f475Smrg	TRACE_IDS;
5411d522f475Smrg	/* restore ownership of tty and pty */
5412d522f475Smrg	set_owner(ttydev, 0, 0, 0666U);
5413d522f475Smrg#if (defined(USE_PTY_DEVICE) && !defined(__sgi) && !defined(__hpux))
5414d522f475Smrg	set_owner(ptydev, 0, 0, 0666U);
5415d522f475Smrg#endif
5416d522f475Smrg    }
5417e39b573cSmrg#endif
5418d522f475Smrg
5419d522f475Smrg    /*
54200bd37d32Smrg     * Close after releasing ownership to avoid race condition: other programs
5421d522f475Smrg     * grabbing it, and *then* having us release ownership....
5422d522f475Smrg     */
5423d522f475Smrg    close(screen->respond);	/* close explicitly to avoid race with slave side */
5424d522f475Smrg#ifdef ALLOWLOGGING
5425d522f475Smrg    if (screen->logging)
542620d2c4d2Smrg	CloseLog(xw);
5427d522f475Smrg#endif
5428d522f475Smrg
5429e39b573cSmrg    xtermPrintOnXError(xw, n);
5430e39b573cSmrg
5431d522f475Smrg#ifdef NO_LEAKS
5432d522f475Smrg    if (n == 0) {
54330bd37d32Smrg	Display *dpy = TScreenOf(xw)->display;
54340bd37d32Smrg
5435d522f475Smrg	TRACE(("Freeing memory leaks\n"));
5436d522f475Smrg
54370bd37d32Smrg	if (toplevel) {
54380bd37d32Smrg	    XtDestroyWidget(toplevel);
54390bd37d32Smrg	    TRACE(("destroyed top-level widget\n"));
54400bd37d32Smrg	}
54410bd37d32Smrg	sortedOpts(0, 0, 0);
54420bd37d32Smrg	noleaks_charproc();
54430bd37d32Smrg	noleaks_ptydata();
5444894e0ac8Smrg#if OPT_GRAPHICS
5445894e0ac8Smrg	noleaks_graphics();
5446894e0ac8Smrg#endif
5447d522f475Smrg#if OPT_WIDE_CHARS
54480bd37d32Smrg	noleaks_CharacterClass();
5449d522f475Smrg#endif
54500bd37d32Smrg	/* XrmSetDatabase(dpy, 0); increases leaks ;-) */
54510bd37d32Smrg	XtCloseDisplay(dpy);
54520bd37d32Smrg	XtDestroyApplicationContext(app_con);
54530bd37d32Smrg	xtermCloseSession();
54540bd37d32Smrg	TRACE(("closed display\n"));
54550bd37d32Smrg
545620d2c4d2Smrg	TRACE_CLOSE();
5457d522f475Smrg    }
5458d522f475Smrg#endif
5459d522f475Smrg
5460d522f475Smrg    exit(n);
5461d522f475Smrg}
5462d522f475Smrg
5463d522f475Smrg/* ARGSUSED */
5464d522f475Smrgstatic void
546520d2c4d2Smrgresize_termcap(XtermWidget xw)
5466d522f475Smrg{
546720d2c4d2Smrg    char *newtc = get_tcap_buffer(xw);
546820d2c4d2Smrg
5469d522f475Smrg#ifndef USE_SYSV_ENVVARS
5470d522f475Smrg    if (!TEK4014_ACTIVE(xw) && *newtc) {
5471d522f475Smrg	TScreen *screen = TScreenOf(xw);
5472d522f475Smrg	char *ptr1, *ptr2;
5473d522f475Smrg	size_t i;
5474d522f475Smrg	int li_first = 0;
5475d522f475Smrg	char *temp;
5476d522f475Smrg	char oldtc[TERMCAP_SIZE];
5477d522f475Smrg
5478d522f475Smrg	strcpy(oldtc, newtc);
5479d522f475Smrg	TRACE(("resize %s\n", oldtc));
5480d522f475Smrg	if ((ptr1 = x_strindex(oldtc, "co#")) == NULL) {
5481d522f475Smrg	    strcat(oldtc, "co#80:");
5482d522f475Smrg	    ptr1 = x_strindex(oldtc, "co#");
5483d522f475Smrg	}
5484d522f475Smrg	if ((ptr2 = x_strindex(oldtc, "li#")) == NULL) {
5485d522f475Smrg	    strcat(oldtc, "li#24:");
5486d522f475Smrg	    ptr2 = x_strindex(oldtc, "li#");
5487d522f475Smrg	}
5488d522f475Smrg	if (ptr1 > ptr2) {
5489d522f475Smrg	    li_first++;
5490d522f475Smrg	    temp = ptr1;
5491d522f475Smrg	    ptr1 = ptr2;
5492d522f475Smrg	    ptr2 = temp;
5493d522f475Smrg	}
5494d522f475Smrg	ptr1 += 3;
5495d522f475Smrg	ptr2 += 3;
5496956cc18dSsnj	strncpy(newtc, oldtc, i = (size_t) (ptr1 - oldtc));
5497d522f475Smrg	temp = newtc + i;
5498d522f475Smrg	sprintf(temp, "%d", (li_first
5499d522f475Smrg			     ? MaxRows(screen)
5500d522f475Smrg			     : MaxCols(screen)));
5501d522f475Smrg	temp += strlen(temp);
55020bd37d32Smrg	if ((ptr1 = strchr(ptr1, ':')) != 0 && (ptr1 < ptr2)) {
55030bd37d32Smrg	    strncpy(temp, ptr1, i = (size_t) (ptr2 - ptr1));
55040bd37d32Smrg	    temp += i;
55050bd37d32Smrg	    sprintf(temp, "%d", (li_first
55060bd37d32Smrg				 ? MaxCols(screen)
55070bd37d32Smrg				 : MaxRows(screen)));
55080bd37d32Smrg	    if ((ptr2 = strchr(ptr2, ':')) != 0) {
55090bd37d32Smrg		strcat(temp, ptr2);
55100bd37d32Smrg	    }
55110bd37d32Smrg	}
5512d522f475Smrg	TRACE(("   ==> %s\n", newtc));
5513d522f475Smrg	TRACE(("   new size %dx%d\n", MaxRows(screen), MaxCols(screen)));
5514d522f475Smrg    }
5515d522f475Smrg#endif /* USE_SYSV_ENVVARS */
5516d522f475Smrg}
5517d522f475Smrg
5518d522f475Smrg#endif /* ! VMS */
5519d522f475Smrg
5520d522f475Smrg/*
5521d522f475Smrg * Does a non-blocking wait for a child process.  If the system
5522d522f475Smrg * doesn't support non-blocking wait, do nothing.
5523d522f475Smrg * Returns the pid of the child, or 0 or -1 if none or error.
5524d522f475Smrg */
5525d522f475Smrgint
5526d522f475Smrgnonblocking_wait(void)
5527d522f475Smrg{
5528d522f475Smrg#ifdef USE_POSIX_WAIT
5529d522f475Smrg    pid_t pid;
5530d522f475Smrg
5531d522f475Smrg    pid = waitpid(-1, NULL, WNOHANG);
5532d522f475Smrg#elif defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP))
5533d522f475Smrg    /* cannot do non-blocking wait */
5534d522f475Smrg    int pid = 0;
5535d522f475Smrg#else /* defined(USE_SYSV_SIGNALS) && (defined(CRAY) || !defined(SIGTSTP)) */
5536d522f475Smrg#if defined(Lynx)
5537d522f475Smrg    int status;
5538d522f475Smrg#else
5539d522f475Smrg    union wait status;
5540d522f475Smrg#endif
5541d522f475Smrg    int pid;
5542d522f475Smrg
5543d522f475Smrg    pid = wait3(&status, WNOHANG, (struct rusage *) NULL);
5544d522f475Smrg#endif /* USE_POSIX_WAIT else */
5545d522f475Smrg    return pid;
5546d522f475Smrg}
5547d522f475Smrg
5548d522f475Smrg#ifndef VMS
5549d522f475Smrg
5550d522f475Smrg/* ARGSUSED */
55510bd37d32Smrgstatic void
5552d522f475Smrgreapchild(int n GCC_UNUSED)
5553d522f475Smrg{
5554d522f475Smrg    int olderrno = errno;
5555d522f475Smrg    int pid;
5556d522f475Smrg
55570bd37d32Smrg    DEBUG_MSG("handle:reapchild\n");
55580bd37d32Smrg
5559d522f475Smrg    pid = wait(NULL);
5560d522f475Smrg
5561d522f475Smrg#ifdef USE_SYSV_SIGNALS
5562d522f475Smrg    /* cannot re-enable signal before waiting for child
5563d522f475Smrg     * because then SVR4 loops.  Sigh.  HP-UX 9.01 too.
5564d522f475Smrg     */
5565d522f475Smrg    (void) signal(SIGCHLD, reapchild);
5566d522f475Smrg#endif
5567d522f475Smrg
5568d522f475Smrg    do {
556920d2c4d2Smrg	if (pid == TScreenOf(term)->pid) {
55700bd37d32Smrg	    DEBUG_MSG("Exiting\n");
55712e4f8982Smrg	    if (hold_screen)
55722e4f8982Smrg		caught_intr = True;
55732e4f8982Smrg	    else
5574d522f475Smrg		need_cleanup = True;
5575d522f475Smrg	}
5576d522f475Smrg    } while ((pid = nonblocking_wait()) > 0);
5577d522f475Smrg
5578d522f475Smrg    errno = olderrno;
5579d522f475Smrg}
5580d522f475Smrg#endif /* !VMS */
5581d522f475Smrg
5582d522f475Smrgstatic void
558320d2c4d2Smrgremove_termcap_entry(char *buf, const char *str)
5584d522f475Smrg{
5585d522f475Smrg    char *base = buf;
5586d522f475Smrg    char *first = base;
5587d522f475Smrg    int count = 0;
5588d522f475Smrg    size_t len = strlen(str);
5589d522f475Smrg
5590d522f475Smrg    TRACE(("*** remove_termcap_entry('%s', '%s')\n", str, buf));
5591d522f475Smrg
5592d522f475Smrg    while (*buf != 0) {
5593d522f475Smrg	if (!count && !strncmp(buf, str, len)) {
5594d522f475Smrg	    while (*buf != 0) {
5595d522f475Smrg		if (*buf == '\\')
5596d522f475Smrg		    buf++;
5597d522f475Smrg		else if (*buf == ':')
5598d522f475Smrg		    break;
5599d522f475Smrg		if (*buf != 0)
5600d522f475Smrg		    buf++;
5601d522f475Smrg	    }
56020bd37d32Smrg	    while ((*first++ = *buf++) != 0) {
56030bd37d32Smrg		;
56040bd37d32Smrg	    }
5605d522f475Smrg	    TRACE(("...removed_termcap_entry('%s', '%s')\n", str, base));
5606d522f475Smrg	    return;
5607d522f475Smrg	} else if (*buf == '\\') {
5608d522f475Smrg	    buf++;
5609d522f475Smrg	} else if (*buf == ':') {
5610d522f475Smrg	    first = buf;
5611d522f475Smrg	    count = 0;
5612d522f475Smrg	} else if (!isspace(CharOf(*buf))) {
5613d522f475Smrg	    count++;
5614d522f475Smrg	}
5615d522f475Smrg	if (*buf != 0)
5616d522f475Smrg	    buf++;
5617d522f475Smrg    }
5618d522f475Smrg    TRACE(("...cannot remove\n"));
5619d522f475Smrg}
5620d522f475Smrg
5621d522f475Smrg/*
5622d522f475Smrg * parse_tty_modes accepts lines of the following form:
5623d522f475Smrg *
5624d522f475Smrg *         [SETTING] ...
5625d522f475Smrg *
5626f2e35a3aSmrg * where setting consists of the words in the ttyModes[] array followed by a
5627f2e35a3aSmrg * character or ^char.
5628d522f475Smrg */
5629d522f475Smrgstatic int
5630f2e35a3aSmrgparse_tty_modes(char *s)
5631d522f475Smrg{
5632d522f475Smrg    int c;
5633f2e35a3aSmrg    Cardinal j, k;
5634d522f475Smrg    int count = 0;
5635f2e35a3aSmrg    Boolean found;
5636d522f475Smrg
5637d522f475Smrg    TRACE(("parse_tty_modes\n"));
5638a1f3da82Smrg    for (;;) {
5639d522f475Smrg	size_t len;
5640d522f475Smrg
5641f2e35a3aSmrg	while (*s && isspace(CharOf(*s))) {
5642d522f475Smrg	    s++;
5643f2e35a3aSmrg	}
5644f2e35a3aSmrg	if (!*s) {
5645d522f475Smrg	    return count;
5646f2e35a3aSmrg	}
5647d522f475Smrg
5648f2e35a3aSmrg	for (len = 0; s[len] && !isspace(CharOf(s[len])); ++len) {
5649f2e35a3aSmrg	    ;
5650f2e35a3aSmrg	}
5651f2e35a3aSmrg	found = False;
5652f2e35a3aSmrg	for (j = 0; j < XtNumber(ttyModes); ++j) {
5653f2e35a3aSmrg	    if (len == ttyModes[j].len
5654f2e35a3aSmrg		&& strncmp(s,
5655f2e35a3aSmrg			   ttyModes[j].name,
5656f2e35a3aSmrg			   ttyModes[j].len) == 0) {
5657f2e35a3aSmrg		found = True;
5658d522f475Smrg		break;
5659f2e35a3aSmrg	    }
5660d522f475Smrg	}
5661f2e35a3aSmrg	if (!found) {
5662d522f475Smrg	    return -1;
5663f2e35a3aSmrg	}
5664d522f475Smrg
5665f2e35a3aSmrg	s += ttyModes[j].len;
5666f2e35a3aSmrg	while (*s && isspace(CharOf(*s))) {
5667d522f475Smrg	    s++;
5668f2e35a3aSmrg	}
5669d522f475Smrg
5670f2e35a3aSmrg	/* check if this needs a parameter */
5671f2e35a3aSmrg	found = False;
5672f2e35a3aSmrg	for (k = 0, c = 0; k < XtNumber(ttyChars); ++k) {
5673f2e35a3aSmrg	    if ((int) j == ttyChars[k].myMode) {
5674f2e35a3aSmrg		if (ttyChars[k].sysMode < 0) {
5675f2e35a3aSmrg		    found = True;
5676f2e35a3aSmrg		    c = ttyChars[k].myDefault;
5677f2e35a3aSmrg		}
5678f2e35a3aSmrg		break;
5679f2e35a3aSmrg	    }
5680f2e35a3aSmrg	}
5681f2e35a3aSmrg
5682f2e35a3aSmrg	if (!found) {
5683f2e35a3aSmrg	    if (!*s
5684f2e35a3aSmrg		|| (c = decode_keyvalue(&s, False)) == -1) {
5685f2e35a3aSmrg		return -1;
5686f2e35a3aSmrg	    }
5687d522f475Smrg	}
5688f2e35a3aSmrg	ttyModes[j].value = c;
5689f2e35a3aSmrg	ttyModes[j].set = 1;
5690f2e35a3aSmrg	count++;
5691f2e35a3aSmrg	TRACE(("...parsed #%d: %s=%#x\n", count, ttyModes[j].name, c));
5692d522f475Smrg    }
5693d522f475Smrg}
5694d522f475Smrg
5695d522f475Smrg#ifndef VMS			/* don't use pipes on OpenVMS */
5696d522f475Smrgint
5697d522f475SmrgGetBytesAvailable(int fd)
5698d522f475Smrg{
5699d522f475Smrg#if defined(FIONREAD)
5700d522f475Smrg    int arg;
5701d522f475Smrg    ioctl(fd, FIONREAD, (char *) &arg);
5702d522f475Smrg    return (int) arg;
5703d522f475Smrg#elif defined(__CYGWIN__)
5704d522f475Smrg    fd_set set;
570520d2c4d2Smrg    struct timeval select_timeout =
5706d522f475Smrg    {0, 0};
5707d522f475Smrg
5708d522f475Smrg    FD_ZERO(&set);
5709d522f475Smrg    FD_SET(fd, &set);
571020d2c4d2Smrg    if (Select(fd + 1, &set, NULL, NULL, &select_timeout) > 0)
5711d522f475Smrg	return 1;
5712d522f475Smrg    else
5713d522f475Smrg	return 0;
5714d522f475Smrg#elif defined(FIORDCK)
5715d522f475Smrg    return (ioctl(fd, FIORDCHK, NULL));
5716d522f475Smrg#else /* !FIORDCK */
5717d522f475Smrg    struct pollfd pollfds[1];
5718d522f475Smrg
5719d522f475Smrg    pollfds[0].fd = fd;
5720d522f475Smrg    pollfds[0].events = POLLIN;
5721d522f475Smrg    return poll(pollfds, 1, 0);
5722d522f475Smrg#endif
5723d522f475Smrg}
5724d522f475Smrg#endif /* !VMS */
5725d522f475Smrg
5726d522f475Smrg/* Utility function to try to hide system differences from
5727d522f475Smrg   everybody who used to call killpg() */
5728d522f475Smrg
5729d522f475Smrgint
5730d522f475Smrgkill_process_group(int pid, int sig)
5731d522f475Smrg{
5732d522f475Smrg    TRACE(("kill_process_group(pid=%d, sig=%d)\n", pid, sig));
5733d522f475Smrg#if defined(SVR4) || defined(SYSV) || !defined(X_NOT_POSIX)
5734d522f475Smrg    return kill(-pid, sig);
5735d522f475Smrg#else
5736d522f475Smrg    return killpg(pid, sig);
5737d522f475Smrg#endif
5738d522f475Smrg}
5739d522f475Smrg
5740d522f475Smrg#if OPT_EBCDIC
5741d522f475Smrgint
5742d522f475SmrgA2E(int x)
5743d522f475Smrg{
5744d522f475Smrg    char c;
5745d522f475Smrg    c = x;
5746d522f475Smrg    __atoe_l(&c, 1);
5747d522f475Smrg    return c;
5748d522f475Smrg}
5749d522f475Smrg
5750d522f475Smrgint
5751d522f475SmrgE2A(int x)
5752d522f475Smrg{
5753d522f475Smrg    char c;
5754d522f475Smrg    c = x;
5755d522f475Smrg    __etoa_l(&c, 1);
5756d522f475Smrg    return c;
5757d522f475Smrg}
5758d522f475Smrg#endif
5759d522f475Smrg
5760d522f475Smrg#if defined(__QNX__) && !defined(__QNXNTO__)
5761d522f475Smrg#include <sys/types.h>
5762d522f475Smrg#include <sys/proc_msg.h>
5763d522f475Smrg#include <sys/kernel.h>
5764d522f475Smrg#include <string.h>
5765d522f475Smrg#include <errno.h>
5766d522f475Smrg
5767d522f475Smrgstruct _proc_session ps;
5768d522f475Smrgstruct _proc_session_reply rps;
5769d522f475Smrg
5770d522f475Smrgint
5771d522f475Smrgqsetlogin(char *login, char *ttyname)
5772d522f475Smrg{
5773d522f475Smrg    int v = getsid(getpid());
5774d522f475Smrg
5775d522f475Smrg    memset(&ps, 0, sizeof(ps));
5776d522f475Smrg    memset(&rps, 0, sizeof(rps));
5777d522f475Smrg
5778d522f475Smrg    ps.type = _PROC_SESSION;
5779d522f475Smrg    ps.subtype = _PROC_SUB_ACTION1;
5780d522f475Smrg    ps.sid = v;
5781d522f475Smrg    strcpy(ps.name, login);
5782d522f475Smrg
5783d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5784d522f475Smrg
5785d522f475Smrg    if (rps.status < 0)
5786d522f475Smrg	return (rps.status);
5787d522f475Smrg
5788d522f475Smrg    ps.type = _PROC_SESSION;
5789d522f475Smrg    ps.subtype = _PROC_SUB_ACTION2;
5790d522f475Smrg    ps.sid = v;
5791d522f475Smrg    sprintf(ps.name, "//%d%s", getnid(), ttyname);
5792d522f475Smrg    Send(1, &ps, &rps, sizeof(ps), sizeof(rps));
5793d522f475Smrg
5794d522f475Smrg    return (rps.status);
5795d522f475Smrg}
5796d522f475Smrg#endif
579701037d57Smrg
579801037d57Smrg#ifdef __minix
579901037d57Smrgint
580001037d57Smrgsetpgrp(void)
580101037d57Smrg{
580201037d57Smrg    return 0;
580301037d57Smrg}
580401037d57Smrg
580501037d57Smrgvoid
580601037d57Smrg_longjmp(jmp_buf _env, int _val)
580701037d57Smrg{
580801037d57Smrg    longjmp(_env, _val);
580901037d57Smrg}
581001037d57Smrg#endif
5811