/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ #include #include #include #include #include #include #include #include #include #include #include "ttymon.h" #include "tmstruct.h" #include "tmextern.h" #include "stty.h" static void insert_def(struct Gdef *); static void zero(char *, int); /* * read_ttydefs - read in the /etc/ttydefs and store in Gdef array * - if id is not NULL, only get entry with that id * - if check is TRUE, print out the entries */ void read_ttydefs(const char *id, int check) { FILE *fp; static struct Gdef def; struct Gdef *gptr; static char line[BUFSIZ]; static char dbuf[BUFSIZ]; char *ptr; int len; int input, state, size, rawc, field; char oldc; static char d_id[MAXID+1], d_nextid[MAXID+1], d_autobaud[MAXID+1], d_if[BUFSIZ], d_ff[BUFSIZ]; static char *states[] = { "", "tty label", "Initial flags", "Final flags", "Autobaud", "Next label" }; if ((fp = fopen(TTYDEFS, "r")) == NULL) { log("can't open \"%s\".\n", TTYDEFS); return; } if (check) { for (len = 0; len < (size_t)(BUFSIZ - 1); len++) dbuf[len] = '-'; dbuf[len] = '\0'; } /* Start searching for the line with the proper "id". */ input = ACTIVE; field = FAILURE; do { line[0] = '\0'; for (ptr = line, oldc = '\0'; ptr < &line[sizeof (line) - 1] && (rawc = getc(fp)) != '\n' && rawc != EOF; ptr++, oldc = (char)rawc) { if ((rawc == '#') && (oldc != '\\')) break; *ptr = (char)rawc; } *ptr = '\0'; /* skip rest of the line */ if (rawc != EOF && rawc != '\n') { if (check && rawc != '#') log("Entry too long."); while ((rawc = getc(fp)) != EOF && rawc != '\n') ; } if (rawc == EOF) { if (ptr == line) break; else input = FINISHED; } /* if empty line, skip */ for (ptr = line; *ptr != '\0' && isspace(*ptr); ptr++) ; if (*ptr == '\0') continue; /* Now we have the complete line */ /* Initialize "def" and "gptr". */ gptr = &def; zero((char *)gptr, sizeof (struct Gdef)); ptr = line; state = T_TTYLABEL; (void) strncpy(d_id, getword(ptr, &size, 0), MAXID); gptr->g_id = d_id; ptr += size; if (*ptr != ':') { field = state; state = FAILURE; } else { ptr++; /* Skip the ':' */ state++; } /* If "id" != NULL, and it does not match, go to next entry */ if ((id != NULL) && (strcmp(id, gptr->g_id) != 0)) continue; if (check) { len = strlen(line); dbuf[len] = '\0'; log("\n%s", dbuf); log("%s", line); log("%s\n", dbuf); dbuf[len] = '-'; } for (; state != FAILURE && state != SUCCESS; ) { switch (state) { case T_IFLAGS: (void) strncpy(d_if, getword(ptr, &size, 1), BUFSIZ); gptr->g_iflags = d_if; ptr += size; if ((*ptr != ':') || (check_flags(d_if) != 0)) { field = state; state = FAILURE; } else { ptr++; state++; } break; case T_FFLAGS: (void) strncpy(d_ff, getword(ptr, &size, 1), BUFSIZ); gptr->g_fflags = d_ff; ptr += size; if ((*ptr != ':') || (check_flags(d_ff) != 0)) { field = state; state = FAILURE; } else { ptr++; state++; } break; case T_AUTOBAUD: (void) strncpy(d_autobaud, getword(ptr, &size, 0), MAXID); if (size > 1) { ptr += size; field = state; state = FAILURE; break; } if (size == 1) { if (*d_autobaud == 'A') { gptr->g_autobaud |= A_FLAG; } else { ptr += size; field = state; state = FAILURE; break; } } ptr += size; if (*ptr != ':') { field = state; state = FAILURE; } else { ptr++; /* Skip the ':' */ state++; } break; case T_NEXTLABEL: (void) strncpy(d_nextid, getword(ptr, &size, 0), MAXID); gptr->g_nextid = d_nextid; ptr += size; if (*ptr != '\0') { field = state; state = FAILURE; } else { state = SUCCESS; } break; } /* end switch */ } /* end for loop */ if (state == SUCCESS) { if (check) { log("ttylabel:\t%s", gptr->g_id); log("initial flags:\t%s", gptr->g_iflags); log("final flags:\t%s", gptr->g_fflags); if (gptr->g_autobaud & A_FLAG) log("autobaud:\tyes"); else log("autobaud:\tno"); log("nextlabel:\t%s", gptr->g_nextid); } if (Ndefs < MAXDEFS) { insert_def(gptr); } else { log("can't add more entries to ttydefs table, " " Maximum entries = %d", MAXDEFS); (void) fclose(fp); return; } if (id != NULL) { return; } } else { *++ptr = '\0'; log("Parsing failure in the \"%s\" field\n" "%s<--error detected here\n", states[field], line); } } while (input == ACTIVE); (void) fclose(fp); } /* * zero - zero out the buffer */ static void zero(char *adr, int size) { if (adr != NULL) { while (size--) *adr++ = '\0'; } } /* * find_def(ttylabel) * - scan Gdef table for an entry with requested "ttylabel". * - return a Gdef ptr if entry with "ttylabel" is found * - return NULL if no entry with matching "ttylabel" */ struct Gdef * find_def(char *ttylabel) { int i; struct Gdef *tp; tp = &Gdef[0]; for (i = 0; i < Ndefs; i++, tp++) { if (strcmp(ttylabel, tp->g_id) == 0) { return (tp); } } return (NULL); } /* * check_flags - check to see if the flags contains options that are * recognizable by stty * - return 0 if no error. Otherwise return -1 */ int check_flags(char *flags) { struct termio termio; struct termios termios; struct termiox termiox; struct winsize winsize; int term; int cnt = 1; char *argvp[MAXARGS]; /* stty args */ static char *binstty = "/usr/bin/stty"; static char buf[BUFSIZ]; char *s_arg; /* this will point to invalid option */ /* put flags into buf, because strtok will break up buffer */ (void) strcpy(buf, flags); argvp[0] = binstty; /* just a place holder */ mkargv(buf, &argvp[1], &cnt, MAXARGS - 1); argvp[cnt] = NULL; /* * because we don't know what type of terminal we have now, * just set term = everything, so all possible stty options * are accepted */ term = ASYNC|TERMIOS|FLOW; if ((s_arg = sttyparse(cnt, argvp, term, &termio, &termios, &termiox, &winsize)) != NULL) { log("invalid mode: %s", s_arg); return (-1); } return (0); } /* * insert_def - insert one entry into Gdef table */ static void insert_def(struct Gdef *gptr) { struct Gdef *tp; if (find_def(gptr->g_id) != NULL) { log("Warning -- duplicate entry <%s>, ignored", gptr->g_id); return; } tp = &Gdef[Ndefs]; tp->g_id = strsave(gptr->g_id); tp->g_iflags = strsave(gptr->g_iflags); tp->g_fflags = strsave(gptr->g_fflags); tp->g_autobaud = gptr->g_autobaud; tp->g_nextid = strsave(gptr->g_nextid); Ndefs++; } /* * mkargv - parse the string into args, starting from args[cnt] */ void mkargv(char *string, char **args, int *cnt, int maxargs) { char *ptrin, *ptrout; int i; int qsize; for (i = 0; i < maxargs; i++) args[i] = NULL; ptrin = ptrout = string; for (i = 0; *ptrin != '\0' && i < maxargs; i++) { /* Skip excess white spaces between arguments. */ while (*ptrin == ' ' || *ptrin == '\t') { ptrin++; ptrout++; } /* Save the address of argument if there is something there. */ if (*ptrin == '\0') break; else args[i] = ptrout; /* Span the argument itself. The '\' character causes quoting */ /* of the next character to take place (except for '\0'). */ while (*ptrin != '\0') { if (*ptrin == '\\') { *ptrout++ = quoted(ptrin, &qsize); ptrin += qsize; /* Is this the end of the argument? If so quit loop. */ } else if (*ptrin == ' ' || *ptrin == '\t') { ptrin++; break; /* If this is a normal letter of the argument, save it, advancing */ /* the pointers at the same time. */ } else *ptrout++ = *ptrin++; } /* Null terminate the string. */ *ptrout++ = '\0'; } (*cnt) += i; } #ifdef DEBUG /* * dump_ttydefs - dump Gdef table to log file */ void dump_ttydefs(void) { int i; struct Gdef *gptr; gptr = &Gdef[0]; log("********** dumping ttydefs table **********"); log("Ndefs = %d", Ndefs); log(" "); for (i = 0; i < Ndefs; i++, gptr++) { log("----------------------------------------"); log("ttylabel:\t%s", gptr->g_id); log("initial flags:\t%s", gptr->g_iflags); log("final flags:\t%s", gptr->g_fflags); if (gptr->g_autobaud & A_FLAG) log("autobaud:\tyes"); else log("Autobaud:\tno"); log("nextlabel:\t%s", gptr->g_nextid); log(" "); } log("********** end dumping ttydefs table **********"); } #endif /* * this is copies from uucp/strsave.c * and is modified that if malloc fails, it will exit */ char * strsave(char *str) { char *rval; if (str == NULL) { if ((rval = malloc(1)) == NULL) { log("strsave: malloc failed"); exit(1); } *rval = '\0'; } else { if ((rval = malloc(strlen(str) + 1)) == NULL) { log("strsave: malloc failed"); exit(1); } (void) strcpy(rval, str); } return (rval); }