resize.c revision 1.1 1 /* $NetBSD: resize.c,v 1.1 2020/12/27 21:13:18 reinoud Exp $ */
2 /* $XTermId: resize.c,v 1.139 2017/05/31 08:58:56 tom Exp $ */
3
4 /*
5 * Copyright 2003-2015,2017 by Thomas E. Dickey
6 *
7 * All Rights Reserved
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the
11 * "Software"), to deal in the Software without restriction, including
12 * without limitation the rights to use, copy, modify, merge, publish,
13 * distribute, sublicense, and/or sell copies of the Software, and to
14 * permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
24 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 *
28 * Except as contained in this notice, the name(s) of the above copyright
29 * holders shall not be used in advertising or otherwise to promote the
30 * sale, use or other dealings in this Software without prior written
31 * authorization.
32 *
33 *
34 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
35 *
36 * All Rights Reserved
37 *
38 * Permission to use, copy, modify, and distribute this software and its
39 * documentation for any purpose and without fee is hereby granted,
40 * provided that the above copyright notice appear in all copies and that
41 * both that copyright notice and this permission notice appear in
42 * supporting documentation, and that the name of Digital Equipment
43 * Corporation not be used in advertising or publicity pertaining to
44 * distribution of the software without specific, written prior permission.
45 *
46 *
47 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 * SOFTWARE.
54 */
55
56 /*
57 * Extracted version from Xterm tailored for NetBSD
58 */
59 /* resize.c */
60
61 #include <stdio.h>
62 #include <ctype.h>
63 #include <stdlib.h>
64 #include <sys/ioctl.h>
65 #include <sys/time.h>
66 #include <errno.h>
67 #include <unistd.h>
68 #include <strings.h>
69 #include <libgen.h>
70 #include <termios.h>
71 #include "xstrings.h"
72
73
74 /* imported from origional <xterm.h> */
75 #define DFT_TERMTYPE "xterm"
76 #define UIntClr(dst,bits) dst = dst & (unsigned) ~(bits)
77
78 #include <signal.h>
79 #include <pwd.h>
80
81 #define ESCAPE(string) "\033" string
82
83 #define EMULATIONS 2
84 #define SUN 1
85 #define VT100 0
86
87 #define TIMEOUT 10
88
89 #define SHELL_UNKNOWN 0
90 #define SHELL_C 1
91 #define SHELL_BOURNE 2
92 /* *INDENT-OFF* */
93 static struct {
94 const char *name;
95 int type;
96 } shell_list[] = {
97 { "csh", SHELL_C }, /* vanilla cshell */
98 { "jcsh", SHELL_C },
99 { "tcsh", SHELL_C },
100 { "sh", SHELL_BOURNE }, /* vanilla Bourne shell */
101 { "ash", SHELL_BOURNE },
102 { "bash", SHELL_BOURNE }, /* GNU Bourne again shell */
103 { "dash", SHELL_BOURNE },
104 { "jsh", SHELL_BOURNE },
105 { "ksh", SHELL_BOURNE }, /* Korn shell (from AT&T toolchest) */
106 { "ksh-i", SHELL_BOURNE }, /* another name for Korn shell */
107 { "ksh93", SHELL_BOURNE }, /* Korn shell */
108 { "mksh", SHELL_BOURNE },
109 { "pdksh", SHELL_BOURNE },
110 { "zsh", SHELL_BOURNE },
111 { NULL, SHELL_BOURNE } /* default (same as xterm's) */
112 };
113 /* *INDENT-ON* */
114
115 static const char *const emuname[EMULATIONS] =
116 {
117 "VT100",
118 "Sun",
119 };
120 static char *myname;
121 static int shell_type = SHELL_UNKNOWN;
122 static const char *const getsize[EMULATIONS] =
123 {
124 ESCAPE("7") ESCAPE("[r") ESCAPE("[9999;9999H") ESCAPE("[6n"),
125 ESCAPE("[18t"),
126 };
127 static const char *const restore[EMULATIONS] =
128 {
129 ESCAPE("8"),
130 0,
131 };
132 static const char *const setsize[EMULATIONS] =
133 {
134 0,
135 ESCAPE("[8;%s;%st"),
136 };
137
138 static struct termios tioorig;
139
140 static const char *const size[EMULATIONS] =
141 {
142 ESCAPE("[%d;%dR"),
143 ESCAPE("[8;%d;%dt"),
144 };
145 static const char sunname[] = "sunsize";
146 static int tty;
147 static FILE *ttyfp;
148
149
150 static void
151 failed(const char *s)
152 {
153 int save = errno;
154 IGNORE_RC(write(2, myname, strlen(myname)));
155 IGNORE_RC(write(2, ": ", (size_t) 2));
156 errno = save;
157 perror(s);
158 exit(EXIT_FAILURE);
159 }
160
161 /* ARGSUSED */
162 static void
163 onintr(int sig GCC_UNUSED)
164 {
165 (void) tcsetattr(tty, TCSADRAIN, &tioorig);
166 exit(EXIT_FAILURE);
167 }
168
169 static void
170 resize_timeout(int sig)
171 {
172 fprintf(stderr, "\n%s: Time out occurred\r\n", myname);
173 onintr(sig);
174 }
175
176 static void
177 Usage(void)
178 {
179 fprintf(stderr, strcmp(myname, sunname) == 0 ?
180 "Usage: %s [rows cols]\n" :
181 "Usage: %s [-v] [-u] [-c] [-s [rows cols]]\n", myname);
182 exit(EXIT_FAILURE);
183 }
184
185
186 static int
187 checkdigits(char *str)
188 {
189 while (*str) {
190 if (!isdigit(CharOf(*str)))
191 return (0);
192 str++;
193 }
194 return (1);
195 }
196
197 static void
198 readstring(FILE *fp, char *buf, const char *str)
199 {
200 int last, c;
201 struct itimerval it;
202
203 signal(SIGALRM, resize_timeout);
204 memset((char *) &it, 0, sizeof(struct itimerval));
205 it.it_value.tv_sec = TIMEOUT;
206 setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
207 if ((c = getc(fp)) == 0233) { /* meta-escape, CSI */
208 c = ESCAPE("")[0];
209 *buf++ = (char) c;
210 *buf++ = '[';
211 } else {
212 *buf++ = (char) c;
213 }
214 if (c != *str) {
215 fprintf(stderr, "%s: unknown character, exiting.\r\n", myname);
216 onintr(0);
217 }
218 last = str[strlen(str) - 1];
219 while ((*buf++ = (char) getc(fp)) != last) {
220 ;
221 }
222 memset((char *) &it, 0, sizeof(struct itimerval));
223 setitimer(ITIMER_REAL, &it, (struct itimerval *) NULL);
224 *buf = 0;
225 }
226
227 /*
228 resets termcap string to reflect current screen size
229 */
230 int
231 main(int argc, char **argv ENVP_ARG)
232 {
233 char *ptr;
234 int emu = VT100;
235 char *shell;
236 int i;
237 int rc;
238 int rows, cols;
239 struct termios tio;
240 char buf[BUFSIZ];
241 char *name_of_tty;
242 const char *setname = "";
243
244 myname = x_basename(argv[0]);
245 if (strcmp(myname, sunname) == 0)
246 emu = SUN;
247 for (argv++, argc--; argc > 0 && **argv == '-'; argv++, argc--) {
248 switch ((*argv)[1]) {
249 case 's': /* Sun emulation */
250 if (emu == SUN)
251 Usage(); /* Never returns */
252 emu = SUN;
253 break;
254 case 'u': /* Bourne (Unix) shell */
255 shell_type = SHELL_BOURNE;
256 break;
257 case 'c': /* C shell */
258 shell_type = SHELL_C;
259 break;
260 case 'v':
261 printf("Xterm(330)\n");
262 exit(EXIT_SUCCESS);
263 default:
264 Usage(); /* Never returns */
265 }
266 }
267
268 if (SHELL_UNKNOWN == shell_type) {
269 /* Find out what kind of shell this user is running.
270 * This is the same algorithm that xterm uses.
271 */
272 if ((ptr = x_getenv("SHELL")) == NULL) {
273 uid_t uid = getuid();
274 struct passwd pw;
275
276 if (x_getpwuid(uid, &pw)) {
277 (void) x_getlogin(uid, &pw);
278 }
279 if (!OkPasswd(&pw)
280 || *(ptr = pw.pw_shell) == 0) {
281 /* this is the same default that xterm uses */
282 ptr = x_strdup("/bin/sh");
283 }
284 }
285
286 shell = x_basename(ptr);
287
288 /* now that we know, what kind is it? */
289 for (i = 0; shell_list[i].name; i++) {
290 if (!strcmp(shell_list[i].name, shell)) {
291 break;
292 }
293 }
294 shell_type = shell_list[i].type;
295 }
296
297 if (argc == 2) {
298 if (!setsize[emu]) {
299 fprintf(stderr,
300 "%s: Can't set window size under %s emulation\n",
301 myname, emuname[emu]);
302 exit(EXIT_FAILURE);
303 }
304 if (!checkdigits(argv[0]) || !checkdigits(argv[1])) {
305 Usage(); /* Never returns */
306 }
307 } else if (argc != 0) {
308 Usage(); /* Never returns */
309 }
310 name_of_tty = x_strdup("/dev/tty");
311
312 if ((ttyfp = fopen(name_of_tty, "r+")) == NULL) {
313 fprintf(stderr, "%s: can't open terminal %s\n",
314 myname, name_of_tty);
315 exit(EXIT_FAILURE);
316 }
317 tty = fileno(ttyfp);
318 if (x_getenv("TERM") == 0) {
319 if (SHELL_BOURNE == shell_type) {
320 setname = "TERM=" DFT_TERMTYPE ";\nexport TERM;\n";
321 } else {
322 setname = "setenv TERM " DFT_TERMTYPE ";\n";
323 }
324 }
325
326 rc = tcgetattr(tty, &tioorig);
327 tio = tioorig;
328 UIntClr(tio.c_iflag, ICRNL);
329 UIntClr(tio.c_lflag, (ICANON | ECHO));
330 tio.c_cflag |= CS8;
331 tio.c_cc[VMIN] = 6;
332 tio.c_cc[VTIME] = 1;
333 if (rc != 0)
334 failed("get tty settings");
335
336 signal(SIGINT, onintr);
337 signal(SIGQUIT, onintr);
338 signal(SIGTERM, onintr);
339
340 rc = tcsetattr(tty, TCSADRAIN, &tio);
341 if (rc != 0)
342 failed("set tty settings");
343
344 if (argc == 2) { /* look for optional parameters of "-s" */
345 char *tmpbuf = TypeMallocN(char,
346 strlen(setsize[emu]) +
347 strlen(argv[0]) +
348 strlen(argv[1]) +
349 1);
350 if (tmpbuf == 0) {
351 fprintf(stderr, "%s: Cannot query size\n", myname);
352 onintr(0);
353 } else {
354 sprintf(tmpbuf, setsize[emu], argv[0], argv[1]);
355 IGNORE_RC(write(tty, tmpbuf, strlen(tmpbuf)));
356 free(tmpbuf);
357 }
358 }
359 IGNORE_RC(write(tty, getsize[emu], strlen(getsize[emu])));
360 readstring(ttyfp, buf, size[emu]);
361 if (sscanf(buf, size[emu], &rows, &cols) != 2) {
362 fprintf(stderr, "%s: Can't get rows and columns\r\n", myname);
363 onintr(0);
364 }
365 if (restore[emu])
366 IGNORE_RC(write(tty, restore[emu], strlen(restore[emu])));
367
368 rc = tcsetattr(tty, TCSADRAIN, &tioorig);
369 if (rc != 0)
370 failed("set tty settings");
371
372 signal(SIGINT, SIG_DFL);
373 signal(SIGQUIT, SIG_DFL);
374 signal(SIGTERM, SIG_DFL);
375
376
377 if (SHELL_BOURNE == shell_type) {
378
379 printf("%sCOLUMNS=%d;\nLINES=%d;\nexport COLUMNS LINES;\n",
380 setname, cols, rows);
381
382 } else { /* not Bourne shell */
383
384 printf("set noglob;\n%ssetenv COLUMNS '%d';\nsetenv LINES '%d';\nunset noglob;\n",
385 setname, cols, rows);
386 }
387 exit(EXIT_SUCCESS);
388 }
389