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