1 /* 2 * Copyright (c) 2010 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Alex Hornung <ahornung@gmail.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 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 16 * distribution. 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. 20 * 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 32 * SUCH DAMAGE. 33 */ 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/proc.h> 38 #include <sys/buf.h> 39 #include <sys/conf.h> 40 #include <sys/poll.h> 41 #include <sys/ioccom.h> 42 #include <sys/malloc.h> 43 #include <sys/ctype.h> 44 #include <sys/syslog.h> 45 #include <sys/udev.h> 46 #include <sys/devfs.h> 47 #include <libprop/proplib.h> 48 49 MALLOC_DEFINE(M_UDEV, "udev", "udev allocs"); 50 51 /* XXX: use UUIDs for identification; would need help from devfs */ 52 53 static cdev_t udev_dev; 54 static d_open_t udev_dev_open; 55 static d_close_t udev_dev_close; 56 static d_read_t udev_dev_read; 57 static d_poll_t udev_dev_poll; 58 static d_ioctl_t udev_dev_ioctl; 59 60 static int _udev_dict_set_cstr(prop_dictionary_t, const char *, char *); 61 static int _udev_dict_set_int(prop_dictionary_t, const char *, int64_t); 62 static int _udev_dict_set_uint(prop_dictionary_t, const char *, uint64_t); 63 static int _udev_dict_delete_key(prop_dictionary_t, const char *); 64 static prop_dictionary_t udev_init_dict_event(cdev_t, const char *); 65 static int udev_init_dict(cdev_t); 66 static int udev_destroy_dict(cdev_t); 67 static void udev_event_insert(int, prop_dictionary_t); 68 static struct udev_event_kernel *udev_event_remove(void); 69 static void udev_event_free(struct udev_event_kernel *); 70 static char *udev_event_externalize(struct udev_event_kernel *); 71 static void udev_getdevs_scan_callback(cdev_t, void *); 72 static int udev_getdevs_ioctl(struct plistref *, u_long, prop_dictionary_t); 73 74 struct cmd_function { 75 const char *cmd; 76 int (*fn)(struct plistref *, u_long, prop_dictionary_t); 77 }; 78 79 struct udev_prop_ctx { 80 prop_array_t cdevs; 81 int error; 82 }; 83 84 struct udev_event_kernel { 85 struct udev_event ev; 86 TAILQ_ENTRY(udev_event_kernel) link; 87 }; 88 89 struct udev_softc { 90 int opened; 91 int initiated; 92 93 struct selinfo sel; 94 95 int qlen; 96 struct lock lock; 97 TAILQ_HEAD(, udev_event_kernel) ev_queue; /* list of thread_io */ 98 } udevctx; 99 100 static struct dev_ops udev_dev_ops = { 101 { "udev", 0, 0 }, 102 .d_open = udev_dev_open, 103 .d_close = udev_dev_close, 104 .d_read = udev_dev_read, 105 .d_poll = udev_dev_poll, 106 .d_ioctl = udev_dev_ioctl 107 }; 108 109 static struct cmd_function cmd_fn[] = { 110 { .cmd = "getdevs", .fn = udev_getdevs_ioctl}, 111 {NULL, NULL} 112 }; 113 114 static int 115 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str) 116 { 117 prop_string_t ps; 118 119 KKASSERT(dict != NULL); 120 121 ps = prop_string_create_cstring(str); 122 if (ps == NULL) { 123 return ENOMEM; 124 } 125 126 if (prop_dictionary_set(dict, key, ps) == false) { 127 prop_object_release(ps); 128 return ENOMEM; 129 } 130 131 prop_object_release(ps); 132 return 0; 133 } 134 135 static int 136 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val) 137 { 138 prop_number_t pn; 139 140 KKASSERT(dict != NULL); 141 142 pn = prop_number_create_integer(val); 143 if (pn == NULL) 144 return ENOMEM; 145 146 if (prop_dictionary_set(dict, key, pn) == false) { 147 prop_object_release(pn); 148 return ENOMEM; 149 } 150 151 prop_object_release(pn); 152 return 0; 153 } 154 155 static int 156 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val) 157 { 158 prop_number_t pn; 159 160 KKASSERT(dict != NULL); 161 162 pn = prop_number_create_unsigned_integer(val); 163 if (pn == NULL) 164 return ENOMEM; 165 166 if (prop_dictionary_set(dict, key, pn) == false) { 167 prop_object_release(pn); 168 return ENOMEM; 169 } 170 171 prop_object_release(pn); 172 return 0; 173 } 174 175 static int 176 _udev_dict_delete_key(prop_dictionary_t dict, const char *key) 177 { 178 KKASSERT(dict != NULL); 179 180 prop_dictionary_remove(dict, key); 181 182 return 0; 183 } 184 185 /* 186 * Initialize an event dictionary, which contains three parameters to 187 * identify the device referred to (name, devnum, kptr) and the affected key. 188 */ 189 static prop_dictionary_t 190 udev_init_dict_event(cdev_t dev, const char *key) 191 { 192 prop_dictionary_t dict; 193 uint64_t kptr; 194 int error; 195 196 kptr = (uint64_t)(uintptr_t)dev; 197 KKASSERT(dev != NULL); 198 199 dict = prop_dictionary_create(); 200 if (dict == NULL) { 201 log(LOG_DEBUG, "udev_init_dict_event: prop_dictionary_create() failed\n"); 202 return NULL; 203 } 204 205 if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name))) 206 goto error_out; 207 if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode))) 208 goto error_out; 209 if ((error = _udev_dict_set_uint(dict, "kptr", kptr))) 210 goto error_out; 211 if ((error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key)))) 212 goto error_out; 213 214 return dict; 215 216 error_out: 217 prop_object_release(dict); 218 return NULL; 219 } 220 221 int 222 udev_dict_set_cstr(cdev_t dev, const char *key, char *str) 223 { 224 prop_dictionary_t dict; 225 int error; 226 227 KKASSERT(dev != NULL); 228 229 if (dev->si_dict == NULL) { 230 error = udev_init_dict(dev); 231 if (error) 232 return -1; 233 } 234 235 /* Queue a key update event */ 236 dict = udev_init_dict_event(dev, key); 237 if (dict == NULL) 238 return ENOMEM; 239 240 if ((error = _udev_dict_set_cstr(dict, "value", str))) { 241 prop_object_release(dict); 242 return error; 243 } 244 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 245 prop_object_release(dict); 246 247 error = _udev_dict_set_cstr(dev->si_dict, key, str); 248 return error; 249 } 250 251 int 252 udev_dict_set_int(cdev_t dev, const char *key, int64_t val) 253 { 254 prop_dictionary_t dict; 255 int error; 256 257 KKASSERT(dev != NULL); 258 259 if (dev->si_dict == NULL) { 260 error = udev_init_dict(dev); 261 if (error) 262 return -1; 263 } 264 265 /* Queue a key update event */ 266 dict = udev_init_dict_event(dev, key); 267 if (dict == NULL) 268 return ENOMEM; 269 if ((error = _udev_dict_set_int(dict, "value", val))) { 270 prop_object_release(dict); 271 return error; 272 } 273 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 274 prop_object_release(dict); 275 276 return _udev_dict_set_int(dev->si_dict, key, val); 277 } 278 279 int 280 udev_dict_set_uint(cdev_t dev, const char *key, uint64_t val) 281 { 282 prop_dictionary_t dict; 283 int error; 284 285 KKASSERT(dev != NULL); 286 287 if (dev->si_dict == NULL) { 288 error = udev_init_dict(dev); 289 if (error) 290 return -1; 291 } 292 293 /* Queue a key update event */ 294 dict = udev_init_dict_event(dev, key); 295 if (dict == NULL) 296 return ENOMEM; 297 if ((error = _udev_dict_set_uint(dict, "value", val))) { 298 prop_object_release(dict); 299 return error; 300 } 301 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 302 prop_object_release(dict); 303 304 return _udev_dict_set_uint(dev->si_dict, key, val); 305 } 306 307 int 308 udev_dict_delete_key(cdev_t dev, const char *key) 309 { 310 prop_dictionary_t dict; 311 312 KKASSERT(dev != NULL); 313 314 /* Queue a key removal event */ 315 dict = udev_init_dict_event(dev, key); 316 if (dict == NULL) 317 return ENOMEM; 318 udev_event_insert(UDEV_EV_KEY_REMOVE, dict); 319 prop_object_release(dict); 320 321 return _udev_dict_delete_key(dev->si_dict, key); 322 } 323 324 static int 325 udev_init_dict(cdev_t dev) 326 { 327 prop_dictionary_t dict; 328 uint64_t kptr; 329 int error; 330 331 kptr = (uint64_t)(uintptr_t)dev; 332 333 KKASSERT(dev != NULL); 334 335 if (dev->si_dict != NULL) { 336 #if 0 337 log(LOG_DEBUG, 338 "udev_init_dict: new dict for %s, but has dict already (%p)!\n", 339 dev->si_name, dev->si_dict); 340 #endif 341 return 0; 342 } 343 344 dict = prop_dictionary_create(); 345 if (dict == NULL) { 346 log(LOG_DEBUG, "udev_init_dict: prop_dictionary_create() failed\n"); 347 return ENOMEM; 348 } 349 350 if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name))) 351 goto error_out; 352 if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode))) 353 goto error_out; 354 if ((error = _udev_dict_set_uint(dict, "kptr", kptr))) 355 goto error_out; 356 357 /* XXX: The next 3 are marginallly useful, if at all */ 358 if ((error = _udev_dict_set_uint(dict, "uid", dev->si_uid))) 359 goto error_out; 360 if ((error = _udev_dict_set_uint(dict, "gid", dev->si_gid))) 361 goto error_out; 362 if ((error = _udev_dict_set_int(dict, "mode", dev->si_perms))) 363 goto error_out; 364 365 if ((error = _udev_dict_set_int(dict, "major", umajor(dev->si_inode)))) 366 goto error_out; 367 if ((error = _udev_dict_set_int(dict, "minor", dev->si_uminor))) 368 goto error_out; 369 if (dev->si_ops->head.name != NULL) { 370 if ((error = _udev_dict_set_cstr(dict, "driver", 371 __DECONST(char *, dev->si_ops->head.name)))) 372 goto error_out; 373 } 374 375 dev->si_dict = dict; 376 return 0; 377 378 error_out: 379 dev->si_dict = NULL; 380 prop_object_release(dict); 381 return error; 382 } 383 384 static int 385 udev_destroy_dict(cdev_t dev) 386 { 387 KKASSERT(dev != NULL); 388 389 if (dev->si_dict != NULL) { 390 prop_object_release(dev->si_dict); 391 dev->si_dict = NULL; 392 } 393 394 return 0; 395 } 396 397 static void 398 udev_event_insert(int ev_type, prop_dictionary_t dict) 399 { 400 struct udev_event_kernel *ev; 401 402 /* Only start queing events after client has initiated properly */ 403 if (!udevctx.initiated) 404 return; 405 406 /* XXX: use objcache eventually */ 407 ev = kmalloc(sizeof(*ev), M_UDEV, M_WAITOK); 408 ev->ev.ev_dict = prop_dictionary_copy(dict); 409 if (ev->ev.ev_dict == NULL) { 410 kfree(ev, M_UDEV); 411 return; 412 } 413 ev->ev.ev_type = ev_type; 414 415 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 416 TAILQ_INSERT_TAIL(&udevctx.ev_queue, ev, link); 417 ++udevctx.qlen; 418 lockmgr(&udevctx.lock, LK_RELEASE); 419 420 wakeup(&udevctx); 421 selwakeup(&udevctx.sel); 422 } 423 424 static struct udev_event_kernel * 425 udev_event_remove(void) 426 { 427 struct udev_event_kernel *ev; 428 429 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 430 if (TAILQ_EMPTY(&udevctx.ev_queue)) { 431 lockmgr(&udevctx.lock, LK_RELEASE); 432 return NULL; 433 } 434 435 ev = TAILQ_FIRST(&udevctx.ev_queue); 436 TAILQ_REMOVE(&udevctx.ev_queue, ev, link); 437 --udevctx.qlen; 438 lockmgr(&udevctx.lock, LK_RELEASE); 439 440 return ev; 441 } 442 443 static void 444 udev_event_free(struct udev_event_kernel *ev) 445 { 446 /* XXX: use objcache eventually */ 447 kfree(ev, M_UDEV); 448 } 449 450 static char * 451 udev_event_externalize(struct udev_event_kernel *ev) 452 { 453 prop_dictionary_t dict; 454 char *xml; 455 int error; 456 457 458 dict = prop_dictionary_create(); 459 if (dict == NULL) { 460 log(LOG_DEBUG, "udev_event_externalize: prop_dictionary_create() failed\n"); 461 return NULL; 462 } 463 464 if ((error = _udev_dict_set_int(dict, "evtype", ev->ev.ev_type))) { 465 prop_object_release(dict); 466 return NULL; 467 } 468 469 if (prop_dictionary_set(dict, "evdict", ev->ev.ev_dict) == false) { 470 prop_object_release(dict); 471 return NULL; 472 } 473 474 prop_object_release(ev->ev.ev_dict); 475 476 xml = prop_dictionary_externalize(dict); 477 478 prop_object_release(dict); 479 480 return xml; 481 } 482 483 int 484 udev_event_attach(cdev_t dev, char *name, int alias) 485 { 486 prop_dictionary_t dict; 487 int error; 488 489 KKASSERT(dev != NULL); 490 491 error = ENOMEM; 492 493 if (alias) { 494 dict = prop_dictionary_copy(dev->si_dict); 495 if (dict == NULL) 496 goto error_out; 497 498 if ((error = _udev_dict_set_cstr(dict, "name", name))) { 499 prop_object_release(dict); 500 goto error_out; 501 } 502 503 _udev_dict_set_int(dict, "alias", 1); 504 505 udev_event_insert(UDEV_EVENT_ATTACH, dict); 506 prop_object_release(dict); 507 } else { 508 error = udev_init_dict(dev); 509 if (error) 510 goto error_out; 511 512 _udev_dict_set_int(dev->si_dict, "alias", 0); 513 udev_event_insert(UDEV_EVENT_ATTACH, dev->si_dict); 514 } 515 516 error_out: 517 return error; 518 } 519 520 int 521 udev_event_detach(cdev_t dev, char *name, int alias) 522 { 523 prop_dictionary_t dict; 524 525 KKASSERT(dev != NULL); 526 527 if (alias) { 528 dict = prop_dictionary_copy(dev->si_dict); 529 if (dict == NULL) 530 goto error_out; 531 532 if (_udev_dict_set_cstr(dict, "name", name)) { 533 prop_object_release(dict); 534 goto error_out; 535 } 536 537 _udev_dict_set_int(dict, "alias", 1); 538 539 udev_event_insert(UDEV_EVENT_DETACH, dict); 540 prop_object_release(dict); 541 } else { 542 udev_event_insert(UDEV_EVENT_DETACH, dev->si_dict); 543 } 544 545 error_out: 546 udev_destroy_dict(dev); 547 548 return 0; 549 } 550 551 /* 552 * dev stuff 553 */ 554 static int 555 udev_dev_open(struct dev_open_args *ap) 556 { 557 if (udevctx.opened) 558 return EBUSY; 559 560 udevctx.opened = 1; 561 562 return 0; 563 } 564 565 static int 566 udev_dev_close(struct dev_close_args *ap) 567 { 568 udevctx.opened = 0; 569 udevctx.initiated = 0; 570 wakeup(&udevctx); 571 572 return 0; 573 } 574 575 static int 576 udev_dev_poll(struct dev_poll_args *ap) 577 { 578 int revents = 0; 579 580 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 581 if (ap->a_events & (POLLIN | POLLRDNORM)) { 582 if (!TAILQ_EMPTY(&udevctx.ev_queue)) 583 revents = ap->a_events & (POLLIN | POLLRDNORM); 584 else 585 selrecord(curthread, &udevctx.sel); 586 } 587 lockmgr(&udevctx.lock, LK_RELEASE); 588 589 ap->a_events = revents; 590 return 0; 591 } 592 593 static int 594 udev_dev_read(struct dev_read_args *ap) 595 { 596 struct udev_event_kernel *ev; 597 struct uio *uio = ap->a_uio; 598 char *xml; 599 size_t len; 600 int error; 601 602 603 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 604 605 for (;;) { 606 if ((ev = udev_event_remove()) != NULL) { 607 if ((xml = udev_event_externalize(ev)) == NULL) { 608 lockmgr(&udevctx.lock, LK_RELEASE); 609 return ENOMEM; 610 } 611 612 len = strlen(xml) + 1; /* account for NULL-termination */ 613 if (uio->uio_resid < len) { 614 error = ENOMEM; 615 } else { 616 error = uiomove((caddr_t)xml, len, uio); 617 } 618 619 kfree(xml, M_TEMP); 620 udev_event_free(ev); 621 lockmgr(&udevctx.lock, LK_RELEASE); 622 return error; 623 } 624 625 if ((error = lksleep(&udevctx, &udevctx.lock, 0, "udevq", 0))) { 626 lockmgr(&udevctx.lock, LK_RELEASE); 627 return error; 628 } 629 } 630 631 lockmgr(&udevctx.lock, LK_RELEASE); 632 633 } 634 635 static int 636 udev_dev_ioctl(struct dev_ioctl_args *ap) 637 { 638 prop_dictionary_t dict; 639 prop_object_t po; 640 prop_string_t ps; 641 struct plistref *pref; 642 int i, error; 643 644 error = 0; 645 646 switch(ap->a_cmd) { 647 case UDEVPROP: 648 /* Use proplib(3) for userspace/kernel communication */ 649 pref = (struct plistref *)ap->a_data; 650 error = prop_dictionary_copyin_ioctl(pref, ap->a_cmd, &dict); 651 if (error) 652 return error; 653 654 po = prop_dictionary_get(dict, "command"); 655 if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) { 656 log(LOG_DEBUG, "udev: prop_dictionary_get() failed\n"); 657 prop_object_release(dict); 658 return EINVAL; 659 } 660 661 ps = po; 662 /* Handle cmd */ 663 for(i = 0; cmd_fn[i].cmd != NULL; i++) { 664 if (prop_string_equals_cstring(ps, cmd_fn[i].cmd)) 665 break; 666 } 667 668 if (cmd_fn[i].cmd != NULL) { 669 error = cmd_fn[i].fn(pref, ap->a_cmd, dict); 670 } else { 671 error = EINVAL; 672 } 673 674 //prop_object_release(po); 675 prop_object_release(dict); 676 break; 677 default: 678 error = ENOTTY; /* Inappropriate ioctl for device */ 679 break; 680 } 681 682 return(error); 683 } 684 685 static void 686 udev_getdevs_scan_callback(cdev_t cdev, void *arg) 687 { 688 struct udev_prop_ctx *ctx = arg; 689 690 KKASSERT(arg != NULL); 691 692 if (cdev->si_dict == NULL) 693 return; 694 695 if (prop_array_add(ctx->cdevs, cdev->si_dict) == false) { 696 ctx->error = EINVAL; 697 return; 698 } 699 } 700 701 static int 702 udev_getdevs_ioctl(struct plistref *pref, u_long cmd, prop_dictionary_t dict) 703 { 704 prop_dictionary_t odict; 705 struct udev_prop_ctx ctx; 706 int error; 707 708 ctx.error = 0; 709 ctx.cdevs = prop_array_create(); 710 if (ctx.cdevs == NULL) { 711 log(LOG_DEBUG, "udev_getdevs_ioctl: prop_array_create() failed\n"); 712 return EINVAL; 713 } 714 715 /* XXX: need devfs_scan_alias_callback() */ 716 devfs_scan_callback(udev_getdevs_scan_callback, &ctx); 717 718 if (ctx.error != 0) { 719 prop_object_release(ctx.cdevs); 720 return (ctx.error); 721 } 722 udevctx.initiated = 1; 723 724 odict = prop_dictionary_create(); 725 if (odict == NULL) { 726 return ENOMEM; 727 } 728 729 if ((prop_dictionary_set(odict, "array", ctx.cdevs)) == 0) { 730 log(LOG_DEBUG, "udev_getdevs_ioctl: prop_dictionary_set failed\n"); 731 prop_object_release(odict); 732 return ENOMEM; 733 } 734 735 error = prop_dictionary_copyout_ioctl(pref, cmd, odict); 736 737 prop_object_release(odict); 738 return error; 739 } 740 741 742 /* 743 * SYSINIT stuff 744 */ 745 static void 746 udev_init(void) 747 { 748 lockinit(&udevctx.lock, "udevevq", 0, LK_CANRECURSE); 749 TAILQ_INIT(&udevctx.ev_queue); 750 } 751 752 static void 753 udev_uninit(void) 754 { 755 } 756 757 static void 758 udev_dev_init(void) 759 { 760 udev_dev = make_dev(&udev_dev_ops, 761 0, 762 UID_ROOT, 763 GID_WHEEL, 764 0600, 765 "udev"); 766 } 767 768 static void 769 udev_dev_uninit(void) 770 { 771 destroy_dev(udev_dev); 772 } 773 774 SYSINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY, udev_init, NULL); 775 SYSUNINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY, udev_uninit, NULL); 776 SYSINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY, udev_dev_init, NULL); 777 SYSUNINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY, udev_dev_uninit, NULL); 778