xref: /illumos-gate/usr/src/cmd/ttymon/sttydefs.c (revision bd97c7ce2344fa3252d8785c35895490916bc79b)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27 /*	  All Rights Reserved	*/
28 
29 #include <stdio.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <errno.h>
33 #include <sys/types.h>
34 #include <ctype.h>
35 #include <string.h>
36 #include <termio.h>
37 #include <sys/stat.h>
38 #include <signal.h>
39 #include <stdarg.h>
40 
41 #include "tmstruct.h"
42 #include "tmextern.h"
43 #include "ttymon.h"
44 
45 static	int  nflg = 0;		/* -n seen */
46 static	int  iflg = 0;		/* -i seen */
47 static	int  fflg = 0;		/* -f seen */
48 static	int  lflg = 0;		/* -l seen */
49 
50 static	void	usage(void);
51 static	void	check_ref(void);
52 static	void	add_entry(struct Gdef *) __NORETURN;
53 static	void	remove_entry(char *);
54 static	int	copy_file(FILE *, FILE *, int, int);
55 static	int	verify(char *, int);
56 static	FILE	*open_temp(char *);
57 
58 /*
59  *	sttydefs - add, remove or check entries in /etc/ttydefs
60  *
61  *	Usage:	   sttydefs -a ttylabel [-n nextlabel] [-i initail-flags]
62  *			    [-f final-flags] [-b]
63  *		   sttydefs -r ttylabel
64  *		   sttydefs -l [ttylabel]
65  *
66  */
67 
68 int
69 main(int argc, char *argv[])
70 {
71 	int c;			/* option letter */
72 	int errflg = 0;		/* error indicator */
73 	int  aflg = 0;		/* -a seen */
74 	int  bflg = 0;		/* -b seen */
75 	int	ret;
76 	const char *argtmp;
77 	char	*nextlabel;
78 	struct Gdef ttydef, *ptr;
79 
80 	if (argc == 1)
81 		usage();
82 
83 	/* Initialize ttydef structure */
84 	memset(&ttydef, 0, sizeof (ttydef));
85 
86 	ptr = &ttydef;
87 	while ((c = getopt(argc, argv, "a:n:i:f:br:l")) != -1) {
88 		switch (c) {
89 		case 'a':
90 			aflg = TRUE;
91 			ptr->g_id = optarg;
92 			break;
93 		case 'n':
94 			nflg = TRUE;
95 			ptr->g_nextid = optarg;
96 			break;
97 		case 'i':
98 			iflg = TRUE;
99 			ptr->g_iflags = optarg;
100 			break;
101 		case 'f':
102 			fflg = TRUE;
103 			ptr->g_fflags = optarg;
104 			break;
105 		case 'b':
106 			bflg = TRUE;
107 			ptr->g_autobaud |= A_FLAG;
108 			break;
109 		case 'r':
110 			if ((argc > 3) || (optind < argc))
111 				usage();
112 			remove_entry(optarg);
113 			break;
114 		case 'l':
115 			lflg = TRUE;
116 			if (argc > 3)
117 				usage();
118 			if ((ret = check_version(TTYDEFS_VERS, TTYDEFS)) != 0) {
119 				if (ret != 2) {
120 					(void) fprintf(stderr,
121 					    "%s version number is incorrect "
122 					    "or missing.\n", TTYDEFS);
123 					exit(1);
124 				}
125 				(void) fprintf(stderr,
126 				    "sttydefs: can't open %s.\n", TTYDEFS);
127 				exit(1);
128 			}
129 			if (argv[optind] == NULL) {
130 				read_ttydefs(NULL, TRUE);
131 				printf("\n");
132 				check_ref();
133 			} else {
134 				if (argc == 3) { /* -l ttylabel */
135 					if (verify(argv[optind], 0) != 0) {
136 						errflg++;
137 						break;
138 					}
139 					argtmp = argv[optind];
140 				} else { /* -lttylabel */
141 					argtmp = argv[optind] + 2;
142 				}
143 				read_ttydefs(argtmp, TRUE);
144 				if (Ndefs == 0) {
145 					(void) fprintf(stderr,
146 					    "ttylabel <%s> not found.\n",
147 					    argtmp);
148 					exit(1);
149 				}
150 				nextlabel = Gdef[--Ndefs].g_nextid;
151 				Ndefs = 0;
152 				read_ttydefs(nextlabel, FALSE);
153 				if (Ndefs == 0) {
154 					(void) printf("\nWarning -- nextlabel "
155 					    "<%s> of <%s> does not reference "
156 					    "any existing ttylabel.\n",
157 					    nextlabel, argtmp);
158 				}
159 			}
160 			exit(0);
161 		case '?':
162 			errflg++;
163 			break;
164 		} /* end switch */
165 		if (errflg)
166 			usage();
167 	} /* end while */
168 	if (optind < argc)
169 		usage();
170 
171 	if (aflg) {
172 		add_entry(ptr);		/* never return */
173 	}
174 	if ((iflg) || (fflg) || (bflg) || (nflg))
175 		usage();
176 	return (0);
177 }
178 
179 /*
180  *	verify	- to check if arg is valid
181  *		- i.e. arg cannot start with '-' and
182  *		  arg must not longer than maxarglen
183  *		- return 0 if ok. Otherwise return -1
184  */
185 static	int
186 verify(char *arg, int maxarglen)
187 {
188 	if (*arg == '-') {
189 		(void) fprintf(stderr, "Invalid argument -- %s.\n", arg);
190 		return (-1);
191 	}
192 	if ((maxarglen) && ((int)strlen(arg) > maxarglen)) {
193 		arg[maxarglen] = '\0';
194 		(void) fprintf(stderr, "string too long, truncated to %s.\n",
195 		    arg);
196 		return (-1);
197 	}
198 	return (0);
199 }
200 
201 /*
202  * usage - print out a usage message
203  */
204 
205 static	void
206 usage(void)
207 {
208 	(void) fprintf(stderr, "Usage:\tsttydefs -a ttylabel [-n nextlabel] "
209 	    "[-i initial-flags]\n\t\t [-f final-flags] [-b]\n");
210 	(void) fprintf(stderr, "\tsttydefs -r ttylabel\n");
211 	(void) fprintf(stderr, "\tsttydefs -l [ttylabel]\n");
212 	exit(2);
213 }
214 
215 /*
216  *	add_entry - add an entry to /etc/ttydefs
217  */
218 
219 static	void
220 add_entry(struct Gdef *ttydef)
221 {
222 	FILE *fp;
223 	int	errflg = 0;
224 	char tbuf[BUFSIZ], *tp;
225 	int  add_version = FALSE;
226 
227 	if (getuid()) {
228 		(void) fprintf(stderr, "User not privileged for operation.\n");
229 		exit(1);
230 	}
231 	tp = tbuf;
232 	*tp = '\0';
233 	if ((fp = fopen(TTYDEFS, "r")) != NULL) {
234 		if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) {
235 			(void) fprintf(stderr,
236 			    "%s version number is incorrect or missing.\n",
237 			    TTYDEFS);
238 			exit(1);
239 		}
240 		if (find_label(fp, ttydef->g_id)) {
241 			(void) fclose(fp);
242 			(void) fprintf(stderr,
243 			    "Invalid request -- ttylabel <%s> already "
244 			    "exists.\n",
245 			    ttydef->g_id);
246 			exit(1);
247 		}
248 		(void) fclose(fp);
249 	} else  {
250 		add_version = TRUE;
251 	}
252 	if ((fp = fopen(TTYDEFS, "a+")) == NULL) {
253 		(void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS,
254 		    strerror(errno));
255 		exit(1);
256 	}
257 
258 	if (add_version) {
259 		(void) fprintf(fp, "# VERSION=%d\n", TTYDEFS_VERS);
260 	}
261 
262 
263 	/* if optional fields are not provided, set to default */
264 	if (!iflg)
265 		ttydef->g_iflags = DEFAULT.g_iflags;
266 	else
267 		if (check_flags(ttydef->g_iflags) != 0)
268 			errflg++;
269 	if (!fflg)
270 		ttydef->g_fflags = DEFAULT.g_fflags;
271 	else
272 		if (check_flags(ttydef->g_fflags) != 0)
273 			errflg++;
274 	if (errflg)
275 		exit(1);
276 
277 	if (!nflg)
278 		ttydef->g_nextid = ttydef->g_id;
279 
280 	if (ttydef->g_autobaud & A_FLAG)  {
281 		(void) fprintf(fp, "%s:%s:%s:A:%s\n", ttydef->g_id,
282 		    ttydef->g_iflags, ttydef->g_fflags, ttydef->g_nextid);
283 	} else {
284 		(void) fprintf(fp, "%s:%s:%s::%s\n", ttydef->g_id,
285 		    ttydef->g_iflags, ttydef->g_fflags, ttydef->g_nextid);
286 	}
287 	(void) fclose(fp);
288 	exit(0);
289 }
290 
291 static	void
292 remove_entry(char *ttylabel)
293 {
294 	FILE *tfp;		/* file pointer for temp file */
295 	int line;		/* line number entry is on */
296 	FILE *fp;		/* scratch file pointer */
297 	char *tname = "/etc/.ttydefs";
298 
299 	if (getuid()) {
300 		(void) fprintf(stderr, "User not privileged for operation.\n");
301 		exit(1);
302 	}
303 	fp = fopen(TTYDEFS, "r");
304 	if (fp == NULL) {
305 		(void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS,
306 		    strerror(errno));
307 		exit(1);
308 	}
309 	if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) {
310 		(void) fprintf(stderr,
311 		    "%s version number is incorrect or missing.\n", TTYDEFS);
312 		exit(1);
313 	}
314 	if ((line = find_label(fp, ttylabel)) == 0) {
315 		(void) fprintf(stderr,
316 		    "Invalid request, ttylabel <%s> does not exist.\n",
317 		    ttylabel);
318 		exit(1);
319 	}
320 	tfp = open_temp(tname);
321 	if (line != 1)
322 		if (copy_file(fp, tfp, 1, line - 1)) {
323 			(void) fprintf(stderr, "Error accessing temp file.\n");
324 			exit(1);
325 		}
326 	if (copy_file(fp, tfp, line + 1, -1)) {
327 		(void) fprintf(stderr, "Error accessing temp file.\n");
328 		exit(1);
329 	}
330 	(void) fclose(fp);
331 	if (fclose(tfp) == EOF) {
332 		(void) unlink(tname);
333 		(void) fprintf(stderr, "Error closing temp file.\n");
334 		exit(1);
335 	}
336 	(void) unlink(TTYDEFS);
337 	if (rename(tname, TTYDEFS) != 0) {
338 		perror("Rename failed");
339 		(void) unlink(tname);
340 		exit(1);
341 	}
342 	exit(0);
343 }
344 
345 /*
346  * open_temp - open up a temp file
347  *
348  *	args:	tname - temp file name
349  */
350 
351 static	FILE *
352 open_temp(char *tname)
353 {
354 	FILE *fp;			/* fp associated with tname */
355 	struct sigaction sigact;	/* for signal handling */
356 
357 	sigact.sa_flags = 0;
358 	sigact.sa_handler = SIG_IGN;
359 	(void) sigemptyset(&sigact.sa_mask);
360 	(void) sigaddset(&sigact.sa_mask, SIGHUP);
361 	(void) sigaddset(&sigact.sa_mask, SIGINT);
362 	(void) sigaddset(&sigact.sa_mask, SIGQUIT);
363 	(void) sigaction(SIGHUP, &sigact, NULL);
364 	(void) sigaction(SIGINT, &sigact, NULL);
365 	(void) sigaction(SIGQUIT, &sigact, NULL);
366 	(void) umask(0333);
367 	if (access(tname, 0) != -1) {
368 		(void) fprintf(stderr, "tempfile busy; try again later.\n");
369 		exit(1);
370 	}
371 	fp = fopen(tname, "w");
372 	if (fp == NULL) {
373 		perror("Cannot create tempfile");
374 		exit(1);
375 	}
376 	return (fp);
377 }
378 
379 /*
380  * copy_file - copy information from one file to another, return 0 on
381  *	success, -1 on failure
382  *
383  *	args:	fp - source file's file pointer
384  *		tfp - destination file's file pointer
385  *		start - starting line number
386  *		finish - ending line number (-1 indicates entire file)
387  */
388 
389 
390 static	int
391 copy_file(FILE *fp, FILE *tfp, int start, int finish)
392 {
393 	int i;		/* loop variable */
394 	char dummy[BUFSIZ];	/* scratch buffer */
395 
396 /*
397  * always start from the beginning because line numbers are absolute
398  */
399 
400 	rewind(fp);
401 
402 /*
403  * get to the starting point of interest
404  */
405 
406 	if (start != 1) {
407 		for (i = 1; i < start; i++)
408 			if (!fgets(dummy, BUFSIZ, fp))
409 				return (-1);
410 	}
411 
412 /*
413  * copy as much as was requested
414  */
415 
416 	if (finish != -1) {
417 		for (i = start; i <= finish; i++) {
418 			if (!fgets(dummy, BUFSIZ, fp))
419 				return (-1);
420 			if (fputs(dummy, tfp) == EOF)
421 				return (-1);
422 		}
423 	} else {
424 		for (;;) {
425 			if (fgets(dummy, BUFSIZ, fp) == NULL) {
426 				if (feof(fp))
427 					break;
428 				else
429 					return (-1);
430 			}
431 			if (fputs(dummy, tfp) == EOF)
432 				return (-1);
433 		}
434 	}
435 	return (0);
436 }
437 
438 /*
439  *	check_ref	- to check if nextlabel are referencing
440  *			  existing ttylabel
441  */
442 static	void
443 check_ref(void)
444 {
445 	int	i;
446 	struct	Gdef	*np;
447 
448 	np = &Gdef[0];
449 	for (i = 0; i < Ndefs; i++, np++) {
450 		if (find_def(np->g_nextid) == NULL) {
451 			(void) printf("Warning -- nextlabel <%s> of <%s> "
452 			    "does not reference any existing ttylabel.\n",
453 			    np->g_nextid, np->g_id);
454 		}
455 	}
456 }
457 
458 /*
459  *	log	- print a message to stdout
460  */
461 
462 void
463 log(const char *msg, ...)
464 {
465 	va_list ap;
466 	if (lflg) {
467 		va_start(ap, msg);
468 		(void) vprintf(msg, ap);
469 		va_end(ap);
470 		(void) printf("\n");
471 	} else {
472 		va_start(ap, msg);
473 		(void) vfprintf(stderr, msg, ap);
474 		va_end(ap);
475 		(void) fprintf(stderr, "\n");
476 	}
477 }
478