1 #include <sys/types.h> 2 #include <sys/device.h> 3 #include <sys/wait.h> 4 #include <sys/socket.h> 5 #include <sys/poll.h> 6 #include <sys/queue.h> 7 #include <sys/un.h> 8 9 #include <err.h> 10 #include <errno.h> 11 #include <fcntl.h> 12 #include <libgen.h> 13 #include <signal.h> 14 #include <stdarg.h> 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 #include <syslog.h> 19 #include <unistd.h> 20 21 #include <libprop/proplib.h> 22 #include <sys/udev.h> 23 24 #define LISTEN_SOCKET_FILE "/tmp/udevd.socket" 25 #define SOCKFILE_NAMELEN strlen(LISTEN_SOCKET_FILE)+1 26 27 int conn_local_server(const char *sockfile, int socktype, int nonblock, 28 int *retsock); 29 prop_dictionary_t udevd_get_command_dict(char *command); 30 void udevd_request_devs(int s); 31 32 struct udev { 33 int gp_fd; 34 int monitor_fd; 35 int refs; 36 37 void *userdata; 38 }; 39 40 struct udev_enumerate { 41 struct udev *udev_ctx; 42 prop_array_t pa; 43 int refs; 44 TAILQ_HEAD(, udev_list_entry) list_entries; 45 }; 46 47 struct udev_list_entry { 48 prop_dictionary_t dict; 49 TAILQ_ENTRY(udev_list_entry) link; 50 }; 51 52 struct udev_monitor { 53 struct udev *udev_ctx; 54 prop_array_t ev_filt; 55 int socket; 56 int user_socket; /* maybe... one day... */ 57 int refs; 58 }; 59 60 struct udev_device { 61 struct udev *udev_ctx; 62 prop_dictionary_t dict; 63 int ev_type; 64 int refs; 65 }; 66 67 struct udev * 68 udev_ref(struct udev *udev_ctx) 69 { 70 atomic_add_int(&udev_ctx->refs, 1); 71 72 return udev_ctx; 73 } 74 75 void 76 udev_unref(struct udev *udev_ctx) 77 { 78 int refcount; 79 80 refcount = atomic_fetchadd_int(&udev_ctx->refs, -1); 81 82 if (refcount == 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); 88 89 free(udev_ctx); 90 } 91 } 92 93 struct udev * 94 udev_new() 95 { 96 struct udev *udev_ctx; 97 98 udev_ctx = malloc(sizeof(struct udev)); 99 100 udev_ctx->refs = 1; 101 udev_ctx->gp_fd = -1; 102 udev_ctx->monitor_fd = -1; 103 udev_ctx->userdata = NULL; 104 105 return udev_ctx; 106 } 107 108 const char *udev_get_dev_path(struct udev *udev_ctx __unused) 109 { 110 return "/dev"; 111 } 112 113 void * 114 udev_get_userdata(struct udev *udev_ctx) 115 { 116 return udev_ctx->userdata; 117 } 118 119 void 120 udev_set_userdata(struct udev *udev_ctx, void *userdata) 121 { 122 udev_ctx->userdata = userdata; 123 } 124 125 struct udev_enumerate * 126 udev_enumerate_new(struct udev *udev_ctx) 127 { 128 struct udev_enumerate *udev_enum; 129 130 udev_enum = malloc(sizeof(struct udev_enumerate)); 131 132 udev_enum->refs = 1; 133 udev_enum->pa = NULL; 134 TAILQ_INIT(&udev_enum->list_entries); 135 udev_enum->udev_ctx = udev_ref(udev_ctx); 136 } 137 138 struct udev_enumerate * 139 udev_enumerate_ref(struct udev_enumerate *udev_enum) 140 { 141 atomic_add_int(&udev_enum->refs, 1); 142 143 return udev_enum; 144 } 145 146 void 147 udev_enumerate_unref(struct udev_enumerate *udev_enum) 148 { 149 struct udev_list_entry *le; 150 int refcount; 151 152 refcount = atomic_fetchadd_int(&udev_enum->refs, -1); 153 154 if (refcount == 1) { 155 atomic_subtract_int(&udev_enum->refs, 0x400); /* in destruction */ 156 if (udev_enum->pa != NULL) 157 prop_object_release(udev_enum->pa); 158 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); 163 free(le); 164 } 165 udev_unref(udev_enum->udev_ctx); 166 free(udev_enum); 167 } 168 } 169 170 struct udev * 171 udev_enumerate_get_udev(struct udev_enumerate *udev_enum) 172 { 173 return udev_enum->udev_ctx; 174 } 175 176 int 177 udev_enumerate_scan_devices(struct udev_enumerate *udev_enum) 178 { 179 prop_array_t pa; 180 181 if (udev_enum->udev_ctx->gp_fd == -1) 182 return -1; 183 184 pa = udevd_request_devs(udev_enum->udev_ctx->gp_fd); 185 if (pa == NULL) 186 return -1; 187 188 prop_object_retain(pa); 189 190 if (udev_enum->pa != NULL) 191 prop_object_release(udev_enum->pa); 192 193 udev_enum->iter = NULL; 194 udev_enum->pa = pa; 195 196 return 0; 197 } 198 199 struct udev_list_entry * 200 udev_enumerate_get_list_entry(struct udev_enumerate *udev_enum) 201 { 202 struct udev_list_entry *le; 203 prop_object_iterator_t iter; 204 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); 208 209 iter = prop_array_iterator(udev_enum->pa); 210 if (iter == NULL) 211 return NULL; 212 213 while ((dict = prop_object_iterator_next(iter)) != NULL) { 214 le = malloc(sizeof(struct udev_list_entry)); 215 if (le == NULL) 216 goto out; 217 218 prop_object_retain(dict); 219 le->dict = dict; 220 TAILQ_INSERT_TAIL(&udev_enum->list_entries, le, link); 221 } 222 223 le = TAILQ_FIRST(&udev_enum->list_entries); 224 225 out: 226 prop_object_iterator_release(iter); 227 return le; 228 } 229 230 prop_array_t 231 udev_enumerate_get_array(struct udev_enumerate *udev_enum) 232 { 233 return udev_enum->pa; 234 } 235 236 struct udev_list_entry * 237 udev_list_entry_get_next(struct udev_list_entry *list_entry) 238 { 239 return TAILQ_NEXT(list_entry, link); 240 } 241 242 prop_dictionary_t 243 udev_list_entry_get_dictionary(struct udev_list_entry *list_entry) 244 { 245 return list_entry->dict; 246 } 247 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)) 252 253 254 255 256 257 258 struct udev_monitor * 259 udev_monitor_new(struct udev *udev_ctx) 260 { 261 struct udev_monitor *udev_monitor; 262 int ret, s; 263 264 ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s); 265 if (ret < 0) 266 return NULL; 267 268 udev_monitor = malloc(sizeof(struct udev_monitor)); 269 if (udev_monitor == NULL) 270 return NULL; 271 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); 277 278 return udev_monitor; 279 } 280 281 282 struct udev_monitor * 283 udev_monitor_ref(struct udev_monitor *udev_monitor) 284 { 285 atomic_add_int(&udev_monitor->refs, 1); 286 287 return udev_monitor; 288 } 289 290 void 291 udev_monitor_unref(struct udev_monitor *udev_monitor) 292 { 293 int refcount; 294 295 refcount = atomic_fetchadd_int(&udev_monitor->refs, -1); 296 297 if (refcount == 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); 301 302 if (udev_monitor->socket != -1) 303 close(udev_monitor->socket); 304 if (udev_monitor->user_socket != -1) 305 close(udev_monitor->user_socket); 306 307 udev_unref(udev_monitor->udev_ctx); 308 free(udev_monitor); 309 } 310 } 311 312 struct udev * 313 udev_monitor_get_udev(struct udev_monitor *udev_monitor) 314 { 315 return udev_monitor->udev_ctx; 316 } 317 318 int 319 udev_monitor_get_fd(struct udev_monitor *udev_monitor) 320 { 321 return udev_monitor->socket; 322 } 323 324 struct udev_device * 325 udev_monitor_receive_device(struct udev_monitor *udev_monitor) 326 { 327 struct udev_device *udev_dev; 328 prop_dictionary_t dict; 329 prop_number_t pn; 330 char *xml; 331 int n, evtype; 332 333 xml = malloc(12*1024*1024); 334 if (xml == NULL) 335 return NULL; 336 337 if ((n = read_xml(udev_monitor->socket, xml, 12*1024*1024)) <= 0) { 338 free(xml); 339 return NULL; 340 } 341 342 xml[n+1] = '\0'; 343 dict = prop_dictionary_internalize(xml); 344 free(xml); 345 if (dict == NULL) 346 return NULL; 347 348 pn = prop_dictionary_get(dict, "evtype"); 349 if (pn == NULL) { 350 prop_object_release(dict); 351 return NULL; 352 } 353 354 udev_dev = malloc(sizeof(struct udev_dev)); 355 if (udev_dev == NULL) { 356 prop_object_release(dict); 357 return NULL; 358 } 359 360 udev_dev->refs = 1; 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) { 364 free(udev_dev); 365 return NULL; 366 } 367 udev_dev->udev_ctx = udev_ref(udev_monitor->udev_ctx); 368 369 out: 370 return udev_dev; 371 } 372 373 int 374 udev_monitor_enable_receiving(struct udev_monitor *udev_monitor) 375 { 376 prop_dictionary_t dict; 377 char *xml; 378 /* ->socket, ->user_socket, ->ev_filt */ 379 380 dict = udevd_get_command_dict(__DECONST(char *, "monitor")); 381 if (dict == NULL) 382 return -1; 383 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); 389 return -1; 390 } 391 } 392 393 xml = prop_dictionary_externalize(dict); 394 prop_object_release(dict); 395 if (xml == NULL) 396 return -1; 397 398 n = send_xml(udev_monitor->socket, xml); 399 free(xml); 400 if (n <= 0) 401 return NULL; 402 403 return 0; 404 } 405 406 int 407 udev_monitor_filter_add_match_subsystem_devtype(struct udev_monitor *udev_monitor, 408 const char *subsystem, 409 const char *devtype __unused) 410 { 411 int ret; 412 413 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 414 EVENT_FILTER_TYPE_WILDCARD, 415 0, 416 "subsystem", 417 subsystem); 418 419 return ret; 420 } 421 422 int 423 udev_monitor_filter_add_match_expr(struct udev_monitor *udev_monitor, 424 const char *key, 425 char *expr) 426 { 427 int ret; 428 429 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 430 EVENT_FILTER_TYPE_WILDCARD, 431 0, 432 key, 433 expr); 434 435 return ret; 436 } 437 438 int 439 udev_monitor_filter_add_nomatch_expr(struct udev_monitor *udev_monitor, 440 const char *key, 441 char *expr) 442 { 443 int ret; 444 445 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 446 EVENT_FILTER_TYPE_WILDCARD, 447 1, 448 key, 449 expr); 450 451 return ret; 452 } 453 454 int 455 udev_monitor_filter_add_match_regex(struct udev_monitor *udev_monitor, 456 const char *key, 457 char *expr) 458 { 459 int ret; 460 461 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 462 EVENT_FILTER_TYPE_REGEX, 463 0, 464 key, 465 expr); 466 467 return ret; 468 } 469 470 int 471 udev_monitor_filter_add_nomatch_regex(struct udev_monitor *udev_monitor, 472 const char *key, 473 char *expr) 474 { 475 int ret; 476 477 ret = _udev_monitor_filter_add_match_gen(udev_monitor, 478 EVENT_FILTER_TYPE_REGEX, 479 1, 480 key, 481 expr); 482 483 return ret; 484 } 485 486 int 487 _udev_monitor_filter_add_match_gen(struct udev_monitor *udev_monitor, 488 int type, 489 int neg, 490 const char *key, 491 char *expr) 492 { 493 prop_array_t pa; 494 prop_dictionary_t dict; 495 int error; 496 497 if (subsystem == NULL) 498 return NULL; 499 500 dict = prop_dictionary_create(); 501 if (dict == NULL) 502 return -1; 503 504 error = _udev_dict_set_cstr(dict, "key", key); 505 if (error != 0) 506 goto error_out; 507 error = _udev_dict_set_int(dict, "type", type); 508 if (error != 0) 509 goto error_out; 510 error = _udev_dict_set_int(dict, "expr", expr); 511 if (error != 0) 512 goto error_out; 513 514 if (neg) { 515 error = _udev_dict_set_int(dict, "negative", 1); 516 if (error != 0) 517 goto error_out; 518 } 519 520 if (udev_monitor->ev_filt == NULL) { 521 pa = prop_array_create(); 522 if (pa == NULL) 523 goto error_out; 524 525 udev_monitor->ev_filt = pa; 526 } 527 528 if (prop_array_add(udev_monitor->ev_filt, dict) == false) 529 goto error_out; 530 531 return 0; 532 533 error_out: 534 prop_object_release(dict); 535 return -1; 536 } 537 538 struct udev_device * 539 udev_device_ref(struct udev_device *udev_device) 540 { 541 atomic_add_int(&udev_device->refs, 1); 542 543 return udev_device; 544 } 545 546 void 547 udev_device_unref(struct udev_device *udev_device) 548 { 549 int refcount; 550 551 refcount = atomic_fetchadd_int(&udev_device->refs, -1); 552 553 if (refcount == 1) { 554 atomic_subtract_int(&udev_device->refs, 0x400); /* in destruction */ 555 if (udev_device->dict != NULL) 556 prop_object_release(udev_device->dict); 557 558 udev_unref(udev_device->udev_ctx); 559 free(udev_device); 560 } 561 } 562 563 prop_dictionary_t 564 udev_device_get_dictionary(struct udev_device *udev_device) 565 { 566 return udev_device->dict; 567 } 568 569 struct udev * 570 udev_device_get_udev(struct udev_device *udev_device) 571 { 572 return udev_device->udev_ctx; 573 } 574 575 int 576 send_xml(int s, char *xml) 577 { 578 ssize_t r,n; 579 size_t sz; 580 581 sz = strlen(xml) + 1; 582 583 r = send(s, &sz, sizeof(sz), 0); 584 if (r <= 0) 585 return r; 586 587 r = 0; 588 while (r < (ssize_t)sz) { 589 n = send(s, xml+r, sz-r, 0); 590 if (n <= 0) 591 return n; 592 r += n; 593 } 594 595 return r; 596 } 597 598 int 599 read_xml(int s, char *buf, size_t buf_sz) 600 { 601 size_t sz; 602 int n, r; 603 604 n = recv(s, &sz, sizeof(sz), MSG_WAITALL); 605 if (n <= 0) 606 return n; 607 608 r = 0; 609 while ((r < (ssize_t)sz) && (r < (ssize_t)buf_sz)) { 610 n = recv(s, buf+r, sz-r, MSG_WAITALL); 611 if (n <= 0) 612 return n; 613 r += n; 614 } 615 616 return r; 617 } 618 619 620 621 static int 622 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str) 623 { 624 prop_string_t ps; 625 626 ps = prop_string_create_cstring(str); 627 if (ps == NULL) 628 return ENOMEM; 629 630 if (prop_dictionary_set(dict, key, ps) == false) { 631 prop_object_release(ps); 632 return ENOMEM; 633 } 634 635 prop_object_release(ps); 636 return 0; 637 } 638 639 static int 640 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val) 641 { 642 prop_number_t pn; 643 644 pn = prop_number_create_integer(val); 645 if (pn == NULL) 646 return ENOMEM; 647 648 if (prop_dictionary_set(dict, key, pn) == false) { 649 prop_object_release(pn); 650 return ENOMEM; 651 } 652 653 prop_object_release(pn); 654 return 0; 655 } 656 657 static int 658 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val) 659 { 660 prop_number_t pn; 661 662 pn = prop_number_create_unsigned_integer(val); 663 if (pn == NULL) 664 return ENOMEM; 665 666 if (prop_dictionary_set(dict, key, pn) == false) { 667 prop_object_release(pn); 668 return ENOMEM; 669 } 670 671 prop_object_release(pn); 672 return 0; 673 } 674 675 int 676 conn_local_server(const char *sockfile, int socktype, int nonblock, 677 int *retsock) 678 { 679 int s; 680 struct sockaddr_un serv_addr; 681 682 *retsock = -1; 683 if ((s = socket(AF_UNIX, socktype, 0)) < 0) 684 return -1; 685 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'; 690 691 if (nonblock && unblock_descriptor(s) < 0) { 692 close(s); 693 return -1; 694 } 695 696 *retsock = s; 697 return connect(s, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); 698 } 699 700 prop_dictionary_t 701 udevd_get_command_dict(char *command) 702 { 703 prop_dictionary_t dict; 704 int error; 705 706 dict = prop_dictionary_create(); 707 if (dict == NULL) 708 return NULL; 709 710 if ((error = _udev_dict_set_cstr(dict, "command", command))) 711 goto error_out; 712 713 return dict; 714 715 error_out: 716 prop_object_release(dict); 717 return NULL; 718 } 719 720 prop_array_t 721 udevd_request_devs(int s) 722 { 723 prop_array_t pa; 724 prop_dictionary_t dict; 725 char *xml; 726 727 int n, t; 728 729 dict = udevd_get_command_dict(__DECONST(char *, "getdevs")); 730 if (dict == NULL) 731 return NULL; 732 733 xml = prop_dictionary_externalize(dict); 734 prop_object_release(dict); 735 if (xml == NULL) 736 return NULL; 737 738 n = send_xml(s, xml); 739 free(xml); 740 741 if (n <= 0) 742 return NULL; 743 744 xml = malloc(12*1024*1024); /* generous 12 MB */ 745 if ((n = read_xml(s, xml, 12*1024*1024)) <= 0) { 746 free(xml); 747 return NULL; 748 } 749 750 xml[n+1] = '\0'; 751 pa = prop_array_internalize(xml); 752 free(xml); 753 return (pa); 754 } 755 756 757 758 int 759 main(void) 760 { 761 int ret, s; 762 763 ret = conn_local_server(LISTEN_SOCKET_FILE, SOCK_STREAM, 0, &s); 764 if (ret < 0) 765 err(1, "conn_local_server"); 766 767 udevd_request_devs(s); 768 769 return 0; 770 } 771