xref: /onnv-gate/usr/src/cmd/rcm_daemon/common/rcm_main.c (revision 8316:1d491502ede3)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*8316SSean.Ye@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * Reconfiguration Coordination Daemon
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * Accept RCM messages in the form of RCM events and process them
300Sstevel@tonic-gate  * - to build and update the system resource map
310Sstevel@tonic-gate  * - to allow clients to register/unregister for resource
320Sstevel@tonic-gate  * - to allow dr initiators to offline a resource before removal
330Sstevel@tonic-gate  * - to call into clients to perform suspend/offline actions
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * The goal is to enable fully automated Dynamic Reconfiguration and better
360Sstevel@tonic-gate  * DR information tracking.
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include <librcm_event.h>
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include "rcm_impl.h"
420Sstevel@tonic-gate 
430Sstevel@tonic-gate /* will run in daemon mode if debug level < DEBUG_LEVEL_FORK */
440Sstevel@tonic-gate #define	DEBUG_LEVEL_FORK	RCM_DEBUG
450Sstevel@tonic-gate 
460Sstevel@tonic-gate #define	DAEMON_LOCK_FILE "/var/run/rcm_daemon_lock"
470Sstevel@tonic-gate 
480Sstevel@tonic-gate static int hold_daemon_lock;
490Sstevel@tonic-gate static int daemon_lock_fd;
500Sstevel@tonic-gate static const char *daemon_lock_file = DAEMON_LOCK_FILE;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate int debug_level = 0;
530Sstevel@tonic-gate static int idle_timeout;
540Sstevel@tonic-gate static int logflag = 0;
550Sstevel@tonic-gate static char *prog;
560Sstevel@tonic-gate 
570Sstevel@tonic-gate static void usage(void);
580Sstevel@tonic-gate static void catch_sighup(void);
590Sstevel@tonic-gate static void catch_sigusr1(void);
600Sstevel@tonic-gate static pid_t enter_daemon_lock(void);
610Sstevel@tonic-gate static void exit_daemon_lock(void);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate extern void init_poll_thread();
640Sstevel@tonic-gate extern void cleanup_poll_thread();
650Sstevel@tonic-gate 
660Sstevel@tonic-gate /*
670Sstevel@tonic-gate  * Print command line syntax for starting rcm_daemon
680Sstevel@tonic-gate  */
690Sstevel@tonic-gate static void
usage()700Sstevel@tonic-gate usage() {
710Sstevel@tonic-gate 	(void) fprintf(stderr,
720Sstevel@tonic-gate 	    gettext("usage: %s [-d debug_level] [-t idle_timeout]\n"), prog);
730Sstevel@tonic-gate 	rcmd_exit(EINVAL);
740Sstevel@tonic-gate }
750Sstevel@tonic-gate 
760Sstevel@tonic-gate /*
77175Sjg  * common cleanup/exit functions to ensure releasing locks
780Sstevel@tonic-gate  */
79175Sjg static void
rcmd_cleanup(int status)80175Sjg rcmd_cleanup(int status)
810Sstevel@tonic-gate {
820Sstevel@tonic-gate 	if (status == 0) {
830Sstevel@tonic-gate 		rcm_log_message(RCM_INFO,
840Sstevel@tonic-gate 		    gettext("rcm_daemon normal exit\n"));
850Sstevel@tonic-gate 	} else {
860Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
870Sstevel@tonic-gate 		    gettext("rcm_daemon exit: errno = %d\n"), status);
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	if (hold_daemon_lock) {
910Sstevel@tonic-gate 		exit_daemon_lock();
920Sstevel@tonic-gate 	}
93175Sjg }
940Sstevel@tonic-gate 
95175Sjg void
rcmd_exit(int status)96175Sjg rcmd_exit(int status)
97175Sjg {
98175Sjg 	rcmd_cleanup(status);
990Sstevel@tonic-gate 	exit(status);
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate  * When SIGHUP is received, reload modules at the next safe moment (when
1040Sstevel@tonic-gate  * there is no DR activity.
1050Sstevel@tonic-gate  */
1060Sstevel@tonic-gate void
catch_sighup(void)1070Sstevel@tonic-gate catch_sighup(void)
1080Sstevel@tonic-gate {
1090Sstevel@tonic-gate 	rcm_log_message(RCM_INFO,
1100Sstevel@tonic-gate 	    gettext("SIGHUP received, will exit when daemon is idle\n"));
1110Sstevel@tonic-gate 	rcmd_thr_signal();
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate  * When SIGUSR1 is received, exit the thread
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate void
catch_sigusr1(void)1180Sstevel@tonic-gate catch_sigusr1(void)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	rcm_log_message(RCM_DEBUG, "SIGUSR1 received in thread %d\n",
1210Sstevel@tonic-gate 	    thr_self());
1220Sstevel@tonic-gate 	cleanup_poll_thread();
1230Sstevel@tonic-gate 	thr_exit(NULL);
1240Sstevel@tonic-gate }
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * Use an advisory lock to ensure that only one daemon process is
1280Sstevel@tonic-gate  * active at any point in time.
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate static pid_t
enter_daemon_lock(void)1310Sstevel@tonic-gate enter_daemon_lock(void)
1320Sstevel@tonic-gate {
1330Sstevel@tonic-gate 	struct flock lock;
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1,
1360Sstevel@tonic-gate 	    "enter_daemon_lock: lock file = %s\n", daemon_lock_file);
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate 	daemon_lock_fd = open(daemon_lock_file, O_CREAT|O_RDWR, 0644);
1390Sstevel@tonic-gate 	if (daemon_lock_fd < 0) {
1400Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, gettext("open(%s) - %s\n"),
1410Sstevel@tonic-gate 		    daemon_lock_file, strerror(errno));
1420Sstevel@tonic-gate 		rcmd_exit(errno);
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	lock.l_type = F_WRLCK;
1460Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
1470Sstevel@tonic-gate 	lock.l_start = 0;
1480Sstevel@tonic-gate 	lock.l_len = 0;
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate 	if (fcntl(daemon_lock_fd, F_SETLK, &lock) == 0) {
1510Sstevel@tonic-gate 		hold_daemon_lock = 1;
1520Sstevel@tonic-gate 		return (getpid());
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	/* failed to get lock, attempt to find lock owner */
1560Sstevel@tonic-gate 	if ((errno == EAGAIN || errno == EDEADLK) &&
1570Sstevel@tonic-gate 	    (fcntl(daemon_lock_fd, F_GETLK, &lock) == 0)) {
1580Sstevel@tonic-gate 		return (lock.l_pid);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	/* die a horrible death */
1620Sstevel@tonic-gate 	rcm_log_message(RCM_ERROR, gettext("lock(%s) - %s"), daemon_lock_file,
1630Sstevel@tonic-gate 	    strerror(errno));
1640Sstevel@tonic-gate 	exit(errno);
1650Sstevel@tonic-gate 	/*NOTREACHED*/
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /*
1690Sstevel@tonic-gate  * Drop the advisory daemon lock, close lock file
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate static void
exit_daemon_lock(void)1720Sstevel@tonic-gate exit_daemon_lock(void)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	struct flock lock;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	lock.l_type = F_UNLCK;
1770Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
1780Sstevel@tonic-gate 	lock.l_start = 0;
1790Sstevel@tonic-gate 	lock.l_len = 0;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
1820Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR, gettext("unlock(%s) - %s"),
1830Sstevel@tonic-gate 		    daemon_lock_file, strerror(errno));
1840Sstevel@tonic-gate 	}
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	(void) close(daemon_lock_fd);
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /*PRINTFLIKE2*/
1900Sstevel@tonic-gate static void
rcm_log_msg_impl(int level,char * message,va_list ap)1910Sstevel@tonic-gate rcm_log_msg_impl(int level, char *message, va_list ap)
1920Sstevel@tonic-gate {
1930Sstevel@tonic-gate 	int log_level;
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if (!logflag) {
1960Sstevel@tonic-gate 		/*
1970Sstevel@tonic-gate 		 * RCM_ERROR goes to stderr, others go to stdout
1980Sstevel@tonic-gate 		 */
1990Sstevel@tonic-gate 		FILE *out = (level <= RCM_ERROR) ? stderr : stdout;
2000Sstevel@tonic-gate 		(void) vfprintf(out, message, ap);
2010Sstevel@tonic-gate 		return;
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * translate RCM_* to LOG_*
2060Sstevel@tonic-gate 	 */
2070Sstevel@tonic-gate 	switch (level) {
2080Sstevel@tonic-gate 	case RCM_ERROR:
2090Sstevel@tonic-gate 		log_level = LOG_ERR;
2100Sstevel@tonic-gate 		break;
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	case RCM_WARNING:
2130Sstevel@tonic-gate 		log_level = LOG_WARNING;
2140Sstevel@tonic-gate 		break;
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate 	case RCM_NOTICE:
2170Sstevel@tonic-gate 		log_level = LOG_NOTICE;
2180Sstevel@tonic-gate 		break;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	case RCM_INFO:
2210Sstevel@tonic-gate 		log_level = LOG_INFO;
2220Sstevel@tonic-gate 		break;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	case RCM_DEBUG:
2250Sstevel@tonic-gate 		log_level = LOG_DEBUG;
2260Sstevel@tonic-gate 		break;
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate 	default:
2290Sstevel@tonic-gate 		/*
2300Sstevel@tonic-gate 		 * Don't log RCM_TRACEn messages
2310Sstevel@tonic-gate 		 */
2320Sstevel@tonic-gate 		return;
2330Sstevel@tonic-gate 	}
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 	(void) vsyslog(log_level, message, ap);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /*
2390Sstevel@tonic-gate  * print error messages to the terminal or to syslog
2400Sstevel@tonic-gate  */
2410Sstevel@tonic-gate void
rcm_log_message(int level,char * message,...)2420Sstevel@tonic-gate rcm_log_message(int level, char *message, ...)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	va_list ap;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	if (level > debug_level) {
2470Sstevel@tonic-gate 		return;
2480Sstevel@tonic-gate 	}
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate 	va_start(ap, message);
2510Sstevel@tonic-gate 	rcm_log_msg_impl(level, message, ap);
2520Sstevel@tonic-gate 	va_end(ap);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate /*
2560Sstevel@tonic-gate  * Print error messages to the terminal or to syslog.
2570Sstevel@tonic-gate  * Same as rcm_log_message except that it does not check for
2580Sstevel@tonic-gate  * level > debug_level
2590Sstevel@tonic-gate  * allowing callers to override the global debug_level.
2600Sstevel@tonic-gate  */
2610Sstevel@tonic-gate void
rcm_log_msg(int level,char * message,...)2620Sstevel@tonic-gate rcm_log_msg(int level, char *message, ...)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	va_list ap;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	va_start(ap, message);
2670Sstevel@tonic-gate 	rcm_log_msg_impl(level, message, ap);
2680Sstevel@tonic-gate 	va_end(ap);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate  * grab daemon_lock and direct messages to syslog
2730Sstevel@tonic-gate  */
2740Sstevel@tonic-gate static void
detachfromtty()2750Sstevel@tonic-gate detachfromtty()
2760Sstevel@tonic-gate {
2770Sstevel@tonic-gate 	(void) chdir("/");
2780Sstevel@tonic-gate 	(void) setsid();
2790Sstevel@tonic-gate 	(void) close(0);
2800Sstevel@tonic-gate 	(void) close(1);
2810Sstevel@tonic-gate 	(void) close(2);
2820Sstevel@tonic-gate 	(void) open("/dev/null", O_RDWR, 0);
2830Sstevel@tonic-gate 	(void) dup2(0, 1);
2840Sstevel@tonic-gate 	(void) dup2(0, 2);
2850Sstevel@tonic-gate 	openlog(prog, LOG_PID, LOG_DAEMON);
2860Sstevel@tonic-gate 	logflag = 1;
2870Sstevel@tonic-gate }
2880Sstevel@tonic-gate 
289175Sjg int
main(int argc,char ** argv)2900Sstevel@tonic-gate main(int argc, char **argv)
2910Sstevel@tonic-gate {
2920Sstevel@tonic-gate 	int c;
2930Sstevel@tonic-gate 	pid_t pid;
2940Sstevel@tonic-gate 	extern char *optarg;
2950Sstevel@tonic-gate 	sigset_t mask;
2960Sstevel@tonic-gate 	struct sigaction act;
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
2990Sstevel@tonic-gate #ifndef	TEXT_DOMAIN
3000Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
3010Sstevel@tonic-gate #endif
3020Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if ((prog = strrchr(argv[0], '/')) == NULL) {
3050Sstevel@tonic-gate 		prog = argv[0];
3060Sstevel@tonic-gate 	} else {
3070Sstevel@tonic-gate 		prog++;
3080Sstevel@tonic-gate 	}
3090Sstevel@tonic-gate 
3101914Scasper 	(void) enable_extended_FILE_stdio(-1, -1);
3111914Scasper 
3120Sstevel@tonic-gate 	/*
3130Sstevel@tonic-gate 	 * process arguments
3140Sstevel@tonic-gate 	 */
3150Sstevel@tonic-gate 	if (argc > 3) {
3160Sstevel@tonic-gate 		usage();
3170Sstevel@tonic-gate 	}
3180Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "d:t:")) != EOF) {
3190Sstevel@tonic-gate 		switch (c) {
3200Sstevel@tonic-gate 		case 'd':
3210Sstevel@tonic-gate 			debug_level = atoi(optarg);
3220Sstevel@tonic-gate 			break;
3230Sstevel@tonic-gate 		case 't':
3240Sstevel@tonic-gate 			idle_timeout = atoi(optarg);
3250Sstevel@tonic-gate 			break;
3260Sstevel@tonic-gate 		case '?':
3270Sstevel@tonic-gate 		default:
3280Sstevel@tonic-gate 			usage();
3290Sstevel@tonic-gate 			/*NOTREACHED*/
3300Sstevel@tonic-gate 		}
3310Sstevel@tonic-gate 	}
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	/*
3340Sstevel@tonic-gate 	 * Check permission
3350Sstevel@tonic-gate 	 */
3360Sstevel@tonic-gate 	if (getuid() != 0) {
3370Sstevel@tonic-gate 		(void) fprintf(stderr, gettext("Must be root to run %s\n"),
3380Sstevel@tonic-gate 		    prog);
3390Sstevel@tonic-gate 		exit(EPERM);
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	/*
3430Sstevel@tonic-gate 	 * When rcm_daemon is started by a call to librcm, it inherits file
3440Sstevel@tonic-gate 	 * descriptors from the DR initiator making a call. The file
3450Sstevel@tonic-gate 	 * descriptors may correspond to devices that can be removed by DR.
3460Sstevel@tonic-gate 	 * Since keeping them remain opened is problematic, close everything
3470Sstevel@tonic-gate 	 * but stdin/stdout/stderr.
3480Sstevel@tonic-gate 	 */
3490Sstevel@tonic-gate 	closefrom(3);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 	/*
352*8316SSean.Ye@Sun.COM 	 * When rcm_daemon is started by the caller, it will inherit the
353*8316SSean.Ye@Sun.COM 	 * signal block mask.  We unblock all signals to make sure the
354*8316SSean.Ye@Sun.COM 	 * signal handling will work normally.
355*8316SSean.Ye@Sun.COM 	 */
356*8316SSean.Ye@Sun.COM 	(void) sigfillset(&mask);
357*8316SSean.Ye@Sun.COM 	(void) thr_sigsetmask(SIG_UNBLOCK, &mask, NULL);
358*8316SSean.Ye@Sun.COM 
359*8316SSean.Ye@Sun.COM 	/*
3600Sstevel@tonic-gate 	 * block SIGUSR1, use it for killing specific threads
3610Sstevel@tonic-gate 	 */
3620Sstevel@tonic-gate 	(void) sigemptyset(&mask);
3630Sstevel@tonic-gate 	(void) sigaddset(&mask, SIGUSR1);
3640Sstevel@tonic-gate 	(void) thr_sigsetmask(SIG_BLOCK, &mask, NULL);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/*
3670Sstevel@tonic-gate 	 * Setup signal handlers for SIGHUP and SIGUSR1
3680Sstevel@tonic-gate 	 * SIGHUP - causes a "delayed" daemon exit, effectively the same
3690Sstevel@tonic-gate 	 *	as a daemon restart.
3700Sstevel@tonic-gate 	 * SIGUSR1 - causes a thr_exit(). Unblocked in selected threads.
3710Sstevel@tonic-gate 	 */
3720Sstevel@tonic-gate 	act.sa_flags = 0;
3730Sstevel@tonic-gate 	act.sa_handler = catch_sighup;
3740Sstevel@tonic-gate 	(void) sigaction(SIGHUP, &act, NULL);
3750Sstevel@tonic-gate 	act.sa_handler = catch_sigusr1;
3760Sstevel@tonic-gate 	(void) sigaction(SIGUSR1, &act, NULL);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/*
3790Sstevel@tonic-gate 	 * ignore SIGPIPE so that the rcm daemon does not exit when it
3800Sstevel@tonic-gate 	 * attempts to read or write from a pipe whose corresponding
3810Sstevel@tonic-gate 	 * rcm script process exited.
3820Sstevel@tonic-gate 	 */
3830Sstevel@tonic-gate 	act.sa_handler = SIG_IGN;
3840Sstevel@tonic-gate 	(void) sigaction(SIGPIPE, &act, NULL);
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 	/*
3870Sstevel@tonic-gate 	 * run in daemon mode
3880Sstevel@tonic-gate 	 */
3890Sstevel@tonic-gate 	if (debug_level < DEBUG_LEVEL_FORK) {
3900Sstevel@tonic-gate 		if (fork()) {
3910Sstevel@tonic-gate 			exit(0);
3920Sstevel@tonic-gate 		}
3930Sstevel@tonic-gate 		detachfromtty();
3940Sstevel@tonic-gate 	}
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/* only one daemon can run at a time */
3970Sstevel@tonic-gate 	if ((pid = enter_daemon_lock()) != getpid()) {
3980Sstevel@tonic-gate 		rcm_log_message(RCM_DEBUG, "%s pid %d already running\n",
3990Sstevel@tonic-gate 		    prog, pid);
4000Sstevel@tonic-gate 		exit(EDEADLK);
4010Sstevel@tonic-gate 	}
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	rcm_log_message(RCM_TRACE1, "%s started, debug level = %d\n",
4040Sstevel@tonic-gate 	    prog, debug_level);
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	/*
4070Sstevel@tonic-gate 	 * Set daemon state to block RCM requests before rcm_daemon is
4080Sstevel@tonic-gate 	 * fully initialized. See rcmd_thr_incr().
4090Sstevel@tonic-gate 	 */
4100Sstevel@tonic-gate 	rcmd_set_state(RCMD_INIT);
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate 	/*
4130Sstevel@tonic-gate 	 * create rcm_daemon door and set permission to 0400
4140Sstevel@tonic-gate 	 */
4150Sstevel@tonic-gate 	if (create_event_service(RCM_SERVICE_DOOR, event_service) == -1) {
4160Sstevel@tonic-gate 		rcm_log_message(RCM_ERROR,
4170Sstevel@tonic-gate 		    gettext("cannot create door service: %s\n"),
4180Sstevel@tonic-gate 		    strerror(errno));
4190Sstevel@tonic-gate 		rcmd_exit(errno);
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 	(void) chmod(RCM_SERVICE_DOOR, S_IRUSR);
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 	init_poll_thread(); /* initialize poll thread related data */
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	/*
4260Sstevel@tonic-gate 	 * Initialize database by asking modules to register.
4270Sstevel@tonic-gate 	 */
4280Sstevel@tonic-gate 	rcmd_db_init();
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	/*
4310Sstevel@tonic-gate 	 * Initialize locking, including lock recovery in the event of
4320Sstevel@tonic-gate 	 * unexpected daemon failure.
4330Sstevel@tonic-gate 	 */
4340Sstevel@tonic-gate 	rcmd_lock_init();
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	/*
4370Sstevel@tonic-gate 	 * Start accepting normal requests
4380Sstevel@tonic-gate 	 */
4390Sstevel@tonic-gate 	rcmd_set_state(RCMD_NORMAL);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/*
4420Sstevel@tonic-gate 	 * Start cleanup thread
4430Sstevel@tonic-gate 	 */
4440Sstevel@tonic-gate 	rcmd_db_clean();
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	/*
447175Sjg 	 * Loop within daemon and return after a period of inactivity.
4480Sstevel@tonic-gate 	 */
4490Sstevel@tonic-gate 	rcmd_start_timer(idle_timeout);
450175Sjg 
451175Sjg 	rcmd_cleanup(0);
452175Sjg 	return (0);
4530Sstevel@tonic-gate }
454