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