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