1*a4ac8bb3Sdnielsen /* 2*a4ac8bb3Sdnielsen * CDDL HEADER START 3*a4ac8bb3Sdnielsen * 4*a4ac8bb3Sdnielsen * The contents of this file are subject to the terms of the 5*a4ac8bb3Sdnielsen * Common Development and Distribution License (the "License"). 6*a4ac8bb3Sdnielsen * You may not use this file except in compliance with the License. 7*a4ac8bb3Sdnielsen * 8*a4ac8bb3Sdnielsen * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*a4ac8bb3Sdnielsen * or http://www.opensolaris.org/os/licensing. 10*a4ac8bb3Sdnielsen * See the License for the specific language governing permissions 11*a4ac8bb3Sdnielsen * and limitations under the License. 12*a4ac8bb3Sdnielsen * 13*a4ac8bb3Sdnielsen * When distributing Covered Code, include this CDDL HEADER in each 14*a4ac8bb3Sdnielsen * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*a4ac8bb3Sdnielsen * If applicable, add the following below this CDDL HEADER, with the 16*a4ac8bb3Sdnielsen * fields enclosed by brackets "[]" replaced with your own identifying 17*a4ac8bb3Sdnielsen * information: Portions Copyright [yyyy] [name of copyright owner] 18*a4ac8bb3Sdnielsen * 19*a4ac8bb3Sdnielsen * CDDL HEADER END 20*a4ac8bb3Sdnielsen */ 21*a4ac8bb3Sdnielsen /* 22*a4ac8bb3Sdnielsen * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*a4ac8bb3Sdnielsen * Use is subject to license terms. 24*a4ac8bb3Sdnielsen */ 25*a4ac8bb3Sdnielsen 26*a4ac8bb3Sdnielsen /* 27*a4ac8bb3Sdnielsen * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006 28*a4ac8bb3Sdnielsen */ 29*a4ac8bb3Sdnielsen 30*a4ac8bb3Sdnielsen #pragma ident "%Z%%M% %I% %E% SMI" 31*a4ac8bb3Sdnielsen 32*a4ac8bb3Sdnielsen #include <sys/param.h> 33*a4ac8bb3Sdnielsen #include <sys/stat.h> 34*a4ac8bb3Sdnielsen #include <sys/types.h> 35*a4ac8bb3Sdnielsen #include <sys/sysevent/eventdefs.h> 36*a4ac8bb3Sdnielsen #include <sys/sysevent/dr.h> 37*a4ac8bb3Sdnielsen 38*a4ac8bb3Sdnielsen #include <stdio.h> 39*a4ac8bb3Sdnielsen #include <stdlib.h> 40*a4ac8bb3Sdnielsen #include <unistd.h> 41*a4ac8bb3Sdnielsen #include <signal.h> 42*a4ac8bb3Sdnielsen #include <syslog.h> 43*a4ac8bb3Sdnielsen #include <string.h> 44*a4ac8bb3Sdnielsen #include <fcntl.h> 45*a4ac8bb3Sdnielsen #include <errno.h> 46*a4ac8bb3Sdnielsen #include <time.h> 47*a4ac8bb3Sdnielsen #include <config_admin.h> 48*a4ac8bb3Sdnielsen #include <libsysevent.h> 49*a4ac8bb3Sdnielsen 50*a4ac8bb3Sdnielsen 51*a4ac8bb3Sdnielsen /* Signal handler type */ 52*a4ac8bb3Sdnielsen typedef void (SigHandler)(int); 53*a4ac8bb3Sdnielsen /* oplhpd process id file descriptor */ 54*a4ac8bb3Sdnielsen static int pid_fd; 55*a4ac8bb3Sdnielsen 56*a4ac8bb3Sdnielsen /* Program Name */ 57*a4ac8bb3Sdnielsen char *oplhpd_prog_name = ""; 58*a4ac8bb3Sdnielsen 59*a4ac8bb3Sdnielsen /* Macros */ 60*a4ac8bb3Sdnielsen #define OPLHPD_DEV_DIR "/devices" /* device base dir */ 61*a4ac8bb3Sdnielsen #define OPLHPD_PID_FILE "/var/run/oplhpd.pid" /* lock file path */ 62*a4ac8bb3Sdnielsen #define OPLHPD_PROG_NAME oplhpd_prog_name 63*a4ac8bb3Sdnielsen 64*a4ac8bb3Sdnielsen /* Event handler to get information */ 65*a4ac8bb3Sdnielsen static sysevent_handle_t *oplhpd_hdl; 66*a4ac8bb3Sdnielsen 67*a4ac8bb3Sdnielsen 68*a4ac8bb3Sdnielsen /* 69*a4ac8bb3Sdnielsen * Function Prototypes 70*a4ac8bb3Sdnielsen */ 71*a4ac8bb3Sdnielsen void quit_daemon(int signo); 72*a4ac8bb3Sdnielsen SigHandler *set_sig_handler(int sig, SigHandler *handler); 73*a4ac8bb3Sdnielsen void init_daemon(void); 74*a4ac8bb3Sdnielsen void oplhpd_init(void); 75*a4ac8bb3Sdnielsen void oplhpd_fini(void); 76*a4ac8bb3Sdnielsen static void oplhpd_event(sysevent_t *ev); 77*a4ac8bb3Sdnielsen 78*a4ac8bb3Sdnielsen extern void notify_scf_of_hotplug(sysevent_t *ev); 79*a4ac8bb3Sdnielsen 80*a4ac8bb3Sdnielsen 81*a4ac8bb3Sdnielsen /* 82*a4ac8bb3Sdnielsen * Terminate and Quit Daemon Process. 83*a4ac8bb3Sdnielsen * signo = 0 ... normal quit 84*a4ac8bb3Sdnielsen * > 0 ... signaled quit 85*a4ac8bb3Sdnielsen * < 0 ... failure quit 86*a4ac8bb3Sdnielsen */ 87*a4ac8bb3Sdnielsen void 88*a4ac8bb3Sdnielsen quit_daemon(int signo) 89*a4ac8bb3Sdnielsen { 90*a4ac8bb3Sdnielsen int status = 0; 91*a4ac8bb3Sdnielsen id_t pgid; 92*a4ac8bb3Sdnielsen 93*a4ac8bb3Sdnielsen syslog(LOG_DEBUG, "*** quit daemon [pid:%d, signal#:%d].\n", 94*a4ac8bb3Sdnielsen getpid(), signo); 95*a4ac8bb3Sdnielsen 96*a4ac8bb3Sdnielsen (void) set_sig_handler(SIGTERM, SIG_IGN); 97*a4ac8bb3Sdnielsen pgid = getpgrp(); 98*a4ac8bb3Sdnielsen (void) kill(-pgid, SIGTERM); 99*a4ac8bb3Sdnielsen 100*a4ac8bb3Sdnielsen (void) close(pid_fd); 101*a4ac8bb3Sdnielsen (void) unlink(OPLHPD_PID_FILE); /* clean up lock file */ 102*a4ac8bb3Sdnielsen 103*a4ac8bb3Sdnielsen if (signo < 0) { 104*a4ac8bb3Sdnielsen status = signo; 105*a4ac8bb3Sdnielsen } 106*a4ac8bb3Sdnielsen _exit(status); 107*a4ac8bb3Sdnielsen } 108*a4ac8bb3Sdnielsen 109*a4ac8bb3Sdnielsen /* 110*a4ac8bb3Sdnielsen * Setting the signal handler utility 111*a4ac8bb3Sdnielsen */ 112*a4ac8bb3Sdnielsen SigHandler * 113*a4ac8bb3Sdnielsen set_sig_handler(int sig, SigHandler *handler) 114*a4ac8bb3Sdnielsen { 115*a4ac8bb3Sdnielsen struct sigaction act, oact; 116*a4ac8bb3Sdnielsen 117*a4ac8bb3Sdnielsen act.sa_handler = handler; 118*a4ac8bb3Sdnielsen act.sa_flags = 0; 119*a4ac8bb3Sdnielsen if (sig == SIGCHLD && handler == SIG_IGN) { 120*a4ac8bb3Sdnielsen act.sa_flags |= SA_NOCLDWAIT; 121*a4ac8bb3Sdnielsen } 122*a4ac8bb3Sdnielsen (void) sigemptyset(&act.sa_mask); 123*a4ac8bb3Sdnielsen (void) sigemptyset(&oact.sa_mask); 124*a4ac8bb3Sdnielsen if (sigaction(sig, &act, &oact) < 0) { 125*a4ac8bb3Sdnielsen return (SIG_ERR); 126*a4ac8bb3Sdnielsen } 127*a4ac8bb3Sdnielsen 128*a4ac8bb3Sdnielsen return (oact.sa_handler); 129*a4ac8bb3Sdnielsen } 130*a4ac8bb3Sdnielsen 131*a4ac8bb3Sdnielsen /* 132*a4ac8bb3Sdnielsen * Setup oplhpd daemon 133*a4ac8bb3Sdnielsen */ 134*a4ac8bb3Sdnielsen void 135*a4ac8bb3Sdnielsen init_daemon() 136*a4ac8bb3Sdnielsen { 137*a4ac8bb3Sdnielsen int i; 138*a4ac8bb3Sdnielsen int ret; 139*a4ac8bb3Sdnielsen int fd; 140*a4ac8bb3Sdnielsen pid_t pid; 141*a4ac8bb3Sdnielsen char pid_str[32]; 142*a4ac8bb3Sdnielsen 143*a4ac8bb3Sdnielsen if (geteuid() != 0) { 144*a4ac8bb3Sdnielsen syslog(LOG_ERR, "must be root to execute %s\n", 145*a4ac8bb3Sdnielsen OPLHPD_PROG_NAME); 146*a4ac8bb3Sdnielsen exit(1); 147*a4ac8bb3Sdnielsen } 148*a4ac8bb3Sdnielsen 149*a4ac8bb3Sdnielsen /* 150*a4ac8bb3Sdnielsen * Daemonize 151*a4ac8bb3Sdnielsen */ 152*a4ac8bb3Sdnielsen if ((pid = fork()) < 0) { 153*a4ac8bb3Sdnielsen perror("fork failed"); 154*a4ac8bb3Sdnielsen exit(1); 155*a4ac8bb3Sdnielsen } 156*a4ac8bb3Sdnielsen if (pid > 0) { 157*a4ac8bb3Sdnielsen /* Parent, exit. */ 158*a4ac8bb3Sdnielsen exit(0); 159*a4ac8bb3Sdnielsen } 160*a4ac8bb3Sdnielsen (void) setsid(); 161*a4ac8bb3Sdnielsen (void) chdir("/"); 162*a4ac8bb3Sdnielsen (void) umask(0); 163*a4ac8bb3Sdnielsen (void) closefrom(0); 164*a4ac8bb3Sdnielsen (void) open("/dev/null", O_RDONLY); 165*a4ac8bb3Sdnielsen (void) open("/dev/null", O_WRONLY); 166*a4ac8bb3Sdnielsen (void) dup(1); 167*a4ac8bb3Sdnielsen 168*a4ac8bb3Sdnielsen (void) openlog(OPLHPD_PROG_NAME, LOG_PID, LOG_DAEMON); 169*a4ac8bb3Sdnielsen 170*a4ac8bb3Sdnielsen /* 171*a4ac8bb3Sdnielsen * Create the lock file for singletonize 172*a4ac8bb3Sdnielsen */ 173*a4ac8bb3Sdnielsen if ((pid_fd = open(OPLHPD_PID_FILE, O_RDWR | O_CREAT, 0644)) < 0) { 174*a4ac8bb3Sdnielsen syslog(LOG_ERR, "could not create pid file: %s", 175*a4ac8bb3Sdnielsen strerror(errno)); 176*a4ac8bb3Sdnielsen exit(1); 177*a4ac8bb3Sdnielsen } 178*a4ac8bb3Sdnielsen if (lockf(pid_fd, F_TLOCK, 0L) < 0) { 179*a4ac8bb3Sdnielsen if (errno == EACCES || errno == EAGAIN) { 180*a4ac8bb3Sdnielsen syslog(LOG_ERR, "another oplhpd is already running"); 181*a4ac8bb3Sdnielsen } else { 182*a4ac8bb3Sdnielsen syslog(LOG_ERR, "could not lock pid file"); 183*a4ac8bb3Sdnielsen } 184*a4ac8bb3Sdnielsen exit(1); 185*a4ac8bb3Sdnielsen } 186*a4ac8bb3Sdnielsen 187*a4ac8bb3Sdnielsen (void) ftruncate(pid_fd, 0); 188*a4ac8bb3Sdnielsen i = sprintf(pid_str, "%d\n", getpid()); 189*a4ac8bb3Sdnielsen while ((ret = write(pid_fd, pid_str, i)) != i) { 190*a4ac8bb3Sdnielsen if (errno == EINTR) { 191*a4ac8bb3Sdnielsen continue; 192*a4ac8bb3Sdnielsen } 193*a4ac8bb3Sdnielsen if (ret < 0) { 194*a4ac8bb3Sdnielsen syslog(LOG_ERR, "pid file write fail: %s", 195*a4ac8bb3Sdnielsen strerror(errno)); 196*a4ac8bb3Sdnielsen exit(1); 197*a4ac8bb3Sdnielsen } 198*a4ac8bb3Sdnielsen } 199*a4ac8bb3Sdnielsen 200*a4ac8bb3Sdnielsen /* 201*a4ac8bb3Sdnielsen * Set signal handlers 202*a4ac8bb3Sdnielsen */ 203*a4ac8bb3Sdnielsen (void) set_sig_handler(SIGTERM, (SigHandler *)quit_daemon); 204*a4ac8bb3Sdnielsen (void) set_sig_handler(SIGQUIT, (SigHandler *)quit_daemon); 205*a4ac8bb3Sdnielsen (void) set_sig_handler(SIGINT, (SigHandler *)quit_daemon); 206*a4ac8bb3Sdnielsen (void) set_sig_handler(SIGCHLD, SIG_IGN); 207*a4ac8bb3Sdnielsen } 208*a4ac8bb3Sdnielsen 209*a4ac8bb3Sdnielsen static void 210*a4ac8bb3Sdnielsen oplhpd_event(sysevent_t *ev) 211*a4ac8bb3Sdnielsen { 212*a4ac8bb3Sdnielsen /* 213*a4ac8bb3Sdnielsen * Inform the SCF of the change in the state of the pci hot plug 214*a4ac8bb3Sdnielsen * cassette. 215*a4ac8bb3Sdnielsen */ 216*a4ac8bb3Sdnielsen notify_scf_of_hotplug(ev); 217*a4ac8bb3Sdnielsen 218*a4ac8bb3Sdnielsen } 219*a4ac8bb3Sdnielsen 220*a4ac8bb3Sdnielsen /* 221*a4ac8bb3Sdnielsen * Initialization for hotplug event. 222*a4ac8bb3Sdnielsen * - Bind event handler. 223*a4ac8bb3Sdnielsen * - Subscribe the handler to the hotplug event. 224*a4ac8bb3Sdnielsen */ 225*a4ac8bb3Sdnielsen void 226*a4ac8bb3Sdnielsen oplhpd_init() 227*a4ac8bb3Sdnielsen { 228*a4ac8bb3Sdnielsen const char *subclass = ESC_DR_AP_STATE_CHANGE; 229*a4ac8bb3Sdnielsen 230*a4ac8bb3Sdnielsen syslog(LOG_DEBUG, "oplhpd_init"); 231*a4ac8bb3Sdnielsen 232*a4ac8bb3Sdnielsen oplhpd_hdl = sysevent_bind_handle(oplhpd_event); 233*a4ac8bb3Sdnielsen if (oplhpd_hdl == NULL) { 234*a4ac8bb3Sdnielsen syslog(LOG_ERR, "event handler bind fail"); 235*a4ac8bb3Sdnielsen quit_daemon(-1); 236*a4ac8bb3Sdnielsen } 237*a4ac8bb3Sdnielsen 238*a4ac8bb3Sdnielsen if (sysevent_subscribe_event(oplhpd_hdl, EC_DR, &subclass, 1) != 0) { 239*a4ac8bb3Sdnielsen syslog(LOG_ERR, "event handler subscribe fail"); 240*a4ac8bb3Sdnielsen sysevent_unbind_handle(oplhpd_hdl); 241*a4ac8bb3Sdnielsen quit_daemon(-1); 242*a4ac8bb3Sdnielsen } 243*a4ac8bb3Sdnielsen 244*a4ac8bb3Sdnielsen for (;;) { 245*a4ac8bb3Sdnielsen (void) pause(); 246*a4ac8bb3Sdnielsen } 247*a4ac8bb3Sdnielsen } 248*a4ac8bb3Sdnielsen 249*a4ac8bb3Sdnielsen void 250*a4ac8bb3Sdnielsen oplhpd_fini() 251*a4ac8bb3Sdnielsen { 252*a4ac8bb3Sdnielsen if (oplhpd_hdl != NULL) { 253*a4ac8bb3Sdnielsen sysevent_unsubscribe_event(oplhpd_hdl, EC_DR); 254*a4ac8bb3Sdnielsen sysevent_unbind_handle(oplhpd_hdl); 255*a4ac8bb3Sdnielsen } 256*a4ac8bb3Sdnielsen } 257*a4ac8bb3Sdnielsen 258*a4ac8bb3Sdnielsen int 259*a4ac8bb3Sdnielsen main(int argc, char *argv[]) 260*a4ac8bb3Sdnielsen { 261*a4ac8bb3Sdnielsen int opt; 262*a4ac8bb3Sdnielsen 263*a4ac8bb3Sdnielsen /* Get Program Name */ 264*a4ac8bb3Sdnielsen if ((oplhpd_prog_name = strrchr(argv[0], '/')) == NULL) { 265*a4ac8bb3Sdnielsen oplhpd_prog_name = argv[0]; 266*a4ac8bb3Sdnielsen } else { 267*a4ac8bb3Sdnielsen oplhpd_prog_name++; 268*a4ac8bb3Sdnielsen } 269*a4ac8bb3Sdnielsen 270*a4ac8bb3Sdnielsen /* Check the daemon running lock and Initialize the signal */ 271*a4ac8bb3Sdnielsen init_daemon(); 272*a4ac8bb3Sdnielsen 273*a4ac8bb3Sdnielsen /* Subscribe to the hotplug event */ 274*a4ac8bb3Sdnielsen oplhpd_init(); 275*a4ac8bb3Sdnielsen 276*a4ac8bb3Sdnielsen /* Unsubscribe the hotplug event */ 277*a4ac8bb3Sdnielsen oplhpd_fini(); 278*a4ac8bb3Sdnielsen 279*a4ac8bb3Sdnielsen return (0); 280*a4ac8bb3Sdnielsen } 281