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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
40 #include <sys/param.h>
42 #include <sys/types.h>
43 #include <libhotplug.h>
44 #include <libhotplug_impl.h>
45 #include "hotplugd_impl.h"
48 * Define long options for command line.
50 static const struct option lopts
[] = {
51 { "help", no_argument
, 0, '?' },
52 { "version", no_argument
, 0, 'V' },
53 { "debug", no_argument
, 0, 'd' },
60 static void usage(void);
61 static boolean_t
check_privileges(void);
62 static int daemonize(void);
63 static void init_signals(void);
64 static void signal_handler(int signum
);
65 static void shutdown_daemon(void);
71 static char version
[] = "1.0";
72 static boolean_t log_flag
= B_FALSE
;
73 static boolean_t debug_flag
= B_FALSE
;
74 static boolean_t exit_flag
= B_FALSE
;
75 static sema_t signal_sem
;
80 * The hotplug daemon is designed to be a background daemon
81 * controlled by SMF. So by default it will daemonize and
82 * do some coordination with its parent process in order to
83 * indicate proper success or failure back to SMF. And all
84 * output will be sent to syslog.
86 * But if given the '-d' command line option, it will instead
87 * run in the foreground in a standalone, debug mode. Errors
88 * and additional debug messages will be printed to the controlling
89 * terminal instead of to syslog.
92 main(int argc
, char *argv
[])
98 if ((prog
= strrchr(argv
[0], '/')) == NULL
)
103 /* Check privileges */
104 if (!check_privileges()) {
105 (void) fprintf(stderr
, "Insufficient privileges. "
106 "(All privileges are required.)\n");
110 /* Process options */
111 while ((opt
= getopt_clip(argc
, argv
, "dV?", lopts
, NULL
)) != -1) {
117 (void) printf("%s: Version %s\n", prog
, version
);
124 (void) fprintf(stderr
, "Unrecognized option '%c'.\n",
131 /* Initialize semaphore for daemon shutdown */
132 if (sema_init(&signal_sem
, 1, USYNC_THREAD
, NULL
) != 0)
135 /* Initialize signal handling */
138 /* Daemonize, if not in DEBUG mode */
142 /* Initialize door service */
143 if (!door_server_init()) {
145 status
= EXIT_FAILURE
;
146 (void) write(pfd
, &status
, sizeof (status
));
152 /* Daemon initialized */
155 (void) write(pfd
, &status
, sizeof (status
));
159 /* Note that daemon is running */
160 log_info("hotplug daemon started.\n");
162 /* Wait for shutdown signal */
164 (void) sema_wait(&signal_sem
);
173 * Print a brief usage synopsis for the command line options.
178 (void) printf("Usage: %s [-d]\n", prog
);
184 * Check if the current process has enough privileges
185 * to run the daemon. Note that all privileges are
186 * required in order for RCM interactions to work.
189 check_privileges(void)
192 boolean_t rv
= B_FALSE
;
194 if ((privset
= priv_allocset()) != NULL
) {
195 if (getppriv(PRIV_EFFECTIVE
, privset
) == 0) {
196 rv
= priv_isfullset(privset
);
198 priv_freeset(privset
);
207 * Fork the daemon process into the background, and detach from
208 * the controlling terminal. Setup a shared pipe that will later
209 * be used to report startup status to the parent process.
221 * Temporarily block all signals. They will remain blocked in
222 * the parent, but will be unblocked in the child once it has
223 * notified the parent of its startup status.
225 (void) sigfillset(&set
);
226 (void) sigdelset(&set
, SIGABRT
);
227 (void) sigprocmask(SIG_BLOCK
, &set
, &oset
);
229 /* Create the shared pipe */
230 if (pipe(pfds
) == -1) {
231 log_err("Cannot create pipe (%s)\n", strerror(errno
));
235 /* Fork the daemon process */
236 if ((pid
= fork()) == -1) {
237 log_err("Cannot fork daemon process (%s)\n", strerror(errno
));
241 /* Parent: waits for exit status from child. */
243 (void) close(pfds
[1]);
244 if (read(pfds
[0], &status
, sizeof (status
)) == sizeof (status
))
246 if ((waitpid(pid
, &status
, 0) == pid
) && WIFEXITED(status
))
247 _exit(WEXITSTATUS(status
));
248 log_err("Failed to spawn daemon process.\n");
252 /* Child continues... */
257 (void) sigprocmask(SIG_SETMASK
, &oset
, NULL
);
258 (void) close(pfds
[0]);
260 /* Detach from controlling terminal */
264 (void) open("/dev/null", O_RDONLY
);
265 (void) open("/dev/null", O_WRONLY
);
266 (void) open("/dev/null", O_WRONLY
);
268 /* Use syslog for future messages */
270 openlog(prog
, LOG_PID
, LOG_DAEMON
);
278 * Initialize signal handling.
283 struct sigaction act
;
286 (void) sigfillset(&set
);
287 (void) sigdelset(&set
, SIGABRT
);
289 (void) sigfillset(&act
.sa_mask
);
290 act
.sa_handler
= signal_handler
;
293 (void) sigaction(SIGTERM
, &act
, NULL
);
294 (void) sigaction(SIGHUP
, &act
, NULL
);
295 (void) sigaction(SIGINT
, &act
, NULL
);
296 (void) sigaction(SIGPIPE
, &act
, NULL
);
298 (void) sigdelset(&set
, SIGTERM
);
299 (void) sigdelset(&set
, SIGHUP
);
300 (void) sigdelset(&set
, SIGINT
);
301 (void) sigdelset(&set
, SIGPIPE
);
307 * Most signals cause the hotplug daemon to shut down.
308 * Shutdown is triggered using a semaphore to wake up
309 * the main thread for a clean exit.
311 * Except SIGPIPE is used to coordinate between the parent
312 * and child processes when the daemon first starts.
315 signal_handler(int signum
)
317 log_info("Received signal %d.\n", signum
);
325 (void) sema_post(&signal_sem
);
333 * Perform a clean shutdown of the daemon.
336 shutdown_daemon(void)
338 log_info("Hotplug daemon shutting down.\n");
345 (void) sema_destroy(&signal_sem
);
351 * Display an error message. Use syslog if in daemon
352 * mode, otherwise print to stderr when in debug mode.
356 log_err(char *fmt
, ...)
361 if (debug_flag
|| !log_flag
)
362 (void) vfprintf(stderr
, fmt
, ap
);
364 vsyslog(LOG_ERR
, fmt
, ap
);
371 * Display an information message. Use syslog if in daemon
372 * mode, otherwise print to stdout when in debug mode.
376 log_info(char *fmt
, ...)
381 if (debug_flag
|| !log_flag
)
382 (void) vfprintf(stdout
, fmt
, ap
);
384 vsyslog(LOG_INFO
, fmt
, ap
);
391 * Print a debug tracing statement. Only works in debug
392 * mode, and always prints to stdout.
396 dprintf(char *fmt
, ...)
402 (void) vprintf(fmt
, ap
);