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 */
48typedef void (SigHandler)(int);
49/* oplhpd process id file descriptor */
50static int pid_fd;
51
52/* Program Name */
53char	*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 */
61static sysevent_handle_t *oplhpd_hdl;
62
63
64/*
65 * Function Prototypes
66 */
67void quit_daemon(int signo);
68SigHandler *set_sig_handler(int sig, SigHandler *handler);
69void init_daemon(void);
70void oplhpd_init(void);
71void oplhpd_fini(void);
72static void oplhpd_event(sysevent_t *ev);
73
74extern 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 */
83void
84quit_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 */
108SigHandler *
109set_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 */
130void
131init_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
205static void
206oplhpd_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 */
221void
222oplhpd_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
245void
246oplhpd_fini()
247{
248	if (oplhpd_hdl != NULL) {
249		sysevent_unsubscribe_event(oplhpd_hdl, EC_DR);
250		sysevent_unbind_handle(oplhpd_hdl);
251	}
252}
253
254int
255main(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