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 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 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 * 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 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 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 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 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 * 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