/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdarg.h>
#include <strings.h>
#include <syslog.h>
#include <priv.h>
#include <wait.h>
#include <getopt.h>
#include <synch.h>
#include <libhotplug.h>
#include <libhotplug_impl.h>
#include "hotplugd_impl.h"
/*
* Define long options for command line.
*/
{ 0, 0, 0, 0 }
};
/*
* Local functions.
*/
static void usage(void);
static boolean_t check_privileges(void);
static int daemonize(void);
static void init_signals(void);
static void signal_handler(int signum);
static void shutdown_daemon(void);
/*
* Global variables.
*/
static char *prog;
/*
* main()
*
* The hotplug daemon is designed to be a background daemon
* controlled by SMF. So by default it will daemonize and
* do some coordination with its parent process in order to
* indicate proper success or failure back to SMF. And all
* output will be sent to syslog.
*
* But if given the '-d' command line option, it will instead
* run in the foreground in a standalone, debug mode. Errors
* and additional debug messages will be printed to the controlling
* terminal instead of to syslog.
*/
int
{
int opt;
int pfd;
int status;
else
prog++;
/* Check privileges */
if (!check_privileges()) {
"(All privileges are required.)\n");
return (-1);
}
/* Process options */
switch (opt) {
case 'd':
debug_flag = B_TRUE;
break;
case 'V':
return (0);
default:
if (optopt == '?') {
usage();
return (0);
}
optopt);
usage();
return (-1);
}
}
/* Initialize semaphore for daemon shutdown */
/* Initialize signal handling */
init_signals();
/* Daemonize, if not in DEBUG mode */
if (!debug_flag)
/* Initialize door service */
if (!door_server_init()) {
if (!debug_flag) {
}
}
/* Daemon initialized */
if (!debug_flag) {
status = 0;
}
/* Note that daemon is running */
log_info("hotplug daemon started.\n");
/* Wait for shutdown signal */
while (!exit_flag)
(void) sema_wait(&signal_sem);
return (0);
}
/*
* usage()
*
* Print a brief usage synopsis for the command line options.
*/
static void
usage(void)
{
}
/*
* check_privileges()
*
* Check if the current process has enough privileges
* to run the daemon. Note that all privileges are
* required in order for RCM interactions to work.
*/
static boolean_t
check_privileges(void)
{
}
}
return (rv);
}
/*
* daemonize()
*
* Fork the daemon process into the background, and detach from
* the controlling terminal. Setup a shared pipe that will later
* be used to report startup status to the parent process.
*/
static int
daemonize(void)
{
int status;
/*
* Temporarily block all signals. They will remain blocked in
* the parent, but will be unblocked in the child once it has
* notified the parent of its startup status.
*/
(void) sigfillset(&set);
/* Create the shared pipe */
}
/* Fork the daemon process */
}
/* Parent: waits for exit status from child. */
if (pid > 0) {
log_err("Failed to spawn daemon process.\n");
}
/* Child continues... */
(void) setsid();
(void) chdir("/");
/* Detach from controlling terminal */
(void) close(0);
(void) close(1);
(void) close(2);
/* Use syslog for future messages */
return (pfds[1]);
}
/*
* init_signals()
*
* Initialize signal handling.
*/
static void
init_signals(void)
{
(void) sigfillset(&set);
}
/*
* signal_handler()
*
* Most signals cause the hotplug daemon to shut down.
* Shutdown is triggered using a semaphore to wake up
* the main thread for a clean exit.
*
* Except SIGPIPE is used to coordinate between the parent
* and child processes when the daemon first starts.
*/
static void
{
switch (signum) {
case 0:
case SIGPIPE:
break;
default:
(void) sema_post(&signal_sem);
break;
}
}
/*
* shutdown_daemon()
*
* Perform a clean shutdown of the daemon.
*/
static void
shutdown_daemon(void)
{
log_info("Hotplug daemon shutting down.\n");
if (log_flag)
closelog();
(void) sema_destroy(&signal_sem);
}
/*
* log_err()
*
* Display an error message. Use syslog if in daemon
* mode, otherwise print to stderr when in debug mode.
*/
/*PRINTFLIKE1*/
void
{
if (debug_flag || !log_flag)
else
}
/*
* log_info()
*
* Display an information message. Use syslog if in daemon
* mode, otherwise print to stdout when in debug mode.
*/
/*PRINTFLIKE1*/
void
{
if (debug_flag || !log_flag)
else
}
/*
* dprintf()
*
* Print a debug tracing statement. Only works in debug
* mode, and always prints to stdout.
*/
/*PRINTFLIKE1*/
void
{
if (debug_flag) {
}
}