xref: /titanic_50/usr/src/cmd/oplhpd/oplhpd.c (revision a4ac8bb3f5b2fff60581bee101792ac7a34bad8c)
1*a4ac8bb3Sdnielsen /*
2*a4ac8bb3Sdnielsen  * CDDL HEADER START
3*a4ac8bb3Sdnielsen  *
4*a4ac8bb3Sdnielsen  * The contents of this file are subject to the terms of the
5*a4ac8bb3Sdnielsen  * Common Development and Distribution License (the "License").
6*a4ac8bb3Sdnielsen  * You may not use this file except in compliance with the License.
7*a4ac8bb3Sdnielsen  *
8*a4ac8bb3Sdnielsen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*a4ac8bb3Sdnielsen  * or http://www.opensolaris.org/os/licensing.
10*a4ac8bb3Sdnielsen  * See the License for the specific language governing permissions
11*a4ac8bb3Sdnielsen  * and limitations under the License.
12*a4ac8bb3Sdnielsen  *
13*a4ac8bb3Sdnielsen  * When distributing Covered Code, include this CDDL HEADER in each
14*a4ac8bb3Sdnielsen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*a4ac8bb3Sdnielsen  * If applicable, add the following below this CDDL HEADER, with the
16*a4ac8bb3Sdnielsen  * fields enclosed by brackets "[]" replaced with your own identifying
17*a4ac8bb3Sdnielsen  * information: Portions Copyright [yyyy] [name of copyright owner]
18*a4ac8bb3Sdnielsen  *
19*a4ac8bb3Sdnielsen  * CDDL HEADER END
20*a4ac8bb3Sdnielsen  */
21*a4ac8bb3Sdnielsen /*
22*a4ac8bb3Sdnielsen  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*a4ac8bb3Sdnielsen  * Use is subject to license terms.
24*a4ac8bb3Sdnielsen  */
25*a4ac8bb3Sdnielsen 
26*a4ac8bb3Sdnielsen /*
27*a4ac8bb3Sdnielsen  * All Rights Reserved, Copyright (c) FUJITSU LIMITED 2006
28*a4ac8bb3Sdnielsen  */
29*a4ac8bb3Sdnielsen 
30*a4ac8bb3Sdnielsen #pragma ident	"%Z%%M%	%I%	%E% SMI"
31*a4ac8bb3Sdnielsen 
32*a4ac8bb3Sdnielsen #include <sys/param.h>
33*a4ac8bb3Sdnielsen #include <sys/stat.h>
34*a4ac8bb3Sdnielsen #include <sys/types.h>
35*a4ac8bb3Sdnielsen #include <sys/sysevent/eventdefs.h>
36*a4ac8bb3Sdnielsen #include <sys/sysevent/dr.h>
37*a4ac8bb3Sdnielsen 
38*a4ac8bb3Sdnielsen #include <stdio.h>
39*a4ac8bb3Sdnielsen #include <stdlib.h>
40*a4ac8bb3Sdnielsen #include <unistd.h>
41*a4ac8bb3Sdnielsen #include <signal.h>
42*a4ac8bb3Sdnielsen #include <syslog.h>
43*a4ac8bb3Sdnielsen #include <string.h>
44*a4ac8bb3Sdnielsen #include <fcntl.h>
45*a4ac8bb3Sdnielsen #include <errno.h>
46*a4ac8bb3Sdnielsen #include <time.h>
47*a4ac8bb3Sdnielsen #include <config_admin.h>
48*a4ac8bb3Sdnielsen #include <libsysevent.h>
49*a4ac8bb3Sdnielsen 
50*a4ac8bb3Sdnielsen 
51*a4ac8bb3Sdnielsen /* Signal handler type */
52*a4ac8bb3Sdnielsen typedef void (SigHandler)(int);
53*a4ac8bb3Sdnielsen /* oplhpd process id file descriptor */
54*a4ac8bb3Sdnielsen static int pid_fd;
55*a4ac8bb3Sdnielsen 
56*a4ac8bb3Sdnielsen /* Program Name */
57*a4ac8bb3Sdnielsen char	*oplhpd_prog_name = "";
58*a4ac8bb3Sdnielsen 
59*a4ac8bb3Sdnielsen /* Macros */
60*a4ac8bb3Sdnielsen #define	OPLHPD_DEV_DIR "/devices"	/* device base dir */
61*a4ac8bb3Sdnielsen #define	OPLHPD_PID_FILE "/var/run/oplhpd.pid" /* lock file path */
62*a4ac8bb3Sdnielsen #define	OPLHPD_PROG_NAME oplhpd_prog_name
63*a4ac8bb3Sdnielsen 
64*a4ac8bb3Sdnielsen /* Event handler to get information */
65*a4ac8bb3Sdnielsen static sysevent_handle_t *oplhpd_hdl;
66*a4ac8bb3Sdnielsen 
67*a4ac8bb3Sdnielsen 
68*a4ac8bb3Sdnielsen /*
69*a4ac8bb3Sdnielsen  * Function Prototypes
70*a4ac8bb3Sdnielsen  */
71*a4ac8bb3Sdnielsen void quit_daemon(int signo);
72*a4ac8bb3Sdnielsen SigHandler *set_sig_handler(int sig, SigHandler *handler);
73*a4ac8bb3Sdnielsen void init_daemon(void);
74*a4ac8bb3Sdnielsen void oplhpd_init(void);
75*a4ac8bb3Sdnielsen void oplhpd_fini(void);
76*a4ac8bb3Sdnielsen static void oplhpd_event(sysevent_t *ev);
77*a4ac8bb3Sdnielsen 
78*a4ac8bb3Sdnielsen extern void notify_scf_of_hotplug(sysevent_t *ev);
79*a4ac8bb3Sdnielsen 
80*a4ac8bb3Sdnielsen 
81*a4ac8bb3Sdnielsen /*
82*a4ac8bb3Sdnielsen  * Terminate and Quit Daemon Process.
83*a4ac8bb3Sdnielsen  * signo = 0 ... normal   quit
84*a4ac8bb3Sdnielsen  *       > 0 ... signaled quit
85*a4ac8bb3Sdnielsen  *       < 0 ... failure  quit
86*a4ac8bb3Sdnielsen  */
87*a4ac8bb3Sdnielsen void
88*a4ac8bb3Sdnielsen quit_daemon(int signo)
89*a4ac8bb3Sdnielsen {
90*a4ac8bb3Sdnielsen 	int status = 0;
91*a4ac8bb3Sdnielsen 	id_t pgid;
92*a4ac8bb3Sdnielsen 
93*a4ac8bb3Sdnielsen 	syslog(LOG_DEBUG, "*** quit daemon [pid:%d, signal#:%d].\n",
94*a4ac8bb3Sdnielsen 			getpid(), signo);
95*a4ac8bb3Sdnielsen 
96*a4ac8bb3Sdnielsen 	(void) set_sig_handler(SIGTERM, SIG_IGN);
97*a4ac8bb3Sdnielsen 	pgid = getpgrp();
98*a4ac8bb3Sdnielsen 	(void) kill(-pgid, SIGTERM);
99*a4ac8bb3Sdnielsen 
100*a4ac8bb3Sdnielsen 	(void) close(pid_fd);
101*a4ac8bb3Sdnielsen 	(void) unlink(OPLHPD_PID_FILE); /* clean up lock file */
102*a4ac8bb3Sdnielsen 
103*a4ac8bb3Sdnielsen 	if (signo < 0) {
104*a4ac8bb3Sdnielsen 		status = signo;
105*a4ac8bb3Sdnielsen 	}
106*a4ac8bb3Sdnielsen 	_exit(status);
107*a4ac8bb3Sdnielsen }
108*a4ac8bb3Sdnielsen 
109*a4ac8bb3Sdnielsen /*
110*a4ac8bb3Sdnielsen  * Setting the signal handler utility
111*a4ac8bb3Sdnielsen  */
112*a4ac8bb3Sdnielsen SigHandler *
113*a4ac8bb3Sdnielsen set_sig_handler(int sig, SigHandler *handler)
114*a4ac8bb3Sdnielsen {
115*a4ac8bb3Sdnielsen 	struct sigaction act, oact;
116*a4ac8bb3Sdnielsen 
117*a4ac8bb3Sdnielsen 	act.sa_handler = handler;
118*a4ac8bb3Sdnielsen 	act.sa_flags = 0;
119*a4ac8bb3Sdnielsen 	if (sig == SIGCHLD && handler == SIG_IGN) {
120*a4ac8bb3Sdnielsen 		act.sa_flags |= SA_NOCLDWAIT;
121*a4ac8bb3Sdnielsen 	}
122*a4ac8bb3Sdnielsen 	(void) sigemptyset(&act.sa_mask);
123*a4ac8bb3Sdnielsen 	(void) sigemptyset(&oact.sa_mask);
124*a4ac8bb3Sdnielsen 	if (sigaction(sig, &act, &oact) < 0) {
125*a4ac8bb3Sdnielsen 		return (SIG_ERR);
126*a4ac8bb3Sdnielsen 	}
127*a4ac8bb3Sdnielsen 
128*a4ac8bb3Sdnielsen 	return (oact.sa_handler);
129*a4ac8bb3Sdnielsen }
130*a4ac8bb3Sdnielsen 
131*a4ac8bb3Sdnielsen /*
132*a4ac8bb3Sdnielsen  * Setup oplhpd daemon
133*a4ac8bb3Sdnielsen  */
134*a4ac8bb3Sdnielsen void
135*a4ac8bb3Sdnielsen init_daemon()
136*a4ac8bb3Sdnielsen {
137*a4ac8bb3Sdnielsen 	int	i;
138*a4ac8bb3Sdnielsen 	int	ret;
139*a4ac8bb3Sdnielsen 	int	fd;
140*a4ac8bb3Sdnielsen 	pid_t	pid;
141*a4ac8bb3Sdnielsen 	char	pid_str[32];
142*a4ac8bb3Sdnielsen 
143*a4ac8bb3Sdnielsen 	if (geteuid() != 0) {
144*a4ac8bb3Sdnielsen 		syslog(LOG_ERR, "must be root to execute %s\n",
145*a4ac8bb3Sdnielsen 				OPLHPD_PROG_NAME);
146*a4ac8bb3Sdnielsen 		exit(1);
147*a4ac8bb3Sdnielsen 	}
148*a4ac8bb3Sdnielsen 
149*a4ac8bb3Sdnielsen 	/*
150*a4ac8bb3Sdnielsen 	 * Daemonize
151*a4ac8bb3Sdnielsen 	 */
152*a4ac8bb3Sdnielsen 	if ((pid = fork()) < 0) {
153*a4ac8bb3Sdnielsen 		perror("fork failed");
154*a4ac8bb3Sdnielsen 		exit(1);
155*a4ac8bb3Sdnielsen 	}
156*a4ac8bb3Sdnielsen 	if (pid > 0) {
157*a4ac8bb3Sdnielsen 	/* Parent, exit. */
158*a4ac8bb3Sdnielsen 		exit(0);
159*a4ac8bb3Sdnielsen 	}
160*a4ac8bb3Sdnielsen 	(void) setsid();
161*a4ac8bb3Sdnielsen 	(void) chdir("/");
162*a4ac8bb3Sdnielsen 	(void) umask(0);
163*a4ac8bb3Sdnielsen 	(void) closefrom(0);
164*a4ac8bb3Sdnielsen 	(void) open("/dev/null", O_RDONLY);
165*a4ac8bb3Sdnielsen 	(void) open("/dev/null", O_WRONLY);
166*a4ac8bb3Sdnielsen 	(void) dup(1);
167*a4ac8bb3Sdnielsen 
168*a4ac8bb3Sdnielsen 	(void) openlog(OPLHPD_PROG_NAME, LOG_PID, LOG_DAEMON);
169*a4ac8bb3Sdnielsen 
170*a4ac8bb3Sdnielsen 	/*
171*a4ac8bb3Sdnielsen 	 * Create the lock file for singletonize
172*a4ac8bb3Sdnielsen 	 */
173*a4ac8bb3Sdnielsen 	if ((pid_fd = open(OPLHPD_PID_FILE, O_RDWR | O_CREAT, 0644)) < 0) {
174*a4ac8bb3Sdnielsen 		syslog(LOG_ERR, "could not create pid file: %s",
175*a4ac8bb3Sdnielsen 		strerror(errno));
176*a4ac8bb3Sdnielsen 		exit(1);
177*a4ac8bb3Sdnielsen 	}
178*a4ac8bb3Sdnielsen 	if (lockf(pid_fd, F_TLOCK, 0L) < 0) {
179*a4ac8bb3Sdnielsen 		if (errno == EACCES || errno == EAGAIN) {
180*a4ac8bb3Sdnielsen 			syslog(LOG_ERR, "another oplhpd is already running");
181*a4ac8bb3Sdnielsen 		} else {
182*a4ac8bb3Sdnielsen 			syslog(LOG_ERR, "could not lock pid file");
183*a4ac8bb3Sdnielsen 		}
184*a4ac8bb3Sdnielsen 		exit(1);
185*a4ac8bb3Sdnielsen 		}
186*a4ac8bb3Sdnielsen 
187*a4ac8bb3Sdnielsen 	(void) ftruncate(pid_fd, 0);
188*a4ac8bb3Sdnielsen 	i = sprintf(pid_str, "%d\n", getpid());
189*a4ac8bb3Sdnielsen 	while ((ret = write(pid_fd, pid_str, i)) != i) {
190*a4ac8bb3Sdnielsen 		if (errno == EINTR) {
191*a4ac8bb3Sdnielsen 			continue;
192*a4ac8bb3Sdnielsen 		}
193*a4ac8bb3Sdnielsen 		if (ret < 0) {
194*a4ac8bb3Sdnielsen 			syslog(LOG_ERR, "pid file write fail: %s",
195*a4ac8bb3Sdnielsen 			strerror(errno));
196*a4ac8bb3Sdnielsen 			exit(1);
197*a4ac8bb3Sdnielsen 		}
198*a4ac8bb3Sdnielsen 	}
199*a4ac8bb3Sdnielsen 
200*a4ac8bb3Sdnielsen 	/*
201*a4ac8bb3Sdnielsen 	 * Set signal handlers
202*a4ac8bb3Sdnielsen 	 */
203*a4ac8bb3Sdnielsen 	(void) set_sig_handler(SIGTERM, (SigHandler *)quit_daemon);
204*a4ac8bb3Sdnielsen 	(void) set_sig_handler(SIGQUIT, (SigHandler *)quit_daemon);
205*a4ac8bb3Sdnielsen 	(void) set_sig_handler(SIGINT,  (SigHandler *)quit_daemon);
206*a4ac8bb3Sdnielsen 	(void) set_sig_handler(SIGCHLD, SIG_IGN);
207*a4ac8bb3Sdnielsen }
208*a4ac8bb3Sdnielsen 
209*a4ac8bb3Sdnielsen static void
210*a4ac8bb3Sdnielsen oplhpd_event(sysevent_t *ev)
211*a4ac8bb3Sdnielsen {
212*a4ac8bb3Sdnielsen 	/*
213*a4ac8bb3Sdnielsen 	 * Inform the SCF of the change in the state of the pci hot plug
214*a4ac8bb3Sdnielsen 	 * cassette.
215*a4ac8bb3Sdnielsen 	 */
216*a4ac8bb3Sdnielsen 	notify_scf_of_hotplug(ev);
217*a4ac8bb3Sdnielsen 
218*a4ac8bb3Sdnielsen }
219*a4ac8bb3Sdnielsen 
220*a4ac8bb3Sdnielsen /*
221*a4ac8bb3Sdnielsen  * Initialization for hotplug event.
222*a4ac8bb3Sdnielsen  * - Bind event handler.
223*a4ac8bb3Sdnielsen  * - Subscribe the handler to the hotplug event.
224*a4ac8bb3Sdnielsen  */
225*a4ac8bb3Sdnielsen void
226*a4ac8bb3Sdnielsen oplhpd_init()
227*a4ac8bb3Sdnielsen {
228*a4ac8bb3Sdnielsen 	const char *subclass = ESC_DR_AP_STATE_CHANGE;
229*a4ac8bb3Sdnielsen 
230*a4ac8bb3Sdnielsen 	syslog(LOG_DEBUG, "oplhpd_init");
231*a4ac8bb3Sdnielsen 
232*a4ac8bb3Sdnielsen 	oplhpd_hdl = sysevent_bind_handle(oplhpd_event);
233*a4ac8bb3Sdnielsen 	if (oplhpd_hdl == NULL) {
234*a4ac8bb3Sdnielsen 		syslog(LOG_ERR, "event handler bind fail");
235*a4ac8bb3Sdnielsen 		quit_daemon(-1);
236*a4ac8bb3Sdnielsen 	}
237*a4ac8bb3Sdnielsen 
238*a4ac8bb3Sdnielsen 	if (sysevent_subscribe_event(oplhpd_hdl, EC_DR, &subclass, 1) != 0) {
239*a4ac8bb3Sdnielsen 		syslog(LOG_ERR, "event handler subscribe fail");
240*a4ac8bb3Sdnielsen 		sysevent_unbind_handle(oplhpd_hdl);
241*a4ac8bb3Sdnielsen 		quit_daemon(-1);
242*a4ac8bb3Sdnielsen 	}
243*a4ac8bb3Sdnielsen 
244*a4ac8bb3Sdnielsen 	for (;;) {
245*a4ac8bb3Sdnielsen 		(void) pause();
246*a4ac8bb3Sdnielsen 	}
247*a4ac8bb3Sdnielsen }
248*a4ac8bb3Sdnielsen 
249*a4ac8bb3Sdnielsen void
250*a4ac8bb3Sdnielsen oplhpd_fini()
251*a4ac8bb3Sdnielsen {
252*a4ac8bb3Sdnielsen 	if (oplhpd_hdl != NULL) {
253*a4ac8bb3Sdnielsen 		sysevent_unsubscribe_event(oplhpd_hdl, EC_DR);
254*a4ac8bb3Sdnielsen 		sysevent_unbind_handle(oplhpd_hdl);
255*a4ac8bb3Sdnielsen 	}
256*a4ac8bb3Sdnielsen }
257*a4ac8bb3Sdnielsen 
258*a4ac8bb3Sdnielsen int
259*a4ac8bb3Sdnielsen main(int argc, char *argv[])
260*a4ac8bb3Sdnielsen {
261*a4ac8bb3Sdnielsen 	int opt;
262*a4ac8bb3Sdnielsen 
263*a4ac8bb3Sdnielsen 	/* Get Program Name */
264*a4ac8bb3Sdnielsen 	if ((oplhpd_prog_name = strrchr(argv[0], '/')) == NULL) {
265*a4ac8bb3Sdnielsen 		oplhpd_prog_name = argv[0];
266*a4ac8bb3Sdnielsen 	} else {
267*a4ac8bb3Sdnielsen 		oplhpd_prog_name++;
268*a4ac8bb3Sdnielsen 	}
269*a4ac8bb3Sdnielsen 
270*a4ac8bb3Sdnielsen 	/* Check the daemon running lock and Initialize the signal */
271*a4ac8bb3Sdnielsen 	init_daemon();
272*a4ac8bb3Sdnielsen 
273*a4ac8bb3Sdnielsen 	/* Subscribe to the hotplug event */
274*a4ac8bb3Sdnielsen 	oplhpd_init();
275*a4ac8bb3Sdnielsen 
276*a4ac8bb3Sdnielsen 	/* Unsubscribe the hotplug event */
277*a4ac8bb3Sdnielsen 	oplhpd_fini();
278*a4ac8bb3Sdnielsen 
279*a4ac8bb3Sdnielsen 	return (0);
280*a4ac8bb3Sdnielsen }
281