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