4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Reconfiguration Coordination Daemon
29 * Accept RCM messages in the form of RCM events and process them
30 * - to build and update the system resource map
31 * - to allow clients to register/unregister for resource
32 * - to allow dr initiators to offline a resource before removal
33 * - to call into clients to perform suspend/offline actions
35 * The goal is to enable fully automated Dynamic Reconfiguration and better
36 * DR information tracking.
39 #include <librcm_event.h>
43 /* will run in daemon mode if debug level < DEBUG_LEVEL_FORK */
44 #define DEBUG_LEVEL_FORK RCM_DEBUG
46 #define DAEMON_LOCK_FILE "/var/run/rcm_daemon_lock"
48 static int hold_daemon_lock
;
49 static int daemon_lock_fd
;
50 static const char *daemon_lock_file
= DAEMON_LOCK_FILE
;
53 static int idle_timeout
;
54 static int logflag
= 0;
57 static void usage(void);
58 static void catch_sighup(void);
59 static void catch_sigusr1(void);
60 static pid_t
enter_daemon_lock(void);
61 static void exit_daemon_lock(void);
63 extern void init_poll_thread();
64 extern void cleanup_poll_thread();
67 * Print command line syntax for starting rcm_daemon
71 (void) fprintf(stderr
,
72 gettext("usage: %s [-d debug_level] [-t idle_timeout]\n"), prog
);
77 * common cleanup/exit functions to ensure releasing locks
80 rcmd_cleanup(int status
)
83 rcm_log_message(RCM_INFO
,
84 gettext("rcm_daemon normal exit\n"));
86 rcm_log_message(RCM_ERROR
,
87 gettext("rcm_daemon exit: errno = %d\n"), status
);
90 if (hold_daemon_lock
) {
103 * When SIGHUP is received, reload modules at the next safe moment (when
104 * there is no DR activity.
109 rcm_log_message(RCM_INFO
,
110 gettext("SIGHUP received, will exit when daemon is idle\n"));
115 * When SIGUSR1 is received, exit the thread
120 rcm_log_message(RCM_DEBUG
, "SIGUSR1 received in thread %d\n",
122 cleanup_poll_thread();
127 * Use an advisory lock to ensure that only one daemon process is
128 * active at any point in time.
131 enter_daemon_lock(void)
135 rcm_log_message(RCM_TRACE1
,
136 "enter_daemon_lock: lock file = %s\n", daemon_lock_file
);
138 daemon_lock_fd
= open(daemon_lock_file
, O_CREAT
|O_RDWR
, 0644);
139 if (daemon_lock_fd
< 0) {
140 rcm_log_message(RCM_ERROR
, gettext("open(%s) - %s\n"),
141 daemon_lock_file
, strerror(errno
));
145 lock
.l_type
= F_WRLCK
;
146 lock
.l_whence
= SEEK_SET
;
150 if (fcntl(daemon_lock_fd
, F_SETLK
, &lock
) == 0) {
151 hold_daemon_lock
= 1;
155 /* failed to get lock, attempt to find lock owner */
156 if ((errno
== EAGAIN
|| errno
== EDEADLK
) &&
157 (fcntl(daemon_lock_fd
, F_GETLK
, &lock
) == 0)) {
161 /* die a horrible death */
162 rcm_log_message(RCM_ERROR
, gettext("lock(%s) - %s"), daemon_lock_file
,
169 * Drop the advisory daemon lock, close lock file
172 exit_daemon_lock(void)
176 lock
.l_type
= F_UNLCK
;
177 lock
.l_whence
= SEEK_SET
;
181 if (fcntl(daemon_lock_fd
, F_SETLK
, &lock
) == -1) {
182 rcm_log_message(RCM_ERROR
, gettext("unlock(%s) - %s"),
183 daemon_lock_file
, strerror(errno
));
186 (void) close(daemon_lock_fd
);
191 rcm_log_msg_impl(int level
, char *message
, va_list ap
)
197 * RCM_ERROR goes to stderr, others go to stdout
199 FILE *out
= (level
<= RCM_ERROR
) ? stderr
: stdout
;
200 (void) vfprintf(out
, message
, ap
);
205 * translate RCM_* to LOG_*
213 log_level
= LOG_WARNING
;
217 log_level
= LOG_NOTICE
;
221 log_level
= LOG_INFO
;
225 log_level
= LOG_DEBUG
;
230 * Don't log RCM_TRACEn messages
235 (void) vsyslog(log_level
, message
, ap
);
239 * print error messages to the terminal or to syslog
242 rcm_log_message(int level
, char *message
, ...)
246 if (level
> debug_level
) {
250 va_start(ap
, message
);
251 rcm_log_msg_impl(level
, message
, ap
);
256 * Print error messages to the terminal or to syslog.
257 * Same as rcm_log_message except that it does not check for
258 * level > debug_level
259 * allowing callers to override the global debug_level.
262 rcm_log_msg(int level
, char *message
, ...)
266 va_start(ap
, message
);
267 rcm_log_msg_impl(level
, message
, ap
);
272 * grab daemon_lock and direct messages to syslog
282 (void) open("/dev/null", O_RDWR
, 0);
285 openlog(prog
, LOG_PID
, LOG_DAEMON
);
290 main(int argc
, char **argv
)
296 struct sigaction act
;
298 (void) setlocale(LC_ALL
, "");
300 #define TEXT_DOMAIN "SYS_TEST"
302 (void) textdomain(TEXT_DOMAIN
);
304 if ((prog
= strrchr(argv
[0], '/')) == NULL
) {
310 (void) enable_extended_FILE_stdio(-1, -1);
318 while ((c
= getopt(argc
, argv
, "d:t:")) != EOF
) {
321 debug_level
= atoi(optarg
);
324 idle_timeout
= atoi(optarg
);
337 (void) fprintf(stderr
, gettext("Must be root to run %s\n"),
343 * When rcm_daemon is started by a call to librcm, it inherits file
344 * descriptors from the DR initiator making a call. The file
345 * descriptors may correspond to devices that can be removed by DR.
346 * Since keeping them remain opened is problematic, close everything
347 * but stdin/stdout/stderr.
352 * When rcm_daemon is started by the caller, it will inherit the
353 * signal block mask. We unblock all signals to make sure the
354 * signal handling will work normally.
356 (void) sigfillset(&mask
);
357 (void) thr_sigsetmask(SIG_UNBLOCK
, &mask
, NULL
);
360 * block SIGUSR1, use it for killing specific threads
362 (void) sigemptyset(&mask
);
363 (void) sigaddset(&mask
, SIGUSR1
);
364 (void) thr_sigsetmask(SIG_BLOCK
, &mask
, NULL
);
367 * Setup signal handlers for SIGHUP and SIGUSR1
368 * SIGHUP - causes a "delayed" daemon exit, effectively the same
369 * as a daemon restart.
370 * SIGUSR1 - causes a thr_exit(). Unblocked in selected threads.
373 act
.sa_handler
= catch_sighup
;
374 (void) sigaction(SIGHUP
, &act
, NULL
);
375 act
.sa_handler
= catch_sigusr1
;
376 (void) sigaction(SIGUSR1
, &act
, NULL
);
379 * ignore SIGPIPE so that the rcm daemon does not exit when it
380 * attempts to read or write from a pipe whose corresponding
381 * rcm script process exited.
383 act
.sa_handler
= SIG_IGN
;
384 (void) sigaction(SIGPIPE
, &act
, NULL
);
389 if (debug_level
< DEBUG_LEVEL_FORK
) {
396 /* only one daemon can run at a time */
397 if ((pid
= enter_daemon_lock()) != getpid()) {
398 rcm_log_message(RCM_DEBUG
, "%s pid %d already running\n",
403 rcm_log_message(RCM_TRACE1
, "%s started, debug level = %d\n",
407 * Set daemon state to block RCM requests before rcm_daemon is
408 * fully initialized. See rcmd_thr_incr().
410 rcmd_set_state(RCMD_INIT
);
413 * create rcm_daemon door and set permission to 0400
415 if (create_event_service(RCM_SERVICE_DOOR
, event_service
) == -1) {
416 rcm_log_message(RCM_ERROR
,
417 gettext("cannot create door service: %s\n"),
421 (void) chmod(RCM_SERVICE_DOOR
, S_IRUSR
);
423 init_poll_thread(); /* initialize poll thread related data */
426 * Initialize database by asking modules to register.
431 * Initialize locking, including lock recovery in the event of
432 * unexpected daemon failure.
437 * Start accepting normal requests
439 rcmd_set_state(RCMD_NORMAL
);
442 * Start cleanup thread
447 * Loop within daemon and return after a period of inactivity.
449 rcmd_start_timer(idle_timeout
);