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>
65 static int hangup_ongoing
= 0;
66 static struct pollfd fds
[NFDS
];
68 extern pthread_mutex_t monitor_lock
;
69 extern TAILQ_HEAD(udev_monitor_list_head
, udev_monitor
) udev_monitor_list
;
70 extern TAILQ_HEAD(pdev_array_list_head
, pdev_array_entry
) pdev_array_list
;
72 static void usage(void);
74 int match_dev_dict(prop_dictionary_t
, prop_dictionary_t
);
75 prop_dictionary_t
find_dev_dict(int64_t, prop_dictionary_t
, int *);
77 void udev_read_event(int);
78 prop_array_t
udev_getdevs(int);
84 fprintf(stderr
, "usage: udevd [-d]\n");
89 match_dev_dict(prop_dictionary_t dict
, prop_dictionary_t match_dict
)
91 prop_number_t pn
, pn2
;
92 prop_string_t ps
, ps2
;
97 if ((ps
= prop_dictionary_get(dict
, "name")) == NULL
)
99 if ((ps2
= prop_dictionary_get(match_dict
, "name")) == NULL
)
101 if (!prop_string_equals(ps
, ps2
))
104 if ((pn
= prop_dictionary_get(dict
, "devnum")) == NULL
)
106 if ((pn2
= prop_dictionary_get(match_dict
, "devnum")) == NULL
)
108 if (!prop_number_equals(pn
, pn2
))
111 if ((pn
= prop_dictionary_get(dict
, "kptr")) == NULL
)
113 if ((pn2
= prop_dictionary_get(match_dict
, "kptr")) == NULL
)
115 if (!prop_number_equals(pn
, pn2
))
122 find_dev_dict(int64_t generation
, prop_dictionary_t match_dict
, int *idx
)
124 struct pdev_array_entry
*pae
;
126 prop_object_iterator_t iter
;
127 prop_dictionary_t dict
;
130 if (generation
== -1)
131 pae
= pdev_array_entry_get_last();
133 pae
= pdev_array_entry_get(generation
);
138 pa
= pae
->pdev_array
;
140 iter
= prop_array_iterator(pa
);
142 pdev_array_entry_unref(pae
);
146 while ((dict
= prop_object_iterator_next(iter
)) != NULL
) {
147 if (match_dev_dict(dict
, match_dict
))
152 prop_object_iterator_release(iter
);
157 pdev_array_entry_unref(pae
);
162 udev_read_event(int fd
)
164 struct pdev_array_entry
*pae
;
165 prop_dictionary_t dict
, evdict
, devdict
;
176 xml
= malloc(sz
); /* 4 MB */
178 if ((n
= read(fd
, xml
, sz
)) <= 0) {
179 if (errno
== ENOMEM
) {
188 dict
= prop_dictionary_internalize(xml
);
191 syslog(LOG_ERR
, "internalization of xml failed");
195 pn
= prop_dictionary_get(dict
, "evtype");
197 syslog(LOG_ERR
, "read_event: no key evtype");
201 evtype
= prop_number_integer_value(pn
);
203 evdict
= prop_dictionary_get(dict
, "evdict");
204 if (evdict
== NULL
) {
205 syslog(LOG_ERR
, "read_event: no key evdict");
210 case UDEV_EVENT_ATTACH
:
211 monitor_queue_event(dict
);
212 pae
= pdev_array_entry_get_last();
213 pa
= prop_array_copy(pae
->pdev_array
);
214 pdev_array_entry_unref(pae
);
217 prop_array_add(pa
, evdict
);
218 pdev_array_entry_insert(pa
);
221 case UDEV_EVENT_DETACH
:
222 monitor_queue_event(dict
);
223 if ((devdict
= find_dev_dict(-1, evdict
, &idx
)) == NULL
)
225 pae
= pdev_array_entry_get_last();
226 pa
= prop_array_copy(pae
->pdev_array
);
227 pdev_array_entry_unref(pae
);
230 prop_array_remove(pa
, idx
);
231 pdev_array_entry_insert(pa
);
234 case UDEV_EV_KEY_UPDATE
:
235 if ((devdict
= find_dev_dict(-1, evdict
, NULL
)) == NULL
)
237 if ((ps
= prop_dictionary_get(evdict
, "key")) == NULL
)
239 if ((po
= prop_dictionary_get(evdict
, "value")) == NULL
)
241 /* prop_object_retain(po); */ /* not necessary afaik */
242 prop_dictionary_set(devdict
, prop_string_cstring_nocopy(ps
), po
);
245 case UDEV_EV_KEY_REMOVE
:
246 if ((devdict
= find_dev_dict(-1, evdict
, NULL
)) == NULL
)
248 if ((ps
= prop_dictionary_get(evdict
, "key")) == NULL
)
250 prop_dictionary_remove(devdict
, prop_string_cstring_nocopy(ps
));
254 syslog(LOG_ERR
, "read_event: unknown evtype %d", evtype
);
258 prop_object_release(dict
);
263 udev_getdevs(int devfd
)
265 prop_dictionary_t pd
, rpd
;
269 pd
= prop_dictionary_create();
271 err(1, "prop_dictionary_create()");
274 ps
= prop_string_create_cstring("getdevs");
276 prop_object_release(pd
);
277 err(1, "prop_string_create_cstring()");
280 if (prop_dictionary_set(pd
, "command", ps
) == false) {
281 prop_object_release(ps
);
282 prop_object_release(pd
);
283 err(1, "prop_dictionary_set()");
286 prop_object_release(ps
);
288 /* Send dictionary to kernel space */
289 if (prop_dictionary_sendrecv_ioctl(pd
, devfd
, UDEVPROP
, &rpd
) != 0)
290 err(1, "prop_array_recv_ioctl()");
292 prop_object_release(pd
);
294 pa
= prop_dictionary_get(rpd
, "array");
297 prop_object_retain(pa
);
300 prop_object_release(rpd
);
305 killed(int sig __unused
)
307 syslog(LOG_ERR
, "udevd stopped");
308 unlink("/var/run/udevd.pid");
314 hangup(int sig __unused
)
319 syslog(LOG_ERR
, "udevd hangup+resume");
321 pidf
= fopen("/var/run/udevd.pid", "w");
323 fprintf(pidf
, "%ld\n", (long)getpid());
328 close(fds
[UDEV_SOCKET_FD_IDX
].fd
);
330 s
= init_local_server(LISTEN_SOCKET_FILE
, SOCK_STREAM
, 0);
332 err(1, "init_local_server");
334 fds
[UDEV_SOCKET_FD_IDX
].fd
= s
;
335 pdev_array_entry_insert(udev_getdevs(udevfd
));
340 ignore_signal(int signum
)
342 struct sigaction act
;
345 act
.sa_handler
= SIG_IGN
;
346 sigemptyset(&act
.sa_mask
);
349 ret
= sigaction(signum
, &act
, NULL
);
354 set_signal(int signum
, sig_t sig_func
)
356 struct sigaction act
;
359 act
.sa_handler
= sig_func
;
360 sigemptyset(&act
.sa_mask
);
363 ret
= sigaction(signum
, &act
, NULL
);
367 int main(int argc
, char *argv
[])
369 int error __unused
, i
, r
, s
;
373 while ((ch
= getopt(argc
, argv
, "d")) != -1) {
386 TAILQ_INIT(&pdev_array_list
);
387 TAILQ_INIT(&udev_monitor_list
);
389 r
= ignore_signal(SIGPIPE
);
391 err(1, "could not ignore_signal SIGPIPE");
393 r
= pthread_mutex_init(&(monitor_lock
), NULL
);
395 err(1, "could not allocate a pthread_mutex");
397 if ((udevfd
= open(UDEV_DEVICE_PATH
, O_RDWR
| O_NONBLOCK
)) == -1)
398 err(1, "%s", UDEV_DEVICE_PATH
);
399 unblock_descriptor(udevfd
);
401 s
= init_local_server(LISTEN_SOCKET_FILE
, SOCK_STREAM
, 0);
403 err(1, "init_local_server");
405 pidf
= fopen("/var/run/udevd.pid", "w");
411 set_signal(SIGTERM
, killed
);
412 set_signal(SIGHUP
, hangup
);
415 if (daemon(0, 0) == -1)
419 fprintf(pidf
, "%ld\n", (long)getpid());
423 syslog(LOG_ERR
, "udevd started");
425 pdev_array_entry_insert(udev_getdevs(udevfd
));
427 memset(fds
, 0 , sizeof(fds
));
428 fds
[UDEV_DEVICE_FD_IDX
].fd
= udevfd
;
429 fds
[UDEV_DEVICE_FD_IDX
].events
= POLLIN
;
430 fds
[UDEV_SOCKET_FD_IDX
].fd
= s
;
431 fds
[UDEV_SOCKET_FD_IDX
].events
= POLLIN
| POLLPRI
;
434 r
= poll(fds
, NFDS
, -1);
436 if (hangup_ongoing
== 0) {
437 if (errno
== EINTR
) {
441 err(1, "polling...");
444 usleep(20000); /* 20 ms */
449 for (i
= 0; (i
< NFDS
) && (r
> 0); i
++) {
450 if (fds
[i
].revents
== 0)
455 case UDEV_DEVICE_FD_IDX
:
456 udev_read_event(udevfd
);
458 case UDEV_SOCKET_FD_IDX
:
459 handle_new_connection(s
);
467 syslog(LOG_ERR
, "udevd is exiting normally");