1/*	$OpenBSD: ttyflags.c,v 1.17 2022/12/04 23:50:47 cheloha Exp $	*/
2/*	$NetBSD: ttyflags.c,v 1.8 1996/04/09 05:20:30 cgd Exp $	*/
3
4/*
5 * Copyright (c) 1996 Theo de Raadt
6 * Copyright (c) 1994 Christopher G. Demetriou
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 *    must display the following acknowledgement:
19 *      This product includes software developed by Christopher G. Demetriou.
20 * 4. The name of the author may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include <sys/types.h>
36#include <sys/ioctl.h>
37
38#include <err.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <limits.h>
42#include <paths.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <ttyent.h>
47#include <unistd.h>
48
49int all(int);
50int ttys(char **, int);
51int ttyflags(struct ttyent *, int);
52void usage(void);
53
54int nflag, vflag;
55
56/*
57 * Ttyflags sets the device-specific tty flags, based on the contents
58 * of /etc/ttys.  It can either set all of the ttys' flags, or set
59 * the flags of the ttys specified on the command line.
60 */
61int
62main(int argc, char *argv[])
63{
64	int aflag, ch, rval, pflag = 0;
65
66	aflag = nflag = vflag = 0;
67	while ((ch = getopt(argc, argv, "panv")) != -1)
68		switch (ch) {
69		case 'a':
70			aflag = 1;
71			break;
72		case 'n':		/* undocumented */
73			nflag = 1;
74			break;
75		case 'p':
76			pflag = 1;
77			break;
78		case 'v':
79			vflag = 1;
80			break;
81		default:
82			usage();
83		}
84	argc -= optind;
85	argv += optind;
86
87	if (aflag && argc != 0)
88		usage();
89
90	if (setttyent() == 0)
91		err(1, "setttyent");
92
93	if (aflag)
94		rval = all(pflag);
95	else
96		rval = ttys(argv, pflag);
97
98	if (endttyent() == 0)
99		warn("endttyent");
100
101	exit(rval);
102}
103
104/*
105 * Change all /etc/ttys entries' flags.
106 */
107int
108all(int print)
109{
110	struct ttyent *tep;
111	int rval;
112
113	rval = 0;
114	for (tep = getttyent(); tep != NULL; tep = getttyent()) {
115		/* pseudo-tty ignore TIOCSFLAGS, so don't bother */
116		if (tep->ty_type == NULL ||
117		    strcmp(tep->ty_type, "network") == 0)
118			continue;
119		if (ttyflags(tep, print))
120			rval = 1;
121	}
122	return (rval);
123}
124
125/*
126 * Change the specified ttys' flags.
127 */
128int
129ttys(char **ttylist, int print)
130{
131	struct ttyent *tep;
132	int rval;
133
134	rval = 0;
135	for (; *ttylist != NULL; ttylist++) {
136		tep = getttynam(*ttylist);
137		if (tep == NULL) {
138			warnx("couldn't find an entry in %s for \"%s\"",
139			    _PATH_TTYS, *ttylist);
140			rval = 1;
141			continue;
142		}
143
144		if (ttyflags(tep, print))
145			rval = 1;
146	}
147	return (rval);
148}
149
150
151/*
152 * Actually do the work; find out what the new flags value should be,
153 * open the device, and change the flags.
154 */
155int
156ttyflags(struct ttyent *tep, int print)
157{
158	int fd, flags = 0, rval = 0, st, sep = 0;
159	char path[PATH_MAX];
160	char strflags[256];
161
162	st = tep->ty_status;
163	strflags[0] = '\0';
164
165	/* Find the full device path name. */
166	(void)snprintf(path, sizeof path, "%s%s", _PATH_DEV, tep->ty_name);
167
168	if (print == 0) {
169		/* Convert ttyent.h flags into ioctl flags. */
170		if (st & TTY_LOCAL) {
171			flags |= TIOCFLAG_CLOCAL;
172			(void)strlcat(strflags, "local", sizeof strflags);
173			sep++;
174		}
175		if (st & TTY_RTSCTS) {
176			flags |= TIOCFLAG_CRTSCTS;
177			if (sep++)
178				(void)strlcat(strflags, "|", sizeof strflags);
179			(void)strlcat(strflags, "rtscts", sizeof strflags);
180		}
181		if (st & TTY_SOFTCAR) {
182			flags |= TIOCFLAG_SOFTCAR;
183			if (sep++)
184				(void)strlcat(strflags, "|", sizeof strflags);
185			(void)strlcat(strflags, "softcar", sizeof strflags);
186		}
187		if (st & TTY_MDMBUF) {
188			flags |= TIOCFLAG_MDMBUF;
189			if (sep++)
190				(void)strlcat(strflags, "|", sizeof strflags);
191			(void)strlcat(strflags, "mdmbuf", sizeof strflags);
192		}
193		if (vflag)
194			printf("%s setting flags to: %s\n", path, strflags);
195	}
196
197	if (nflag)
198		return (0);
199
200	/* Open the device NON-BLOCKING, set the flags, and close it. */
201	if ((fd = open(path, O_RDONLY | O_NONBLOCK)) == -1) {
202		if (!(errno == ENXIO ||
203		      (errno == ENOENT && (st & TTY_ON) == 0)))
204			rval = 1;
205		if (vflag)
206			warn("open %s", path);
207		return (rval);
208	}
209	if (print == 0) {
210		if (ioctl(fd, TIOCSFLAGS, &flags) == -1)
211			if (errno != ENOTTY || vflag) {
212				warn("TIOCSFLAGS on %s", path);
213				rval = (errno != ENOTTY);
214			}
215	} else {
216		if (ioctl(fd, TIOCGFLAGS, &flags) == -1)
217			if (errno != ENOTTY || vflag) {
218				warn("TIOCGFLAGS on %s", path);
219				rval = (errno != ENOTTY);
220			}
221		if (flags & TIOCFLAG_CLOCAL) {
222			(void)strlcat(strflags, "local", sizeof strflags);
223			sep++;
224		}
225		if (flags & TIOCFLAG_CRTSCTS) {
226			if (sep++)
227				(void)strlcat(strflags, "|", sizeof strflags);
228			(void)strlcat(strflags, "rtscts", sizeof strflags);
229		}
230		if (flags & TIOCFLAG_SOFTCAR) {
231			if (sep++)
232				(void)strlcat(strflags, "|", sizeof strflags);
233			(void)strlcat(strflags, "softcar", sizeof strflags);
234		}
235		if (flags & TIOCFLAG_MDMBUF) {
236			if (sep++)
237				(void)strlcat(strflags, "|", sizeof strflags);
238			(void)strlcat(strflags, "mdmbuf", sizeof strflags);
239		}
240		printf("%s flags are: %s\n", path, strflags);
241	}
242	if (close(fd) == -1) {
243		warn("close %s", path);
244		return (1);
245	}
246	return (rval);
247}
248
249/*
250 * Print usage information when a bogus set of arguments is given.
251 */
252void
253usage(void)
254{
255	(void)fprintf(stderr, "usage: ttyflags [-pv] [-a | tty ...]\n");
256	exit(1);
257}
258