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>
42 #include <cpu/inttypes.h>
58 #include <libprop/proplib.h>
66 extern pthread_mutex_t monitor_lock;
67 extern TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list;
68 extern TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list;
70 static void usage(void);
72 int match_dev_dict(prop_dictionary_t, prop_dictionary_t);
73 prop_dictionary_t find_dev_dict(int64_t, prop_dictionary_t, int *);
75 void udev_read_event(int);
76 prop_array_t udev_getdevs(int);
82 fprintf(stderr, "usage: udevd [-d]\n");
87 match_dev_dict(prop_dictionary_t dict, prop_dictionary_t match_dict)
89 prop_number_t pn, pn2;
90 prop_string_t ps, ps2;
95 if ((ps = prop_dictionary_get(dict, "name")) == NULL)
97 if ((ps2 = prop_dictionary_get(match_dict, "name")) == NULL)
99 if (!prop_string_equals(ps, ps2))
102 if ((pn = prop_dictionary_get(dict, "devnum")) == NULL)
104 if ((pn2 = prop_dictionary_get(match_dict, "devnum")) == NULL)
106 if (!prop_number_equals(pn, pn2))
109 if ((pn = prop_dictionary_get(dict, "kptr")) == NULL)
111 if ((pn2 = prop_dictionary_get(match_dict, "kptr")) == NULL)
113 if (!prop_number_equals(pn, pn2))
120 find_dev_dict(int64_t generation, prop_dictionary_t match_dict, int *idx)
122 struct pdev_array_entry *pae;
124 prop_object_iterator_t iter;
125 prop_dictionary_t dict;
128 if (generation == -1)
129 pae = pdev_array_entry_get_last();
131 pae = pdev_array_entry_get(generation);
136 pa = pae->pdev_array;
138 iter = prop_array_iterator(pa);
140 pdev_array_entry_unref(pae);
144 while ((dict = prop_object_iterator_next(iter)) != NULL) {
145 if (match_dev_dict(dict, match_dict))
150 prop_object_iterator_release(iter);
155 pdev_array_entry_unref(pae);
160 udev_read_event(int fd)
162 struct pdev_array_entry *pae;
163 prop_dictionary_t dict, evdict, devdict;
174 xml = malloc(sz); /* 4 MB */
176 if ((n = read(fd, xml, sz)) <= 0) {
177 if (errno == ENOMEM) {
186 dict = prop_dictionary_internalize(xml);
189 syslog(LOG_ERR, "internalization of xml failed");
193 pn = prop_dictionary_get(dict, "evtype");
195 syslog(LOG_ERR, "read_event: no key evtype");
199 evtype = prop_number_integer_value(pn);
201 evdict = prop_dictionary_get(dict, "evdict");
202 if (evdict == NULL) {
203 syslog(LOG_ERR, "read_event: no key evdict");
208 case UDEV_EVENT_ATTACH:
209 monitor_queue_event(dict);
210 pae = pdev_array_entry_get_last();
211 pa = prop_array_copy(pae->pdev_array);
212 pdev_array_entry_unref(pae);
215 prop_array_add(pa, evdict);
216 pdev_array_entry_insert(pa);
219 case UDEV_EVENT_DETACH:
220 monitor_queue_event(dict);
221 if ((devdict = find_dev_dict(-1, evdict, &idx)) == NULL)
223 pae = pdev_array_entry_get_last();
224 pa = prop_array_copy(pae->pdev_array);
225 pdev_array_entry_unref(pae);
228 prop_array_remove(pa, idx);
229 pdev_array_entry_insert(pa);
232 case UDEV_EV_KEY_UPDATE:
233 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL)
235 if ((ps = prop_dictionary_get(evdict, "key")) == NULL)
237 if ((po = prop_dictionary_get(evdict, "value")) == NULL)
239 /* prop_object_retain(po); */ /* not necessary afaik */
240 prop_dictionary_set(devdict, prop_string_cstring_nocopy(ps), po);
243 case UDEV_EV_KEY_REMOVE:
244 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL)
246 if ((ps = prop_dictionary_get(evdict, "key")) == NULL)
248 prop_dictionary_remove(devdict, prop_string_cstring_nocopy(ps));
252 syslog(LOG_ERR, "read_event: unknown evtype %d", evtype);
256 prop_object_release(dict);
261 udev_getdevs(int devfd)
263 prop_dictionary_t pd, rpd;
267 pd = prop_dictionary_create();
269 err(1, "prop_dictionary_create()");
272 ps = prop_string_create_cstring("getdevs");
274 prop_object_release(pd);
275 err(1, "prop_string_create_cstring()");
278 if (prop_dictionary_set(pd, "command", ps) == false) {
279 prop_object_release(ps);
280 prop_object_release(pd);
281 err(1, "prop_dictionary_set()");
284 prop_object_release(ps);
286 /* Send dictionary to kernel space */
287 if (prop_dictionary_sendrecv_ioctl(pd, devfd, UDEVPROP, &rpd) != 0)
288 err(1, "prop_array_recv_ioctl()");
290 prop_object_release(pd);
292 pa = prop_dictionary_get(rpd, "array");
295 prop_object_retain(pa);
298 prop_object_release(rpd);
303 killed(int sig __unused)
305 syslog(LOG_ERR, "udevd stopped");
306 unlink("/var/run/udevd.pid");
311 ignore_signal(int signum)
313 struct sigaction act;
316 act.sa_handler = SIG_IGN;
317 sigemptyset(&act.sa_mask);
320 ret = sigaction(signum, &act, NULL);
325 set_killed_signal(void)
327 struct sigaction act;
330 act.sa_handler = killed;
331 sigemptyset(&act.sa_mask);
334 ret = sigaction(SIGTERM, &act, NULL);
338 int main(int argc, char *argv[])
340 int error __unused, i, r, s;
341 struct pollfd fds[NFDS];
345 while ((ch = getopt(argc, argv, "d")) != -1) {
358 TAILQ_INIT(&pdev_array_list);
359 TAILQ_INIT(&udev_monitor_list);
361 r = ignore_signal(SIGPIPE);
363 err(1, "could not ignore_signal SIGPIPE");
365 r = pthread_mutex_init(&(monitor_lock), NULL);
367 err(1, "could not allocate a pthread_mutex");
369 if ((udevfd = open(UDEV_DEVICE_PATH, O_RDWR | O_NONBLOCK)) == -1)
370 err(1, "%s", UDEV_DEVICE_PATH);
371 unblock_descriptor(udevfd);
373 s = init_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0);
375 err(1, "init_local_server");
377 pidf = fopen("/var/run/udevd.pid", "w");
384 if (daemon(0, 0) == -1)
387 fprintf(pidf, "%ld\n", (long)getpid());
390 syslog(LOG_ERR, "udevd started");
392 pdev_array_entry_insert(udev_getdevs(udevfd));
394 memset(fds, 0 , sizeof(fds));
395 fds[UDEV_DEVICE_FD_IDX].fd = udevfd;
396 fds[UDEV_DEVICE_FD_IDX].events = POLLIN;
397 fds[UDEV_SOCKET_FD_IDX].fd = s;
398 fds[UDEV_SOCKET_FD_IDX].events = POLLIN | POLLPRI;
401 r = poll(fds, NFDS, -1);
403 err(1, "polling...");
405 for (i = 0; (i < NFDS) && (r > 0); i++) {
406 if (fds[i].revents == 0)
411 case UDEV_DEVICE_FD_IDX:
412 udev_read_event(udevfd);
414 case UDEV_SOCKET_FD_IDX:
415 handle_new_connection(s);