xref: /netbsd-src/usr.bin/resize/resize.c (revision 66a2df677d651ddc19b09b511f39746a461f094f)
1*66a2df67Schristos /* $XTermId: resize.c,v 1.144 2020/06/03 00:26:23 tom Exp $ */
2ef6e52b4Sreinoud 
3ef6e52b4Sreinoud /*
4*66a2df67Schristos  * Copyright 2003-2018,2020 by Thomas E. Dickey
5ef6e52b4Sreinoud  *
6ef6e52b4Sreinoud  *                         All Rights Reserved
7ef6e52b4Sreinoud  *
8ef6e52b4Sreinoud  * Permission is hereby granted, free of charge, to any person obtaining a
9ef6e52b4Sreinoud  * copy of this software and associated documentation files (the
10ef6e52b4Sreinoud  * "Software"), to deal in the Software without restriction, including
11ef6e52b4Sreinoud  * without limitation the rights to use, copy, modify, merge, publish,
12ef6e52b4Sreinoud  * distribute, sublicense, and/or sell copies of the Software, and to
13ef6e52b4Sreinoud  * permit persons to whom the Software is furnished to do so, subject to
14ef6e52b4Sreinoud  * the following conditions:
15ef6e52b4Sreinoud  *
16ef6e52b4Sreinoud  * The above copyright notice and this permission notice shall be included
17ef6e52b4Sreinoud  * in all copies or substantial portions of the Software.
18ef6e52b4Sreinoud  *
19ef6e52b4Sreinoud  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20ef6e52b4Sreinoud  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21ef6e52b4Sreinoud  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22ef6e52b4Sreinoud  * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23ef6e52b4Sreinoud  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24ef6e52b4Sreinoud  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25ef6e52b4Sreinoud  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26ef6e52b4Sreinoud  *
27ef6e52b4Sreinoud  * Except as contained in this notice, the name(s) of the above copyright
28ef6e52b4Sreinoud  * holders shall not be used in advertising or otherwise to promote the
29ef6e52b4Sreinoud  * sale, use or other dealings in this Software without prior written
30ef6e52b4Sreinoud  * authorization.
31ef6e52b4Sreinoud  *
32ef6e52b4Sreinoud  *
33ef6e52b4Sreinoud  * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
34ef6e52b4Sreinoud  *
35ef6e52b4Sreinoud  *                         All Rights Reserved
36ef6e52b4Sreinoud  *
37ef6e52b4Sreinoud  * Permission to use, copy, modify, and distribute this software and its
38ef6e52b4Sreinoud  * documentation for any purpose and without fee is hereby granted,
39ef6e52b4Sreinoud  * provided that the above copyright notice appear in all copies and that
40ef6e52b4Sreinoud  * both that copyright notice and this permission notice appear in
41ef6e52b4Sreinoud  * supporting documentation, and that the name of Digital Equipment
42ef6e52b4Sreinoud  * Corporation not be used in advertising or publicity pertaining to
43ef6e52b4Sreinoud  * distribution of the software without specific, written prior permission.
44ef6e52b4Sreinoud  *
45ef6e52b4Sreinoud  *
46ef6e52b4Sreinoud  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47ef6e52b4Sreinoud  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48ef6e52b4Sreinoud  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49ef6e52b4Sreinoud  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50ef6e52b4Sreinoud  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51ef6e52b4Sreinoud  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52ef6e52b4Sreinoud  * SOFTWARE.
53ef6e52b4Sreinoud  */
54ef6e52b4Sreinoud 
55ef6e52b4Sreinoud /* resize.c */
56ef6e52b4Sreinoud 
57ef6e52b4Sreinoud #include <stdio.h>
58ef6e52b4Sreinoud #include <ctype.h>
59ef6e52b4Sreinoud 
60*66a2df67Schristos #ifdef RESIZE_ONLY
61*66a2df67Schristos #include "resize.h"
62*66a2df67Schristos #else
63*66a2df67Schristos #include <xterm.h>
64*66a2df67Schristos #include <version.h>
65*66a2df67Schristos #include <xstrings.h>
66*66a2df67Schristos #include <xtermcap.h>
67*66a2df67Schristos #include <xterm_io.h>
68*66a2df67Schristos #endif
69ef6e52b4Sreinoud 
70*66a2df67Schristos #ifndef USE_TERMINFO		/* avoid conflict with configure script */
71*66a2df67Schristos #if defined(__QNX__) || defined(__SCO__) || defined(linux) || defined(__OpenBSD__) || defined(__UNIXWARE__)
72*66a2df67Schristos #define USE_TERMINFO
73*66a2df67Schristos #endif
74*66a2df67Schristos #endif
75*66a2df67Schristos 
76*66a2df67Schristos #if defined(__QNX__)
77*66a2df67Schristos #include <unix.h>
78*66a2df67Schristos #endif
79*66a2df67Schristos 
80*66a2df67Schristos /*
81*66a2df67Schristos  * Some OS's may want to use both, like SCO for example.  We catch here anyone
82*66a2df67Schristos  * who hasn't decided what they want.
83*66a2df67Schristos  */
84*66a2df67Schristos #if !defined(USE_TERMCAP) && !defined(USE_TERMINFO)
85*66a2df67Schristos #define USE_TERMINFO
86*66a2df67Schristos #endif
87ef6e52b4Sreinoud 
88ef6e52b4Sreinoud #include <signal.h>
89ef6e52b4Sreinoud #include <pwd.h>
90ef6e52b4Sreinoud 
91*66a2df67Schristos #ifdef USE_IGNORE_RC
92*66a2df67Schristos int ignore_unused;
93*66a2df67Schristos #endif
94*66a2df67Schristos 
95*66a2df67Schristos #ifdef __MVS__
96*66a2df67Schristos #define ESCAPE(string) "\047" string
97*66a2df67Schristos #else
98ef6e52b4Sreinoud #define ESCAPE(string) "\033" string
99*66a2df67Schristos #endif
100ef6e52b4Sreinoud 
101ef6e52b4Sreinoud #define	EMULATIONS	2
102ef6e52b4Sreinoud #define	SUN		1
103ef6e52b4Sreinoud #define	VT100		0
104ef6e52b4Sreinoud 
105ef6e52b4Sreinoud #define	TIMEOUT		10
106ef6e52b4Sreinoud 
107ef6e52b4Sreinoud #define	SHELL_UNKNOWN	0
108ef6e52b4Sreinoud #define	SHELL_C		1
109ef6e52b4Sreinoud #define	SHELL_BOURNE	2
110*66a2df67Schristos 
111ef6e52b4Sreinoud /* *INDENT-OFF* */
112ef6e52b4Sreinoud static struct {
113ef6e52b4Sreinoud     const char *name;
114ef6e52b4Sreinoud     int type;
115ef6e52b4Sreinoud } shell_list[] = {
116ef6e52b4Sreinoud     { "csh",	SHELL_C },	/* vanilla cshell */
117ef6e52b4Sreinoud     { "jcsh",   SHELL_C },
118ef6e52b4Sreinoud     { "tcsh",   SHELL_C },
119ef6e52b4Sreinoud     { "sh",	SHELL_BOURNE }, /* vanilla Bourne shell */
120ef6e52b4Sreinoud     { "ash",    SHELL_BOURNE },
121ef6e52b4Sreinoud     { "bash",	SHELL_BOURNE }, /* GNU Bourne again shell */
122ef6e52b4Sreinoud     { "dash",	SHELL_BOURNE },
123ef6e52b4Sreinoud     { "jsh",    SHELL_BOURNE },
124ef6e52b4Sreinoud     { "ksh",	SHELL_BOURNE }, /* Korn shell (from AT&T toolchest) */
125ef6e52b4Sreinoud     { "ksh-i",	SHELL_BOURNE }, /* another name for Korn shell */
126ef6e52b4Sreinoud     { "ksh93",	SHELL_BOURNE }, /* Korn shell */
127ef6e52b4Sreinoud     { "mksh",   SHELL_BOURNE },
128ef6e52b4Sreinoud     { "pdksh",  SHELL_BOURNE },
129ef6e52b4Sreinoud     { "zsh",    SHELL_BOURNE },
130ef6e52b4Sreinoud     { NULL,	SHELL_BOURNE }	/* default (same as xterm's) */
131ef6e52b4Sreinoud };
132ef6e52b4Sreinoud /* *INDENT-ON* */
133ef6e52b4Sreinoud 
134ef6e52b4Sreinoud static const char *const emuname[EMULATIONS] =
135ef6e52b4Sreinoud {
136ef6e52b4Sreinoud     "VT100",
137ef6e52b4Sreinoud     "Sun",
138ef6e52b4Sreinoud };
139ef6e52b4Sreinoud static char *myname;
140ef6e52b4Sreinoud static int shell_type = SHELL_UNKNOWN;
141ef6e52b4Sreinoud static const char *const getsize[EMULATIONS] =
142ef6e52b4Sreinoud {
143ef6e52b4Sreinoud     ESCAPE("7") ESCAPE("[r") ESCAPE("[9999;9999H") ESCAPE("[6n"),
144ef6e52b4Sreinoud     ESCAPE("[18t"),
145ef6e52b4Sreinoud };
146*66a2df67Schristos #if defined(USE_STRUCT_WINSIZE)
147*66a2df67Schristos static const char *const getwsize[EMULATIONS] =
148*66a2df67Schristos {				/* size in pixels */
149*66a2df67Schristos     0,
150*66a2df67Schristos     ESCAPE("[14t"),
151*66a2df67Schristos };
152*66a2df67Schristos #endif /* USE_STRUCT_WINSIZE */
153ef6e52b4Sreinoud static const char *const restore[EMULATIONS] =
154ef6e52b4Sreinoud {
155ef6e52b4Sreinoud     ESCAPE("8"),
156ef6e52b4Sreinoud     0,
157ef6e52b4Sreinoud };
158ef6e52b4Sreinoud static const char *const setsize[EMULATIONS] =
159ef6e52b4Sreinoud {
160ef6e52b4Sreinoud     0,
161ef6e52b4Sreinoud     ESCAPE("[8;%s;%st"),
162ef6e52b4Sreinoud };
163ef6e52b4Sreinoud 
164*66a2df67Schristos #ifdef USE_ANY_SYSV_TERMIO
165*66a2df67Schristos static struct termio tioorig;
166*66a2df67Schristos #elif defined(USE_TERMIOS)
167ef6e52b4Sreinoud static struct termios tioorig;
168*66a2df67Schristos #else
169*66a2df67Schristos static struct sgttyb sgorig;
170*66a2df67Schristos #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
171ef6e52b4Sreinoud 
172ef6e52b4Sreinoud static const char *const size[EMULATIONS] =
173ef6e52b4Sreinoud {
174ef6e52b4Sreinoud     ESCAPE("[%d;%dR"),
175ef6e52b4Sreinoud     ESCAPE("[8;%d;%dt"),
176ef6e52b4Sreinoud };
177ef6e52b4Sreinoud static const char sunname[] = "sunsize";
178ef6e52b4Sreinoud static int tty;
179ef6e52b4Sreinoud static FILE *ttyfp;
180ef6e52b4Sreinoud 
181*66a2df67Schristos #if defined(USE_STRUCT_WINSIZE)
182*66a2df67Schristos static const char *wsize[EMULATIONS] =
183*66a2df67Schristos {
184*66a2df67Schristos     0,
185*66a2df67Schristos     ESCAPE("[4;%hd;%hdt"),
186*66a2df67Schristos };
187*66a2df67Schristos #endif /* USE_STRUCT_WINSIZE */
188*66a2df67Schristos 
189*66a2df67Schristos static void failed(const char *) GCC_NORETURN;
190*66a2df67Schristos static void onintr(int) GCC_NORETURN;
191*66a2df67Schristos static void resize_timeout(int) GCC_NORETURN;
192*66a2df67Schristos static void Usage(void) GCC_NORETURN;
193ef6e52b4Sreinoud 
194ef6e52b4Sreinoud static void
failed(const char * s)195ef6e52b4Sreinoud failed(const char *s)
196ef6e52b4Sreinoud {
197ef6e52b4Sreinoud     int save = errno;
198ef6e52b4Sreinoud     IGNORE_RC(write(2, myname, strlen(myname)));
199ef6e52b4Sreinoud     IGNORE_RC(write(2, ": ", (size_t) 2));
200ef6e52b4Sreinoud     errno = save;
201ef6e52b4Sreinoud     perror(s);
202ef6e52b4Sreinoud     exit(EXIT_FAILURE);
203ef6e52b4Sreinoud }
204ef6e52b4Sreinoud 
205ef6e52b4Sreinoud /* ARGSUSED */
206ef6e52b4Sreinoud static void
onintr(int sig GCC_UNUSED)207ef6e52b4Sreinoud onintr(int sig GCC_UNUSED)
208ef6e52b4Sreinoud {
209*66a2df67Schristos #ifdef USE_ANY_SYSV_TERMIO
210*66a2df67Schristos     (void) ioctl(tty, TCSETAW, &tioorig);
211*66a2df67Schristos #elif defined(USE_TERMIOS)
212ef6e52b4Sreinoud     (void) tcsetattr(tty, TCSADRAIN, &tioorig);
213*66a2df67Schristos #else /* not USE_TERMIOS */
214*66a2df67Schristos     (void) ioctl(tty, TIOCSETP, &sgorig);
215*66a2df67Schristos #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
216ef6e52b4Sreinoud     exit(EXIT_FAILURE);
217ef6e52b4Sreinoud }
218ef6e52b4Sreinoud 
219ef6e52b4Sreinoud static void
resize_timeout(int sig)220ef6e52b4Sreinoud resize_timeout(int sig)
221ef6e52b4Sreinoud {
222ef6e52b4Sreinoud     fprintf(stderr, "\n%s: Time out occurred\r\n", myname);
223ef6e52b4Sreinoud     onintr(sig);
224ef6e52b4Sreinoud }
225ef6e52b4Sreinoud 
226ef6e52b4Sreinoud static void
Usage(void)227ef6e52b4Sreinoud Usage(void)
228ef6e52b4Sreinoud {
229ef6e52b4Sreinoud     fprintf(stderr, strcmp(myname, sunname) == 0 ?
230ef6e52b4Sreinoud 	    "Usage: %s [rows cols]\n" :
231ef6e52b4Sreinoud 	    "Usage: %s [-v] [-u] [-c] [-s [rows cols]]\n", myname);
232ef6e52b4Sreinoud     exit(EXIT_FAILURE);
233ef6e52b4Sreinoud }
234ef6e52b4Sreinoud 
235*66a2df67Schristos #ifdef USE_TERMCAP
236*66a2df67Schristos static void
print_termcap(const char * termcap)237*66a2df67Schristos print_termcap(const char *termcap)
238*66a2df67Schristos {
239*66a2df67Schristos     int ch;
240*66a2df67Schristos 
241*66a2df67Schristos     putchar('\'');
242*66a2df67Schristos     while ((ch = *termcap++) != '\0') {
243*66a2df67Schristos 	switch (ch & 0xff) {
244*66a2df67Schristos 	case 127:		/* undo bug in GNU termcap */
245*66a2df67Schristos 	    printf("^?");
246*66a2df67Schristos 	    break;
247*66a2df67Schristos 	case '\'':		/* must escape anyway (unlikely) */
248*66a2df67Schristos 	    /* FALLTHRU */
249*66a2df67Schristos 	case '!':		/* must escape for SunOS csh */
250*66a2df67Schristos 	    putchar('\\');
251*66a2df67Schristos 	    /* FALLTHRU */
252*66a2df67Schristos 	default:
253*66a2df67Schristos 	    putchar(ch);
254*66a2df67Schristos 	    break;
255*66a2df67Schristos 	}
256*66a2df67Schristos     }
257*66a2df67Schristos     putchar('\'');
258*66a2df67Schristos }
259*66a2df67Schristos #endif /* USE_TERMCAP */
260ef6e52b4Sreinoud 
261ef6e52b4Sreinoud static int
checkdigits(char * str)262ef6e52b4Sreinoud checkdigits(char *str)
263ef6e52b4Sreinoud {
264ef6e52b4Sreinoud     while (*str) {
265ef6e52b4Sreinoud 	if (!isdigit(CharOf(*str)))
266ef6e52b4Sreinoud 	    return (0);
267ef6e52b4Sreinoud 	str++;
268ef6e52b4Sreinoud     }
269ef6e52b4Sreinoud     return (1);
270ef6e52b4Sreinoud }
271ef6e52b4Sreinoud 
272ef6e52b4Sreinoud static void
readstring(FILE * fp,char * buf,const char * str)273ef6e52b4Sreinoud readstring(FILE *fp, char *buf, const char *str)
274ef6e52b4Sreinoud {
275ef6e52b4Sreinoud     int last, c;
276*66a2df67Schristos #if !defined(USG) && !defined(__minix)
277*66a2df67Schristos     /* What is the advantage of setitimer() over alarm()? */
278ef6e52b4Sreinoud     struct itimerval it;
279*66a2df67Schristos #endif
280ef6e52b4Sreinoud 
281ef6e52b4Sreinoud     signal(SIGALRM, resize_timeout);
282*66a2df67Schristos #if defined(USG) || defined(__minix)
283*66a2df67Schristos     alarm(TIMEOUT);
284*66a2df67Schristos #else
285ef6e52b4Sreinoud     memset((char *) &it, 0, sizeof(struct itimerval));
286ef6e52b4Sreinoud     it.it_value.tv_sec = TIMEOUT;
287ef6e52b4Sreinoud     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
288*66a2df67Schristos #endif
289ef6e52b4Sreinoud     if ((c = getc(fp)) == 0233) {	/* meta-escape, CSI */
290ef6e52b4Sreinoud 	c = ESCAPE("")[0];
291ef6e52b4Sreinoud 	*buf++ = (char) c;
292ef6e52b4Sreinoud 	*buf++ = '[';
293ef6e52b4Sreinoud     } else {
294ef6e52b4Sreinoud 	*buf++ = (char) c;
295ef6e52b4Sreinoud     }
296ef6e52b4Sreinoud     if (c != *str) {
297ef6e52b4Sreinoud 	fprintf(stderr, "%s: unknown character, exiting.\r\n", myname);
298ef6e52b4Sreinoud 	onintr(0);
299ef6e52b4Sreinoud     }
300ef6e52b4Sreinoud     last = str[strlen(str) - 1];
301ef6e52b4Sreinoud     while ((*buf++ = (char) getc(fp)) != last) {
302ef6e52b4Sreinoud 	;
303ef6e52b4Sreinoud     }
304*66a2df67Schristos #if defined(USG) || defined(__minix)
305*66a2df67Schristos     alarm(0);
306*66a2df67Schristos #else
307ef6e52b4Sreinoud     memset((char *) &it, 0, sizeof(struct itimerval));
308ef6e52b4Sreinoud     setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
309*66a2df67Schristos #endif
310ef6e52b4Sreinoud     *buf = 0;
311ef6e52b4Sreinoud }
312ef6e52b4Sreinoud 
313ef6e52b4Sreinoud /*
314ef6e52b4Sreinoud    resets termcap string to reflect current screen size
315ef6e52b4Sreinoud  */
316ef6e52b4Sreinoud int
main(int argc,char ** argv ENVP_ARG)317ef6e52b4Sreinoud main(int argc, char **argv ENVP_ARG)
318ef6e52b4Sreinoud {
319*66a2df67Schristos #ifdef USE_TERMCAP
320*66a2df67Schristos     char *env;
321*66a2df67Schristos #endif
322ef6e52b4Sreinoud     char *ptr;
323ef6e52b4Sreinoud     int emu = VT100;
324ef6e52b4Sreinoud     char *shell;
325ef6e52b4Sreinoud     int i;
326ef6e52b4Sreinoud     int rc;
327ef6e52b4Sreinoud     int rows, cols;
328*66a2df67Schristos #ifdef USE_ANY_SYSV_TERMIO
329*66a2df67Schristos     struct termio tio;
330*66a2df67Schristos #elif defined(USE_TERMIOS)
331ef6e52b4Sreinoud     struct termios tio;
332*66a2df67Schristos #else
333*66a2df67Schristos     struct sgttyb sg;
334*66a2df67Schristos #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
335*66a2df67Schristos #ifdef USE_TERMCAP
336*66a2df67Schristos     int ok_tcap = 1;
337*66a2df67Schristos     char termcap[TERMCAP_SIZE];
338*66a2df67Schristos     char newtc[TERMCAP_SIZE];
339*66a2df67Schristos #endif /* USE_TERMCAP */
340ef6e52b4Sreinoud     char buf[BUFSIZ];
341*66a2df67Schristos #ifdef TTYSIZE_STRUCT
342*66a2df67Schristos     TTYSIZE_STRUCT ts;
343*66a2df67Schristos #endif
344ef6e52b4Sreinoud     char *name_of_tty;
345*66a2df67Schristos #ifdef CANT_OPEN_DEV_TTY
346*66a2df67Schristos     extern char *ttyname();
347*66a2df67Schristos #endif
348ef6e52b4Sreinoud     const char *setname = "";
349ef6e52b4Sreinoud 
350ef6e52b4Sreinoud     myname = x_basename(argv[0]);
351ef6e52b4Sreinoud     if (strcmp(myname, sunname) == 0)
352ef6e52b4Sreinoud 	emu = SUN;
353ef6e52b4Sreinoud     for (argv++, argc--; argc > 0 && **argv == '-'; argv++, argc--) {
354ef6e52b4Sreinoud 	switch ((*argv)[1]) {
355ef6e52b4Sreinoud 	case 's':		/* Sun emulation */
356ef6e52b4Sreinoud 	    if (emu == SUN)
357ef6e52b4Sreinoud 		Usage();	/* Never returns */
358ef6e52b4Sreinoud 	    emu = SUN;
359ef6e52b4Sreinoud 	    break;
360ef6e52b4Sreinoud 	case 'u':		/* Bourne (Unix) shell */
361ef6e52b4Sreinoud 	    shell_type = SHELL_BOURNE;
362ef6e52b4Sreinoud 	    break;
363ef6e52b4Sreinoud 	case 'c':		/* C shell */
364ef6e52b4Sreinoud 	    shell_type = SHELL_C;
365ef6e52b4Sreinoud 	    break;
366ef6e52b4Sreinoud 	case 'v':
367*66a2df67Schristos 	    printf("%s\n", xtermVersion());
368ef6e52b4Sreinoud 	    exit(EXIT_SUCCESS);
369ef6e52b4Sreinoud 	default:
370ef6e52b4Sreinoud 	    Usage();		/* Never returns */
371ef6e52b4Sreinoud 	}
372ef6e52b4Sreinoud     }
373ef6e52b4Sreinoud 
374ef6e52b4Sreinoud     if (SHELL_UNKNOWN == shell_type) {
375ef6e52b4Sreinoud 	/* Find out what kind of shell this user is running.
376ef6e52b4Sreinoud 	 * This is the same algorithm that xterm uses.
377ef6e52b4Sreinoud 	 */
378ef6e52b4Sreinoud 	if ((ptr = x_getenv("SHELL")) == NULL) {
379ef6e52b4Sreinoud 	    uid_t uid = getuid();
380ef6e52b4Sreinoud 	    struct passwd pw;
381ef6e52b4Sreinoud 
382ef6e52b4Sreinoud 	    if (x_getpwuid(uid, &pw)) {
383ef6e52b4Sreinoud 		(void) x_getlogin(uid, &pw);
384ef6e52b4Sreinoud 	    }
385ef6e52b4Sreinoud 	    if (!OkPasswd(&pw)
386ef6e52b4Sreinoud 		|| *(ptr = pw.pw_shell) == 0) {
387ef6e52b4Sreinoud 		/* this is the same default that xterm uses */
388ef6e52b4Sreinoud 		ptr = x_strdup("/bin/sh");
389ef6e52b4Sreinoud 	    }
390ef6e52b4Sreinoud 	}
391ef6e52b4Sreinoud 
392ef6e52b4Sreinoud 	shell = x_basename(ptr);
393ef6e52b4Sreinoud 
394ef6e52b4Sreinoud 	/* now that we know, what kind is it? */
395ef6e52b4Sreinoud 	for (i = 0; shell_list[i].name; i++) {
396ef6e52b4Sreinoud 	    if (!strcmp(shell_list[i].name, shell)) {
397ef6e52b4Sreinoud 		break;
398ef6e52b4Sreinoud 	    }
399ef6e52b4Sreinoud 	}
400ef6e52b4Sreinoud 	shell_type = shell_list[i].type;
401ef6e52b4Sreinoud     }
402ef6e52b4Sreinoud 
403ef6e52b4Sreinoud     if (argc == 2) {
404ef6e52b4Sreinoud 	if (!setsize[emu]) {
405ef6e52b4Sreinoud 	    fprintf(stderr,
406ef6e52b4Sreinoud 		    "%s: Can't set window size under %s emulation\n",
407ef6e52b4Sreinoud 		    myname, emuname[emu]);
408ef6e52b4Sreinoud 	    exit(EXIT_FAILURE);
409ef6e52b4Sreinoud 	}
410ef6e52b4Sreinoud 	if (!checkdigits(argv[0]) || !checkdigits(argv[1])) {
411ef6e52b4Sreinoud 	    Usage();		/* Never returns */
412ef6e52b4Sreinoud 	}
413ef6e52b4Sreinoud     } else if (argc != 0) {
414ef6e52b4Sreinoud 	Usage();		/* Never returns */
415ef6e52b4Sreinoud     }
416*66a2df67Schristos #ifdef CANT_OPEN_DEV_TTY
417*66a2df67Schristos     if ((name_of_tty = ttyname(fileno(stderr))) == NULL)
418*66a2df67Schristos #endif
419ef6e52b4Sreinoud 	name_of_tty = x_strdup("/dev/tty");
420ef6e52b4Sreinoud 
421ef6e52b4Sreinoud     if ((ttyfp = fopen(name_of_tty, "r+")) == NULL) {
422ef6e52b4Sreinoud 	fprintf(stderr, "%s:  can't open terminal %s\n",
423ef6e52b4Sreinoud 		myname, name_of_tty);
424ef6e52b4Sreinoud 	exit(EXIT_FAILURE);
425ef6e52b4Sreinoud     }
426ef6e52b4Sreinoud     tty = fileno(ttyfp);
427*66a2df67Schristos #ifdef USE_TERMCAP
428*66a2df67Schristos     if ((env = x_getenv("TERM")) == 0) {
429*66a2df67Schristos 	env = x_strdup(DFT_TERMTYPE);
430*66a2df67Schristos 	if (SHELL_BOURNE == shell_type) {
431*66a2df67Schristos 	    setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
432*66a2df67Schristos 	} else {
433*66a2df67Schristos 	    setname = "setenv TERM " DFT_TERMTYPE ";\n";
434*66a2df67Schristos 	}
435*66a2df67Schristos     }
436*66a2df67Schristos     termcap[0] = 0;		/* ...just in case we've accidentally gotten terminfo */
437*66a2df67Schristos     if (tgetent(termcap, env) <= 0 || termcap[0] == 0) {
438*66a2df67Schristos 	ok_tcap = 0;
439*66a2df67Schristos     }
440*66a2df67Schristos #endif /* USE_TERMCAP */
441*66a2df67Schristos #ifdef USE_TERMINFO
442ef6e52b4Sreinoud     if (x_getenv("TERM") == 0) {
443ef6e52b4Sreinoud 	if (SHELL_BOURNE == shell_type) {
444ef6e52b4Sreinoud 	    setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
445ef6e52b4Sreinoud 	} else {
446ef6e52b4Sreinoud 	    setname = "setenv TERM " DFT_TERMTYPE ";\n";
447ef6e52b4Sreinoud 	}
448ef6e52b4Sreinoud     }
449*66a2df67Schristos #endif /* USE_TERMINFO */
450ef6e52b4Sreinoud 
451*66a2df67Schristos #ifdef USE_ANY_SYSV_TERMIO
452*66a2df67Schristos     rc = ioctl(tty, TCGETA, &tioorig);
453*66a2df67Schristos     tio = tioorig;
454*66a2df67Schristos     UIntClr(tio.c_iflag, (ICRNL | IUCLC));
455*66a2df67Schristos     UIntClr(tio.c_lflag, (ICANON | ECHO));
456*66a2df67Schristos     tio.c_cflag |= CS8;
457*66a2df67Schristos     tio.c_cc[VMIN] = 6;
458*66a2df67Schristos     tio.c_cc[VTIME] = 1;
459*66a2df67Schristos #elif defined(USE_TERMIOS)
460ef6e52b4Sreinoud     rc = tcgetattr(tty, &tioorig);
461ef6e52b4Sreinoud     tio = tioorig;
462ef6e52b4Sreinoud     UIntClr(tio.c_iflag, ICRNL);
463ef6e52b4Sreinoud     UIntClr(tio.c_lflag, (ICANON | ECHO));
464ef6e52b4Sreinoud     tio.c_cflag |= CS8;
465ef6e52b4Sreinoud     tio.c_cc[VMIN] = 6;
466ef6e52b4Sreinoud     tio.c_cc[VTIME] = 1;
467*66a2df67Schristos #else /* not USE_TERMIOS */
468*66a2df67Schristos     rc = ioctl(tty, TIOCGETP, &sgorig);
469*66a2df67Schristos     sg = sgorig;
470*66a2df67Schristos     sg.sg_flags |= RAW;
471*66a2df67Schristos     UIntClr(sg.sg_flags, ECHO);
472*66a2df67Schristos #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
473ef6e52b4Sreinoud     if (rc != 0)
474ef6e52b4Sreinoud 	failed("get tty settings");
475ef6e52b4Sreinoud 
476ef6e52b4Sreinoud     signal(SIGINT, onintr);
477ef6e52b4Sreinoud     signal(SIGQUIT, onintr);
478ef6e52b4Sreinoud     signal(SIGTERM, onintr);
479ef6e52b4Sreinoud 
480*66a2df67Schristos #ifdef USE_ANY_SYSV_TERMIO
481*66a2df67Schristos     rc = ioctl(tty, TCSETAW, &tio);
482*66a2df67Schristos #elif defined(USE_TERMIOS)
483ef6e52b4Sreinoud     rc = tcsetattr(tty, TCSADRAIN, &tio);
484*66a2df67Schristos #else /* not USE_TERMIOS */
485*66a2df67Schristos     rc = ioctl(tty, TIOCSETP, &sg);
486*66a2df67Schristos #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
487ef6e52b4Sreinoud     if (rc != 0)
488ef6e52b4Sreinoud 	failed("set tty settings");
489ef6e52b4Sreinoud 
490ef6e52b4Sreinoud     if (argc == 2) {		/* look for optional parameters of "-s" */
491ef6e52b4Sreinoud 	char *tmpbuf = TypeMallocN(char,
492ef6e52b4Sreinoud 				   strlen(setsize[emu]) +
493ef6e52b4Sreinoud 				   strlen(argv[0]) +
494ef6e52b4Sreinoud 				   strlen(argv[1]) +
495ef6e52b4Sreinoud 				   1);
496ef6e52b4Sreinoud 	if (tmpbuf == 0) {
497ef6e52b4Sreinoud 	    fprintf(stderr, "%s: Cannot query size\n", myname);
498ef6e52b4Sreinoud 	    onintr(0);
499ef6e52b4Sreinoud 	} else {
500ef6e52b4Sreinoud 	    sprintf(tmpbuf, setsize[emu], argv[0], argv[1]);
501ef6e52b4Sreinoud 	    IGNORE_RC(write(tty, tmpbuf, strlen(tmpbuf)));
502ef6e52b4Sreinoud 	    free(tmpbuf);
503ef6e52b4Sreinoud 	}
504ef6e52b4Sreinoud     }
505ef6e52b4Sreinoud     IGNORE_RC(write(tty, getsize[emu], strlen(getsize[emu])));
506ef6e52b4Sreinoud     readstring(ttyfp, buf, size[emu]);
507ef6e52b4Sreinoud     if (sscanf(buf, size[emu], &rows, &cols) != 2) {
508ef6e52b4Sreinoud 	fprintf(stderr, "%s: Can't get rows and columns\r\n", myname);
509ef6e52b4Sreinoud 	onintr(0);
510ef6e52b4Sreinoud     }
511ef6e52b4Sreinoud     if (restore[emu])
512ef6e52b4Sreinoud 	IGNORE_RC(write(tty, restore[emu], strlen(restore[emu])));
513*66a2df67Schristos #if defined(USE_STRUCT_WINSIZE)
514*66a2df67Schristos     /* finally, set the tty's window size */
515*66a2df67Schristos     if (getwsize[emu]) {
516*66a2df67Schristos 	/* get the window size in pixels */
517*66a2df67Schristos 	IGNORE_RC(write(tty, getwsize[emu], strlen(getwsize[emu])));
518*66a2df67Schristos 	readstring(ttyfp, buf, wsize[emu]);
519*66a2df67Schristos 	if (sscanf(buf, wsize[emu], &ts.ws_xpixel, &ts.ws_ypixel) != 2) {
520*66a2df67Schristos 	    fprintf(stderr, "%s: Can't get window size\r\n", myname);
521*66a2df67Schristos 	    onintr(0);
522*66a2df67Schristos 	}
523*66a2df67Schristos 	setup_winsize(ts, rows, cols, 0, 0);
524*66a2df67Schristos 	SET_TTYSIZE(tty, ts);
525*66a2df67Schristos     } else if (ioctl(tty, TIOCGWINSZ, &ts) != -1) {
526*66a2df67Schristos 	/* we don't have any way of directly finding out
527*66a2df67Schristos 	   the current height & width of the window in pixels.  We try
528*66a2df67Schristos 	   our best by computing the font height and width from the "old"
529*66a2df67Schristos 	   window-size values, and multiplying by these ratios... */
530*66a2df67Schristos #define scaled(old,new,len) (old)?((unsigned)(new)*(len)/(old)):(len)
531*66a2df67Schristos 	setup_winsize(ts, rows, cols,
532*66a2df67Schristos 		      scaled(TTYSIZE_ROWS(ts), rows, ts.ws_ypixel),
533*66a2df67Schristos 		      scaled(TTYSIZE_COLS(ts), cols, ts.ws_xpixel));
534*66a2df67Schristos 	SET_TTYSIZE(tty, ts);
535*66a2df67Schristos     }
536*66a2df67Schristos #endif /* USE_STRUCT_WINSIZE */
537ef6e52b4Sreinoud 
538*66a2df67Schristos #ifdef USE_ANY_SYSV_TERMIO
539*66a2df67Schristos     rc = ioctl(tty, TCSETAW, &tioorig);
540*66a2df67Schristos #elif defined(USE_TERMIOS)
541ef6e52b4Sreinoud     rc = tcsetattr(tty, TCSADRAIN, &tioorig);
542*66a2df67Schristos #else /* not USE_TERMIOS */
543*66a2df67Schristos     rc = ioctl(tty, TIOCSETP, &sgorig);
544*66a2df67Schristos #endif /* USE_ANY_SYSV_TERMIO/USE_TERMIOS */
545ef6e52b4Sreinoud     if (rc != 0)
546ef6e52b4Sreinoud 	failed("set tty settings");
547ef6e52b4Sreinoud 
548ef6e52b4Sreinoud     signal(SIGINT, SIG_DFL);
549ef6e52b4Sreinoud     signal(SIGQUIT, SIG_DFL);
550ef6e52b4Sreinoud     signal(SIGTERM, SIG_DFL);
551ef6e52b4Sreinoud 
552*66a2df67Schristos #ifdef USE_TERMCAP
553*66a2df67Schristos     if (ok_tcap) {
554*66a2df67Schristos 	/* update termcap string */
555*66a2df67Schristos 	/* first do columns */
556*66a2df67Schristos 	if ((ptr = x_strindex(termcap, "co#")) == NULL) {
557*66a2df67Schristos 	    fprintf(stderr, "%s: No `co#'\n", myname);
558*66a2df67Schristos 	    exit(EXIT_FAILURE);
559*66a2df67Schristos 	}
560*66a2df67Schristos 
561*66a2df67Schristos 	i = (int) (ptr - termcap) + 3;
562*66a2df67Schristos 	strncpy(newtc, termcap, (size_t) i);
563*66a2df67Schristos 	sprintf(newtc + i, "%d", cols);
564*66a2df67Schristos 	if ((ptr = strchr(ptr, ':')) != 0)
565*66a2df67Schristos 	    strcat(newtc, ptr);
566*66a2df67Schristos 
567*66a2df67Schristos 	/* now do lines */
568*66a2df67Schristos 	if ((ptr = x_strindex(newtc, "li#")) == NULL) {
569*66a2df67Schristos 	    fprintf(stderr, "%s: No `li#'\n", myname);
570*66a2df67Schristos 	    exit(EXIT_FAILURE);
571*66a2df67Schristos 	}
572*66a2df67Schristos 
573*66a2df67Schristos 	i = (int) (ptr - newtc) + 3;
574*66a2df67Schristos 	strncpy(termcap, newtc, (size_t) i);
575*66a2df67Schristos 	sprintf(termcap + i, "%d", rows);
576*66a2df67Schristos 	if ((ptr = strchr(ptr, ':')) != 0)
577*66a2df67Schristos 	    strcat(termcap, ptr);
578*66a2df67Schristos     }
579*66a2df67Schristos #endif /* USE_TERMCAP */
580ef6e52b4Sreinoud 
581ef6e52b4Sreinoud     if (SHELL_BOURNE == shell_type) {
582ef6e52b4Sreinoud 
583*66a2df67Schristos #ifdef USE_TERMCAP
584*66a2df67Schristos 	if (ok_tcap) {
585*66a2df67Schristos 	    printf("%sTERMCAP=", setname);
586*66a2df67Schristos 	    print_termcap(termcap);
587*66a2df67Schristos 	    printf(";\nexport TERMCAP;\n");
588*66a2df67Schristos 	}
589*66a2df67Schristos #endif /* USE_TERMCAP */
590*66a2df67Schristos #ifdef USE_TERMINFO
591ef6e52b4Sreinoud 	printf("%sCOLUMNS=%d;\nLINES=%d;\nexport COLUMNS LINES;\n",
592ef6e52b4Sreinoud 	       setname, cols, rows);
593*66a2df67Schristos #endif /* USE_TERMINFO */
594ef6e52b4Sreinoud 
595ef6e52b4Sreinoud     } else {			/* not Bourne shell */
596ef6e52b4Sreinoud 
597*66a2df67Schristos #ifdef USE_TERMCAP
598*66a2df67Schristos 	if (ok_tcap) {
599*66a2df67Schristos 	    printf("set noglob;\n%ssetenv TERMCAP ", setname);
600*66a2df67Schristos 	    print_termcap(termcap);
601*66a2df67Schristos 	    printf(";\nunset noglob;\n");
602*66a2df67Schristos 	}
603*66a2df67Schristos #endif /* USE_TERMCAP */
604*66a2df67Schristos #ifdef USE_TERMINFO
605ef6e52b4Sreinoud 	printf("set noglob;\n%ssetenv COLUMNS '%d';\nsetenv LINES '%d';\nunset noglob;\n",
606ef6e52b4Sreinoud 	       setname, cols, rows);
607*66a2df67Schristos #endif /* USE_TERMINFO */
608ef6e52b4Sreinoud     }
609ef6e52b4Sreinoud     exit(EXIT_SUCCESS);
610ef6e52b4Sreinoud }
611