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>
39 #define _PATH_DEV_HOTPLUG "/dev/hotplug"
40 #define _PATH_ETC_HOTPLUG "/etc/hotplug"
41 #define _PATH_ETC_HOTPLUG_ATTACH _PATH_ETC_HOTPLUG "/attach"
42 #define _PATH_ETC_HOTPLUG_DETACH _PATH_ETC_HOTPLUG "/detach"
43 #define _LOG_TAG "hotplugd"
44 #define _LOG_FACILITY LOG_DAEMON
45 #define _LOG_OPT (LOG_NDELAY | LOG_PID)
48 DV_DULL
, /* generic, no special info */
49 DV_CPU
, /* CPU (carries resource utilization) */
50 DV_DISK
, /* disk drive (label, etc) */
51 DV_IFNET
, /* network interface */
52 DV_TAPE
, /* tape device */
53 DV_TTY
/* serial line interface (???) */
56 extern char *__progname
;
58 volatile sig_atomic_t quit
= 0;
60 void exec_script(const char *, int, const char *);
63 __dead2
void usage(void);
66 main(int argc
, char *argv
[])
69 struct sigaction sact
;
71 struct udev_enumerate
*udev_enum
;
72 struct udev_list_entry
*udev_le
, *udev_le_first
;
73 struct udev_monitor
*udev_monitor
;
74 struct udev_device
*udev_dev
;
75 enum obsd_devclass devclass
;
78 while ((ch
= getopt(argc
, argv
, "?")) != -1)
95 bzero(&sact
, sizeof(sact
));
96 sigemptyset(&sact
.sa_mask
);
98 sact
.sa_handler
= sigquit
;
99 sigaction(SIGINT
, &sact
, NULL
);
100 sigaction(SIGQUIT
, &sact
, NULL
);
101 sigaction(SIGTERM
, &sact
, NULL
);
102 sact
.sa_handler
= SIG_IGN
;
103 sigaction(SIGHUP
, &sact
, NULL
);
104 sact
.sa_handler
= sigchild
;
105 sact
.sa_flags
= SA_NOCLDSTOP
;
106 sigaction(SIGCHLD
, &sact
, NULL
);
108 openlog(_LOG_TAG
, _LOG_OPT
, _LOG_FACILITY
);
110 if (daemon(0, 0) == -1)
113 syslog(LOG_INFO
, "started");
115 udev_enum
= udev_enumerate_new(udev
);
116 if (udev_enum
== NULL
)
117 err(1, "udev_enumerate_new");
119 ret
= udev_enumerate_scan_devices(udev_enum
);
121 err(1, "udev_enumerate_scan_device ret = %d", ret
);
123 udev_le_first
= udev_enumerate_get_list_entry(udev_enum
);
124 if (udev_le_first
== NULL
)
125 err(1, "udev_enumerate_get_list_entry error");
127 udev_list_entry_foreach(udev_le
, udev_le_first
) {
128 udev_dev
= udev_list_entry_get_device(udev_le
);
130 class = atoi(udev_device_get_property_value(udev_dev
, "devtype"));
131 devclass
= ((class == D_TTY
) ? DV_TTY
: ((class == D_TAPE
) ? DV_TAPE
: ((class == D_DISK
) ? DV_DISK
: DV_DULL
)));
133 syslog(LOG_INFO
, "%s attached, class %d",
134 udev_device_get_devnode(udev_dev
), devclass
);
135 exec_script(_PATH_ETC_HOTPLUG_ATTACH
, devclass
,
136 udev_device_get_devnode(udev_dev
));
139 udev_enumerate_unref(udev_enum
);
140 udev_monitor
= udev_monitor_new(udev
);
142 ret
= udev_monitor_enable_receiving(udev_monitor
);
144 err(1, "udev_monitor_enable_receiving ret = %d", ret
);
147 if ((udev_dev
= udev_monitor_receive_device(udev_monitor
)) == NULL
) {
148 syslog(LOG_ERR
, "read: %m");
152 prop
= udev_device_get_action(udev_dev
);
153 class = atoi(udev_device_get_property_value(udev_dev
, "devtype"));
154 devclass
= ((class == D_TTY
) ? DV_TTY
: ((class == D_TAPE
) ? DV_TAPE
: ((class == D_DISK
) ? DV_DISK
: DV_DULL
)));
156 if (strcmp(prop
, "attach") == 0) {
157 syslog(LOG_INFO
, "%s attached, class %d",
158 udev_device_get_devnode(udev_dev
), devclass
);
159 exec_script(_PATH_ETC_HOTPLUG_ATTACH
, devclass
,
160 udev_device_get_devnode(udev_dev
));
161 } else if (strcmp(prop
, "detach") == 0) {
162 syslog(LOG_INFO
, "%s detached, class %d",
163 udev_device_get_devnode(udev_dev
), devclass
);
164 exec_script(_PATH_ETC_HOTPLUG_DETACH
, devclass
,
165 udev_device_get_devnode(udev_dev
));
167 syslog(LOG_NOTICE
, "unknown event (%s)", prop
);
171 syslog(LOG_INFO
, "terminated");
175 udev_monitor_unref(udev_monitor
);
182 exec_script(const char *file
, int class, const char *name
)
187 snprintf(strclass
, sizeof(strclass
), "%d", class);
189 if (access(file
, X_OK
| R_OK
)) {
190 syslog(LOG_ERR
, "could not access %s", file
);
194 if ((pid
= fork()) == -1) {
195 syslog(LOG_ERR
, "fork: %m");
200 execl(file
, basename(file
), strclass
, name
, NULL
);
201 syslog(LOG_ERR
, "execl %s: %m", file
);
209 sigchild(int signum __unused
)
211 int saved_errno
, status
;
216 while ((pid
= waitpid(WAIT_ANY
, &status
, WNOHANG
)) != 0) {
222 syslog(LOG_ERR
, "waitpid: %m");
226 if (WIFEXITED(status
)) {
227 if (WEXITSTATUS(status
) != 0) {
229 syslog(LOG_NOTICE
, "child exit status: %d",
230 WEXITSTATUS(status
));
234 syslog(LOG_NOTICE
, "child is terminated abnormally");
243 sigquit(int signum __unused
)
251 fprintf(stderr
, "usage: %s [-d device]\n", __progname
);