Unleashed v1.4
[unleashed.git] / usr / src / cmd / acpihpd / acpihpd.c
blob6beee85f54a4b945507b92fa023b5287b47f3cbe
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 * Copyright (c) 2010, Intel Corporation.
28 * All rights reserved.
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>
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>
52 /* Signal handler type */
53 typedef void (sig_handler_t)(int);
55 #define ACPIHPD_PID_FILE "/var/run/acpihpd.pid" /* lock file path */
57 /* Program Name */
58 char *g_prog_name;
59 int g_debuglevel = 0;
61 static int s_pid_fd;
62 static sysevent_handle_t *s_acpihpd_hdl;
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 *, ...);
73 int
74 main(int argc, char *argv[])
76 int c;
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++;
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;
92 break;
94 case ':':
95 syslog(LOG_ERR,
96 "missed argument for option %c.", optopt);
97 break;
99 case '?':
100 syslog(LOG_ERR, "unrecognized option %c.", optopt);
101 break;
105 s_acpihpd_hdl = NULL;
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);
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);
119 debug_print(2, "daemon is running.");
120 /*CONSTCOND*/
121 while (1) {
122 (void) pause();
125 return (SMF_EXIT_OK);
128 static int
129 daemon_init(void)
131 int i, ret;
132 pid_t pid;
133 char pid_str[32];
135 if (geteuid() != 0) {
136 debug_print(0, "must be root to execute %s", g_prog_name);
137 return (1);
140 if ((pid = fork()) < 0) {
141 return (1);
144 if (pid > 0) {
145 /* Parent to exit. */
146 exit(SMF_EXIT_OK);
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);
159 * Create the lock file for singleton
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);
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");
174 return (1);
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;
183 if (ret < 0) {
184 debug_print(0, "pid file write failed: %s",
185 strerror(errno));
186 return (1);
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);
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);
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);
205 if (set_sig_handler(SIGCHLD, SIG_IGN) != 0) {
206 debug_print(2, "could not set signal handler(SIGCHLD)");
207 return (1);
210 return (0);
213 static void
214 daemon_quit(int signo)
216 int status = 0;
217 id_t pgid;
219 debug_print(1, "daemon quit [signal#:%d].", signo);
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);
228 if (signo < 0) {
229 status = signo;
231 _exit(status);
234 static int
235 set_sig_handler(int sig, sig_handler_t *handler)
237 struct sigaction act;
239 act.sa_handler = handler;
240 act.sa_flags = 0;
241 if (sig == SIGCHLD && handler == SIG_IGN) {
242 act.sa_flags |= SA_NOCLDWAIT;
245 (void) sigemptyset(&act.sa_mask);
246 if (sigaction(sig, &act, NULL) < 0) {
247 return (1);
250 return (0);
253 static int
254 acpihpd_init(void)
256 const char *subclass = ESC_DR_REQ;
258 debug_print(2, "acpihpd_init");
260 if ((s_acpihpd_hdl = sysevent_bind_handle(acpihpd_event)) == NULL) {
261 debug_print(2, "could not bind to sysevent.");
262 return (-1);
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);
272 return (0);
275 static void
276 acpihpd_fini(void)
278 debug_print(2, "acpihpd_fini");
280 if (s_acpihpd_hdl != NULL) {
281 sysevent_unsubscribe_event(s_acpihpd_hdl, EC_DR);
282 sysevent_unbind_handle(s_acpihpd_hdl);
286 static void
287 acpihpd_event(sysevent_t *ev)
289 debug_print(2, "*** got an event ***");
291 /* Inform cfgadm of the hot-plug event. */
292 notify_hotplug(ev);
295 void
296 debug_print(int level, const char *fmt, ...)
298 va_list ap;
299 int pri, pr_out = 0;
301 if (level <= g_debuglevel) {
302 switch (level) {
303 case 0:
304 pri = LOG_ERR;
305 pr_out = 1;
306 break;
308 case 1:
309 pri = LOG_NOTICE;
310 pr_out = 1;
311 break;
313 case 2:
314 pri = LOG_DEBUG;
315 pr_out = 1;
316 break;
319 if (pr_out) {
320 va_start(ap, fmt);
321 vsyslog(pri, fmt, ap);
322 va_end(ap);