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