1 /* $OpenBSD: hotplugd.c,v 1.11 2009/06/26 01:06:04 kurt Exp $ */
3 * Copyright (c) 2004 Alexander Yurchenko <grange@openbsd.org>
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 * Devices hot plugging daemon.
22 #include <sys/types.h>
23 #include <sys/device.h>
24 #include <sys/hotplug.h>
40 #define _PATH_DEV_HOTPLUG "/dev/hotplug"
41 #define _PATH_ETC_HOTPLUG "/etc/hotplug"
42 #define _PATH_ETC_HOTPLUG_ATTACH _PATH_ETC_HOTPLUG "/attach"
43 #define _PATH_ETC_HOTPLUG_DETACH _PATH_ETC_HOTPLUG "/detach"
44 #define _LOG_TAG "hotplugd"
45 #define _LOG_FACILITY LOG_DAEMON
46 #define _LOG_OPT (LOG_NDELAY | LOG_PID)
48 extern char *__progname;
50 volatile sig_atomic_t quit = 0;
51 const char *device = _PATH_DEV_HOTPLUG;
54 void exec_script(const char *, int, char *);
57 __dead void usage(void);
60 main(int argc, char *argv[])
63 struct sigaction sact;
64 struct hotplug_event he;
66 while ((ch = getopt(argc, argv, "d:")) != -1)
82 if ((devfd = open(device, O_RDONLY)) == -1)
85 bzero(&sact, sizeof(sact));
86 sigemptyset(&sact.sa_mask);
88 sact.sa_handler = sigquit;
89 sigaction(SIGINT, &sact, NULL);
90 sigaction(SIGQUIT, &sact, NULL);
91 sigaction(SIGTERM, &sact, NULL);
92 sact.sa_handler = SIG_IGN;
93 sigaction(SIGHUP, &sact, NULL);
94 sact.sa_handler = sigchild;
95 sact.sa_flags = SA_NOCLDSTOP;
96 sigaction(SIGCHLD, &sact, NULL);
98 openlog(_LOG_TAG, _LOG_OPT, _LOG_FACILITY);
99 if (daemon(0, 0) == -1)
102 syslog(LOG_INFO, "started");
105 if (read(devfd, &he, sizeof(he)) == -1) {
109 syslog(LOG_ERR, "read: %m");
113 switch (he.he_type) {
115 syslog(LOG_INFO, "%s attached, class %d",
116 he.he_devname, he.he_devclass);
117 exec_script(_PATH_ETC_HOTPLUG_ATTACH, he.he_devclass,
121 syslog(LOG_INFO, "%s detached, class %d",
122 he.he_devname, he.he_devclass);
123 exec_script(_PATH_ETC_HOTPLUG_DETACH, he.he_devclass,
127 syslog(LOG_NOTICE, "unknown event (0x%x)", he.he_type);
131 syslog(LOG_INFO, "terminated");
140 exec_script(const char *file, int class, char *name)
145 snprintf(strclass, sizeof(strclass), "%d", class);
147 if (access(file, X_OK | R_OK)) {
148 syslog(LOG_ERR, "could not access %s", file);
152 if ((pid = fork()) == -1) {
153 syslog(LOG_ERR, "fork: %m");
158 execl(file, basename(file), strclass, name, (char *)NULL);
159 syslog(LOG_ERR, "execl %s: %m", file);
167 sigchild(int signum __unused)
169 struct syslog_data sdata = SYSLOG_DATA_INIT;
170 int saved_errno, status;
175 sdata.log_tag = _LOG_TAG;
176 sdata.log_fac = _LOG_FACILITY;
177 sdata.log_stat = _LOG_OPT;
179 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) {
184 syslog_r(LOG_ERR, &sdata, "waitpid: %m");
188 if (WIFEXITED(status)) {
189 if (WEXITSTATUS(status) != 0) {
190 syslog_r(LOG_NOTICE, &sdata,
191 "child exit status: %d",
192 WEXITSTATUS(status));
195 syslog_r(LOG_NOTICE, &sdata,
196 "child is terminated abnormally");
205 sigquit(int signum __unused)
213 fprintf(stderr, "usage: %s [-d device]\n", __progname);