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