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