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