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 <stdio.h> 34 #include <unistd.h> 35 #include <stdlib.h> 36 #include <errno.h> 37 #include <sys/types.h> 38 #include <ctype.h> 39 #include <string.h> 40 #include <termio.h> 41 #include <sys/stat.h> 42 #include <signal.h> 43 #include <stdarg.h> 44 45 #include "tmstruct.h" 46 #include "ttymon.h" 47 48 static int nflg = 0; /* -n seen */ 49 static int iflg = 0; /* -i seen */ 50 static int fflg = 0; /* -f seen */ 51 static int lflg = 0; /* -l seen */ 52 53 struct Gdef Gdef[MAXDEFS]; /* array to hold entries in /etc/ttydefs */ 54 int Ndefs = 0; /* highest index to Gdef that was used */ 55 static struct Gdef DEFAULT = { /* default terminal settings */ 56 "default", 57 "9600", 58 "9600 sane", 59 0, 60 /* 61 * next label is set to 4800 so we can start searching ttydefs. 62 * if 4800 is not in ttydefs, we will loop back to use DEFAULT 63 */ 64 "4800" 65 }; 66 67 68 static void usage(); 69 static void check_ref(); 70 static void add_entry(); 71 static void remove_entry(); 72 static int copy_file(); 73 static int verify(); 74 static FILE *open_temp(); 75 extern void read_ttydefs(); 76 extern int check_version(); 77 extern int find_label(); 78 79 /* 80 * sttydefs - add, remove or check entries in /etc/ttydefs 81 * 82 * Usage: sttydefs -a ttylabel [-n nextlabel] [-i initail-flags] 83 * [-f final-flags] [-b] 84 * sttydefs -r ttylabel 85 * sttydefs -l [ttylabel] 86 * 87 */ 88 89 int 90 main(int argc, char *argv[]) 91 { 92 int c; /* option letter */ 93 int errflg = 0; /* error indicator */ 94 int aflg = 0; /* -a seen */ 95 int bflg = 0; /* -b seen */ 96 int ret; 97 #ifdef __STDC__ 98 const 99 #endif 100 char *argtmp; 101 char *nextlabel; 102 struct Gdef ttydef, *ptr; 103 104 extern char *optarg; 105 extern int optind; 106 107 if (argc == 1) 108 usage(); 109 110 /* Initialize ttydef structure */ 111 memset (&ttydef, 0, sizeof(ttydef)); 112 113 ptr = &ttydef; 114 while ((c = getopt(argc, argv, "a:n:i:f:br:l")) != -1) { 115 switch (c) { 116 case 'a': 117 aflg = TRUE; 118 ptr->g_id = optarg; 119 break; 120 case 'n': 121 nflg = TRUE; 122 ptr->g_nextid = optarg; 123 break; 124 case 'i': 125 iflg = TRUE; 126 ptr->g_iflags = optarg; 127 break; 128 case 'f': 129 fflg = TRUE; 130 ptr->g_fflags = optarg; 131 break; 132 case 'b': 133 bflg = TRUE; 134 ptr->g_autobaud |= A_FLAG; 135 break; 136 case 'r': 137 if ((argc > 3) || (optind < argc)) 138 usage(); 139 remove_entry(optarg); 140 break; 141 case 'l': 142 lflg = TRUE; 143 if (argc > 3) 144 usage(); 145 if ((ret = check_version(TTYDEFS_VERS, TTYDEFS)) != 0) { 146 if (ret != 2) { 147 (void)fprintf(stderr, "%s version number is incorrect or missing.\n",TTYDEFS); 148 exit(1); 149 } 150 (void)fprintf(stderr, "sttydefs: can't open %s.\n",TTYDEFS); 151 exit(1); 152 } 153 if (argv[optind] == NULL) { 154 read_ttydefs(NULL,TRUE); 155 printf("\n"); 156 check_ref(); 157 } 158 else { 159 if (argc == 3) { /* -l ttylabel */ 160 if (verify(argv[optind],0) != 0) { 161 errflg++; 162 break; 163 } 164 argtmp = argv[optind]; 165 } 166 else { /* -lttylabel */ 167 argtmp = argv[optind]+2; 168 } 169 read_ttydefs(argtmp,TRUE); 170 if (Ndefs == 0) { 171 (void)fprintf(stderr, 172 "ttylabel <%s> not found.\n", argtmp); 173 exit(1); 174 } 175 nextlabel = Gdef[--Ndefs].g_nextid; 176 Ndefs = 0; 177 read_ttydefs(nextlabel,FALSE); 178 if (Ndefs == 0) { 179 (void)printf("\nWarning -- nextlabel <%s> of <%s> does not reference any existing ttylabel.\n", 180 nextlabel, argtmp); 181 } 182 } 183 exit(0); 184 break; /*NOTREACHED*/ 185 case '?': 186 errflg++; 187 break; 188 } /* end switch */ 189 if (errflg) 190 usage(); 191 } /* end while */ 192 if (optind < argc) 193 usage(); 194 195 if (aflg) { 196 add_entry(ptr); /* never return */ 197 } 198 if ((iflg) || (fflg) || (bflg) || (nflg)) 199 usage(); 200 return (0); 201 } 202 203 /* 204 * verify - to check if arg is valid 205 * - i.e. arg cannot start with '-' and 206 * arg must not longer than maxarglen 207 * - return 0 if ok. Otherwise return -1 208 */ 209 static int 210 verify(arg,maxarglen) 211 char *arg; 212 int maxarglen; 213 { 214 if (*arg == '-') { 215 (void)fprintf(stderr, "Invalid argument -- %s.\n", arg); 216 return(-1); 217 } 218 if ((maxarglen) && ((int)strlen(arg) > maxarglen)) { 219 arg[maxarglen] = '\0'; 220 (void)fprintf(stderr,"string too long, truncated to %s.\n",arg); 221 return(-1); 222 } 223 return(0); 224 } 225 226 /* 227 * usage - print out a usage message 228 */ 229 230 static void 231 usage() 232 { 233 (void)fprintf(stderr, "Usage:\tsttydefs -a ttylabel [-n nextlabel] [-i initial-flags]\n\t\t [-f final-flags] [-b]\n"); 234 (void)fprintf(stderr, "\tsttydefs -r ttylabel\n"); 235 (void)fprintf(stderr, "\tsttydefs -l [ttylabel]\n"); 236 exit(2); 237 } 238 239 /* 240 * add_entry - add an entry to /etc/ttydefs 241 */ 242 243 static void 244 add_entry(ttydef) 245 struct Gdef *ttydef; 246 { 247 FILE *fp; 248 int errflg = 0; 249 char tbuf[BUFSIZ], *tp; 250 int add_version = FALSE; 251 extern int check_flags(); 252 253 if (getuid()) { 254 (void)fprintf(stderr, "User not privileged for operation.\n"); 255 exit(1); 256 } 257 tp = tbuf; 258 *tp = '\0'; 259 if ((fp = fopen(TTYDEFS, "r")) != NULL) { 260 if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) { 261 (void)fprintf(stderr, 262 "%s version number is incorrect or missing.\n",TTYDEFS); 263 exit(1); 264 } 265 if (find_label(fp,ttydef->g_id)) { 266 (void)fclose(fp); 267 (void)fprintf(stderr, 268 "Invalid request -- ttylabel <%s> already exists.\n", 269 ttydef->g_id); 270 exit(1); 271 } 272 (void)fclose(fp); 273 } 274 else { 275 add_version = TRUE; 276 } 277 if ((fp = fopen(TTYDEFS, "a+")) == NULL) { 278 (void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS, 279 strerror(errno)); 280 exit(1); 281 } 282 283 if (add_version) { 284 (void)fprintf(fp,"# VERSION=%d\n", TTYDEFS_VERS); 285 } 286 287 288 /* if optional fields are not provided, set to default */ 289 if (!iflg) 290 ttydef->g_iflags = DEFAULT.g_iflags; 291 else 292 if (check_flags(ttydef->g_iflags) != 0 ) 293 errflg++; 294 if (!fflg) 295 ttydef->g_fflags = DEFAULT.g_fflags; 296 else 297 if (check_flags(ttydef->g_fflags) != 0 ) 298 errflg++; 299 if (errflg) 300 exit(1); 301 302 if (!nflg) 303 ttydef->g_nextid = ttydef->g_id; 304 305 if (ttydef->g_autobaud & A_FLAG) { 306 (void)fprintf(fp,"%s:%s:%s:A:%s\n", ttydef->g_id, ttydef->g_iflags, 307 ttydef->g_fflags, ttydef->g_nextid); 308 } 309 else { 310 (void)fprintf(fp,"%s:%s:%s::%s\n", ttydef->g_id, ttydef->g_iflags, 311 ttydef->g_fflags, ttydef->g_nextid); 312 } 313 (void)fclose(fp); 314 exit(0); 315 } 316 317 static void 318 remove_entry(ttylabel) 319 char *ttylabel; 320 { 321 FILE *tfp; /* file pointer for temp file */ 322 int line; /* line number entry is on */ 323 FILE *fp; /* scratch file pointer */ 324 char *tname = "/etc/.ttydefs"; 325 326 if (getuid()) { 327 (void)fprintf(stderr, "User not privileged for operation.\n"); 328 exit(1); 329 } 330 fp = fopen(TTYDEFS, "r"); 331 if (fp == NULL) { 332 (void) fprintf(stderr, "Could not open \"%s\": %s", TTYDEFS, 333 strerror(errno)); 334 exit(1); 335 } 336 if (check_version(TTYDEFS_VERS, TTYDEFS) != 0) { 337 (void)fprintf(stderr, 338 "%s version number is incorrect or missing.\n",TTYDEFS); 339 exit(1); 340 } 341 if ((line = find_label(fp, ttylabel)) == 0) { 342 (void)fprintf(stderr, 343 "Invalid request, ttylabel <%s> does not exist.\n", ttylabel); 344 exit(1); 345 } 346 tfp = open_temp(tname); 347 if (line != 1) 348 if (copy_file(fp, tfp, 1, line - 1)) { 349 (void)fprintf(stderr,"Error accessing temp file.\n"); 350 exit(1); 351 } 352 if (copy_file(fp, tfp, line + 1, -1)) { 353 (void)fprintf(stderr,"Error accessing temp file.\n"); 354 exit(1); 355 } 356 (void)fclose(fp); 357 if (fclose(tfp) == EOF) { 358 (void)unlink(tname); 359 (void)fprintf(stderr,"Error closing temp file.\n"); 360 exit(1); 361 } 362 (void)unlink(TTYDEFS); 363 if (rename(tname, TTYDEFS) != 0 ) { 364 perror("Rename failed"); 365 (void)unlink(tname); 366 exit(1); 367 } 368 exit(0); 369 } 370 371 /* 372 * open_temp - open up a temp file 373 * 374 * args: tname - temp file name 375 */ 376 377 static FILE * 378 open_temp(tname) 379 char *tname; 380 { 381 FILE *fp; /* fp associated with tname */ 382 struct sigaction sigact; /* for signal handling */ 383 384 sigact.sa_flags = 0; 385 sigact.sa_handler = SIG_IGN; 386 (void) sigemptyset(&sigact.sa_mask); 387 (void) sigaddset(&sigact.sa_mask, SIGHUP); 388 (void) sigaddset(&sigact.sa_mask, SIGINT); 389 (void) sigaddset(&sigact.sa_mask, SIGQUIT); 390 (void) sigaction(SIGHUP, &sigact, NULL); 391 (void) sigaction(SIGINT, &sigact, NULL); 392 (void) sigaction(SIGQUIT, &sigact, NULL); 393 (void)umask(0333); 394 if (access(tname, 0) != -1) { 395 (void)fprintf(stderr,"tempfile busy; try again later.\n"); 396 exit(1); 397 } 398 fp = fopen(tname, "w"); 399 if (fp == NULL) { 400 perror("Cannot create tempfile"); 401 exit(1); 402 } 403 return(fp); 404 } 405 406 /* 407 * copy_file - copy information from one file to another, return 0 on 408 * success, -1 on failure 409 * 410 * args: fp - source file's file pointer 411 * tfp - destination file's file pointer 412 * start - starting line number 413 * finish - ending line number (-1 indicates entire file) 414 */ 415 416 417 static int 418 copy_file(fp, tfp, start, finish) 419 FILE *fp; 420 FILE *tfp; 421 register int start; 422 register int finish; 423 { 424 register int i; /* loop variable */ 425 char dummy[BUFSIZ]; /* scratch buffer */ 426 427 /* 428 * always start from the beginning because line numbers are absolute 429 */ 430 431 rewind(fp); 432 433 /* 434 * get to the starting point of interest 435 */ 436 437 if (start != 1) { 438 for (i = 1; i < start; i++) 439 if (!fgets(dummy, BUFSIZ, fp)) 440 return(-1); 441 } 442 443 /* 444 * copy as much as was requested 445 */ 446 447 if (finish != -1) { 448 for (i = start; i <= finish; i++) { 449 if (!fgets(dummy, BUFSIZ, fp)) 450 return(-1); 451 if (fputs(dummy, tfp) == EOF) 452 return(-1); 453 } 454 } 455 else { 456 for (;;) { 457 if (fgets(dummy, BUFSIZ, fp) == NULL) { 458 if (feof(fp)) 459 break; 460 else 461 return(-1); 462 } 463 if (fputs(dummy, tfp) == EOF) 464 return(-1); 465 } 466 } 467 return(0); 468 } 469 470 /* 471 * check_ref - to check if nextlabel are referencing 472 * existing ttylabel 473 */ 474 static void 475 check_ref() 476 { 477 int i; 478 struct Gdef *np; 479 extern struct Gdef *find_def(); 480 np = &Gdef[0]; 481 for (i = 0; i < Ndefs; i++, np++) { 482 if (find_def(np->g_nextid) == NULL) { 483 (void)printf("Warning -- nextlabel <%s> of <%s> does not reference any existing ttylabel.\n", 484 np->g_nextid, np->g_id); 485 } 486 } 487 return; 488 } 489 490 /* 491 * log - print a message to stdout 492 */ 493 494 void 495 log(const char *msg, ...) 496 { 497 va_list ap; 498 if (lflg) { 499 va_start(ap, msg); 500 (void) vprintf(msg, ap); 501 va_end(ap); 502 (void) printf("\n"); 503 } else { 504 va_start(ap, msg); 505 (void) vfprintf(stderr, msg, ap); 506 va_end(ap); 507 (void) fprintf(stderr,"\n"); 508 } 509 } 510