1*a3114836SGerry Liu /* 2*a3114836SGerry Liu * CDDL HEADER START 3*a3114836SGerry Liu * 4*a3114836SGerry Liu * The contents of this file are subject to the terms of the 5*a3114836SGerry Liu * Common Development and Distribution License (the "License"). 6*a3114836SGerry Liu * You may not use this file except in compliance with the License. 7*a3114836SGerry Liu * 8*a3114836SGerry Liu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*a3114836SGerry Liu * or http://www.opensolaris.org/os/licensing. 10*a3114836SGerry Liu * See the License for the specific language governing permissions 11*a3114836SGerry Liu * and limitations under the License. 12*a3114836SGerry Liu * 13*a3114836SGerry Liu * When distributing Covered Code, include this CDDL HEADER in each 14*a3114836SGerry Liu * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*a3114836SGerry Liu * If applicable, add the following below this CDDL HEADER, with the 16*a3114836SGerry Liu * fields enclosed by brackets "[]" replaced with your own identifying 17*a3114836SGerry Liu * information: Portions Copyright [yyyy] [name of copyright owner] 18*a3114836SGerry Liu * 19*a3114836SGerry Liu * CDDL HEADER END 20*a3114836SGerry Liu */ 21*a3114836SGerry Liu 22*a3114836SGerry Liu /* 23*a3114836SGerry Liu * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*a3114836SGerry Liu * Use is subject to license terms. 25*a3114836SGerry Liu */ 26*a3114836SGerry Liu /* 27*a3114836SGerry Liu * Copyright (c) 2010, Intel Corporation. 28*a3114836SGerry Liu * All rights reserved. 29*a3114836SGerry Liu */ 30*a3114836SGerry Liu 31*a3114836SGerry Liu #include <sys/param.h> 32*a3114836SGerry Liu #include <sys/stat.h> 33*a3114836SGerry Liu #include <sys/types.h> 34*a3114836SGerry Liu #include <sys/sysevent/eventdefs.h> 35*a3114836SGerry Liu #include <sys/sysevent/dr.h> 36*a3114836SGerry Liu 37*a3114836SGerry Liu #include <stdio.h> 38*a3114836SGerry Liu #include <stdlib.h> 39*a3114836SGerry Liu #include <unistd.h> 40*a3114836SGerry Liu #include <signal.h> 41*a3114836SGerry Liu #include <syslog.h> 42*a3114836SGerry Liu #include <string.h> 43*a3114836SGerry Liu #include <strings.h> 44*a3114836SGerry Liu #include <fcntl.h> 45*a3114836SGerry Liu #include <errno.h> 46*a3114836SGerry Liu #include <time.h> 47*a3114836SGerry Liu #include <config_admin.h> 48*a3114836SGerry Liu #include <libscf.h> 49*a3114836SGerry Liu #include <libsysevent.h> 50*a3114836SGerry Liu #include <stdarg.h> 51*a3114836SGerry Liu 52*a3114836SGerry Liu /* Signal handler type */ 53*a3114836SGerry Liu typedef void (sig_handler_t)(int); 54*a3114836SGerry Liu 55*a3114836SGerry Liu #define ACPIHPD_PID_FILE "/var/run/acpihpd.pid" /* lock file path */ 56*a3114836SGerry Liu 57*a3114836SGerry Liu /* Program Name */ 58*a3114836SGerry Liu char *g_prog_name; 59*a3114836SGerry Liu int g_debuglevel = 0; 60*a3114836SGerry Liu 61*a3114836SGerry Liu static int s_pid_fd; 62*a3114836SGerry Liu static sysevent_handle_t *s_acpihpd_hdl; 63*a3114836SGerry Liu 64*a3114836SGerry Liu static int daemon_init(void); 65*a3114836SGerry Liu static void daemon_quit(int); 66*a3114836SGerry Liu static int set_sig_handler(int, sig_handler_t *); 67*a3114836SGerry Liu static int acpihpd_init(void); 68*a3114836SGerry Liu static void acpihpd_fini(void); 69*a3114836SGerry Liu static void acpihpd_event(sysevent_t *); 70*a3114836SGerry Liu extern void notify_hotplug(sysevent_t *ev); 71*a3114836SGerry Liu void debug_print(int, const char *, ...); 72*a3114836SGerry Liu 73*a3114836SGerry Liu int 74*a3114836SGerry Liu main(int argc, char *argv[]) 75*a3114836SGerry Liu { 76*a3114836SGerry Liu int c; 77*a3114836SGerry Liu 78*a3114836SGerry Liu /* Get Program Name */ 79*a3114836SGerry Liu if ((g_prog_name = strrchr(argv[0], '/')) == NULL) { 80*a3114836SGerry Liu g_prog_name = argv[0]; 81*a3114836SGerry Liu } else { 82*a3114836SGerry Liu g_prog_name++; 83*a3114836SGerry Liu } 84*a3114836SGerry Liu 85*a3114836SGerry Liu while ((c = getopt(argc, argv, ":d:")) != -1) { 86*a3114836SGerry Liu switch (c) { 87*a3114836SGerry Liu case 'd': 88*a3114836SGerry Liu g_debuglevel = atoi(optarg); 89*a3114836SGerry Liu if ((g_debuglevel < 0) || (g_debuglevel > 2)) { 90*a3114836SGerry Liu g_debuglevel = 0; 91*a3114836SGerry Liu } 92*a3114836SGerry Liu break; 93*a3114836SGerry Liu 94*a3114836SGerry Liu case ':': 95*a3114836SGerry Liu syslog(LOG_ERR, 96*a3114836SGerry Liu "missed argument for option %c.", optopt); 97*a3114836SGerry Liu break; 98*a3114836SGerry Liu 99*a3114836SGerry Liu case '?': 100*a3114836SGerry Liu syslog(LOG_ERR, "unrecognized option %c.", optopt); 101*a3114836SGerry Liu break; 102*a3114836SGerry Liu } 103*a3114836SGerry Liu } 104*a3114836SGerry Liu 105*a3114836SGerry Liu s_acpihpd_hdl = NULL; 106*a3114836SGerry Liu 107*a3114836SGerry Liu /* Check the daemon running lock and initialize the signal */ 108*a3114836SGerry Liu if (daemon_init() != 0) { 109*a3114836SGerry Liu debug_print(0, "%s could not startup!", g_prog_name); 110*a3114836SGerry Liu exit(SMF_EXIT_ERR_FATAL); 111*a3114836SGerry Liu } 112*a3114836SGerry Liu 113*a3114836SGerry Liu /* Subscribe to the hotplug event */ 114*a3114836SGerry Liu if (acpihpd_init() != 0) { 115*a3114836SGerry Liu debug_print(0, "%s could not startup!", g_prog_name); 116*a3114836SGerry Liu daemon_quit(SMF_EXIT_ERR_FATAL); 117*a3114836SGerry Liu } 118*a3114836SGerry Liu 119*a3114836SGerry Liu debug_print(2, "daemon is running."); 120*a3114836SGerry Liu /*CONSTCOND*/ 121*a3114836SGerry Liu while (1) { 122*a3114836SGerry Liu (void) pause(); 123*a3114836SGerry Liu } 124*a3114836SGerry Liu 125*a3114836SGerry Liu return (SMF_EXIT_OK); 126*a3114836SGerry Liu } 127*a3114836SGerry Liu 128*a3114836SGerry Liu static int 129*a3114836SGerry Liu daemon_init(void) 130*a3114836SGerry Liu { 131*a3114836SGerry Liu int i, ret; 132*a3114836SGerry Liu pid_t pid; 133*a3114836SGerry Liu char pid_str[32]; 134*a3114836SGerry Liu 135*a3114836SGerry Liu if (geteuid() != 0) { 136*a3114836SGerry Liu debug_print(0, "must be root to execute %s", g_prog_name); 137*a3114836SGerry Liu return (1); 138*a3114836SGerry Liu } 139*a3114836SGerry Liu 140*a3114836SGerry Liu if ((pid = fork()) < 0) { 141*a3114836SGerry Liu return (1); 142*a3114836SGerry Liu } 143*a3114836SGerry Liu 144*a3114836SGerry Liu if (pid > 0) { 145*a3114836SGerry Liu /* Parent to exit. */ 146*a3114836SGerry Liu exit(SMF_EXIT_OK); 147*a3114836SGerry Liu } 148*a3114836SGerry Liu 149*a3114836SGerry Liu (void) setsid(); 150*a3114836SGerry Liu (void) chdir("/"); 151*a3114836SGerry Liu (void) umask(0); 152*a3114836SGerry Liu (void) closefrom(0); 153*a3114836SGerry Liu (void) open("/dev/null", O_RDONLY); 154*a3114836SGerry Liu (void) open("/dev/null", O_WRONLY); 155*a3114836SGerry Liu (void) dup(1); 156*a3114836SGerry Liu (void) openlog(g_prog_name, LOG_PID, LOG_DAEMON); 157*a3114836SGerry Liu 158*a3114836SGerry Liu /* 159*a3114836SGerry Liu * Create the lock file for singleton 160*a3114836SGerry Liu */ 161*a3114836SGerry Liu if ((s_pid_fd = open(ACPIHPD_PID_FILE, O_RDWR | O_CREAT, 0644)) < 0) { 162*a3114836SGerry Liu debug_print(0, "could not create pid file: %s", 163*a3114836SGerry Liu strerror(errno)); 164*a3114836SGerry Liu return (1); 165*a3114836SGerry Liu } 166*a3114836SGerry Liu 167*a3114836SGerry Liu if (lockf(s_pid_fd, F_TLOCK, 0L) < 0) { 168*a3114836SGerry Liu if (errno == EACCES || errno == EAGAIN) { 169*a3114836SGerry Liu debug_print(0, "another acpihpd is already running"); 170*a3114836SGerry Liu } else { 171*a3114836SGerry Liu debug_print(0, "could not lock pid file"); 172*a3114836SGerry Liu } 173*a3114836SGerry Liu 174*a3114836SGerry Liu return (1); 175*a3114836SGerry Liu } 176*a3114836SGerry Liu 177*a3114836SGerry Liu (void) ftruncate(s_pid_fd, 0); 178*a3114836SGerry Liu i = sprintf(pid_str, "%ld", (long)getpid()); 179*a3114836SGerry Liu while ((ret = write(s_pid_fd, pid_str, i)) != i) { 180*a3114836SGerry Liu if (errno == EINTR) { 181*a3114836SGerry Liu continue; 182*a3114836SGerry Liu } 183*a3114836SGerry Liu if (ret < 0) { 184*a3114836SGerry Liu debug_print(0, "pid file write failed: %s", 185*a3114836SGerry Liu strerror(errno)); 186*a3114836SGerry Liu return (1); 187*a3114836SGerry Liu } 188*a3114836SGerry Liu } 189*a3114836SGerry Liu 190*a3114836SGerry Liu if (set_sig_handler(SIGTERM, (sig_handler_t *)daemon_quit) != 0) { 191*a3114836SGerry Liu debug_print(2, "could not set signal handler(SIGTERM)"); 192*a3114836SGerry Liu return (1); 193*a3114836SGerry Liu } 194*a3114836SGerry Liu 195*a3114836SGerry Liu if (set_sig_handler(SIGQUIT, (sig_handler_t *)daemon_quit) != 0) { 196*a3114836SGerry Liu debug_print(2, "could not set signal handler(SIGQUIT)"); 197*a3114836SGerry Liu return (1); 198*a3114836SGerry Liu } 199*a3114836SGerry Liu 200*a3114836SGerry Liu if (set_sig_handler(SIGINT, (sig_handler_t *)daemon_quit) != 0) { 201*a3114836SGerry Liu debug_print(2, "could not set signal handler(SIGINT)"); 202*a3114836SGerry Liu return (1); 203*a3114836SGerry Liu } 204*a3114836SGerry Liu 205*a3114836SGerry Liu if (set_sig_handler(SIGCHLD, SIG_IGN) != 0) { 206*a3114836SGerry Liu debug_print(2, "could not set signal handler(SIGCHLD)"); 207*a3114836SGerry Liu return (1); 208*a3114836SGerry Liu } 209*a3114836SGerry Liu 210*a3114836SGerry Liu return (0); 211*a3114836SGerry Liu } 212*a3114836SGerry Liu 213*a3114836SGerry Liu static void 214*a3114836SGerry Liu daemon_quit(int signo) 215*a3114836SGerry Liu { 216*a3114836SGerry Liu int status = 0; 217*a3114836SGerry Liu id_t pgid; 218*a3114836SGerry Liu 219*a3114836SGerry Liu debug_print(1, "daemon quit [signal#:%d].", signo); 220*a3114836SGerry Liu 221*a3114836SGerry Liu acpihpd_fini(); 222*a3114836SGerry Liu (void) set_sig_handler(SIGTERM, SIG_IGN); 223*a3114836SGerry Liu pgid = getpgrp(); 224*a3114836SGerry Liu (void) kill(-pgid, SIGTERM); 225*a3114836SGerry Liu (void) close(s_pid_fd); 226*a3114836SGerry Liu (void) unlink(ACPIHPD_PID_FILE); 227*a3114836SGerry Liu 228*a3114836SGerry Liu if (signo < 0) { 229*a3114836SGerry Liu status = signo; 230*a3114836SGerry Liu } 231*a3114836SGerry Liu _exit(status); 232*a3114836SGerry Liu } 233*a3114836SGerry Liu 234*a3114836SGerry Liu static int 235*a3114836SGerry Liu set_sig_handler(int sig, sig_handler_t *handler) 236*a3114836SGerry Liu { 237*a3114836SGerry Liu struct sigaction act; 238*a3114836SGerry Liu 239*a3114836SGerry Liu act.sa_handler = handler; 240*a3114836SGerry Liu act.sa_flags = 0; 241*a3114836SGerry Liu if (sig == SIGCHLD && handler == SIG_IGN) { 242*a3114836SGerry Liu act.sa_flags |= SA_NOCLDWAIT; 243*a3114836SGerry Liu } 244*a3114836SGerry Liu 245*a3114836SGerry Liu (void) sigemptyset(&act.sa_mask); 246*a3114836SGerry Liu if (sigaction(sig, &act, NULL) < 0) { 247*a3114836SGerry Liu return (1); 248*a3114836SGerry Liu } 249*a3114836SGerry Liu 250*a3114836SGerry Liu return (0); 251*a3114836SGerry Liu } 252*a3114836SGerry Liu 253*a3114836SGerry Liu static int 254*a3114836SGerry Liu acpihpd_init(void) 255*a3114836SGerry Liu { 256*a3114836SGerry Liu const char *subclass = ESC_DR_REQ; 257*a3114836SGerry Liu 258*a3114836SGerry Liu debug_print(2, "acpihpd_init"); 259*a3114836SGerry Liu 260*a3114836SGerry Liu if ((s_acpihpd_hdl = sysevent_bind_handle(acpihpd_event)) == NULL) { 261*a3114836SGerry Liu debug_print(2, "could not bind to sysevent."); 262*a3114836SGerry Liu return (-1); 263*a3114836SGerry Liu } 264*a3114836SGerry Liu 265*a3114836SGerry Liu if (sysevent_subscribe_event(s_acpihpd_hdl, EC_DR, &subclass, 1) != 0) { 266*a3114836SGerry Liu debug_print(2, "could not subscribe an event."); 267*a3114836SGerry Liu sysevent_unbind_handle(s_acpihpd_hdl); 268*a3114836SGerry Liu s_acpihpd_hdl = NULL; 269*a3114836SGerry Liu return (-1); 270*a3114836SGerry Liu } 271*a3114836SGerry Liu 272*a3114836SGerry Liu return (0); 273*a3114836SGerry Liu } 274*a3114836SGerry Liu 275*a3114836SGerry Liu static void 276*a3114836SGerry Liu acpihpd_fini(void) 277*a3114836SGerry Liu { 278*a3114836SGerry Liu debug_print(2, "acpihpd_fini"); 279*a3114836SGerry Liu 280*a3114836SGerry Liu if (s_acpihpd_hdl != NULL) { 281*a3114836SGerry Liu sysevent_unsubscribe_event(s_acpihpd_hdl, EC_DR); 282*a3114836SGerry Liu sysevent_unbind_handle(s_acpihpd_hdl); 283*a3114836SGerry Liu } 284*a3114836SGerry Liu } 285*a3114836SGerry Liu 286*a3114836SGerry Liu static void 287*a3114836SGerry Liu acpihpd_event(sysevent_t *ev) 288*a3114836SGerry Liu { 289*a3114836SGerry Liu debug_print(2, "*** got an event ***"); 290*a3114836SGerry Liu 291*a3114836SGerry Liu /* Inform cfgadm of the hot-plug event. */ 292*a3114836SGerry Liu notify_hotplug(ev); 293*a3114836SGerry Liu } 294*a3114836SGerry Liu 295*a3114836SGerry Liu void 296*a3114836SGerry Liu debug_print(int level, const char *fmt, ...) 297*a3114836SGerry Liu { 298*a3114836SGerry Liu va_list ap; 299*a3114836SGerry Liu int pri, pr_out = 0; 300*a3114836SGerry Liu 301*a3114836SGerry Liu if (level <= g_debuglevel) { 302*a3114836SGerry Liu switch (level) { 303*a3114836SGerry Liu case 0: 304*a3114836SGerry Liu pri = LOG_ERR; 305*a3114836SGerry Liu pr_out = 1; 306*a3114836SGerry Liu break; 307*a3114836SGerry Liu 308*a3114836SGerry Liu case 1: 309*a3114836SGerry Liu pri = LOG_NOTICE; 310*a3114836SGerry Liu pr_out = 1; 311*a3114836SGerry Liu break; 312*a3114836SGerry Liu 313*a3114836SGerry Liu case 2: 314*a3114836SGerry Liu pri = LOG_DEBUG; 315*a3114836SGerry Liu pr_out = 1; 316*a3114836SGerry Liu break; 317*a3114836SGerry Liu } 318*a3114836SGerry Liu 319*a3114836SGerry Liu if (pr_out) { 320*a3114836SGerry Liu va_start(ap, fmt); 321*a3114836SGerry Liu vsyslog(pri, fmt, ap); 322*a3114836SGerry Liu va_end(ap); 323*a3114836SGerry Liu } 324*a3114836SGerry Liu } 325*a3114836SGerry Liu } 326