1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1980, 1991, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33
34__FBSDID("$FreeBSD$");
35
36#ifndef lint
37static const char copyright[] =
38"@(#) Copyright (c) 1980, 1991, 1993\n\
39	The Regents of the University of California.  All rights reserved.\n";
40#endif
41
42#ifndef lint
43static const char sccsid[] = "@(#)tset.c	8.1 (Berkeley) 6/9/93";
44#endif
45
46#include <sys/types.h>
47#include <sys/ioctl.h>
48
49#include <ctype.h>
50#include <err.h>
51#include <stdio.h>
52#include <stdlib.h>
53#include <string.h>
54#include <termcap.h>
55#include <termios.h>
56#include <unistd.h>
57
58#include "extern.h"
59
60void	obsolete(char *[]);
61void	report(const char *, int, u_int);
62void	usage(void);
63
64struct termios mode, oldmode;
65
66int	erasech;		/* new erase character */
67int	intrchar;		/* new interrupt character */
68int	isreset;		/* invoked as reset */
69int	killch;			/* new kill character */
70int	Lines, Columns;		/* window size */
71speed_t	Ospeed;
72
73int
74main(int argc, char *argv[])
75{
76#ifdef TIOCGWINSZ
77	struct winsize win;
78#endif
79	int ch, noinit, noset, quiet, Sflag, sflag, showterm, usingupper;
80	char *p, *tcapbuf;
81	const char *ttype;
82
83	if (tcgetattr(STDERR_FILENO, &mode) < 0)
84		err(1, "standard error");
85
86	oldmode = mode;
87	Ospeed = cfgetospeed(&mode);
88
89	if ((p = strrchr(*argv, '/')))
90		++p;
91	else
92		p = *argv;
93	usingupper = isupper(*p);
94	if (!strcasecmp(p, "reset")) {
95		isreset = 1;
96		reset_mode();
97	}
98
99	obsolete(argv);
100	noinit = noset = quiet = Sflag = sflag = showterm = 0;
101	while ((ch = getopt(argc, argv, "-a:d:e:Ii:k:m:np:QSrs")) != -1) {
102		switch (ch) {
103		case '-':		/* display term only */
104			noset = 1;
105			break;
106		case 'a':		/* OBSOLETE: map identifier to type */
107			add_mapping("arpanet", optarg);
108			break;
109		case 'd':		/* OBSOLETE: map identifier to type */
110			add_mapping("dialup", optarg);
111			break;
112		case 'e':		/* erase character */
113			erasech = optarg[0] == '^' && optarg[1] != '\0' ?
114			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
115			    optarg[0];
116			break;
117		case 'I':		/* no initialization strings */
118			noinit = 1;
119			break;
120		case 'i':		/* interrupt character */
121			intrchar = optarg[0] == '^' && optarg[1] != '\0' ?
122			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
123			    optarg[0];
124			break;
125		case 'k':		/* kill character */
126			killch = optarg[0] == '^' && optarg[1] != '\0' ?
127			    optarg[1] == '?' ? '\177' : CTRL(optarg[1]) :
128			    optarg[0];
129			break;
130		case 'm':		/* map identifier to type */
131			add_mapping(NULL, optarg);
132			break;
133		case 'n':		/* OBSOLETE: set new tty driver */
134			break;
135		case 'p':		/* OBSOLETE: map identifier to type */
136			add_mapping("plugboard", optarg);
137			break;
138		case 'Q':		/* don't output control key settings */
139			quiet = 1;
140			break;
141		case 'S':		/* output TERM/TERMCAP strings */
142			Sflag = 1;
143			break;
144		case 'r':		/* display term on stderr */
145			showterm = 1;
146			break;
147		case 's':		/* output TERM/TERMCAP strings */
148			sflag = 1;
149			break;
150		case '?':
151		default:
152			usage();
153		}
154	}
155	argc -= optind;
156	argv += optind;
157
158	if (argc > 1)
159		usage();
160
161	ttype = get_termcap_entry(*argv, &tcapbuf);
162
163	if (!noset) {
164		Columns = tgetnum("co");
165		Lines = tgetnum("li");
166
167#ifdef TIOCGWINSZ
168		/* Set window size */
169		(void)ioctl(STDERR_FILENO, TIOCGWINSZ, &win);
170		if (win.ws_row == 0 && win.ws_col == 0 &&
171		    Lines > 0 && Columns > 0) {
172			win.ws_row = Lines;
173			win.ws_col = Columns;
174			(void)ioctl(STDERR_FILENO, TIOCSWINSZ, &win);
175		}
176#endif
177		set_control_chars();
178		set_conversions(usingupper);
179
180		if (!noinit)
181			set_init();
182
183		/* Set the modes if they've changed. */
184		if (memcmp(&mode, &oldmode, sizeof(mode)))
185			tcsetattr(STDERR_FILENO, TCSADRAIN, &mode);
186	}
187
188	if (noset)
189		(void)printf("%s\n", ttype);
190	else {
191		if (showterm)
192			(void)fprintf(stderr, "Terminal type is %s.\n", ttype);
193		/*
194		 * If erase, kill and interrupt characters could have been
195		 * modified and not -Q, display the changes.
196		 */
197		if (!quiet) {
198			report("Erase", VERASE, CERASE);
199			report("Kill", VKILL, CKILL);
200			report("Interrupt", VINTR, CINTR);
201		}
202	}
203
204	if (Sflag) {
205		(void)printf("%s ", ttype);
206		if (strlen(tcapbuf) > 0)
207			wrtermcap(tcapbuf);
208	}
209
210	if (sflag) {
211		/*
212		 * Figure out what shell we're using.  A hack, we look for an
213		 * environmental variable SHELL ending in "csh".
214		 */
215		if ((p = getenv("SHELL")) &&
216		    !strcmp(p + strlen(p) - 3, "csh")) {
217			printf("set noglob;\nsetenv TERM %s;\n", ttype);
218			if (strlen(tcapbuf) > 0) {
219				printf("setenv TERMCAP '");
220				wrtermcap(tcapbuf);
221				printf("';\n");
222			}
223			printf("unset noglob;\n");
224		} else {
225			printf("TERM=%s;\n", ttype);
226			if (strlen(tcapbuf) > 0) {
227				printf("TERMCAP='");
228				wrtermcap(tcapbuf);
229				printf("';\nexport TERMCAP;\n");
230			}
231			printf("export TERM;\n");
232		}
233	}
234
235	exit(0);
236}
237
238/*
239 * Tell the user if a control key has been changed from the default value.
240 */
241void
242report(const char *name, int which, u_int def)
243{
244	u_int old, new;
245
246	new = mode.c_cc[which];
247	old = oldmode.c_cc[which];
248
249	if (old == new && old == def)
250		return;
251
252	(void)fprintf(stderr, "%s %s ", name, old == new ? "is" : "set to");
253
254	if (new == 010)
255		(void)fprintf(stderr, "backspace.\n");
256	else if (new == 0177)
257		(void)fprintf(stderr, "delete.\n");
258	else if (new < 040) {
259		new ^= 0100;
260		(void)fprintf(stderr, "control-%c (^%c).\n", new, new);
261	} else
262		(void)fprintf(stderr, "%c.\n", new);
263}
264
265/*
266 * Convert the obsolete argument form into something that getopt can handle.
267 * This means that -e, -i and -k get default arguments supplied for them.
268 */
269void
270obsolete(char *argv[])
271{
272	for (; *argv; ++argv) {
273		if (argv[0][0] != '-' || (argv[1] && argv[1][0] != '-') ||
274		    (argv[0][1] != 'e' && argv[0][1] != 'i' && argv[0][1] != 'k') ||
275			argv[0][2] != '\0')
276			continue;
277		switch(argv[0][1]) {
278		case 'e':
279			argv[0] = strdup("-e^H");
280			break;
281		case 'i':
282			argv[0] = strdup("-i^C");
283			break;
284		case 'k':
285			argv[0] = strdup("-k^U");
286			break;
287		}
288	}
289}
290
291void
292usage(void)
293{
294	(void)fprintf(stderr, "%s\n%s\n",
295"usage: tset  [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]",
296"       reset [-IQrSs] [-] [-e ch] [-i ch] [-k ch] [-m mapping] [terminal]");
297	exit(1);
298}
299
300