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>
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)
49 DV_DULL, /* generic, no special info */
50 DV_CPU, /* CPU (carries resource utilization) */
51 DV_DISK, /* disk drive (label, etc) */
52 DV_IFNET, /* network interface */
53 DV_TAPE, /* tape device */
54 DV_TTY /* serial line interface (???) */
57 extern char *__progname;
59 volatile sig_atomic_t quit = 0;
61 void exec_script(const char *, int, const char *);
64 __dead void usage(void);
67 main(int argc, char *argv[])
70 struct sigaction sact;
72 struct udev_enumerate *udev_enum;
73 struct udev_list_entry *udev_le, *udev_le_first;
74 struct udev_monitor *udev_monitor;
75 struct udev_device *udev_dev;
76 enum obsd_devclass devclass;
79 while ((ch = getopt(argc, argv, "?")) != -1)
96 bzero(&sact, sizeof(sact));
97 sigemptyset(&sact.sa_mask);
99 sact.sa_handler = sigquit;
100 sigaction(SIGINT, &sact, NULL);
101 sigaction(SIGQUIT, &sact, NULL);
102 sigaction(SIGTERM, &sact, NULL);
103 sact.sa_handler = SIG_IGN;
104 sigaction(SIGHUP, &sact, NULL);
105 sact.sa_handler = sigchild;
106 sact.sa_flags = SA_NOCLDSTOP;
107 sigaction(SIGCHLD, &sact, NULL);
109 openlog(_LOG_TAG, _LOG_OPT, _LOG_FACILITY);
111 if (daemon(0, 0) == -1)
114 syslog(LOG_INFO, "started");
116 udev_enum = udev_enumerate_new(udev);
117 if (udev_enum == NULL)
118 err(1, "udev_enumerate_new");
120 ret = udev_enumerate_scan_devices(udev_enum);
122 err(1, "udev_enumerate_scan_device ret = %d", ret);
124 udev_le_first = udev_enumerate_get_list_entry(udev_enum);
125 if (udev_le_first == NULL)
126 err(1, "udev_enumerate_get_list_entry error");
128 udev_list_entry_foreach(udev_le, udev_le_first) {
129 udev_dev = udev_list_entry_get_device(udev_le);
131 class = atoi(udev_device_get_property_value(udev_dev, "devtype"));
132 devclass = ((class == D_TTY) ? DV_TTY : ((class == D_TAPE) ? DV_TAPE : ((class == D_DISK) ? DV_DISK : DV_DULL)));
134 syslog(LOG_INFO, "%s attached, class %d",
135 udev_device_get_devnode(udev_dev), devclass);
136 exec_script(_PATH_ETC_HOTPLUG_ATTACH, devclass,
137 udev_device_get_devnode(udev_dev));
140 udev_enumerate_unref(udev_enum);
141 udev_monitor = udev_monitor_new(udev);
143 ret = udev_monitor_enable_receiving(udev_monitor);
145 err(1, "udev_monitor_enable_receiving ret = %d", ret);
148 if ((udev_dev = udev_monitor_receive_device(udev_monitor)) == NULL) {
149 syslog(LOG_ERR, "read: %m");
153 prop = udev_device_get_action(udev_dev);
154 class = atoi(udev_device_get_property_value(udev_dev, "devtype"));
155 devclass = ((class == D_TTY) ? DV_TTY : ((class == D_TAPE) ? DV_TAPE : ((class == D_DISK) ? DV_DISK : DV_DULL)));
157 if (strcmp(prop, "attach") == 0) {
158 syslog(LOG_INFO, "%s attached, class %d",
159 udev_device_get_devnode(udev_dev), devclass);
160 exec_script(_PATH_ETC_HOTPLUG_ATTACH, devclass,
161 udev_device_get_devnode(udev_dev));
162 } else if (strcmp(prop, "detach") == 0) {
163 syslog(LOG_INFO, "%s detached, class %d",
164 udev_device_get_devnode(udev_dev), devclass);
165 exec_script(_PATH_ETC_HOTPLUG_DETACH, devclass,
166 udev_device_get_devnode(udev_dev));
168 syslog(LOG_NOTICE, "unknown event (%s)", prop);
172 syslog(LOG_INFO, "terminated");
176 udev_monitor_unref(udev_monitor);
183 exec_script(const char *file, int class, const char *name)
188 snprintf(strclass, sizeof(strclass), "%d", class);
190 if (access(file, X_OK | R_OK)) {
191 syslog(LOG_ERR, "could not access %s", file);
195 if ((pid = fork()) == -1) {
196 syslog(LOG_ERR, "fork: %m");
201 execl(file, basename(file), strclass, name, (char *)NULL);
202 syslog(LOG_ERR, "execl %s: %m", file);
210 sigchild(int signum __unused)
212 struct syslog_data sdata = SYSLOG_DATA_INIT;
213 int saved_errno, status;
218 sdata.log_tag = _LOG_TAG;
219 sdata.log_fac = _LOG_FACILITY;
220 sdata.log_stat = _LOG_OPT;
222 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) != 0) {
227 syslog_r(LOG_ERR, &sdata, "waitpid: %m");
231 if (WIFEXITED(status)) {
232 if (WEXITSTATUS(status) != 0) {
233 syslog_r(LOG_NOTICE, &sdata,
234 "child exit status: %d",
235 WEXITSTATUS(status));
238 syslog_r(LOG_NOTICE, &sdata,
239 "child is terminated abnormally");
248 sigquit(int signum __unused)
256 fprintf(stderr, "usage: %s [-d device]\n", __progname);