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