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
) {
181 if ((xml
= realloc(xml
, sz
)) == NULL
) {
182 syslog(LOG_ERR
, "could not realloc xml memory");
191 dict
= prop_dictionary_internalize(xml
);
194 syslog(LOG_ERR
, "internalization of xml failed");
198 pn
= prop_dictionary_get(dict
, "evtype");
200 syslog(LOG_ERR
, "read_event: no key evtype");
204 evtype
= prop_number_integer_value(pn
);
206 evdict
= prop_dictionary_get(dict
, "evdict");
207 if (evdict
== NULL
) {
208 syslog(LOG_ERR
, "read_event: no key evdict");
213 case UDEV_EVENT_ATTACH
:
214 monitor_queue_event(dict
);
215 pae
= pdev_array_entry_get_last();
216 pa
= prop_array_copy(pae
->pdev_array
);
217 pdev_array_entry_unref(pae
);
220 prop_array_add(pa
, evdict
);
221 pdev_array_entry_insert(pa
);
224 case UDEV_EVENT_DETACH
:
225 monitor_queue_event(dict
);
226 if ((devdict
= find_dev_dict(-1, evdict
, &idx
)) == NULL
)
228 pae
= pdev_array_entry_get_last();
229 pa
= prop_array_copy(pae
->pdev_array
);
230 pdev_array_entry_unref(pae
);
233 prop_array_remove(pa
, idx
);
234 pdev_array_entry_insert(pa
);
237 case UDEV_EV_KEY_UPDATE
:
238 if ((devdict
= find_dev_dict(-1, evdict
, NULL
)) == NULL
)
240 if ((ps
= prop_dictionary_get(evdict
, "key")) == NULL
)
242 if ((po
= prop_dictionary_get(evdict
, "value")) == NULL
)
244 /* prop_object_retain(po); */ /* not necessary afaik */
245 prop_dictionary_set(devdict
, prop_string_cstring_nocopy(ps
), po
);
248 case UDEV_EV_KEY_REMOVE
:
249 if ((devdict
= find_dev_dict(-1, evdict
, NULL
)) == NULL
)
251 if ((ps
= prop_dictionary_get(evdict
, "key")) == NULL
)
253 prop_dictionary_remove(devdict
, prop_string_cstring_nocopy(ps
));
257 syslog(LOG_ERR
, "read_event: unknown evtype %d", evtype
);
261 prop_object_release(dict
);
266 udev_getdevs(int devfd
)
268 prop_dictionary_t pd
, rpd
;
272 pd
= prop_dictionary_create();
274 err(1, "prop_dictionary_create()");
277 ps
= prop_string_create_cstring("getdevs");
279 prop_object_release(pd
);
280 err(1, "prop_string_create_cstring()");
283 if (prop_dictionary_set(pd
, "command", ps
) == false) {
284 prop_object_release(ps
);
285 prop_object_release(pd
);
286 err(1, "prop_dictionary_set()");
289 prop_object_release(ps
);
291 /* Send dictionary to kernel space */
292 if (prop_dictionary_sendrecv_ioctl(pd
, devfd
, UDEVPROP
, &rpd
) != 0)
293 err(1, "prop_array_recv_ioctl()");
295 prop_object_release(pd
);
297 pa
= prop_dictionary_get(rpd
, "array");
300 prop_object_retain(pa
);
303 prop_object_release(rpd
);
308 killed(int sig __unused
)
310 syslog(LOG_ERR
, "udevd stopped");
311 unlink("/var/run/udevd.pid");
317 hangup(int sig __unused
)
322 syslog(LOG_ERR
, "udevd hangup+resume");
324 pidf
= fopen("/var/run/udevd.pid", "w");
326 fprintf(pidf
, "%ld\n", (long)getpid());
331 close(fds
[UDEV_SOCKET_FD_IDX
].fd
);
333 s
= init_local_server(LISTEN_SOCKET_FILE
, SOCK_STREAM
, 0);
335 err(1, "init_local_server");
337 fds
[UDEV_SOCKET_FD_IDX
].fd
= s
;
338 pdev_array_entry_insert(udev_getdevs(udevfd
));
343 ignore_signal(int signum
)
345 struct sigaction act
;
348 act
.sa_handler
= SIG_IGN
;
349 sigemptyset(&act
.sa_mask
);
352 ret
= sigaction(signum
, &act
, NULL
);
357 set_signal(int signum
, sig_t sig_func
)
359 struct sigaction act
;
362 act
.sa_handler
= sig_func
;
363 sigemptyset(&act
.sa_mask
);
366 ret
= sigaction(signum
, &act
, NULL
);
370 int main(int argc
, char *argv
[])
372 int error __unused
, i
, r
, s
;
376 while ((ch
= getopt(argc
, argv
, "d")) != -1) {
389 TAILQ_INIT(&pdev_array_list
);
390 TAILQ_INIT(&udev_monitor_list
);
392 r
= ignore_signal(SIGPIPE
);
394 err(1, "could not ignore_signal SIGPIPE");
396 r
= pthread_mutex_init(&(monitor_lock
), NULL
);
398 err(1, "could not allocate a pthread_mutex");
400 if ((udevfd
= open(UDEV_DEVICE_PATH
, O_RDWR
| O_NONBLOCK
)) == -1)
401 err(1, "%s", UDEV_DEVICE_PATH
);
402 unblock_descriptor(udevfd
);
404 s
= init_local_server(LISTEN_SOCKET_FILE
, SOCK_STREAM
, 0);
406 err(1, "init_local_server");
408 pidf
= fopen("/var/run/udevd.pid", "w");
414 set_signal(SIGTERM
, killed
);
415 set_signal(SIGHUP
, hangup
);
418 if (daemon(0, 0) == -1)
422 fprintf(pidf
, "%ld\n", (long)getpid());
426 syslog(LOG_ERR
, "udevd started");
428 pdev_array_entry_insert(udev_getdevs(udevfd
));
430 memset(fds
, 0 , sizeof(fds
));
431 fds
[UDEV_DEVICE_FD_IDX
].fd
= udevfd
;
432 fds
[UDEV_DEVICE_FD_IDX
].events
= POLLIN
;
433 fds
[UDEV_SOCKET_FD_IDX
].fd
= s
;
434 fds
[UDEV_SOCKET_FD_IDX
].events
= POLLIN
| POLLPRI
;
437 r
= poll(fds
, NFDS
, -1);
439 if (hangup_ongoing
== 0) {
440 if (errno
== EINTR
) {
444 err(1, "polling...");
447 usleep(20000); /* 20 ms */
452 for (i
= 0; (i
< NFDS
) && (r
> 0); i
++) {
453 if (fds
[i
].revents
== 0)
458 case UDEV_DEVICE_FD_IDX
:
459 udev_read_event(udevfd
);
461 case UDEV_SOCKET_FD_IDX
:
462 handle_new_connection(s
);
470 syslog(LOG_ERR
, "udevd is exiting normally");