2 * Copyright (c) 2010 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Alex Hornung <ahornung@gmail.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/types.h>
35 #include <sys/device.h>
37 #include <sys/socket.h>
38 #include <sys/ioctl.h>
40 #include <sys/queue.h>
57 #include <libprop/proplib.h>
64 static int hangup_ongoing = 0;
65 static struct pollfd fds[NFDS];
67 extern pthread_mutex_t monitor_lock;
68 extern TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list;
69 extern TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list;
71 static void usage(void);
73 int match_dev_dict(prop_dictionary_t, prop_dictionary_t);
74 prop_dictionary_t find_dev_dict(int64_t, prop_dictionary_t, int *);
76 void udev_read_event(int);
77 prop_array_t udev_getdevs(int);
83 fprintf(stderr, "usage: udevd [-d]\n");
88 match_dev_dict(prop_dictionary_t dict, prop_dictionary_t match_dict)
90 prop_number_t pn, pn2;
91 prop_string_t ps, ps2;
96 if ((ps = prop_dictionary_get(dict, "name")) == NULL)
98 if ((ps2 = prop_dictionary_get(match_dict, "name")) == NULL)
100 if (!prop_string_equals(ps, ps2))
103 if ((pn = prop_dictionary_get(dict, "devnum")) == NULL)
105 if ((pn2 = prop_dictionary_get(match_dict, "devnum")) == NULL)
107 if (!prop_number_equals(pn, pn2))
110 if ((pn = prop_dictionary_get(dict, "kptr")) == NULL)
112 if ((pn2 = prop_dictionary_get(match_dict, "kptr")) == NULL)
114 if (!prop_number_equals(pn, pn2))
121 find_dev_dict(int64_t generation, prop_dictionary_t match_dict, int *idx)
123 struct pdev_array_entry *pae;
125 prop_object_iterator_t iter;
126 prop_dictionary_t dict;
129 if (generation == -1)
130 pae = pdev_array_entry_get_last();
132 pae = pdev_array_entry_get(generation);
137 pa = pae->pdev_array;
139 iter = prop_array_iterator(pa);
141 pdev_array_entry_unref(pae);
145 while ((dict = prop_object_iterator_next(iter)) != NULL) {
146 if (match_dev_dict(dict, match_dict))
151 prop_object_iterator_release(iter);
156 pdev_array_entry_unref(pae);
161 udev_read_event(int fd)
163 struct pdev_array_entry *pae;
164 prop_dictionary_t dict, evdict, devdict;
175 xml = malloc(sz); /* 4 MB */
177 if ((n = read(fd, xml, sz)) <= 0) {
178 if (errno == ENOMEM) {
180 if ((xml = realloc(xml, sz)) == NULL) {
181 syslog(LOG_ERR, "could not realloc xml memory");
190 dict = prop_dictionary_internalize(xml);
193 syslog(LOG_ERR, "internalization of xml failed");
197 pn = prop_dictionary_get(dict, "evtype");
199 syslog(LOG_ERR, "read_event: no key evtype");
203 evtype = prop_number_integer_value(pn);
205 evdict = prop_dictionary_get(dict, "evdict");
206 if (evdict == NULL) {
207 syslog(LOG_ERR, "read_event: no key evdict");
212 case UDEV_EVENT_ATTACH:
213 monitor_queue_event(dict);
214 pae = pdev_array_entry_get_last();
215 pa = prop_array_copy(pae->pdev_array);
216 pdev_array_entry_unref(pae);
219 prop_array_add(pa, evdict);
220 pdev_array_entry_insert(pa);
223 case UDEV_EVENT_DETACH:
224 monitor_queue_event(dict);
225 if ((devdict = find_dev_dict(-1, evdict, &idx)) == NULL)
227 pae = pdev_array_entry_get_last();
228 pa = prop_array_copy(pae->pdev_array);
229 pdev_array_entry_unref(pae);
232 prop_array_remove(pa, idx);
233 pdev_array_entry_insert(pa);
236 case UDEV_EV_KEY_UPDATE:
237 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL)
239 if ((ps = prop_dictionary_get(evdict, "key")) == NULL)
241 if ((po = prop_dictionary_get(evdict, "value")) == NULL)
243 /* prop_object_retain(po); */ /* not necessary afaik */
244 prop_dictionary_set(devdict, prop_string_cstring_nocopy(ps), po);
247 case UDEV_EV_KEY_REMOVE:
248 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL)
250 if ((ps = prop_dictionary_get(evdict, "key")) == NULL)
252 prop_dictionary_remove(devdict, prop_string_cstring_nocopy(ps));
256 syslog(LOG_ERR, "read_event: unknown evtype %d", evtype);
260 prop_object_release(dict);
265 udev_getdevs(int devfd)
267 prop_dictionary_t pd, rpd;
271 pd = prop_dictionary_create();
273 err(1, "prop_dictionary_create()");
276 ps = prop_string_create_cstring("getdevs");
278 prop_object_release(pd);
279 err(1, "prop_string_create_cstring()");
282 if (prop_dictionary_set(pd, "command", ps) == false) {
283 prop_object_release(ps);
284 prop_object_release(pd);
285 err(1, "prop_dictionary_set()");
288 prop_object_release(ps);
290 /* Send dictionary to kernel space */
291 if (prop_dictionary_sendrecv_ioctl(pd, devfd, UDEVPROP, &rpd) != 0)
292 err(1, "prop_array_recv_ioctl()");
294 prop_object_release(pd);
296 pa = prop_dictionary_get(rpd, "array");
299 prop_object_retain(pa);
302 prop_object_release(rpd);
307 killed(int sig __unused)
309 syslog(LOG_ERR, "udevd stopped");
310 unlink("/var/run/udevd.pid");
316 hangup(int sig __unused)
321 syslog(LOG_ERR, "udevd hangup+resume");
323 pidf = fopen("/var/run/udevd.pid", "w");
325 fprintf(pidf, "%ld\n", (long)getpid());
330 close(fds[UDEV_SOCKET_FD_IDX].fd);
332 s = init_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0);
334 err(1, "init_local_server");
336 fds[UDEV_SOCKET_FD_IDX].fd = s;
337 pdev_array_entry_insert(udev_getdevs(udevfd));
342 ignore_signal(int signum)
344 struct sigaction act;
347 act.sa_handler = SIG_IGN;
348 sigemptyset(&act.sa_mask);
351 ret = sigaction(signum, &act, NULL);
356 set_signal(int signum, sig_t sig_func)
358 struct sigaction act;
361 act.sa_handler = sig_func;
362 sigemptyset(&act.sa_mask);
365 ret = sigaction(signum, &act, NULL);
369 int main(int argc, char *argv[])
371 int error __unused, i, r, s;
375 while ((ch = getopt(argc, argv, "d")) != -1) {
388 TAILQ_INIT(&pdev_array_list);
389 TAILQ_INIT(&udev_monitor_list);
391 r = ignore_signal(SIGPIPE);
393 err(1, "could not ignore_signal SIGPIPE");
395 r = pthread_mutex_init(&(monitor_lock), NULL);
397 err(1, "could not allocate a pthread_mutex");
399 if ((udevfd = open(UDEV_DEVICE_PATH, O_RDWR | O_NONBLOCK)) == -1)
400 err(1, "%s", UDEV_DEVICE_PATH);
401 unblock_descriptor(udevfd);
403 s = init_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0);
405 err(1, "init_local_server");
407 pidf = fopen("/var/run/udevd.pid", "w");
413 set_signal(SIGTERM, killed);
414 set_signal(SIGHUP, hangup);
417 if (daemon(0, 0) == -1)
421 fprintf(pidf, "%ld\n", (long)getpid());
425 syslog(LOG_ERR, "udevd started");
427 pdev_array_entry_insert(udev_getdevs(udevfd));
429 memset(fds, 0 , sizeof(fds));
430 fds[UDEV_DEVICE_FD_IDX].fd = udevfd;
431 fds[UDEV_DEVICE_FD_IDX].events = POLLIN;
432 fds[UDEV_SOCKET_FD_IDX].fd = s;
433 fds[UDEV_SOCKET_FD_IDX].events = POLLIN | POLLPRI;
436 r = poll(fds, NFDS, -1);
438 if (hangup_ongoing == 0) {
439 if (errno == EINTR) {
443 err(1, "polling...");
446 usleep(20000); /* 20 ms */
451 for (i = 0; (i < NFDS) && (r > 0); i++) {
452 if (fds[i].revents == 0)
457 case UDEV_DEVICE_FD_IDX:
458 udev_read_event(udevfd);
460 case UDEV_SOCKET_FD_IDX:
461 handle_new_connection(s);
469 syslog(LOG_ERR, "udevd is exiting normally");