xref: /illumos-gate/usr/src/cmd/consadm/consadm.c (revision 30699046)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
234bc0a2efScasper  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include "utils.h"
287c478bd9Sstevel@tonic-gate #include <locale.h>
297c478bd9Sstevel@tonic-gate #include <poll.h>
307c478bd9Sstevel@tonic-gate #include <setjmp.h>
317c478bd9Sstevel@tonic-gate #include <signal.h>
327c478bd9Sstevel@tonic-gate #include <strings.h>
337c478bd9Sstevel@tonic-gate #include <stropts.h>
347c478bd9Sstevel@tonic-gate #include <syslog.h>
357c478bd9Sstevel@tonic-gate #include <sys/sysmsg_impl.h>
367c478bd9Sstevel@tonic-gate #include <sys/stat.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
387c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
397c478bd9Sstevel@tonic-gate #include <sys/termios.h>
407c478bd9Sstevel@tonic-gate #include <sys/types.h>
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #define	CONSADM			"/usr/sbin/consadm"
437c478bd9Sstevel@tonic-gate #define	CONSADMD		"/usr/sbin/consadmd"
447c478bd9Sstevel@tonic-gate #define	CONSADMLOCK		"/tmp/CoNsAdM.lck"
457c478bd9Sstevel@tonic-gate #define	CONSDAEMON		"consadmd"
467c478bd9Sstevel@tonic-gate #define	MSGLOG			"/dev/msglog"
477c478bd9Sstevel@tonic-gate #define	CONSOLE			"/dev/console"
487c478bd9Sstevel@tonic-gate #define	WSCONS			"/dev/wscons"
497c478bd9Sstevel@tonic-gate #define	CONSCONFIG		"/etc/consadm.conf"
507c478bd9Sstevel@tonic-gate #define	SETCONSOLEPID		"/etc/consadm.pid"
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #define	CONFIG			0
537c478bd9Sstevel@tonic-gate #define	UNCONFIG		1
547c478bd9Sstevel@tonic-gate #define	COMMENT			'#'
557c478bd9Sstevel@tonic-gate #define	NEWLINE			'\n'
567c478bd9Sstevel@tonic-gate #define	SPACE			' '
577c478bd9Sstevel@tonic-gate #define	TAB			'	'
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	E_SUCCESS	0		/* Exit status for success */
607c478bd9Sstevel@tonic-gate #define	E_ERROR		1		/* Exit status for error */
617c478bd9Sstevel@tonic-gate #define	E_USAGE		2		/* Exit status for usage error */
627c478bd9Sstevel@tonic-gate #define	E_NO_CARRIER	3		/* Exit status for no carrier */
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate /* useful data structures for lock function */
657c478bd9Sstevel@tonic-gate static struct flock fl;
667c478bd9Sstevel@tonic-gate #define	LOCK_EX F_WRLCK
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate static char usage[] =
697c478bd9Sstevel@tonic-gate 	"Usage:	\n"
707c478bd9Sstevel@tonic-gate 	"\tconsadm [ -p ] [ -a device ... ]\n"
717c478bd9Sstevel@tonic-gate 	"\tconsadm [ -p ] [ -d device ... ]\n"
727c478bd9Sstevel@tonic-gate 	"\tconsadm [ -p ]\n";
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* data structures ... */
757c478bd9Sstevel@tonic-gate static char conshdr[] =
767c478bd9Sstevel@tonic-gate 	"#\n# consadm.conf\n#"
777c478bd9Sstevel@tonic-gate 	"# Configuration parameters for console message redirection.\n"
78bbf21555SRichard Lowe 	"# Do NOT edit this file by hand -- use consadm(8) instead.\n"
797c478bd9Sstevel@tonic-gate 	"#\n";
807c478bd9Sstevel@tonic-gate const char *pname;		/* program name */
817c478bd9Sstevel@tonic-gate static sigjmp_buf deadline;
827c478bd9Sstevel@tonic-gate 
837c478bd9Sstevel@tonic-gate /* command line arguments */
847c478bd9Sstevel@tonic-gate static int display;
857c478bd9Sstevel@tonic-gate static int persist;
867c478bd9Sstevel@tonic-gate static int addflag;
877c478bd9Sstevel@tonic-gate static int deleteflag;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate /* function headers */
907c478bd9Sstevel@tonic-gate static void setaux(char *);
917c478bd9Sstevel@tonic-gate static void unsetaux(char *);
927c478bd9Sstevel@tonic-gate static void getconsole(void);
937c478bd9Sstevel@tonic-gate static boolean_t has_carrier(int fd);
947c478bd9Sstevel@tonic-gate static boolean_t modem_support(int fd);
957c478bd9Sstevel@tonic-gate static void setfallback(char *argv[]);
967c478bd9Sstevel@tonic-gate static void removefallback(void);
977c478bd9Sstevel@tonic-gate static void fallbackdaemon(void);
987c478bd9Sstevel@tonic-gate static void persistlist(void);
997c478bd9Sstevel@tonic-gate static int verifyarg(char *, int);
1007c478bd9Sstevel@tonic-gate static int safeopen(char *);
101*30699046SRichard Lowe static void catch_term(int);
102*30699046SRichard Lowe static void catch_alarm(int);
103*30699046SRichard Lowe static void catch_hup(int);
104*30699046SRichard Lowe static void cleanup_on_exit(int);
1057c478bd9Sstevel@tonic-gate static void addtolist(char *);
1067c478bd9Sstevel@tonic-gate static void removefromlist(char *);
1077c478bd9Sstevel@tonic-gate static int pathcmp(char *, char *);
1087c478bd9Sstevel@tonic-gate static int lckfunc(int, int);
1097c478bd9Sstevel@tonic-gate typedef void (*sig_handler_t)();
1107c478bd9Sstevel@tonic-gate static int getlock(void);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate /*
1137c478bd9Sstevel@tonic-gate  * In main, return codes carry the following meaning:
1147c478bd9Sstevel@tonic-gate  * 0 - successful
1157c478bd9Sstevel@tonic-gate  * 1 - error during the command execution
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate int
main(int argc,char * argv[])1197c478bd9Sstevel@tonic-gate main(int argc, char *argv[])
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	int	index;
1227c478bd9Sstevel@tonic-gate 	struct	sigaction sa;
1237c478bd9Sstevel@tonic-gate 	int	c;
1247c478bd9Sstevel@tonic-gate 	char	*p = strrchr(argv[0], '/');
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if (p == NULL)
1277c478bd9Sstevel@tonic-gate 		p = argv[0];
1287c478bd9Sstevel@tonic-gate 	else
1297c478bd9Sstevel@tonic-gate 		p++;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	pname = p;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
1347c478bd9Sstevel@tonic-gate #if	!defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
1357c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
1367c478bd9Sstevel@tonic-gate #endif
1377c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	if (getuid() != 0)
1407c478bd9Sstevel@tonic-gate 		die(gettext("must be root to run this program\n"));
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	/*
1437c478bd9Sstevel@tonic-gate 	 * Handle normal termination signals that may be received.
1447c478bd9Sstevel@tonic-gate 	 */
1457c478bd9Sstevel@tonic-gate 	sa.sa_handler = SIG_IGN;
1467c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
1477c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sa.sa_mask);
1487c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGHUP, &sa, NULL);
1497c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGINT, &sa, NULL);
1507c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGQUIT, &sa, NULL);
1517c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &sa, NULL);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/*
1547c478bd9Sstevel@tonic-gate 	 * To make sure persistent state gets removed.
1557c478bd9Sstevel@tonic-gate 	 */
1567c478bd9Sstevel@tonic-gate 	sa.sa_handler = cleanup_on_exit;
1577c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
1587c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sa.sa_mask);
1597c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGSEGV, &sa, NULL);
1607c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGILL, &sa, NULL);
1617c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGABRT, &sa, NULL);
1627c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGBUS, &sa, NULL);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if (strcmp(pname, CONSDAEMON) == 0) {
1657c478bd9Sstevel@tonic-gate 		fallbackdaemon();
1667c478bd9Sstevel@tonic-gate 		return (E_SUCCESS);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	if (argc == 1)
1707c478bd9Sstevel@tonic-gate 		display++;
1717c478bd9Sstevel@tonic-gate 	else {
1727c478bd9Sstevel@tonic-gate 		while ((c = getopt(argc, argv, "adp")) != EOF)  {
1737c478bd9Sstevel@tonic-gate 			switch (c) {
1747c478bd9Sstevel@tonic-gate 			case 'a':
1757c478bd9Sstevel@tonic-gate 				addflag++;
1767c478bd9Sstevel@tonic-gate 				break;
1777c478bd9Sstevel@tonic-gate 			case 'd':
1787c478bd9Sstevel@tonic-gate 				deleteflag++;
1797c478bd9Sstevel@tonic-gate 				break;
1807c478bd9Sstevel@tonic-gate 			case 'p':
1817c478bd9Sstevel@tonic-gate 				persist++;
1827c478bd9Sstevel@tonic-gate 				break;
1837c478bd9Sstevel@tonic-gate 			default:
1847c478bd9Sstevel@tonic-gate 				(void) fprintf(stderr, gettext(usage));
1857c478bd9Sstevel@tonic-gate 				exit(E_USAGE);
1867c478bd9Sstevel@tonic-gate 				/*NOTREACHED*/
1877c478bd9Sstevel@tonic-gate 			}
1887c478bd9Sstevel@tonic-gate 		}
1897c478bd9Sstevel@tonic-gate 	}
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	if (display) {
1927c478bd9Sstevel@tonic-gate 		getconsole();
1937c478bd9Sstevel@tonic-gate 		return (E_SUCCESS);
1947c478bd9Sstevel@tonic-gate 	}
1957c478bd9Sstevel@tonic-gate 	if (addflag && deleteflag) {
1967c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(usage));
1977c478bd9Sstevel@tonic-gate 		return (E_ERROR);
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 	if (addflag) {
2007c478bd9Sstevel@tonic-gate 		if (optind == argc) {
2017c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(usage));
2027c478bd9Sstevel@tonic-gate 			return (E_ERROR);
2037c478bd9Sstevel@tonic-gate 		}
2047c478bd9Sstevel@tonic-gate 		/* separately check every device path specified */
2057c478bd9Sstevel@tonic-gate 		for (index = optind; index < argc; index++) {
2067c478bd9Sstevel@tonic-gate 			if (verifyarg(argv[index], addflag))
2077c478bd9Sstevel@tonic-gate 				return (E_ERROR);
2087c478bd9Sstevel@tonic-gate 		}
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 		for (index = optind; index < argc; index++) {
2117c478bd9Sstevel@tonic-gate 			setaux(argv[index]);
2127c478bd9Sstevel@tonic-gate 			if (persist)
2137c478bd9Sstevel@tonic-gate 				addtolist(argv[index]);
2147c478bd9Sstevel@tonic-gate 		}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 		/*
2177c478bd9Sstevel@tonic-gate 		 * start/restart daemon based on the auxilary
2187c478bd9Sstevel@tonic-gate 		 * consoles at this time.
2197c478bd9Sstevel@tonic-gate 		 */
2207c478bd9Sstevel@tonic-gate 		setfallback(argv);
2217c478bd9Sstevel@tonic-gate 		return (E_SUCCESS);
2227c478bd9Sstevel@tonic-gate 	} else if (deleteflag) {
2237c478bd9Sstevel@tonic-gate 		if (optind == argc) {
2247c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(usage));
2257c478bd9Sstevel@tonic-gate 			return (E_ERROR);
2267c478bd9Sstevel@tonic-gate 		}
2277c478bd9Sstevel@tonic-gate 		/* separately check every device path specified */
2287c478bd9Sstevel@tonic-gate 		for (index = optind; index < argc; index++) {
2297c478bd9Sstevel@tonic-gate 			if (verifyarg(argv[index], 0))
2307c478bd9Sstevel@tonic-gate 				return (E_ERROR);
2317c478bd9Sstevel@tonic-gate 		}
2327c478bd9Sstevel@tonic-gate 
2337c478bd9Sstevel@tonic-gate 		for (index = optind; index < argc; index++) {
2347c478bd9Sstevel@tonic-gate 			unsetaux(argv[index]);
2357c478bd9Sstevel@tonic-gate 			if (persist && deleteflag)
2367c478bd9Sstevel@tonic-gate 				removefromlist(argv[index]);
2377c478bd9Sstevel@tonic-gate 		}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 		/*
2407c478bd9Sstevel@tonic-gate 		 * kill off daemon and restart with
2417c478bd9Sstevel@tonic-gate 		 * new list of auxiliary consoles
2427c478bd9Sstevel@tonic-gate 		 */
2437c478bd9Sstevel@tonic-gate 		setfallback(argv);
2447c478bd9Sstevel@tonic-gate 		return (E_SUCCESS);
2457c478bd9Sstevel@tonic-gate 	} else if (persist) {
2467c478bd9Sstevel@tonic-gate 		if (optind < argc) {
2477c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, gettext(usage));
2487c478bd9Sstevel@tonic-gate 			return (E_ERROR);
2497c478bd9Sstevel@tonic-gate 		}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 		persistlist();
2527c478bd9Sstevel@tonic-gate 		return (E_SUCCESS);
2537c478bd9Sstevel@tonic-gate 	} else {
2547c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, gettext(usage));
2557c478bd9Sstevel@tonic-gate 		return (E_ERROR);
2567c478bd9Sstevel@tonic-gate 	}
2577c478bd9Sstevel@tonic-gate } /* main */
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate /* for daemon to handle termination from user command */
2607c478bd9Sstevel@tonic-gate static void
catch_term(int signal __unused)261*30699046SRichard Lowe catch_term(int signal __unused)
2627c478bd9Sstevel@tonic-gate {
2637c478bd9Sstevel@tonic-gate 	exit(E_SUCCESS);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate /* handle lack of carrier on open */
2677c478bd9Sstevel@tonic-gate static void
catch_alarm(int signal __unused)268*30699046SRichard Lowe catch_alarm(int signal __unused)
2697c478bd9Sstevel@tonic-gate {
2707c478bd9Sstevel@tonic-gate 	siglongjmp(deadline, 1);
2717c478bd9Sstevel@tonic-gate }
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate /* caught a sighup */
2747c478bd9Sstevel@tonic-gate static void
catch_hup(int signal __unused)275*30699046SRichard Lowe catch_hup(int signal __unused)
2767c478bd9Sstevel@tonic-gate {
2777c478bd9Sstevel@tonic-gate 	/*
2787c478bd9Sstevel@tonic-gate 	 * ttymon sends sighup to consadmd because it has the serial
2797c478bd9Sstevel@tonic-gate 	 * port open.  We catch the signal here, but process it
2807c478bd9Sstevel@tonic-gate 	 * within fallbackdaemon().  We ignore the signal if the
2817c478bd9Sstevel@tonic-gate 	 * errno returned was EINTR.
2827c478bd9Sstevel@tonic-gate 	 */
2837c478bd9Sstevel@tonic-gate }
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate /* Remove persistent state on receiving signal. */
2867c478bd9Sstevel@tonic-gate static void
cleanup_on_exit(int signal __unused)287*30699046SRichard Lowe cleanup_on_exit(int signal __unused)
2887c478bd9Sstevel@tonic-gate {
2897c478bd9Sstevel@tonic-gate 	(void) unlink(CONSADMLOCK);
2907c478bd9Sstevel@tonic-gate 	exit(E_ERROR);
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate  * send ioctl to /dev/sysmsg to route msgs of the device specified.
2957c478bd9Sstevel@tonic-gate  */
2967c478bd9Sstevel@tonic-gate static void
setaux(char * dev)2977c478bd9Sstevel@tonic-gate setaux(char *dev)
2987c478bd9Sstevel@tonic-gate {
2997c478bd9Sstevel@tonic-gate 	int	fd;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 	if ((fd = safeopen(SYSMSG)) < 0)
3027c478bd9Sstevel@tonic-gate 		die(gettext("%s is missing or not a valid device\n"), SYSMSG);
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	if (ioctl(fd, CIOCSETCONSOLE, dev) != 0) {
3057c478bd9Sstevel@tonic-gate 		/*
3067c478bd9Sstevel@tonic-gate 		 * Let setting duplicate device be warning, consadm
3077c478bd9Sstevel@tonic-gate 		 * must proceed to set persistence if requested.
3087c478bd9Sstevel@tonic-gate 		 */
3097c478bd9Sstevel@tonic-gate 		if (errno == EBUSY)
3107c478bd9Sstevel@tonic-gate 			die(gettext("%s is already the default console\n"),
3117c478bd9Sstevel@tonic-gate 			    dev);
3127c478bd9Sstevel@tonic-gate 		else if (errno != EEXIST)
3137c478bd9Sstevel@tonic-gate 			die(gettext("cannot get table entry"));
3147c478bd9Sstevel@tonic-gate 	}
3157c478bd9Sstevel@tonic-gate 	syslog(LOG_WARNING, "%s: Added auxiliary device %s", CONSADM, dev);
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	(void) close(fd);
3187c478bd9Sstevel@tonic-gate }
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate /*
3217c478bd9Sstevel@tonic-gate  * Send ioctl to device specified and
3227c478bd9Sstevel@tonic-gate  * Remove the entry from the list of auxiliary devices.
3237c478bd9Sstevel@tonic-gate  */
3247c478bd9Sstevel@tonic-gate static void
unsetaux(char * dev)3257c478bd9Sstevel@tonic-gate unsetaux(char *dev)
3267c478bd9Sstevel@tonic-gate {
3277c478bd9Sstevel@tonic-gate 	int	fd;
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 	if ((fd = safeopen(SYSMSG)) < 0)
3307c478bd9Sstevel@tonic-gate 		die(gettext("%s is missing or not a valid device\n"), SYSMSG);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	if (ioctl(fd, CIOCRMCONSOLE, dev) != 0) {
3337c478bd9Sstevel@tonic-gate 		if (errno == EBUSY)
3347c478bd9Sstevel@tonic-gate 			die(gettext("cannot unset the default console\n"));
3357c478bd9Sstevel@tonic-gate 	} else
3367c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "%s: Removed auxiliary device %s",
3377c478bd9Sstevel@tonic-gate 		    CONSADM, dev);
3387c478bd9Sstevel@tonic-gate 	(void) close(fd);
3397c478bd9Sstevel@tonic-gate }
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate static int
getlock(void)3427c478bd9Sstevel@tonic-gate getlock(void)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate 	int lckfd;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if ((lckfd = open(CONSADMLOCK, O_CREAT | O_EXCL | O_WRONLY,
3477c478bd9Sstevel@tonic-gate 	    S_IRUSR | S_IWUSR)) < 0) {
3487c478bd9Sstevel@tonic-gate 		if (errno == EEXIST)
3497c478bd9Sstevel@tonic-gate 			die(gettext("currently busy, try again later.\n"));
3507c478bd9Sstevel@tonic-gate 		else
3517c478bd9Sstevel@tonic-gate 			die(gettext("cannot open %s"), CONSADMLOCK);
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 	if (lckfunc(lckfd, LOCK_EX) == -1) {
3547c478bd9Sstevel@tonic-gate 		(void) close(lckfd);
3557c478bd9Sstevel@tonic-gate 		(void) unlink(CONSADMLOCK);
3567c478bd9Sstevel@tonic-gate 		die(gettext("fcntl operation failed"));
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 	return (lckfd);
3597c478bd9Sstevel@tonic-gate }
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate static void
addtolist(char * dev)3627c478bd9Sstevel@tonic-gate addtolist(char *dev)
3637c478bd9Sstevel@tonic-gate {
3647c478bd9Sstevel@tonic-gate 	int	lckfd, fd;
3657c478bd9Sstevel@tonic-gate 	FILE	*fp, *nfp;
3667c478bd9Sstevel@tonic-gate 	char	newfile[MAXPATHLEN];
3677c478bd9Sstevel@tonic-gate 	char	buf[MAXPATHLEN];
3687c478bd9Sstevel@tonic-gate 	int	len;
3697c478bd9Sstevel@tonic-gate 	boolean_t	found = B_FALSE;
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate 	/* update file of devices configured to get console msgs. */
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	lckfd = getlock();
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	/* Open new file */
3767c478bd9Sstevel@tonic-gate 	(void) snprintf(newfile, sizeof (newfile), "%s%d",
3777c478bd9Sstevel@tonic-gate 	    CONSCONFIG, (int)getpid());
3787c478bd9Sstevel@tonic-gate 	if (((fd = creat(newfile, 0644)) < 0) ||
3797c478bd9Sstevel@tonic-gate 	    ((nfp = fdopen(fd, "w")) == NULL)) {
3807c478bd9Sstevel@tonic-gate 		(void) close(lckfd);
3817c478bd9Sstevel@tonic-gate 		(void) unlink(CONSADMLOCK);
3827c478bd9Sstevel@tonic-gate 		die(gettext("could not create new %s file"), CONSCONFIG);
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	/* Add header to new file */
3867c478bd9Sstevel@tonic-gate 	(void) fprintf(nfp, "%s", conshdr);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	/* Check that the file doesn't already exist */
3897c478bd9Sstevel@tonic-gate 	if ((fp = fopen(CONSCONFIG, "r")) != NULL) {
3907c478bd9Sstevel@tonic-gate 		while (fgets(buf, MAXPATHLEN, fp) != NULL) {
3917c478bd9Sstevel@tonic-gate 			if (buf[0] == COMMENT || buf[0] == NEWLINE ||
3927c478bd9Sstevel@tonic-gate 			    buf[0] == SPACE || buf[0] == TAB)
3937c478bd9Sstevel@tonic-gate 				continue;
3947c478bd9Sstevel@tonic-gate 			len = strlen(buf);
395d95bfcb7SToomas Soome 			buf[len - 1] = '\0'; /* Clear carriage return */
3967c478bd9Sstevel@tonic-gate 			if (pathcmp(dev, buf) == 0) {
3977c478bd9Sstevel@tonic-gate 				/* they match so use name passed in. */
3987c478bd9Sstevel@tonic-gate 				(void) fprintf(nfp, "%s\n", dev);
3997c478bd9Sstevel@tonic-gate 				found = B_TRUE;
4007c478bd9Sstevel@tonic-gate 			} else
4017c478bd9Sstevel@tonic-gate 				(void) fprintf(nfp, "%s\n", buf);
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 	}
4047c478bd9Sstevel@tonic-gate 	/* User specified persistent settings */
4057c478bd9Sstevel@tonic-gate 	if (found == B_FALSE)
4067c478bd9Sstevel@tonic-gate 		(void) fprintf(nfp, "%s\n", dev);
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
4097c478bd9Sstevel@tonic-gate 	(void) fclose(nfp);
4107c478bd9Sstevel@tonic-gate 	(void) rename(newfile, CONSCONFIG);
4117c478bd9Sstevel@tonic-gate 	(void) close(lckfd);
4127c478bd9Sstevel@tonic-gate 	(void) unlink(CONSADMLOCK);
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate /* The list in CONSCONFIG gives the persistence capability in the proto */
4167c478bd9Sstevel@tonic-gate static void
removefromlist(char * dev)4177c478bd9Sstevel@tonic-gate removefromlist(char *dev)
4187c478bd9Sstevel@tonic-gate {
4197c478bd9Sstevel@tonic-gate 	int	lckfd;
4207c478bd9Sstevel@tonic-gate 	FILE	*fp, *nfp;
4217c478bd9Sstevel@tonic-gate 	char	newfile[MAXPATHLEN + 1];
4227c478bd9Sstevel@tonic-gate 	char	len;
4237c478bd9Sstevel@tonic-gate 	char	value[MAXPATHLEN + 1];
4247c478bd9Sstevel@tonic-gate 	boolean_t	newcontents = B_FALSE;
4257c478bd9Sstevel@tonic-gate 
4267c478bd9Sstevel@tonic-gate 	/* update file of devices configured to get console msgs. */
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate 	lckfd = getlock();
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	if ((fp = fopen(CONSCONFIG, "r")) == NULL) {
4317c478bd9Sstevel@tonic-gate 		(void) close(lckfd);
4327c478bd9Sstevel@tonic-gate 		(void) unlink(CONSADMLOCK);
4337c478bd9Sstevel@tonic-gate 		return;
4347c478bd9Sstevel@tonic-gate 	}
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate 	/* Open new file */
4377c478bd9Sstevel@tonic-gate 	(void) snprintf(newfile, sizeof (newfile), "%s%d",
4387c478bd9Sstevel@tonic-gate 	    CONSCONFIG, (int)getpid());
4397c478bd9Sstevel@tonic-gate 	if ((nfp = fopen(newfile, "w")) == NULL) {
4407c478bd9Sstevel@tonic-gate 		(void) close(lckfd);
4417c478bd9Sstevel@tonic-gate 		(void) unlink(CONSADMLOCK);
4427c478bd9Sstevel@tonic-gate 		die(gettext("cannot create new %s file"), CONSCONFIG);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	/* Add header to new file */
4467c478bd9Sstevel@tonic-gate 	(void) fprintf(nfp, "%s", conshdr);
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	/*
4497c478bd9Sstevel@tonic-gate 	 * Check whether the path duplicates what is already in the
4507c478bd9Sstevel@tonic-gate 	 * file.
4517c478bd9Sstevel@tonic-gate 	 */
4527c478bd9Sstevel@tonic-gate 	while (fgets(value, MAXPATHLEN, fp) != NULL) {
4537c478bd9Sstevel@tonic-gate 		/* skip comments */
4547c478bd9Sstevel@tonic-gate 		if (value[0] == COMMENT || value[0] == NEWLINE ||
4557c478bd9Sstevel@tonic-gate 		    value[0] == SPACE || value[0] == TAB)
4567c478bd9Sstevel@tonic-gate 			continue;
4577c478bd9Sstevel@tonic-gate 		len = strlen(value);
458d95bfcb7SToomas Soome 		value[len - 1] = '\0'; /* Clear carriage return */
4597c478bd9Sstevel@tonic-gate 		if (pathcmp(dev, value) == 0) {
4607c478bd9Sstevel@tonic-gate 			/* they match so don't write it */
4617c478bd9Sstevel@tonic-gate 			continue;
4627c478bd9Sstevel@tonic-gate 		}
4637c478bd9Sstevel@tonic-gate 		(void) fprintf(nfp, "%s\n", value);
4647c478bd9Sstevel@tonic-gate 		newcontents = B_TRUE;
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
4677c478bd9Sstevel@tonic-gate 	(void) fclose(nfp);
4687c478bd9Sstevel@tonic-gate 	/* Remove the file if there aren't any auxiliary consoles */
4697c478bd9Sstevel@tonic-gate 	if (newcontents)
4707c478bd9Sstevel@tonic-gate 		(void) rename(newfile, CONSCONFIG);
4717c478bd9Sstevel@tonic-gate 	else {
4727c478bd9Sstevel@tonic-gate 		(void) unlink(CONSCONFIG);
4737c478bd9Sstevel@tonic-gate 		(void) unlink(newfile);
4747c478bd9Sstevel@tonic-gate 	}
4757c478bd9Sstevel@tonic-gate 	(void) close(lckfd);
4767c478bd9Sstevel@tonic-gate 	(void) unlink(CONSADMLOCK);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate static int
pathcmp(char * adev,char * bdev)4807c478bd9Sstevel@tonic-gate pathcmp(char *adev, char *bdev)
4817c478bd9Sstevel@tonic-gate {
4827c478bd9Sstevel@tonic-gate 	struct stat	st1;
4837c478bd9Sstevel@tonic-gate 	struct stat	st2;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	if (strcmp(adev, bdev) == 0)
4867c478bd9Sstevel@tonic-gate 		return (0);
4877c478bd9Sstevel@tonic-gate 
4884bc0a2efScasper 	if (stat(adev, &st1) != 0 || !S_ISCHR(st1.st_mode))
4897c478bd9Sstevel@tonic-gate 		die(gettext("invalid device %s\n"), adev);
4907c478bd9Sstevel@tonic-gate 
4914bc0a2efScasper 	if (stat(bdev, &st2) != 0 || !S_ISCHR(st2.st_mode))
4927c478bd9Sstevel@tonic-gate 		die(gettext("invalid device %s\n"), bdev);
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	if (st1.st_rdev == st2.st_rdev)
4957c478bd9Sstevel@tonic-gate 		return (0);
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	return (1);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate  * Display configured consoles.
5027c478bd9Sstevel@tonic-gate  */
5037c478bd9Sstevel@tonic-gate static void
getconsole(void)5047c478bd9Sstevel@tonic-gate getconsole(void)
5057c478bd9Sstevel@tonic-gate {
5067c478bd9Sstevel@tonic-gate 	int	fd;
5077c478bd9Sstevel@tonic-gate 	int	bufsize = 0;		/* size of device cache */
5087c478bd9Sstevel@tonic-gate 	char	*infop, *ptr, *p;	/* info structure for ioctl's */
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	if ((fd = safeopen(SYSMSG)) < 0)
5117c478bd9Sstevel@tonic-gate 		die(gettext("%s is missing or not a valid device\n"), SYSMSG);
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if ((bufsize = ioctl(fd, CIOCGETCONSOLE, NULL)) < 0)
5147c478bd9Sstevel@tonic-gate 		die(gettext("cannot get table entry\n"));
5157c478bd9Sstevel@tonic-gate 	if (bufsize == 0)
5167c478bd9Sstevel@tonic-gate 		return;
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate 	if ((infop = calloc(bufsize, sizeof (char))) == NULL)
5197c478bd9Sstevel@tonic-gate 		die(gettext("cannot allocate buffer"));
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if (ioctl(fd, CIOCGETCONSOLE, infop) < 0)
5227c478bd9Sstevel@tonic-gate 		die(gettext("cannot get table entry\n"));
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 	ptr = infop;
5257c478bd9Sstevel@tonic-gate 	while (ptr != NULL) {
5267c478bd9Sstevel@tonic-gate 		p = strchr(ptr, ' ');
5277c478bd9Sstevel@tonic-gate 		if (p == NULL) {
5287c478bd9Sstevel@tonic-gate 			(void) printf("%s\n", ptr);
5297c478bd9Sstevel@tonic-gate 			break;
5307c478bd9Sstevel@tonic-gate 		}
5317c478bd9Sstevel@tonic-gate 		*p++ = '\0';
5327c478bd9Sstevel@tonic-gate 		(void) printf("%s\n", ptr);
5337c478bd9Sstevel@tonic-gate 		ptr = p;
5347c478bd9Sstevel@tonic-gate 	}
5357c478bd9Sstevel@tonic-gate 	(void) close(fd);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate  * It is supposed that if the device supports TIOCMGET then it
5407c478bd9Sstevel@tonic-gate  * might be a serial device.
5417c478bd9Sstevel@tonic-gate  */
5427c478bd9Sstevel@tonic-gate static boolean_t
modem_support(int fd)5437c478bd9Sstevel@tonic-gate modem_support(int fd)
5447c478bd9Sstevel@tonic-gate {
5457c478bd9Sstevel@tonic-gate 	int	modem_state;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	if (ioctl(fd, TIOCMGET, &modem_state) == 0)
5487c478bd9Sstevel@tonic-gate 		return (B_TRUE);
5497c478bd9Sstevel@tonic-gate 	else
5507c478bd9Sstevel@tonic-gate 		return (B_FALSE);
5517c478bd9Sstevel@tonic-gate }
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate static boolean_t
has_carrier(int fd)5547c478bd9Sstevel@tonic-gate has_carrier(int fd)
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	int	modem_state;
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (ioctl(fd, TIOCMGET, &modem_state) == 0)
5597c478bd9Sstevel@tonic-gate 		return ((modem_state & TIOCM_CAR) != 0);
5607c478bd9Sstevel@tonic-gate 	else {
5617c478bd9Sstevel@tonic-gate 		return (B_FALSE);
5627c478bd9Sstevel@tonic-gate 	}
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate static void
setfallback(char * argv[])5667c478bd9Sstevel@tonic-gate setfallback(char *argv[])
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	pid_t	pid;
5697c478bd9Sstevel@tonic-gate 	FILE	*fp;
5707c478bd9Sstevel@tonic-gate 	char	*cmd = CONSADMD;
5717c478bd9Sstevel@tonic-gate 	int	lckfd, fd;
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	lckfd = getlock();
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	/*
5767c478bd9Sstevel@tonic-gate 	 * kill off any existing daemon
5777c478bd9Sstevel@tonic-gate 	 * remove /etc/consadm.pid
5787c478bd9Sstevel@tonic-gate 	 */
5797c478bd9Sstevel@tonic-gate 	removefallback();
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	/* kick off a daemon */
5827c478bd9Sstevel@tonic-gate 	if ((pid = fork()) == (pid_t)0) {
5837c478bd9Sstevel@tonic-gate 		/* always fallback to /dev/console */
5847c478bd9Sstevel@tonic-gate 		argv[0] = cmd;
5857c478bd9Sstevel@tonic-gate 		argv[1] = NULL;
5867c478bd9Sstevel@tonic-gate 		(void) close(0);
5877c478bd9Sstevel@tonic-gate 		(void) close(1);
5887c478bd9Sstevel@tonic-gate 		(void) close(2);
5897c478bd9Sstevel@tonic-gate 		(void) close(lckfd);
5907c478bd9Sstevel@tonic-gate 		if ((fd = open(MSGLOG, O_RDWR)) < 0)
5917c478bd9Sstevel@tonic-gate 			die(gettext("cannot open %s"), MSGLOG);
5927c478bd9Sstevel@tonic-gate 		(void) dup2(fd, 1);
5937c478bd9Sstevel@tonic-gate 		(void) dup2(fd, 2);
5947c478bd9Sstevel@tonic-gate 		(void) execv(cmd, argv);
5957c478bd9Sstevel@tonic-gate 		exit(E_SUCCESS);
5967c478bd9Sstevel@tonic-gate 	} else if (pid == -1)
5977c478bd9Sstevel@tonic-gate 		die(gettext("%s not started"), CONSADMD);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	if ((fp = fopen(SETCONSOLEPID, "w")) == NULL)
6007c478bd9Sstevel@tonic-gate 		die(gettext("cannot open %s"), SETCONSOLEPID);
6017c478bd9Sstevel@tonic-gate 	/* write daemon pid to file */
6027c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "%d\n", (int)pid);
6037c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
6047c478bd9Sstevel@tonic-gate 	(void) close(lckfd);
6057c478bd9Sstevel@tonic-gate 	(void) unlink(CONSADMLOCK);
6067c478bd9Sstevel@tonic-gate }
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate /*
6097c478bd9Sstevel@tonic-gate  * Remove the daemon that would have implemented the automatic
6107c478bd9Sstevel@tonic-gate  * fallback in event of carrier loss on the serial console.
6117c478bd9Sstevel@tonic-gate  */
6127c478bd9Sstevel@tonic-gate static void
removefallback(void)6137c478bd9Sstevel@tonic-gate removefallback(void)
6147c478bd9Sstevel@tonic-gate {
6157c478bd9Sstevel@tonic-gate 	FILE	*fp;
6167c478bd9Sstevel@tonic-gate 	int	pid;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	if ((fp = fopen(SETCONSOLEPID, "r+")) == NULL)
6197c478bd9Sstevel@tonic-gate 		/* file doesn't exist, so no work to do */
6207c478bd9Sstevel@tonic-gate 		return;
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if (fscanf(fp, "%d\n", &pid) <= 0) {
6237c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
6247c478bd9Sstevel@tonic-gate 		(void) unlink(SETCONSOLEPID);
6257c478bd9Sstevel@tonic-gate 		return;
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/*
6297c478bd9Sstevel@tonic-gate 	 * Don't shoot ourselves in the foot by killing init,
6307c478bd9Sstevel@tonic-gate 	 * sched, pageout, or fsflush.
6317c478bd9Sstevel@tonic-gate 	 */
6327c478bd9Sstevel@tonic-gate 	if (pid == 0 || pid == 1 || pid == 2 || pid == 3) {
6337c478bd9Sstevel@tonic-gate 		(void) unlink(SETCONSOLEPID);
6347c478bd9Sstevel@tonic-gate 		return;
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 	/*
6377c478bd9Sstevel@tonic-gate 	 * kill off the existing daemon listed in
6387c478bd9Sstevel@tonic-gate 	 * /etc/consadm.pid
6397c478bd9Sstevel@tonic-gate 	 */
6407c478bd9Sstevel@tonic-gate 	(void) kill((pid_t)pid, SIGTERM);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
6437c478bd9Sstevel@tonic-gate 	(void) unlink(SETCONSOLEPID);
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate /*
6477c478bd9Sstevel@tonic-gate  * Assume we always fall back to /dev/console.
6487c478bd9Sstevel@tonic-gate  * parameter passed in will always be the auxiliary device.
6497c478bd9Sstevel@tonic-gate  * The daemon will not start after the last device has been removed.
6507c478bd9Sstevel@tonic-gate  */
6517c478bd9Sstevel@tonic-gate static void
fallbackdaemon(void)6527c478bd9Sstevel@tonic-gate fallbackdaemon(void)
6537c478bd9Sstevel@tonic-gate {
6547c478bd9Sstevel@tonic-gate 	int	fd, sysmfd, ret = 0;
6557c478bd9Sstevel@tonic-gate 	char	**devpaths;
6567c478bd9Sstevel@tonic-gate 	pollfd_t	*fds;
6577c478bd9Sstevel@tonic-gate 	nfds_t	nfds = 0;
6587c478bd9Sstevel@tonic-gate 	int	index;
6597c478bd9Sstevel@tonic-gate 	int	pollagain;
6607c478bd9Sstevel@tonic-gate 	struct	sigaction sa;
6617c478bd9Sstevel@tonic-gate 	int	bufsize = 0;		/* length of device cache paths */
6627c478bd9Sstevel@tonic-gate 	int	cachesize = 0;		/* size of device cache */
6637c478bd9Sstevel@tonic-gate 	char	*infop, *ptr, *p;	/* info structure for ioctl's */
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	/*
6667c478bd9Sstevel@tonic-gate 	 * catch SIGTERM cause it might be coming from user via consadm
6677c478bd9Sstevel@tonic-gate 	 */
6687c478bd9Sstevel@tonic-gate 	sa.sa_handler = catch_term;
6697c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
6707c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sa.sa_mask);
6717c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &sa, NULL);
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	/*
6747c478bd9Sstevel@tonic-gate 	 * catch SIGHUP cause it might be coming from a disconnect
6757c478bd9Sstevel@tonic-gate 	 */
6767c478bd9Sstevel@tonic-gate 	sa.sa_handler = catch_hup;
6777c478bd9Sstevel@tonic-gate 	sa.sa_flags = 0;
6787c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sa.sa_mask);
6797c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGHUP, &sa, NULL);
6807c478bd9Sstevel@tonic-gate 
6817c478bd9Sstevel@tonic-gate 	if ((sysmfd = safeopen(SYSMSG)) < 0)
6827c478bd9Sstevel@tonic-gate 		die(gettext("%s is missing or not a valid device\n"), SYSMSG);
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	if ((bufsize = ioctl(sysmfd, CIOCGETCONSOLE, NULL)) < 0)
6857c478bd9Sstevel@tonic-gate 		die(gettext("cannot get table entry\n"));
6867c478bd9Sstevel@tonic-gate 	if (bufsize == 0)
6877c478bd9Sstevel@tonic-gate 		return;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	if ((infop = calloc(bufsize, sizeof (char))) == NULL)
6907c478bd9Sstevel@tonic-gate 		die(gettext("cannot allocate buffer"));
6917c478bd9Sstevel@tonic-gate 
6927c478bd9Sstevel@tonic-gate 	if (ioctl(sysmfd, CIOCGETCONSOLE, infop) < 0)
6937c478bd9Sstevel@tonic-gate 		die(gettext("cannot get table entry\n"));
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	ptr = infop;
6967c478bd9Sstevel@tonic-gate 	while (ptr != NULL) {
6977c478bd9Sstevel@tonic-gate 		p = strchr(ptr, ' ');
6987c478bd9Sstevel@tonic-gate 		if (p == NULL) {
6997c478bd9Sstevel@tonic-gate 			cachesize++;
7007c478bd9Sstevel@tonic-gate 			break;
7017c478bd9Sstevel@tonic-gate 		}
7027c478bd9Sstevel@tonic-gate 		p++;
7037c478bd9Sstevel@tonic-gate 		cachesize++;
7047c478bd9Sstevel@tonic-gate 		ptr = p;
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	if ((fds = calloc(cachesize, sizeof (struct pollfd))) == NULL)
7087c478bd9Sstevel@tonic-gate 		die(gettext("cannot allocate buffer"));
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if ((devpaths = calloc(cachesize, sizeof (char *))) == NULL)
7117c478bd9Sstevel@tonic-gate 		die(gettext("cannot allocate buffer"));
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	ptr = infop;
7147c478bd9Sstevel@tonic-gate 	while (ptr != NULL) {
7157c478bd9Sstevel@tonic-gate 		p = strchr(ptr, ' ');
7167c478bd9Sstevel@tonic-gate 		if (p == NULL) {
7177c478bd9Sstevel@tonic-gate 			if ((fd = safeopen(ptr)) < 0) {
7187c478bd9Sstevel@tonic-gate 				warn(gettext("cannot open %s, continuing"),
7197c478bd9Sstevel@tonic-gate 				    ptr);
7207c478bd9Sstevel@tonic-gate 				break;
7217c478bd9Sstevel@tonic-gate 			}
7227c478bd9Sstevel@tonic-gate 			if (!has_carrier(fd)) {
7237c478bd9Sstevel@tonic-gate 				(void) close(fd);
7247c478bd9Sstevel@tonic-gate 				warn(gettext(
7257c478bd9Sstevel@tonic-gate 		    "no carrier on %s, device will not be monitored.\n"),
7267c478bd9Sstevel@tonic-gate 				    ptr);
7277c478bd9Sstevel@tonic-gate 				break;
7287c478bd9Sstevel@tonic-gate 			} else {
7297c478bd9Sstevel@tonic-gate 				fds[nfds].fd = fd;
7307c478bd9Sstevel@tonic-gate 				fds[nfds].events = 0;
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 				if ((devpaths[nfds] =
7337c478bd9Sstevel@tonic-gate 				    malloc(strlen(ptr) + 1)) == NULL)
7347c478bd9Sstevel@tonic-gate 					die(gettext("cannot allocate buffer"));
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 				(void) strcpy(devpaths[nfds], ptr);
7377c478bd9Sstevel@tonic-gate 				nfds++;
7387c478bd9Sstevel@tonic-gate 				if (nfds >= cachesize)
7397c478bd9Sstevel@tonic-gate 					break;
7407c478bd9Sstevel@tonic-gate 			}
7417c478bd9Sstevel@tonic-gate 			break;
7427c478bd9Sstevel@tonic-gate 		}
7437c478bd9Sstevel@tonic-gate 		*p++ = '\0';
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 		if ((fd = safeopen(ptr)) < 0) {
7467c478bd9Sstevel@tonic-gate 			warn(gettext("cannot open %s, continuing"), ptr);
7477c478bd9Sstevel@tonic-gate 			ptr = p;
7487c478bd9Sstevel@tonic-gate 			continue;
7497c478bd9Sstevel@tonic-gate 		}
7507c478bd9Sstevel@tonic-gate 		if (!has_carrier(fd)) {
7517c478bd9Sstevel@tonic-gate 			(void) close(fd);
7527c478bd9Sstevel@tonic-gate 			warn(gettext(
7537c478bd9Sstevel@tonic-gate 		    "no carrier on %s, device will not be monitored.\n"),
7547c478bd9Sstevel@tonic-gate 			    ptr);
7557c478bd9Sstevel@tonic-gate 			ptr = p;
7567c478bd9Sstevel@tonic-gate 			continue;
7577c478bd9Sstevel@tonic-gate 		} else {
7587c478bd9Sstevel@tonic-gate 			fds[nfds].fd = fd;
7597c478bd9Sstevel@tonic-gate 			fds[nfds].events = 0;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 			if ((devpaths[nfds] = malloc(strlen(ptr) + 1)) == NULL)
7627c478bd9Sstevel@tonic-gate 				die(gettext("cannot allocate buffer"));
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 			(void) strcpy(devpaths[nfds], ptr);
7657c478bd9Sstevel@tonic-gate 			nfds++;
7667c478bd9Sstevel@tonic-gate 			if (nfds >= cachesize)
7677c478bd9Sstevel@tonic-gate 				break;
7687c478bd9Sstevel@tonic-gate 		}
7697c478bd9Sstevel@tonic-gate 		ptr = p;
7707c478bd9Sstevel@tonic-gate 	}
7717c478bd9Sstevel@tonic-gate 	(void) close(sysmfd);
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate 	/* no point polling if no devices with carrier */
7747c478bd9Sstevel@tonic-gate 	if (nfds == 0)
7757c478bd9Sstevel@tonic-gate 		return;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	for (;;) {
7787c478bd9Sstevel@tonic-gate 		/* daemon sleeps waiting for a hangup on the console */
7797c478bd9Sstevel@tonic-gate 		ret = poll(fds, nfds, INFTIM);
7807c478bd9Sstevel@tonic-gate 		if (ret == -1) {
7817c478bd9Sstevel@tonic-gate 			/* Check if ttymon is trying to get rid of us */
7827c478bd9Sstevel@tonic-gate 			if (errno == EINTR)
7837c478bd9Sstevel@tonic-gate 				continue;
7847c478bd9Sstevel@tonic-gate 			warn(gettext("cannot poll device"));
7857c478bd9Sstevel@tonic-gate 			return;
7867c478bd9Sstevel@tonic-gate 		} else if (ret == 0) {
7877c478bd9Sstevel@tonic-gate 			warn(gettext("timeout (%d milleseconds) occured\n"),
7887c478bd9Sstevel@tonic-gate 			    INFTIM);
7897c478bd9Sstevel@tonic-gate 			return;
7907c478bd9Sstevel@tonic-gate 		} else {
7917c478bd9Sstevel@tonic-gate 			/* Go through poll list looking for events. */
7927c478bd9Sstevel@tonic-gate 			for (index = 0; index < nfds; index++) {
7937c478bd9Sstevel@tonic-gate 				/* expected result */
7947c478bd9Sstevel@tonic-gate 				if ((fds[index].revents & POLLHUP) ==
7957c478bd9Sstevel@tonic-gate 				    POLLHUP) {
7967c478bd9Sstevel@tonic-gate 					/*
7977c478bd9Sstevel@tonic-gate 					 * unsetaux console.  Take out of list
7987c478bd9Sstevel@tonic-gate 					 * of current auxiliary consoles.
7997c478bd9Sstevel@tonic-gate 					 */
8007c478bd9Sstevel@tonic-gate 					unsetaux((char *)devpaths[index]);
8017c478bd9Sstevel@tonic-gate 					warn(gettext(
8027c478bd9Sstevel@tonic-gate 				    "lost carrier, unsetting console %s\n"),
8037c478bd9Sstevel@tonic-gate 					    devpaths[index]);
8047c478bd9Sstevel@tonic-gate 					syslog(LOG_WARNING,
8057c478bd9Sstevel@tonic-gate 			    "%s: lost carrier, unsetting auxiliary device %s",
8067c478bd9Sstevel@tonic-gate 					    CONSADM, devpaths[index]);
8077c478bd9Sstevel@tonic-gate 					free(devpaths[index]);
8087c478bd9Sstevel@tonic-gate 					devpaths[index] = NULL;
8097c478bd9Sstevel@tonic-gate 					(void) close(fds[index].fd);
8107c478bd9Sstevel@tonic-gate 					fds[index].fd = -1;
8117c478bd9Sstevel@tonic-gate 					fds[index].revents = 0;
8127c478bd9Sstevel@tonic-gate 					continue;
8137c478bd9Sstevel@tonic-gate 				}
8147c478bd9Sstevel@tonic-gate 				if ((fds[index].revents & POLLERR) ==
8157c478bd9Sstevel@tonic-gate 				    POLLERR) {
8167c478bd9Sstevel@tonic-gate 					warn(gettext("poll error\n"));
8177c478bd9Sstevel@tonic-gate 					continue;
8187c478bd9Sstevel@tonic-gate 				} else if (fds[index].revents != 0) {
8197c478bd9Sstevel@tonic-gate 					warn(gettext(
8207c478bd9Sstevel@tonic-gate 					    "unexpected poll result 0x%x\n"),
8217c478bd9Sstevel@tonic-gate 					    fds[index].revents);
8227c478bd9Sstevel@tonic-gate 					continue;
8237c478bd9Sstevel@tonic-gate 				}
8247c478bd9Sstevel@tonic-gate 			}
8257c478bd9Sstevel@tonic-gate 			/* check whether any left to poll */
8267c478bd9Sstevel@tonic-gate 			pollagain = B_FALSE;
8277c478bd9Sstevel@tonic-gate 			for (index = 0; index < nfds; index++)
8287c478bd9Sstevel@tonic-gate 				if (fds[index].fd != -1)
8297c478bd9Sstevel@tonic-gate 					pollagain = B_TRUE;
8307c478bd9Sstevel@tonic-gate 			if (pollagain == B_TRUE)
8317c478bd9Sstevel@tonic-gate 				continue;
8327c478bd9Sstevel@tonic-gate 			else
8337c478bd9Sstevel@tonic-gate 				return;
8347c478bd9Sstevel@tonic-gate 		}
8357c478bd9Sstevel@tonic-gate 	}
8367c478bd9Sstevel@tonic-gate }
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate static void
persistlist(void)8397c478bd9Sstevel@tonic-gate persistlist(void)
8407c478bd9Sstevel@tonic-gate {
8417c478bd9Sstevel@tonic-gate 	FILE	*fp;
8427c478bd9Sstevel@tonic-gate 	char	value[MAXPATHLEN + 1];
8437c478bd9Sstevel@tonic-gate 	int	lckfd;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	lckfd = getlock();
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	if ((fp = fopen(CONSCONFIG, "r")) != NULL) {
8487c478bd9Sstevel@tonic-gate 		while (fgets(value, MAXPATHLEN, fp) != NULL) {
8497c478bd9Sstevel@tonic-gate 			/* skip comments */
8507c478bd9Sstevel@tonic-gate 			if (value[0] == COMMENT ||
8517c478bd9Sstevel@tonic-gate 			    value[0] == NEWLINE ||
8527c478bd9Sstevel@tonic-gate 			    value[0] == SPACE || value[0] == TAB)
8537c478bd9Sstevel@tonic-gate 				continue;
8547c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "%s", value);
8557c478bd9Sstevel@tonic-gate 		}
8567c478bd9Sstevel@tonic-gate 		(void) fclose(fp);
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 	(void) close(lckfd);
8597c478bd9Sstevel@tonic-gate 	(void) unlink(CONSADMLOCK);
8607c478bd9Sstevel@tonic-gate }
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate static int
verifyarg(char * dev,int flag)8637c478bd9Sstevel@tonic-gate verifyarg(char *dev, int flag)
8647c478bd9Sstevel@tonic-gate {
8657c478bd9Sstevel@tonic-gate 	struct stat	st;
8667c478bd9Sstevel@tonic-gate 	int	fd;
8677c478bd9Sstevel@tonic-gate 	int	ret = 0;
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	if (dev == NULL) {
8707c478bd9Sstevel@tonic-gate 		warn(gettext("specify device(s)\n"));
8717c478bd9Sstevel@tonic-gate 		ret = 1;
8727c478bd9Sstevel@tonic-gate 		goto err_exit;
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	if (dev[0] != '/') {
8767c478bd9Sstevel@tonic-gate 		warn(gettext("device name must begin with a '/'\n"));
8777c478bd9Sstevel@tonic-gate 		ret = 1;
8787c478bd9Sstevel@tonic-gate 		goto err_exit;
8797c478bd9Sstevel@tonic-gate 	}
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	if ((pathcmp(dev, SYSMSG) == 0) ||
8827c478bd9Sstevel@tonic-gate 	    (pathcmp(dev, WSCONS) == 0) ||
8837c478bd9Sstevel@tonic-gate 	    (pathcmp(dev, CONSOLE) == 0)) {
8847c478bd9Sstevel@tonic-gate 		/* they match */
8857c478bd9Sstevel@tonic-gate 		warn(gettext("invalid device %s\n"), dev);
8867c478bd9Sstevel@tonic-gate 		ret = 1;
8877c478bd9Sstevel@tonic-gate 		goto err_exit;
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	if (stat(dev, &st) || ! S_ISCHR(st.st_mode)) {
8917c478bd9Sstevel@tonic-gate 		warn(gettext("invalid device %s\n"), dev);
8927c478bd9Sstevel@tonic-gate 		ret = 1;
8937c478bd9Sstevel@tonic-gate 		goto err_exit;
8947c478bd9Sstevel@tonic-gate 	}
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 	/* Delete operation doesn't require this checking */
8977c478bd9Sstevel@tonic-gate 	if ((fd = safeopen(dev)) < 0) {
8987c478bd9Sstevel@tonic-gate 		if (flag) {
8997c478bd9Sstevel@tonic-gate 			warn(gettext("invalid device %s\n"), dev);
9007c478bd9Sstevel@tonic-gate 			ret = 1;
9017c478bd9Sstevel@tonic-gate 		}
9027c478bd9Sstevel@tonic-gate 		goto err_exit;
9037c478bd9Sstevel@tonic-gate 	}
9047c478bd9Sstevel@tonic-gate 	if (!modem_support(fd)) {
9057c478bd9Sstevel@tonic-gate 		warn(gettext("invalid device %s\n"), dev);
9067c478bd9Sstevel@tonic-gate 		(void) close(fd);
9077c478bd9Sstevel@tonic-gate 		ret = 1;
9087c478bd9Sstevel@tonic-gate 		goto err_exit;
9097c478bd9Sstevel@tonic-gate 	}
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	/* Only verify carrier if it's an add operation */
9127c478bd9Sstevel@tonic-gate 	if (flag) {
9137c478bd9Sstevel@tonic-gate 		if (!has_carrier(fd)) {
9147c478bd9Sstevel@tonic-gate 			warn(gettext("failure, no carrier on %s\n"), dev);
9157c478bd9Sstevel@tonic-gate 			ret = 1;
9167c478bd9Sstevel@tonic-gate 			goto err_exit;
9177c478bd9Sstevel@tonic-gate 		}
9187c478bd9Sstevel@tonic-gate 	}
9197c478bd9Sstevel@tonic-gate err_exit:
9207c478bd9Sstevel@tonic-gate 	return (ret);
9217c478bd9Sstevel@tonic-gate }
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate /*
9247c478bd9Sstevel@tonic-gate  * Open the pseudo device, but be prepared to catch sigalarm if we block
9257c478bd9Sstevel@tonic-gate  * cause there isn't any carrier present.
9267c478bd9Sstevel@tonic-gate  */
9277c478bd9Sstevel@tonic-gate static int
safeopen(char * devp)9287c478bd9Sstevel@tonic-gate safeopen(char *devp)
9297c478bd9Sstevel@tonic-gate {
9307c478bd9Sstevel@tonic-gate 	int	fd;
9317c478bd9Sstevel@tonic-gate 	struct	sigaction sigact;
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	sigact.sa_flags = SA_RESETHAND | SA_NODEFER;
9347c478bd9Sstevel@tonic-gate 	sigact.sa_handler = catch_alarm;
9357c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sigact.sa_mask);
9367c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &sigact, NULL);
9377c478bd9Sstevel@tonic-gate 	if (sigsetjmp(deadline, 1) != 0)
9387c478bd9Sstevel@tonic-gate 		return (-1);
9397c478bd9Sstevel@tonic-gate 	(void) alarm(5);
9407c478bd9Sstevel@tonic-gate 	/* The sysmsg driver sets NONBLOCK and NDELAY, but what the hell */
9417c478bd9Sstevel@tonic-gate 	if ((fd = open(devp, O_RDWR | O_NOCTTY | O_NONBLOCK | O_NDELAY)) < 0)
9427c478bd9Sstevel@tonic-gate 		return (-1);
9437c478bd9Sstevel@tonic-gate 	(void) alarm(0);
9447c478bd9Sstevel@tonic-gate 	sigact.sa_flags = 0;
9457c478bd9Sstevel@tonic-gate 	sigact.sa_handler = SIG_DFL;
9467c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&sigact.sa_mask);
9477c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &sigact, NULL);
9487c478bd9Sstevel@tonic-gate 	return (fd);
9497c478bd9Sstevel@tonic-gate }
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate static int
lckfunc(int fd,int flag)9527c478bd9Sstevel@tonic-gate lckfunc(int fd, int flag)
9537c478bd9Sstevel@tonic-gate {
9547c478bd9Sstevel@tonic-gate 	fl.l_type = flag;
9557c478bd9Sstevel@tonic-gate 	return (fcntl(fd, F_SETLKW, &fl));
9567c478bd9Sstevel@tonic-gate }
957