2 #include <sys/device.h>
4 #include <sys/socket.h>
21 #include <libprop/proplib.h>
24 #define LISTEN_SOCKET_FILE "/tmp/udevd.socket"
25 #define SOCKFILE_NAMELEN strlen(LISTEN_SOCKET_FILE)+1
27 int conn_local_server(const char *sockfile
, int socktype
, int nonblock
,
29 prop_dictionary_t
udevd_get_command_dict(char *command
);
30 void udevd_request_devs(int s
);
40 struct udev_enumerate
{
41 struct udev
*udev_ctx
;
44 TAILQ_HEAD(, udev_list_entry
) list_entries
;
47 struct udev_list_entry
{
48 prop_dictionary_t dict
;
49 TAILQ_ENTRY(udev_list_entry
) link
;
53 struct udev
*udev_ctx
;
56 int user_socket
; /* maybe... one day... */
61 struct udev
*udev_ctx
;
62 prop_dictionary_t dict
;
68 udev_ref(struct udev
*udev_ctx
)
70 atomic_add_int(&udev_ctx
->refs
, 1);
76 udev_unref(struct udev
*udev_ctx
)
80 refcount
= atomic_fetchadd_int(&udev_ctx
->refs
, -1);
83 atomic_subtract_int(&udev_ctx
->refs
, 0x400); /* in destruction */
84 if (udev_ctx
->gp_fd
!= -1)
85 close (udev_ctx
->gp_fd
);
86 if (udev_ctx
->monitor_fd
!= -1)
87 close (udev_ctx
->monitor_fd
);
96 struct udev
*udev_ctx
;
98 udev_ctx
= malloc(sizeof(struct udev
));
101 udev_ctx
->gp_fd
= -1;
102 udev_ctx
->monitor_fd
= -1;
103 udev_ctx
->userdata
= NULL
;
108 const char *udev_get_dev_path(struct udev
*udev_ctx __unused
)
114 udev_get_userdata(struct udev
*udev_ctx
)
116 return udev_ctx
->userdata
;
120 udev_set_userdata(struct udev
*udev_ctx
, void *userdata
)
122 udev_ctx
->userdata
= userdata
;
125 struct udev_enumerate
*
126 udev_enumerate_new(struct udev
*udev_ctx
)
128 struct udev_enumerate
*udev_enum
;
130 udev_enum
= malloc(sizeof(struct udev_enumerate
));
133 udev_enum
->pa
= NULL
;
134 TAILQ_INIT(&udev_enum
->list_entries
);
135 udev_enum
->udev_ctx
= udev_ref(udev_ctx
);
138 struct udev_enumerate
*
139 udev_enumerate_ref(struct udev_enumerate
*udev_enum
)
141 atomic_add_int(&udev_enum
->refs
, 1);
147 udev_enumerate_unref(struct udev_enumerate
*udev_enum
)
149 struct udev_list_entry
*le
;
152 refcount
= atomic_fetchadd_int(&udev_enum
->refs
, -1);
155 atomic_subtract_int(&udev_enum
->refs
, 0x400); /* in destruction */
156 if (udev_enum
->pa
!= NULL
)
157 prop_object_release(udev_enum
->pa
);
159 while (!TAILQ_EMPTY(&udev_enum
->list_entries
)) {
160 le
= TAILQ_FIRST(&udev_enum
->list_entries
);
161 TAILQ_REMOVE(&udev_enum
->list_entries
, le
, link
);
162 prop_object_release(le
->dict
);
165 udev_unref(udev_enum
->udev_ctx
);
171 udev_enumerate_get_udev(struct udev_enumerate
*udev_enum
)
173 return udev_enum
->udev_ctx
;
177 udev_enumerate_scan_devices(struct udev_enumerate
*udev_enum
)
181 if (udev_enum
->udev_ctx
->gp_fd
== -1)
184 pa
= udevd_request_devs(udev_enum
->udev_ctx
->gp_fd
);
188 prop_object_retain(pa
);
190 if (udev_enum
->pa
!= NULL
)
191 prop_object_release(udev_enum
->pa
);
193 udev_enum
->iter
= NULL
;
199 struct udev_list_entry
*
200 udev_enumerate_get_list_entry(struct udev_enumerate
*udev_enum
)
202 struct udev_list_entry
*le
;
203 prop_object_iterator_t iter
;
205 /* If the list is not empty, assume it was populated in an earlier call */
206 if (!TAILQ_EMPTY(&udev_enum
->list_entries
))
207 return TAILQ_FIRST(&udev_enum
->list_entries
);
209 iter
= prop_array_iterator(udev_enum
->pa
);
213 while ((dict
= prop_object_iterator_next(iter
)) != NULL
) {
214 le
= malloc(sizeof(struct udev_list_entry
));
218 prop_object_retain(dict
);
220 TAILQ_INSERT_TAIL(&udev_enum
->list_entries
, le
, link
);
223 le
= TAILQ_FIRST(&udev_enum
->list_entries
);
226 prop_object_iterator_release(iter
);
231 udev_enumerate_get_array(struct udev_enumerate
*udev_enum
)
233 return udev_enum
->pa
;
236 struct udev_list_entry
*
237 udev_list_entry_get_next(struct udev_list_entry
*list_entry
)
239 return TAILQ_NEXT(list_entry
, link
);
243 udev_list_entry_get_dictionary(struct udev_list_entry
*list_entry
)
245 return list_entry
->dict
;
248 #define udev_list_entry_foreach(list_entry, first_entry) \
249 for(list_entry = first_entry; \
250 list_entry != NULL; \
251 list_entry = udev_list_entry_get_next(list_entry))
258 struct udev_monitor
*
259 udev_monitor_new(struct udev
*udev_ctx
)
261 struct udev_monitor
*udev_monitor
;
264 ret
= conn_local_server(LISTEN_SOCKET_FILE
, SOCK_STREAM
, 0, &s
);
268 udev_monitor
= malloc(sizeof(struct udev_monitor
));
269 if (udev_monitor
== NULL
)
272 udev_monitor
->refs
= 1;
273 udev_monitor
->ev_filt
= NULL
;
274 udev_monitor
->socket
= s
;
275 udev_monitor
->user_socket
= 1;
276 udev_monitor
->udev_ctx
= udev_ref(udev_ctx
);
282 struct udev_monitor
*
283 udev_monitor_ref(struct udev_monitor
*udev_monitor
)
285 atomic_add_int(&udev_monitor
->refs
, 1);
291 udev_monitor_unref(struct udev_monitor
*udev_monitor
)
295 refcount
= atomic_fetchadd_int(&udev_monitor
->refs
, -1);
298 atomic_subtract_int(&udev_monitor
->refs
, 0x400); /* in destruction */
299 if (udev_monitor
->ev_filt
!= NULL
)
300 prop_object_release(udev_monitor
->ev_filt
);
302 if (udev_monitor
->socket
!= -1)
303 close(udev_monitor
->socket
);
304 if (udev_monitor
->user_socket
!= -1)
305 close(udev_monitor
->user_socket
);
307 udev_unref(udev_monitor
->udev_ctx
);
313 udev_monitor_get_udev(struct udev_monitor
*udev_monitor
)
315 return udev_monitor
->udev_ctx
;
319 udev_monitor_get_fd(struct udev_monitor
*udev_monitor
)
321 return udev_monitor
->socket
;
325 udev_monitor_receive_device(struct udev_monitor
*udev_monitor
)
327 struct udev_device
*udev_dev
;
328 prop_dictionary_t dict
;
333 xml
= malloc(12*1024*1024);
337 if ((n
= read_xml(udev_monitor
->socket
, xml
, 12*1024*1024)) <= 0) {
343 dict
= prop_dictionary_internalize(xml
);
348 pn
= prop_dictionary_get(dict
, "evtype");
350 prop_object_release(dict
);
354 udev_dev
= malloc(sizeof(struct udev_dev
));
355 if (udev_dev
== NULL
) {
356 prop_object_release(dict
);
361 udev_dev
->ev_type
= prop_number_integer_value(pn
);
362 udev_dev
->dict
= prop_dictionary_get(dict
, "evdict");
363 if (udev_dev
->dict
== NULL
) {
367 udev_dev
->udev_ctx
= udev_ref(udev_monitor
->udev_ctx
);
374 udev_monitor_enable_receiving(struct udev_monitor
*udev_monitor
)
376 prop_dictionary_t dict
;
378 /* ->socket, ->user_socket, ->ev_filt */
380 dict
= udevd_get_command_dict(__DECONST(char *, "monitor"));
384 /* Add event filters to message, if available */
385 if (udev_monitor
->ev_filt
!= NULL
) {
386 if (prop_dictionary_set(dict
, "filters",
387 udev_monitor
->ev_filt
) == false) {
388 prop_object_release(dict
);
393 xml
= prop_dictionary_externalize(dict
);
394 prop_object_release(dict
);
398 n
= send_xml(udev_monitor
->socket
, xml
);
407 udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor
*udev_monitor
,
408 const char *subsystem
,
409 const char *devtype __unused
)
413 ret
= _udev_monitor_filter_add_match_gen(udev_monitor
,
414 EVENT_FILTER_TYPE_WILDCARD
,
423 udev_monitor_filter_add_match_expr(struct udev_monitor
*udev_monitor
,
429 ret
= _udev_monitor_filter_add_match_gen(udev_monitor
,
430 EVENT_FILTER_TYPE_WILDCARD
,
439 udev_monitor_filter_add_nomatch_expr(struct udev_monitor
*udev_monitor
,
445 ret
= _udev_monitor_filter_add_match_gen(udev_monitor
,
446 EVENT_FILTER_TYPE_WILDCARD
,
455 udev_monitor_filter_add_match_regex(struct udev_monitor
*udev_monitor
,
461 ret
= _udev_monitor_filter_add_match_gen(udev_monitor
,
462 EVENT_FILTER_TYPE_REGEX
,
471 udev_monitor_filter_add_nomatch_regex(struct udev_monitor
*udev_monitor
,
477 ret
= _udev_monitor_filter_add_match_gen(udev_monitor
,
478 EVENT_FILTER_TYPE_REGEX
,
487 _udev_monitor_filter_add_match_gen(struct udev_monitor
*udev_monitor
,
494 prop_dictionary_t dict
;
497 if (subsystem
== NULL
)
500 dict
= prop_dictionary_create();
504 error
= _udev_dict_set_cstr(dict
, "key", key
);
507 error
= _udev_dict_set_int(dict
, "type", type
);
510 error
= _udev_dict_set_int(dict
, "expr", expr
);
515 error
= _udev_dict_set_int(dict
, "negative", 1);
520 if (udev_monitor
->ev_filt
== NULL
) {
521 pa
= prop_array_create();
525 udev_monitor
->ev_filt
= pa
;
528 if (prop_array_add(udev_monitor
->ev_filt
, dict
) == false)
534 prop_object_release(dict
);
539 udev_device_ref(struct udev_device
*udev_device
)
541 atomic_add_int(&udev_device
->refs
, 1);
547 udev_device_unref(struct udev_device
*udev_device
)
551 refcount
= atomic_fetchadd_int(&udev_device
->refs
, -1);
554 atomic_subtract_int(&udev_device
->refs
, 0x400); /* in destruction */
555 if (udev_device
->dict
!= NULL
)
556 prop_object_release(udev_device
->dict
);
558 udev_unref(udev_device
->udev_ctx
);
564 udev_device_get_dictionary(struct udev_device
*udev_device
)
566 return udev_device
->dict
;
570 udev_device_get_udev(struct udev_device
*udev_device
)
572 return udev_device
->udev_ctx
;
576 send_xml(int s
, char *xml
)
581 sz
= strlen(xml
) + 1;
583 r
= send(s
, &sz
, sizeof(sz
), 0);
588 while (r
< (ssize_t
)sz
) {
589 n
= send(s
, xml
+r
, sz
-r
, 0);
599 read_xml(int s
, char *buf
, size_t buf_sz
)
604 n
= recv(s
, &sz
, sizeof(sz
), MSG_WAITALL
);
609 while ((r
< (ssize_t
)sz
) && (r
< (ssize_t
)buf_sz
)) {
610 n
= recv(s
, buf
+r
, sz
-r
, MSG_WAITALL
);
622 _udev_dict_set_cstr(prop_dictionary_t dict
, const char *key
, char *str
)
626 ps
= prop_string_create_cstring(str
);
630 if (prop_dictionary_set(dict
, key
, ps
) == false) {
631 prop_object_release(ps
);
635 prop_object_release(ps
);
640 _udev_dict_set_int(prop_dictionary_t dict
, const char *key
, int64_t val
)
644 pn
= prop_number_create_integer(val
);
648 if (prop_dictionary_set(dict
, key
, pn
) == false) {
649 prop_object_release(pn
);
653 prop_object_release(pn
);
658 _udev_dict_set_uint(prop_dictionary_t dict
, const char *key
, uint64_t val
)
662 pn
= prop_number_create_unsigned_integer(val
);
666 if (prop_dictionary_set(dict
, key
, pn
) == false) {
667 prop_object_release(pn
);
671 prop_object_release(pn
);
676 conn_local_server(const char *sockfile
, int socktype
, int nonblock
,
680 struct sockaddr_un serv_addr
;
683 if ((s
= socket(AF_UNIX
, socktype
, 0)) < 0)
686 memset(&serv_addr
, 0, sizeof(serv_addr
));
687 serv_addr
.sun_family
= AF_UNIX
;
688 strncpy(serv_addr
.sun_path
, sockfile
, SOCKFILE_NAMELEN
);
689 serv_addr
.sun_path
[SOCKFILE_NAMELEN
- 1] = '\0';
691 if (nonblock
&& unblock_descriptor(s
) < 0) {
697 return connect(s
, (struct sockaddr
*)&serv_addr
, sizeof(serv_addr
));
701 udevd_get_command_dict(char *command
)
703 prop_dictionary_t dict
;
706 dict
= prop_dictionary_create();
710 if ((error
= _udev_dict_set_cstr(dict
, "command", command
)))
716 prop_object_release(dict
);
721 udevd_request_devs(int s
)
724 prop_dictionary_t dict
;
729 dict
= udevd_get_command_dict(__DECONST(char *, "getdevs"));
733 xml
= prop_dictionary_externalize(dict
);
734 prop_object_release(dict
);
738 n
= send_xml(s
, xml
);
744 xml
= malloc(12*1024*1024); /* generous 12 MB */
745 if ((n
= read_xml(s
, xml
, 12*1024*1024)) <= 0) {
751 pa
= prop_array_internalize(xml
);
763 ret
= conn_local_server(LISTEN_SOCKET_FILE
, SOCK_STREAM
, 0, &s
);
765 err(1, "conn_local_server");
767 udevd_request_devs(s
);