xref: /illumos-gate/usr/src/cmd/acpihpd/acpihpd.c (revision a3114836)
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