/* * 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. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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); }