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>
64 extern pthread_mutex_t monitor_lock;
65 extern TAILQ_HEAD(udev_monitor_list_head, udev_monitor) udev_monitor_list;
66 extern TAILQ_HEAD(pdev_array_list_head, pdev_array_entry) pdev_array_list;
68 int match_dev_dict(prop_dictionary_t, prop_dictionary_t);
69 prop_dictionary_t find_dev_dict(int64_t, prop_dictionary_t, int *);
71 void udev_read_event(int);
72 prop_array_t udev_getdevs(int);
75 match_dev_dict(prop_dictionary_t dict, prop_dictionary_t match_dict)
77 prop_number_t pn, pn2;
78 prop_string_t ps, ps2;
83 if ((ps = prop_dictionary_get(dict, "name")) == NULL)
85 if ((ps2 = prop_dictionary_get(match_dict, "name")) == NULL)
87 if (!prop_string_equals(ps, ps2))
90 if ((pn = prop_dictionary_get(dict, "devnum")) == NULL)
92 if ((pn2 = prop_dictionary_get(match_dict, "devnum")) == NULL)
94 if (!prop_number_equals(pn, pn2))
97 if ((pn = prop_dictionary_get(dict, "kptr")) == NULL)
99 if ((pn2 = prop_dictionary_get(match_dict, "kptr")) == NULL)
101 if (!prop_number_equals(pn, pn2))
108 find_dev_dict(int64_t generation, prop_dictionary_t match_dict, int *idx)
110 struct pdev_array_entry *pae;
112 prop_object_iterator_t iter;
113 prop_dictionary_t dict;
116 if (generation == -1)
117 pae = pdev_array_entry_get_last();
119 pae = pdev_array_entry_get(generation);
124 pa = pae->pdev_array;
126 iter = prop_array_iterator(pa);
128 pdev_array_entry_unref(pae);
132 while ((dict = prop_object_iterator_next(iter)) != NULL) {
133 if (match_dev_dict(dict, match_dict))
138 prop_object_iterator_release(iter);
143 pdev_array_entry_unref(pae);
148 udev_read_event(int fd)
150 struct pdev_array_entry *pae;
151 prop_dictionary_t dict, evdict, devdict;
162 xml = malloc(sz); /* 4 MB */
164 if ((n = read(fd, xml, sz)) <= 0) {
165 if (errno == ENOMEM) {
174 dict = prop_dictionary_internalize(xml);
177 syslog(LOG_ERR, "internalization of xml failed");
181 pn = prop_dictionary_get(dict, "evtype");
183 syslog(LOG_ERR, "read_event: no key evtype");
187 evtype = prop_number_integer_value(pn);
189 evdict = prop_dictionary_get(dict, "evdict");
190 if (evdict == NULL) {
191 syslog(LOG_ERR, "read_event: no key evdict");
196 case UDEV_EVENT_ATTACH:
197 monitor_queue_event(dict);
198 pae = pdev_array_entry_get_last();
199 pa = prop_array_copy(pae->pdev_array);
200 pdev_array_entry_unref(pae);
203 prop_array_add(pa, evdict);
204 pdev_array_entry_insert(pa);
207 case UDEV_EVENT_DETACH:
208 monitor_queue_event(dict);
209 if ((devdict = find_dev_dict(-1, evdict, &idx)) == NULL)
211 pae = pdev_array_entry_get_last();
212 pa = prop_array_copy(pae->pdev_array);
213 pdev_array_entry_unref(pae);
216 prop_array_remove(pa, idx);
217 //pdev_array_entry_insert(pa);
220 case UDEV_EV_KEY_UPDATE:
221 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL)
223 if ((ps = prop_dictionary_get(evdict, "key")) == NULL)
225 if ((po = prop_dictionary_get(evdict, "value")) == NULL)
227 /* prop_object_retain(po); */ /* not necessary afaik */
228 prop_dictionary_set(devdict, prop_string_cstring_nocopy(ps), po);
231 case UDEV_EV_KEY_REMOVE:
232 if ((devdict = find_dev_dict(-1, evdict, NULL)) == NULL)
234 if ((ps = prop_dictionary_get(evdict, "key")) == NULL)
236 prop_dictionary_remove(devdict, prop_string_cstring_nocopy(ps));
240 syslog(LOG_ERR, "read_event: unknown evtype %d", evtype);
244 prop_object_release(dict);
249 udev_getdevs(int devfd)
251 prop_dictionary_t pd, rpd;
255 pd = prop_dictionary_create();
257 err(1, "prop_dictionary_create()");
260 ps = prop_string_create_cstring("getdevs");
262 prop_object_release(pd);
263 err(1, "prop_string_create_cstring()");
266 if (prop_dictionary_set(pd, "command", ps) == false) {
267 prop_object_release(ps);
268 prop_object_release(pd);
269 err(1, "prop_dictionary_set()");
272 prop_object_release(ps);
274 /* Send dictionary to kernel space */
275 if (prop_dictionary_sendrecv_ioctl(pd, devfd, UDEVPROP, &rpd) != 0)
276 err(1, "prop_array_recv_ioctl()");
278 prop_object_release(pd);
280 pa = prop_dictionary_get(rpd, "array");
283 prop_object_retain(pa);
286 prop_object_release(rpd);
291 killed(int sig __unused)
293 syslog(LOG_ERR, "udevd stopped");
294 unlink("/var/run/udevd.pid");
298 ignore_signal(int signum)
300 struct sigaction act;
303 act.sa_handler = SIG_IGN;
304 sigemptyset(&act.sa_mask);
307 ret = sigaction(signum, &act, NULL);
312 set_killed_signal(void)
314 struct sigaction act;
317 act.sa_handler = killed;
318 sigemptyset(&act.sa_mask);
321 ret = sigaction(SIGTERM, &act, NULL);
325 int main(int argc __unused, char *argv[] __unused)
327 int error __unused, i, r, s;
328 struct pollfd fds[NFDS];
331 TAILQ_INIT(&pdev_array_list);
332 TAILQ_INIT(&udev_monitor_list);
334 r = ignore_signal(SIGPIPE);
336 err(1, "could not ignore_signal SIGPIPE");
338 r = pthread_mutex_init(&(monitor_lock), NULL);
340 err(1, "could not allocate a pthread_mutex");
342 if ((udevfd = open(UDEV_DEVICE_PATH, O_RDWR | O_NONBLOCK)) == -1)
343 err(1, "%s", UDEV_DEVICE_PATH);
344 unblock_descriptor(udevfd);
346 s = init_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0);
348 err(1, "init_local_server");
350 pidf = fopen("/var/run/udevd.pid", "w");
356 if (daemon(0, 0) == -1)
359 fprintf(pidf, "%ld\n", (long)getpid());
362 syslog(LOG_ERR, "udevd started");
364 pdev_array_entry_insert(udev_getdevs(udevfd));
366 memset(fds, 0 , sizeof(fds));
367 fds[UDEV_DEVICE_FD_IDX].fd = udevfd;
368 fds[UDEV_DEVICE_FD_IDX].events = POLLIN;
369 fds[UDEV_SOCKET_FD_IDX].fd = s;
370 fds[UDEV_SOCKET_FD_IDX].events = POLLIN | POLLPRI;
373 r = poll(fds, NFDS, -1);
375 err(1, "polling...");
377 for (i = 0; (i < NFDS) && (r > 0); i++) {
378 if (fds[i].revents == 0)
383 case UDEV_DEVICE_FD_IDX:
384 udev_read_event(udevfd);
386 case UDEV_SOCKET_FD_IDX:
387 handle_new_connection(s);