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