xref: /illumos-gate/usr/src/cmd/ttymon/tmttydefs.c (revision 2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea)
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	<unistd.h>
34 #include	<stdlib.h>
35 #include	<stdio.h>
36 #include	<ctype.h>
37 #include	<string.h>
38 #include	<sys/types.h>
39 #include	<sys/stat.h>
40 #include	<termio.h>
41 #include 	<sys/stermio.h>
42 #include 	<sys/termiox.h>
43 #include	"ttymon.h"
44 #include	"tmstruct.h"
45 #include	"tmextern.h"
46 #include	"stty.h"
47 
48 static 	void	insert_def();
49 static	void	zero();
50 int	check_flags();
51 void	mkargv();
52 
53 extern	struct	Gdef Gdef[];
54 extern	int	Ndefs;
55 char	*strsave();
56 
57 /*
58  *	read_ttydefs	- read in the /etc/ttydefs and store in Gdef array
59  *			- if id is not NULL, only get entry with that id
60  *			- if check is TRUE, print out the entries
61  */
62 void
63 read_ttydefs(id,check)
64 char 	*id;
65 int	check;
66 {
67 	FILE 	 *fp;
68 	static 	 struct Gdef def;
69 	register struct Gdef *gptr;
70 	static 	 char 	line[BUFSIZ];
71 	static 	 char 	dbuf[BUFSIZ];
72 	register char 	*ptr;
73 	int	 len;
74 	int 	 input,state,size,rawc,field;
75 	char 	 oldc;
76 	static 	 char 	d_id[MAXID+1],
77 		      	d_nextid[MAXID+1],
78 		      	d_autobaud[MAXID+1],
79 		      	d_if[BUFSIZ],
80 		      	d_ff[BUFSIZ];
81 	static 	 char *states[] = {
82 	   "","tty label","Initial flags","Final flags","Autobaud","Next label"
83 	};
84 	extern 	 char 	*getword();
85 
86 	if ((fp = fopen(TTYDEFS,"r")) == NULL) {
87 		log("can't open \"%s\".\n", TTYDEFS);
88 		return;
89 	}
90 
91 	if (check) {
92 		for (len = 0; len < (size_t)(BUFSIZ - 1); len++)
93 			dbuf[len] = '-';
94 		dbuf[len] = '\0';
95 	}
96 
97 	/* Start searching for the line with the proper "id". */
98 	input = ACTIVE;
99 	do {
100 		line[0] = '\0';
101 		for (ptr= line,oldc = '\0'; ptr < &line[sizeof(line)-1] &&
102 		 (rawc=getc(fp))!='\n' && rawc != EOF; ptr++,oldc=(char)rawc){
103 			if ((rawc == '#') && (oldc != '\\'))
104 				break;
105 			*ptr = (char)rawc;
106 		}
107 		*ptr = '\0';
108 
109 		/* skip rest of the line */
110 		if (rawc != EOF && rawc != '\n') {
111 			if (check && rawc != '#')
112 				log("Entry too long.");
113 			while ((rawc = getc(fp)) != EOF && rawc != '\n')
114 				;
115 		}
116 
117 		if (rawc == EOF) {
118 			if (ptr == line) break;
119 			else input = FINISHED;
120 		}
121 
122 		/* if empty line, skip */
123 		for (ptr=line; *ptr != '\0' && isspace(*ptr); ptr++)
124 			;
125 		if (*ptr == '\0') continue;
126 
127 		/* Now we have the complete line */
128 
129 		/* Initialize "def" and "gptr". */
130 		gptr = &def;
131 		zero((char *)gptr, sizeof(struct Gdef));
132 
133 		ptr = line;
134 		state = T_TTYLABEL;
135 		(void)strncpy(d_id,getword(ptr,&size,0),MAXID);
136 		gptr->g_id = d_id;
137 		ptr += size;
138 		if (*ptr != ':') {
139 			field = state;
140 			state = FAILURE;
141 		} else {
142 			ptr++;	/* Skip the ':' */
143 			state++ ;
144 		}
145 
146 		/* If "id" != NULL, and it does not match, go to next entry */
147 		if ((id != NULL) && (strcmp(id,gptr->g_id) != 0))
148 			continue;
149 
150 		if (check) {
151 			len = strlen(line);
152 			dbuf[len] = '\0';
153 			log("\n%s", dbuf);
154 			log("%s", line);
155 			log("%s\n", dbuf);
156 			dbuf[len] = '-';
157 		}
158 
159 
160 		for (; state != FAILURE && state != SUCCESS;) {
161 			switch(state) {
162 
163 			case T_IFLAGS:
164 				(void)strncpy(d_if,getword(ptr,&size,1),BUFSIZ);
165 				gptr->g_iflags = d_if;
166 				ptr += size;
167 				if ((*ptr != ':') || (check_flags(d_if) != 0)) {
168 					field = state;
169 					state = FAILURE;
170 				} else {
171 					ptr++;
172 					state++ ;
173 				}
174 				break;
175 
176 			case T_FFLAGS:
177 				(void)strncpy(d_ff,getword(ptr,&size,1),BUFSIZ);
178 				gptr->g_fflags = d_ff;
179 				ptr += size;
180 				if ((*ptr != ':') || (check_flags(d_ff) != 0)) {
181 					field = state;
182 					state = FAILURE;
183 				} else {
184 					ptr++;
185 					state++ ;
186 				}
187 				break;
188 
189 			case T_AUTOBAUD:
190 				(void)strncpy(d_autobaud,getword(ptr,&size,0),MAXID);
191 				if (size > 1) {
192 					ptr += size;
193 					field = state;
194 					state = FAILURE;
195 					break;
196 				}
197 				if (size == 1) {
198 					if (*d_autobaud == 'A')
199 						gptr->g_autobaud |= A_FLAG;
200 					else {
201 						ptr += size;
202 						field = state;
203 						state = FAILURE;
204 						break;
205 					}
206 				}
207 				ptr += size;
208 				if (*ptr != ':') {
209 					field = state;
210 					state = FAILURE;
211 				} else {
212 					ptr++;	/* Skip the ':' */
213 					state++ ;
214 				}
215 				break;
216 
217 			case T_NEXTLABEL:
218 				(void)strncpy(d_nextid,getword(ptr,&size,0),MAXID);
219 				gptr->g_nextid = d_nextid;
220 				ptr += size;
221 				if (*ptr != '\0') {
222 					field = state;
223 					state = FAILURE;
224 				} else state = SUCCESS;
225 				break;
226 
227 			} /* end switch */
228 		} /* end for loop */
229 
230 		if (state == SUCCESS) {
231 
232 			if (check) {
233 				log("ttylabel:\t%s", gptr->g_id);
234 				log("initial flags:\t%s", gptr->g_iflags);
235 				log("final flags:\t%s", gptr->g_fflags);
236 				if (gptr->g_autobaud & A_FLAG)
237 					log("autobaud:\tyes");
238 				else
239 					log("autobaud:\tno");
240 				log("nextlabel:\t%s", gptr->g_nextid);
241 			}
242 			if (Ndefs < MAXDEFS)
243 				insert_def(gptr);
244 			else {
245 				log("can't add more entries to ttydefs table, "
246 				   " Maximum entries = %d", MAXDEFS);
247 				(void)fclose(fp);
248 				return;
249 			}
250 			if (id != NULL) {
251 				return;
252 			}
253 		}
254 		else {
255 			*++ptr = '\0';
256 			log("Parsing failure in the \"%s\" field\n"
257 			    "%s<--error detected here\n", states[field],line);
258 		}
259 	} while (input == ACTIVE);
260 	(void)fclose(fp);
261 	return;
262 }
263 
264 /*
265  *	zero	- zero out the buffer
266  */
267 static void
268 zero(adr,size)
269 register char *adr;
270 register int size;
271 {
272 	if (adr != NULL)
273 		while (size--) *adr++ = '\0';
274 }
275 
276 /*
277  * find_def(ttylabel)
278  *	- scan Gdef table for an entry with requested "ttylabel".
279  *	- return a Gdef ptr if entry with "ttylabel" is found
280  *	- return NULL if no entry with matching "ttylabel"
281  */
282 
283 struct Gdef *
284 find_def(ttylabel)
285 char	*ttylabel;
286 {
287 	int	i;
288 	struct	Gdef	*tp;
289 	tp = &Gdef[0];
290 	for (i = 0; i < Ndefs; i++,tp++) {
291 		if (strcmp(ttylabel, tp->g_id) == 0) {
292 			return(tp);
293 		}
294 	}
295 	return(NULL);
296 }
297 
298 /*
299  *	check_flags	- check to see if the flags contains options that are
300  *			  recognizable by stty
301  *			- return 0 if no error. Otherwise return -1
302  */
303 int
304 check_flags(flags)
305 char	*flags;
306 {
307 	struct 	 termio termio;
308 	struct 	 termios termios;
309 	struct 	 termiox termiox;
310 	struct 	 winsize winsize;
311 	int	 term;
312 	int	 cnt = 1;
313 	char	 *argvp[MAXARGS];	/* stty args */
314 	static   char	 *binstty = "/usr/bin/stty";
315 	static	 char	buf[BUFSIZ];
316 	extern	 char	*sttyparse();
317 	char	*s_arg;		/* this will point to invalid option */
318 
319 	/* put flags into buf, because strtok will break up buffer */
320 	(void)strcpy(buf,flags);
321 	argvp[0] = binstty;	/* just a place holder */
322 	mkargv(buf,&argvp[1],&cnt,MAXARGS-1);
323 	argvp[cnt] = (char *)0;
324 
325 	/*
326 	 * because we don't know what type of terminal we have now,
327 	 * just set term = everything, so all possible stty options
328 	 * are accepted
329 	 */
330 	term = ASYNC|TERMIOS|FLOW;
331 	if ((s_arg = sttyparse(cnt, argvp, term, &termio, &termios,
332 			&termiox, &winsize)) != NULL) {
333 		log("invalid mode: %s", s_arg);
334 		return(-1);
335 	}
336 	return(0);
337 }
338 
339 /*
340  *	insert_def	- insert one entry into Gdef table
341  */
342 static void
343 insert_def(gptr)
344 struct	Gdef	*gptr;
345 {
346 	struct	Gdef	*tp;
347 	extern	struct	Gdef	*find_def();
348 
349 	if (find_def(gptr->g_id) != NULL) {
350 		log("Warning -- duplicate entry <%s>, ignored", gptr->g_id);
351 		return;
352 	}
353 	tp = &Gdef[Ndefs];
354 	tp->g_id = strsave(gptr->g_id);
355 	tp->g_iflags = strsave(gptr->g_iflags);
356 	tp->g_fflags = strsave(gptr->g_fflags);
357 	tp->g_autobaud = gptr->g_autobaud;
358 	tp->g_nextid = strsave(gptr->g_nextid);
359 	Ndefs++;
360 	return;
361 }
362 
363 /*
364  *	mkargv	- parse the string into args, starting from args[cnt]
365  */
366 
367 void
368 mkargv(string,args,cnt,maxargs)
369 char 	*string, **args;
370 int 	*cnt, maxargs;
371 {
372 	register char *ptrin,*ptrout;
373 	register int i;
374 	int qsize;
375 	extern	char	quoted();
376 
377 	for (i=0; i < maxargs; i++) args[i] = (char *)NULL;
378 	for (ptrin = ptrout = string,i=0; *ptrin != '\0' && i < maxargs; i++) {
379 		/* Skip excess white spaces between arguments. */
380 		while(*ptrin == ' ' || *ptrin == '\t') {
381 			ptrin++;
382 			ptrout++;
383 		}
384 		/* Save the address of argument if there is something there. */
385 		if (*ptrin == '\0') break;
386 		else args[i] = ptrout;
387 
388 /* Span the argument itself.  The '\' character causes quoting */
389 /* of the next character to take place (except for '\0'). */
390 		while (*ptrin != '\0') {
391 			if (*ptrin == '\\') {
392 				*ptrout++ = quoted(ptrin,&qsize);
393 				ptrin += qsize;
394 
395 /* Is this the end of the argument?  If so quit loop. */
396 			} else if (*ptrin == ' ' || *ptrin == '\t') {
397 				ptrin++;
398 				break;
399 
400 /* If this is a normal letter of the argument, save it, advancing */
401 /* the pointers at the same time. */
402 			} else *ptrout++ = *ptrin++;
403 		}
404 		/* Null terminate the string. */
405 		*ptrout++ = '\0';
406 	}
407 	(*cnt) += i;
408 }
409 
410 #ifdef	DEBUG
411 /*
412  *	dump_ttydefs	- dump Gdef table to log file
413  */
414 void
415 dump_ttydefs()
416 {
417 	int	i;
418 	struct	Gdef	*gptr;
419 	gptr = &Gdef[0];
420 	log("********** dumping ttydefs table **********");
421 	log("Ndefs = %d", Ndefs);
422 	log(" ");
423 	for (i = 0; i < Ndefs; i++,gptr++) {
424 		log("----------------------------------------");
425 		log("ttylabel:\t%s", gptr->g_id);
426 		log("initial flags:\t%s", gptr->g_iflags);
427 		log("final flags:\t%s", gptr->g_fflags);
428 		if (gptr->g_autobaud & A_FLAG)
429 			log("autobaud:\tyes");
430 		else
431 			log("Autobaud:\tno");
432 		log("nextlabel:\t%s", gptr->g_nextid);
433 		log(" ");
434 	}
435 	log("********** end dumping ttydefs table **********");
436 	return;
437 }
438 #endif
439 
440 
441 /*
442  * this is copies from uucp/strsave.c
443  * and is modified that if malloc fails, it will exit
444  */
445 char *
446 strsave(str)
447 register char *str;
448 {
449 	register char *rval;
450 
451 	if (str == NULL) {
452 		if ((rval = (char *)malloc(1)) == NULL) {
453 			log("strsave: malloc failed");
454 			exit(1);
455 		}
456 		*rval = '\0';
457 	}
458 	else {
459 		if ((rval = (char *)malloc(strlen(str) + 1)) == NULL) {
460 			log("strsave: malloc failed");
461 			exit(1);
462 		}
463 		(void)strcpy(rval, str);
464 	}
465 	return(rval);
466 }
467