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
main(int argc,char * argv[])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
daemon_init(void)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
daemon_quit(int signo)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
set_sig_handler(int sig,sig_handler_t * handler)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
acpihpd_init(void)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
acpihpd_fini(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
acpihpd_event(sysevent_t * ev)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
debug_print(int level,const char * fmt,...)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