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