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