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 */ 67static struct flock fl; 68#define LOCK_EX F_WRLCK 69 70static 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 ... */ 77static 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"; 82const char *pname; /* program name */ 83static sigjmp_buf deadline; 84 85/* command line arguments */ 86static int display; 87static int persist; 88static int addflag; 89static int deleteflag; 90 91/* function headers */ 92static void setaux(char *); 93static void unsetaux(char *); 94static void getconsole(void); 95static boolean_t has_carrier(int fd); 96static boolean_t modem_support(int fd); 97static void setfallback(char *argv[]); 98static void removefallback(void); 99static void fallbackdaemon(void); 100static void persistlist(void); 101static int verifyarg(char *, int); 102static int safeopen(char *); 103static void catch_term(void); 104static void catch_alarm(void); 105static void catch_hup(void); 106static void cleanup_on_exit(void); 107static void addtolist(char *); 108static void removefromlist(char *); 109static int pathcmp(char *, char *); 110static int lckfunc(int, int); 111typedef void (*sig_handler_t)(); 112static 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 120int 121main(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 */ 262static void 263catch_term() 264{ 265 exit(E_SUCCESS); 266} 267 268/* handle lack of carrier on open */ 269static void 270catch_alarm() 271{ 272 siglongjmp(deadline, 1); 273} 274 275/* caught a sighup */ 276static void 277catch_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. */ 288static void 289cleanup_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 */ 298static void 299setaux(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 */ 326static void 327unsetaux(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 343static int 344getlock(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 363static void 364addtolist(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 */ 418static void 419removefromlist(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 481static int 482pathcmp(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 */ 505static void 506getconsole(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 */ 544static boolean_t 545modem_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 555static boolean_t 556has_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 567static void 568setfallback(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 */ 614static void 615removefallback(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 */ 653static void 654fallbackdaemon(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 840static void 841persistlist(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 864static int 865verifyarg(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 } 921err_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 */ 929static int 930safeopen(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 953static int 954lckfunc(int fd, int flag) 955{ 956 fl.l_type = flag; 957 return (fcntl(fd, F_SETLKW, &fl)); 958} 959