OpenSolaris_b135/cmd/oplhpd/oplhpd.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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
 * or http://www.opensolaris.org/os/licensing.
 * 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 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/sysevent/eventdefs.h>
#include <sys/sysevent/dr.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
#include <config_admin.h>
#include <libsysevent.h>


/* Signal handler type */
typedef void (SigHandler)(int);
/* oplhpd process id file descriptor */
static int pid_fd;

/* Program Name */
char	*oplhpd_prog_name = "";

/* Macros */
#define	OPLHPD_DEV_DIR "/devices"	/* device base dir */
#define	OPLHPD_PID_FILE "/var/run/oplhpd.pid" /* lock file path */
#define	OPLHPD_PROG_NAME oplhpd_prog_name

/* Event handler to get information */
static sysevent_handle_t *oplhpd_hdl;


/*
 * Function Prototypes
 */
void quit_daemon(int signo);
SigHandler *set_sig_handler(int sig, SigHandler *handler);
void init_daemon(void);
void oplhpd_init(void);
void oplhpd_fini(void);
static void oplhpd_event(sysevent_t *ev);

extern void notify_scf_of_hotplug(sysevent_t *ev);


/*
 * Terminate and Quit Daemon Process.
 * signo = 0 ... normal   quit
 *       > 0 ... signaled quit
 *       < 0 ... failure  quit
 */
void
quit_daemon(int signo)
{
	int status = 0;
	id_t pgid;

	syslog(LOG_DEBUG, "*** quit daemon [pid:%d, signal#:%d].\n",
			getpid(), signo);

	(void) set_sig_handler(SIGTERM, SIG_IGN);
	pgid = getpgrp();
	(void) kill(-pgid, SIGTERM);

	(void) close(pid_fd);
	(void) unlink(OPLHPD_PID_FILE); /* clean up lock file */

	if (signo < 0) {
		status = signo;
	}
	_exit(status);
}

/*
 * Setting the signal handler utility
 */
SigHandler *
set_sig_handler(int sig, SigHandler *handler)
{
	struct sigaction act, oact;

	act.sa_handler = handler;
	act.sa_flags = 0;
	if (sig == SIGCHLD && handler == SIG_IGN) {
		act.sa_flags |= SA_NOCLDWAIT;
	}
	(void) sigemptyset(&act.sa_mask);
	(void) sigemptyset(&oact.sa_mask);
	if (sigaction(sig, &act, &oact) < 0) {
		return (SIG_ERR);
	}

	return (oact.sa_handler);
}

/*
 * Setup oplhpd daemon
 */
void
init_daemon()
{
	int	i;
	int	ret;
	int	fd;
	pid_t	pid;
	char	pid_str[32];

	if (geteuid() != 0) {
		syslog(LOG_ERR, "must be root to execute %s\n",
				OPLHPD_PROG_NAME);
		exit(1);
	}

	/*
	 * Daemonize
	 */
	if ((pid = fork()) < 0) {
		perror("fork failed");
		exit(1);
	}
	if (pid > 0) {
	/* Parent, exit. */
		exit(0);
	}
	(void) setsid();
	(void) chdir("/");
	(void) umask(0);
	(void) closefrom(0);
	(void) open("/dev/null", O_RDONLY);
	(void) open("/dev/null", O_WRONLY);
	(void) dup(1);

	(void) openlog(OPLHPD_PROG_NAME, LOG_PID, LOG_DAEMON);

	/*
	 * Create the lock file for singletonize
	 */
	if ((pid_fd = open(OPLHPD_PID_FILE, O_RDWR | O_CREAT, 0644)) < 0) {
		syslog(LOG_ERR, "could not create pid file: %s",
		strerror(errno));
		exit(1);
	}
	if (lockf(pid_fd, F_TLOCK, 0L) < 0) {
		if (errno == EACCES || errno == EAGAIN) {
			syslog(LOG_ERR, "another oplhpd is already running");
		} else {
			syslog(LOG_ERR, "could not lock pid file");
		}
		exit(1);
		}

	(void) ftruncate(pid_fd, 0);
	i = sprintf(pid_str, "%d\n", getpid());
	while ((ret = write(pid_fd, pid_str, i)) != i) {
		if (errno == EINTR) {
			continue;
		}
		if (ret < 0) {
			syslog(LOG_ERR, "pid file write fail: %s",
			strerror(errno));
			exit(1);
		}
	}

	/*
	 * Set signal handlers
	 */
	(void) set_sig_handler(SIGTERM, (SigHandler *)quit_daemon);
	(void) set_sig_handler(SIGQUIT, (SigHandler *)quit_daemon);
	(void) set_sig_handler(SIGINT,  (SigHandler *)quit_daemon);
	(void) set_sig_handler(SIGCHLD, SIG_IGN);
}

static void
oplhpd_event(sysevent_t *ev)
{
	/*
	 * Inform the SCF of the change in the state of the pci hot plug
	 * cassette.
	 */
	notify_scf_of_hotplug(ev);

}

/*
 * Initialization for hotplug event.
 * - Bind event handler.
 * - Subscribe the handler to the hotplug event.
 */
void
oplhpd_init()
{
	const char *subclass = ESC_DR_AP_STATE_CHANGE;

	syslog(LOG_DEBUG, "oplhpd_init");

	oplhpd_hdl = sysevent_bind_handle(oplhpd_event);
	if (oplhpd_hdl == NULL) {
		syslog(LOG_ERR, "event handler bind fail");
		quit_daemon(-1);
	}

	if (sysevent_subscribe_event(oplhpd_hdl, EC_DR, &subclass, 1) != 0) {
		syslog(LOG_ERR, "event handler subscribe fail");
		sysevent_unbind_handle(oplhpd_hdl);
		quit_daemon(-1);
	}

	for (;;) {
		(void) pause();
	}
}

void
oplhpd_fini()
{
	if (oplhpd_hdl != NULL) {
		sysevent_unsubscribe_event(oplhpd_hdl, EC_DR);
		sysevent_unbind_handle(oplhpd_hdl);
	}
}

int
main(int argc, char *argv[])
{
	int opt;

	/* Get Program Name */
	if ((oplhpd_prog_name = strrchr(argv[0], '/')) == NULL) {
		oplhpd_prog_name = argv[0];
	} else {
		oplhpd_prog_name++;
	}

	/* Check the daemon running lock and Initialize the signal */
	init_daemon();

	/* Subscribe to the hotplug event */
	oplhpd_init();

	/* Unsubscribe the hotplug event */
	oplhpd_fini();

	return (0);
}