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 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "utils.h" 30 #include <locale.h> 31 #include <poll.h> 32 #include <setjmp.h> 33 #include <signal.h> 34 #include <strings.h> 35 #include <stropts.h> 36 #include <syslog.h> 37 #include <sys/sysmsg_impl.h> 38 #include <sys/stat.h> 39 #include <sys/sysmacros.h> 40 #include <sys/systeminfo.h> 41 #include <sys/termios.h> 42 #include <sys/types.h> 43 44 #define CONSADM "/usr/sbin/consadm" 45 #define CONSADMD "/usr/sbin/consadmd" 46 #define CONSADMLOCK "/tmp/CoNsAdM.lck" 47 #define CONSDAEMON "consadmd" 48 #define MSGLOG "/dev/msglog" 49 #define CONSOLE "/dev/console" 50 #define WSCONS "/dev/wscons" 51 #define CONSCONFIG "/etc/consadm.conf" 52 #define SETCONSOLEPID "/etc/consadm.pid" 53 54 #define CONFIG 0 55 #define UNCONFIG 1 56 #define COMMENT '#' 57 #define NEWLINE '\n' 58 #define SPACE ' ' 59 #define TAB ' ' 60 61 #define E_SUCCESS 0 /* Exit status for success */ 62 #define E_ERROR 1 /* Exit status for error */ 63 #define E_USAGE 2 /* Exit status for usage error */ 64 #define E_NO_CARRIER 3 /* Exit status for no carrier */ 65 66 /* useful data structures for lock function */ 67 static struct flock fl; 68 #define LOCK_EX F_WRLCK 69 70 static char usage[] = 71 "Usage: \n" 72 "\tconsadm [ -p ] [ -a device ... ]\n" 73 "\tconsadm [ -p ] [ -d device ... ]\n" 74 "\tconsadm [ -p ]\n"; 75 76 /* data structures ... */ 77 static char conshdr[] = 78 "#\n# consadm.conf\n#" 79 "# Configuration parameters for console message redirection.\n" 80 "# Do NOT edit this file by hand -- use consadm(1m) instead.\n" 81 "#\n"; 82 const char *pname; /* program name */ 83 static sigjmp_buf deadline; 84 85 /* command line arguments */ 86 static int display; 87 static int persist; 88 static int addflag; 89 static int deleteflag; 90 91 /* function headers */ 92 static void setaux(char *); 93 static void unsetaux(char *); 94 static void getconsole(void); 95 static boolean_t has_carrier(int fd); 96 static boolean_t modem_support(int fd); 97 static void setfallback(char *argv[]); 98 static void removefallback(void); 99 static void fallbackdaemon(void); 100 static void persistlist(void); 101 static int verifyarg(char *, int); 102 static int safeopen(char *); 103 static void catch_term(void); 104 static void catch_alarm(void); 105 static void catch_hup(void); 106 static void cleanup_on_exit(void); 107 static void addtolist(char *); 108 static void removefromlist(char *); 109 static int pathcmp(char *, char *); 110 static int lckfunc(int, int); 111 typedef void (*sig_handler_t)(); 112 static int getlock(void); 113 114 /* 115 * In main, return codes carry the following meaning: 116 * 0 - successful 117 * 1 - error during the command execution 118 */ 119 120 int 121 main(int argc, char *argv[]) 122 { 123 int index; 124 struct sigaction sa; 125 int c; 126 char *p = strrchr(argv[0], '/'); 127 128 if (p == NULL) 129 p = argv[0]; 130 else 131 p++; 132 133 pname = p; 134 135 (void) setlocale(LC_ALL, ""); 136 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 137 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 138 #endif 139 (void) textdomain(TEXT_DOMAIN); 140 141 if (getuid() != 0) 142 die(gettext("must be root to run this program\n")); 143 144 /* 145 * Handle normal termination signals that may be received. 146 */ 147 sa.sa_handler = SIG_IGN; 148 sa.sa_flags = 0; 149 (void) sigemptyset(&sa.sa_mask); 150 (void) sigaction(SIGHUP, &sa, NULL); 151 (void) sigaction(SIGINT, &sa, NULL); 152 (void) sigaction(SIGQUIT, &sa, NULL); 153 (void) sigaction(SIGTERM, &sa, NULL); 154 155 /* 156 * To make sure persistent state gets removed. 157 */ 158 sa.sa_handler = cleanup_on_exit; 159 sa.sa_flags = 0; 160 (void) sigemptyset(&sa.sa_mask); 161 (void) sigaction(SIGSEGV, &sa, NULL); 162 (void) sigaction(SIGILL, &sa, NULL); 163 (void) sigaction(SIGABRT, &sa, NULL); 164 (void) sigaction(SIGBUS, &sa, NULL); 165 166 if (strcmp(pname, CONSDAEMON) == 0) { 167 fallbackdaemon(); 168 return (E_SUCCESS); 169 } 170 171 if (argc == 1) 172 display++; 173 else { 174 while ((c = getopt(argc, argv, "adp")) != EOF) { 175 switch (c) { 176 case 'a': 177 addflag++; 178 break; 179 case 'd': 180 deleteflag++; 181 break; 182 case 'p': 183 persist++; 184 break; 185 default: 186 (void) fprintf(stderr, gettext(usage)); 187 exit(E_USAGE); 188 /*NOTREACHED*/ 189 } 190 } 191 } 192 193 if (display) { 194 getconsole(); 195 return (E_SUCCESS); 196 } 197 if (addflag && deleteflag) { 198 (void) fprintf(stderr, gettext(usage)); 199 return (E_ERROR); 200 } 201 if (addflag) { 202 if (optind == argc) { 203 (void) fprintf(stderr, gettext(usage)); 204 return (E_ERROR); 205 } 206 /* separately check every device path specified */ 207 for (index = optind; index < argc; index++) { 208 if (verifyarg(argv[index], addflag)) 209 return (E_ERROR); 210 } 211 212 for (index = optind; index < argc; index++) { 213 setaux(argv[index]); 214 if (persist) 215 addtolist(argv[index]); 216 } 217 218 /* 219 * start/restart daemon based on the auxilary 220 * consoles at this time. 221 */ 222 setfallback(argv); 223 return (E_SUCCESS); 224 } else if (deleteflag) { 225 if (optind == argc) { 226 (void) fprintf(stderr, gettext(usage)); 227 return (E_ERROR); 228 } 229 /* separately check every device path specified */ 230 for (index = optind; index < argc; index++) { 231 if (verifyarg(argv[index], 0)) 232 return (E_ERROR); 233 } 234 235 for (index = optind; index < argc; index++) { 236 unsetaux(argv[index]); 237 if (persist && deleteflag) 238 removefromlist(argv[index]); 239 } 240 241 /* 242 * kill off daemon and restart with 243 * new list of auxiliary consoles 244 */ 245 setfallback(argv); 246 return (E_SUCCESS); 247 } else if (persist) { 248 if (optind < argc) { 249 (void) fprintf(stderr, gettext(usage)); 250 return (E_ERROR); 251 } 252 253 persistlist(); 254 return (E_SUCCESS); 255 } else { 256 (void) fprintf(stderr, gettext(usage)); 257 return (E_ERROR); 258 } 259 } /* main */ 260 261 /* for daemon to handle termination from user command */ 262 static void 263 catch_term() 264 { 265 exit(E_SUCCESS); 266 } 267 268 /* handle lack of carrier on open */ 269 static void 270 catch_alarm() 271 { 272 siglongjmp(deadline, 1); 273 } 274 275 /* caught a sighup */ 276 static void 277 catch_hup() 278 { 279 /* 280 * ttymon sends sighup to consadmd because it has the serial 281 * port open. We catch the signal here, but process it 282 * within fallbackdaemon(). We ignore the signal if the 283 * errno returned was EINTR. 284 */ 285 } 286 287 /* Remove persistent state on receiving signal. */ 288 static void 289 cleanup_on_exit() 290 { 291 (void) unlink(CONSADMLOCK); 292 exit(E_ERROR); 293 } 294 295 /* 296 * send ioctl to /dev/sysmsg to route msgs of the device specified. 297 */ 298 static void 299 setaux(char *dev) 300 { 301 int fd; 302 303 if ((fd = safeopen(SYSMSG)) < 0) 304 die(gettext("%s is missing or not a valid device\n"), SYSMSG); 305 306 if (ioctl(fd, CIOCSETCONSOLE, dev) != 0) { 307 /* 308 * Let setting duplicate device be warning, consadm 309 * must proceed to set persistence if requested. 310 */ 311 if (errno == EBUSY) 312 die(gettext("%s is already the default console\n"), 313 dev); 314 else if (errno != EEXIST) 315 die(gettext("cannot get table entry")); 316 } 317 syslog(LOG_WARNING, "%s: Added auxiliary device %s", CONSADM, dev); 318 319 (void) close(fd); 320 } 321 322 /* 323 * Send ioctl to device specified and 324 * Remove the entry from the list of auxiliary devices. 325 */ 326 static void 327 unsetaux(char *dev) 328 { 329 int fd; 330 331 if ((fd = safeopen(SYSMSG)) < 0) 332 die(gettext("%s is missing or not a valid device\n"), SYSMSG); 333 334 if (ioctl(fd, CIOCRMCONSOLE, dev) != 0) { 335 if (errno == EBUSY) 336 die(gettext("cannot unset the default console\n")); 337 } else 338 syslog(LOG_WARNING, "%s: Removed auxiliary device %s", 339 CONSADM, dev); 340 (void) close(fd); 341 } 342 343 static int 344 getlock(void) 345 { 346 int lckfd; 347 348 if ((lckfd = open(CONSADMLOCK, O_CREAT | O_EXCL | O_WRONLY, 349 S_IRUSR | S_IWUSR)) < 0) { 350 if (errno == EEXIST) 351 die(gettext("currently busy, try again later.\n")); 352 else 353 die(gettext("cannot open %s"), CONSADMLOCK); 354 } 355 if (lckfunc(lckfd, LOCK_EX) == -1) { 356 (void) close(lckfd); 357 (void) unlink(CONSADMLOCK); 358 die(gettext("fcntl operation failed")); 359 } 360 return (lckfd); 361 } 362 363 static void 364 addtolist(char *dev) 365 { 366 int lckfd, fd; 367 FILE *fp, *nfp; 368 char newfile[MAXPATHLEN]; 369 char buf[MAXPATHLEN]; 370 int len; 371 boolean_t found = B_FALSE; 372 373 /* update file of devices configured to get console msgs. */ 374 375 lckfd = getlock(); 376 377 /* Open new file */ 378 (void) snprintf(newfile, sizeof (newfile), "%s%d", 379 CONSCONFIG, (int)getpid()); 380 if (((fd = creat(newfile, 0644)) < 0) || 381 ((nfp = fdopen(fd, "w")) == NULL)) { 382 (void) close(lckfd); 383 (void) unlink(CONSADMLOCK); 384 die(gettext("could not create new %s file"), CONSCONFIG); 385 } 386 387 /* Add header to new file */ 388 (void) fprintf(nfp, "%s", conshdr); 389 390 /* Check that the file doesn't already exist */ 391 if ((fp = fopen(CONSCONFIG, "r")) != NULL) { 392 while (fgets(buf, MAXPATHLEN, fp) != NULL) { 393 if (buf[0] == COMMENT || buf[0] == NEWLINE || 394 buf[0] == SPACE || buf[0] == TAB) 395 continue; 396 len = strlen(buf); 397 buf[len - 1] = NULL; /* Clear carriage return */ 398 if (pathcmp(dev, buf) == 0) { 399 /* they match so use name passed in. */ 400 (void) fprintf(nfp, "%s\n", dev); 401 found = B_TRUE; 402 } else 403 (void) fprintf(nfp, "%s\n", buf); 404 } 405 } 406 /* User specified persistent settings */ 407 if (found == B_FALSE) 408 (void) fprintf(nfp, "%s\n", dev); 409 410 (void) fclose(fp); 411 (void) fclose(nfp); 412 (void) rename(newfile, CONSCONFIG); 413 (void) close(lckfd); 414 (void) unlink(CONSADMLOCK); 415 } 416 417 /* The list in CONSCONFIG gives the persistence capability in the proto */ 418 static void 419 removefromlist(char *dev) 420 { 421 int lckfd; 422 FILE *fp, *nfp; 423 char newfile[MAXPATHLEN + 1]; 424 char len; 425 char value[MAXPATHLEN + 1]; 426 boolean_t newcontents = B_FALSE; 427 428 /* update file of devices configured to get console msgs. */ 429 430 lckfd = getlock(); 431 432 if ((fp = fopen(CONSCONFIG, "r")) == NULL) { 433 (void) close(lckfd); 434 (void) unlink(CONSADMLOCK); 435 return; 436 } 437 438 /* Open new file */ 439 (void) snprintf(newfile, sizeof (newfile), "%s%d", 440 CONSCONFIG, (int)getpid()); 441 if ((nfp = fopen(newfile, "w")) == NULL) { 442 (void) close(lckfd); 443 (void) unlink(CONSADMLOCK); 444 die(gettext("cannot create new %s file"), CONSCONFIG); 445 } 446 447 /* Add header to new file */ 448 (void) fprintf(nfp, "%s", conshdr); 449 450 /* 451 * Check whether the path duplicates what is already in the 452 * file. 453 */ 454 while (fgets(value, MAXPATHLEN, fp) != NULL) { 455 /* skip comments */ 456 if (value[0] == COMMENT || value[0] == NEWLINE || 457 value[0] == SPACE || value[0] == TAB) 458 continue; 459 len = strlen(value); 460 value[len - 1] = NULL; /* Clear carriage return */ 461 if (pathcmp(dev, value) == 0) { 462 /* they match so don't write it */ 463 continue; 464 } 465 (void) fprintf(nfp, "%s\n", value); 466 newcontents = B_TRUE; 467 } 468 (void) fclose(fp); 469 (void) fclose(nfp); 470 /* Remove the file if there aren't any auxiliary consoles */ 471 if (newcontents) 472 (void) rename(newfile, CONSCONFIG); 473 else { 474 (void) unlink(CONSCONFIG); 475 (void) unlink(newfile); 476 } 477 (void) close(lckfd); 478 (void) unlink(CONSADMLOCK); 479 } 480 481 static int 482 pathcmp(char *adev, char *bdev) 483 { 484 struct stat st1; 485 struct stat st2; 486 487 if (strcmp(adev, bdev) == 0) 488 return (0); 489 490 if (stat(adev, &st1) != 0 || !S_ISCHR(st1.st_mode)) 491 die(gettext("invalid device %s\n"), adev); 492 493 if (stat(bdev, &st2) != 0 || !S_ISCHR(st2.st_mode)) 494 die(gettext("invalid device %s\n"), bdev); 495 496 if (st1.st_rdev == st2.st_rdev) 497 return (0); 498 499 return (1); 500 } 501 502 /* 503 * Display configured consoles. 504 */ 505 static void 506 getconsole(void) 507 { 508 int fd; 509 int bufsize = 0; /* size of device cache */ 510 char *infop, *ptr, *p; /* info structure for ioctl's */ 511 512 if ((fd = safeopen(SYSMSG)) < 0) 513 die(gettext("%s is missing or not a valid device\n"), SYSMSG); 514 515 if ((bufsize = ioctl(fd, CIOCGETCONSOLE, NULL)) < 0) 516 die(gettext("cannot get table entry\n")); 517 if (bufsize == 0) 518 return; 519 520 if ((infop = calloc(bufsize, sizeof (char))) == NULL) 521 die(gettext("cannot allocate buffer")); 522 523 if (ioctl(fd, CIOCGETCONSOLE, infop) < 0) 524 die(gettext("cannot get table entry\n")); 525 526 ptr = infop; 527 while (ptr != NULL) { 528 p = strchr(ptr, ' '); 529 if (p == NULL) { 530 (void) printf("%s\n", ptr); 531 break; 532 } 533 *p++ = '\0'; 534 (void) printf("%s\n", ptr); 535 ptr = p; 536 } 537 (void) close(fd); 538 } 539 540 /* 541 * It is supposed that if the device supports TIOCMGET then it 542 * might be a serial device. 543 */ 544 static boolean_t 545 modem_support(int fd) 546 { 547 int modem_state; 548 549 if (ioctl(fd, TIOCMGET, &modem_state) == 0) 550 return (B_TRUE); 551 else 552 return (B_FALSE); 553 } 554 555 static boolean_t 556 has_carrier(int fd) 557 { 558 int modem_state; 559 560 if (ioctl(fd, TIOCMGET, &modem_state) == 0) 561 return ((modem_state & TIOCM_CAR) != 0); 562 else { 563 return (B_FALSE); 564 } 565 } 566 567 static void 568 setfallback(char *argv[]) 569 { 570 pid_t pid; 571 FILE *fp; 572 char *cmd = CONSADMD; 573 int lckfd, fd; 574 575 lckfd = getlock(); 576 577 /* 578 * kill off any existing daemon 579 * remove /etc/consadm.pid 580 */ 581 removefallback(); 582 583 /* kick off a daemon */ 584 if ((pid = fork()) == (pid_t)0) { 585 /* always fallback to /dev/console */ 586 argv[0] = cmd; 587 argv[1] = NULL; 588 (void) close(0); 589 (void) close(1); 590 (void) close(2); 591 (void) close(lckfd); 592 if ((fd = open(MSGLOG, O_RDWR)) < 0) 593 die(gettext("cannot open %s"), MSGLOG); 594 (void) dup2(fd, 1); 595 (void) dup2(fd, 2); 596 (void) execv(cmd, argv); 597 exit(E_SUCCESS); 598 } else if (pid == -1) 599 die(gettext("%s not started"), CONSADMD); 600 601 if ((fp = fopen(SETCONSOLEPID, "w")) == NULL) 602 die(gettext("cannot open %s"), SETCONSOLEPID); 603 /* write daemon pid to file */ 604 (void) fprintf(fp, "%d\n", (int)pid); 605 (void) fclose(fp); 606 (void) close(lckfd); 607 (void) unlink(CONSADMLOCK); 608 } 609 610 /* 611 * Remove the daemon that would have implemented the automatic 612 * fallback in event of carrier loss on the serial console. 613 */ 614 static void 615 removefallback(void) 616 { 617 FILE *fp; 618 int pid; 619 620 if ((fp = fopen(SETCONSOLEPID, "r+")) == NULL) 621 /* file doesn't exist, so no work to do */ 622 return; 623 624 if (fscanf(fp, "%d\n", &pid) <= 0) { 625 (void) fclose(fp); 626 (void) unlink(SETCONSOLEPID); 627 return; 628 } 629 630 /* 631 * Don't shoot ourselves in the foot by killing init, 632 * sched, pageout, or fsflush. 633 */ 634 if (pid == 0 || pid == 1 || pid == 2 || pid == 3) { 635 (void) unlink(SETCONSOLEPID); 636 return; 637 } 638 /* 639 * kill off the existing daemon listed in 640 * /etc/consadm.pid 641 */ 642 (void) kill((pid_t)pid, SIGTERM); 643 644 (void) fclose(fp); 645 (void) unlink(SETCONSOLEPID); 646 } 647 648 /* 649 * Assume we always fall back to /dev/console. 650 * parameter passed in will always be the auxiliary device. 651 * The daemon will not start after the last device has been removed. 652 */ 653 static void 654 fallbackdaemon(void) 655 { 656 int fd, sysmfd, ret = 0; 657 char **devpaths; 658 pollfd_t *fds; 659 nfds_t nfds = 0; 660 int index; 661 int pollagain; 662 struct sigaction sa; 663 int bufsize = 0; /* length of device cache paths */ 664 int cachesize = 0; /* size of device cache */ 665 char *infop, *ptr, *p; /* info structure for ioctl's */ 666 667 /* 668 * catch SIGTERM cause it might be coming from user via consadm 669 */ 670 sa.sa_handler = catch_term; 671 sa.sa_flags = 0; 672 (void) sigemptyset(&sa.sa_mask); 673 (void) sigaction(SIGTERM, &sa, NULL); 674 675 /* 676 * catch SIGHUP cause it might be coming from a disconnect 677 */ 678 sa.sa_handler = catch_hup; 679 sa.sa_flags = 0; 680 (void) sigemptyset(&sa.sa_mask); 681 (void) sigaction(SIGHUP, &sa, NULL); 682 683 if ((sysmfd = safeopen(SYSMSG)) < 0) 684 die(gettext("%s is missing or not a valid device\n"), SYSMSG); 685 686 if ((bufsize = ioctl(sysmfd, CIOCGETCONSOLE, NULL)) < 0) 687 die(gettext("cannot get table entry\n")); 688 if (bufsize == 0) 689 return; 690 691 if ((infop = calloc(bufsize, sizeof (char))) == NULL) 692 die(gettext("cannot allocate buffer")); 693 694 if (ioctl(sysmfd, CIOCGETCONSOLE, infop) < 0) 695 die(gettext("cannot get table entry\n")); 696 697 ptr = infop; 698 while (ptr != NULL) { 699 p = strchr(ptr, ' '); 700 if (p == NULL) { 701 cachesize++; 702 break; 703 } 704 p++; 705 cachesize++; 706 ptr = p; 707 } 708 709 if ((fds = calloc(cachesize, sizeof (struct pollfd))) == NULL) 710 die(gettext("cannot allocate buffer")); 711 712 if ((devpaths = calloc(cachesize, sizeof (char *))) == NULL) 713 die(gettext("cannot allocate buffer")); 714 715 ptr = infop; 716 while (ptr != NULL) { 717 p = strchr(ptr, ' '); 718 if (p == NULL) { 719 if ((fd = safeopen(ptr)) < 0) { 720 warn(gettext("cannot open %s, continuing"), 721 ptr); 722 break; 723 } 724 if (!has_carrier(fd)) { 725 (void) close(fd); 726 warn(gettext( 727 "no carrier on %s, device will not be monitored.\n"), 728 ptr); 729 break; 730 } else { 731 fds[nfds].fd = fd; 732 fds[nfds].events = 0; 733 734 if ((devpaths[nfds] = 735 malloc(strlen(ptr) + 1)) == NULL) 736 die(gettext("cannot allocate buffer")); 737 738 (void) strcpy(devpaths[nfds], ptr); 739 nfds++; 740 if (nfds >= cachesize) 741 break; 742 } 743 break; 744 } 745 *p++ = '\0'; 746 747 if ((fd = safeopen(ptr)) < 0) { 748 warn(gettext("cannot open %s, continuing"), ptr); 749 ptr = p; 750 continue; 751 } 752 if (!has_carrier(fd)) { 753 (void) close(fd); 754 warn(gettext( 755 "no carrier on %s, device will not be monitored.\n"), 756 ptr); 757 ptr = p; 758 continue; 759 } else { 760 fds[nfds].fd = fd; 761 fds[nfds].events = 0; 762 763 if ((devpaths[nfds] = malloc(strlen(ptr) + 1)) == NULL) 764 die(gettext("cannot allocate buffer")); 765 766 (void) strcpy(devpaths[nfds], ptr); 767 nfds++; 768 if (nfds >= cachesize) 769 break; 770 } 771 ptr = p; 772 } 773 (void) close(sysmfd); 774 775 /* no point polling if no devices with carrier */ 776 if (nfds == 0) 777 return; 778 779 for (;;) { 780 /* daemon sleeps waiting for a hangup on the console */ 781 ret = poll(fds, nfds, INFTIM); 782 if (ret == -1) { 783 /* Check if ttymon is trying to get rid of us */ 784 if (errno == EINTR) 785 continue; 786 warn(gettext("cannot poll device")); 787 return; 788 } else if (ret == 0) { 789 warn(gettext("timeout (%d milleseconds) occured\n"), 790 INFTIM); 791 return; 792 } else { 793 /* Go through poll list looking for events. */ 794 for (index = 0; index < nfds; index++) { 795 /* expected result */ 796 if ((fds[index].revents & POLLHUP) == 797 POLLHUP) { 798 /* 799 * unsetaux console. Take out of list 800 * of current auxiliary consoles. 801 */ 802 unsetaux((char *)devpaths[index]); 803 warn(gettext( 804 "lost carrier, unsetting console %s\n"), 805 devpaths[index]); 806 syslog(LOG_WARNING, 807 "%s: lost carrier, unsetting auxiliary device %s", 808 CONSADM, devpaths[index]); 809 free(devpaths[index]); 810 devpaths[index] = NULL; 811 (void) close(fds[index].fd); 812 fds[index].fd = -1; 813 fds[index].revents = 0; 814 continue; 815 } 816 if ((fds[index].revents & POLLERR) == 817 POLLERR) { 818 warn(gettext("poll error\n")); 819 continue; 820 } else if (fds[index].revents != 0) { 821 warn(gettext( 822 "unexpected poll result 0x%x\n"), 823 fds[index].revents); 824 continue; 825 } 826 } 827 /* check whether any left to poll */ 828 pollagain = B_FALSE; 829 for (index = 0; index < nfds; index++) 830 if (fds[index].fd != -1) 831 pollagain = B_TRUE; 832 if (pollagain == B_TRUE) 833 continue; 834 else 835 return; 836 } 837 } 838 } 839 840 static void 841 persistlist(void) 842 { 843 FILE *fp; 844 char value[MAXPATHLEN + 1]; 845 int lckfd; 846 847 lckfd = getlock(); 848 849 if ((fp = fopen(CONSCONFIG, "r")) != NULL) { 850 while (fgets(value, MAXPATHLEN, fp) != NULL) { 851 /* skip comments */ 852 if (value[0] == COMMENT || 853 value[0] == NEWLINE || 854 value[0] == SPACE || value[0] == TAB) 855 continue; 856 (void) fprintf(stdout, "%s", value); 857 } 858 (void) fclose(fp); 859 } 860 (void) close(lckfd); 861 (void) unlink(CONSADMLOCK); 862 } 863 864 static int 865 verifyarg(char *dev, int flag) 866 { 867 struct stat st; 868 int fd; 869 int ret = 0; 870 871 if (dev == NULL) { 872 warn(gettext("specify device(s)\n")); 873 ret = 1; 874 goto err_exit; 875 } 876 877 if (dev[0] != '/') { 878 warn(gettext("device name must begin with a '/'\n")); 879 ret = 1; 880 goto err_exit; 881 } 882 883 if ((pathcmp(dev, SYSMSG) == 0) || 884 (pathcmp(dev, WSCONS) == 0) || 885 (pathcmp(dev, CONSOLE) == 0)) { 886 /* they match */ 887 warn(gettext("invalid device %s\n"), dev); 888 ret = 1; 889 goto err_exit; 890 } 891 892 if (stat(dev, &st) || ! S_ISCHR(st.st_mode)) { 893 warn(gettext("invalid device %s\n"), dev); 894 ret = 1; 895 goto err_exit; 896 } 897 898 /* Delete operation doesn't require this checking */ 899 if ((fd = safeopen(dev)) < 0) { 900 if (flag) { 901 warn(gettext("invalid device %s\n"), dev); 902 ret = 1; 903 } 904 goto err_exit; 905 } 906 if (!modem_support(fd)) { 907 warn(gettext("invalid device %s\n"), dev); 908 (void) close(fd); 909 ret = 1; 910 goto err_exit; 911 } 912 913 /* Only verify carrier if it's an add operation */ 914 if (flag) { 915 if (!has_carrier(fd)) { 916 warn(gettext("failure, no carrier on %s\n"), dev); 917 ret = 1; 918 goto err_exit; 919 } 920 } 921 err_exit: 922 return (ret); 923 } 924 925 /* 926 * Open the pseudo device, but be prepared to catch sigalarm if we block 927 * cause there isn't any carrier present. 928 */ 929 static int 930 safeopen(char *devp) 931 { 932 int fd; 933 struct sigaction sigact; 934 935 sigact.sa_flags = SA_RESETHAND | SA_NODEFER; 936 sigact.sa_handler = catch_alarm; 937 (void) sigemptyset(&sigact.sa_mask); 938 (void) sigaction(SIGALRM, &sigact, NULL); 939 if (sigsetjmp(deadline, 1) != 0) 940 return (-1); 941 (void) alarm(5); 942 /* The sysmsg driver sets NONBLOCK and NDELAY, but what the hell */ 943 if ((fd = open(devp, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY)) < 0) 944 return (-1); 945 (void) alarm(0); 946 sigact.sa_flags = 0; 947 sigact.sa_handler = SIG_DFL; 948 (void) sigemptyset(&sigact.sa_mask); 949 (void) sigaction(SIGALRM, &sigact, NULL); 950 return (fd); 951 } 952 953 static int 954 lckfunc(int fd, int flag) 955 { 956 fl.l_type = flag; 957 return (fcntl(fd, F_SETLKW, &fl)); 958 } 959