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
read_ttydefs(const char * id,int check)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
zero(char * adr,int size)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 *
find_def(char * ttylabel)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
check_flags(char * flags)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
insert_def(struct Gdef * gptr)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
mkargv(char * string,char ** args,int * cnt,int maxargs)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
dump_ttydefs(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 *
strsave(char * str)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