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 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 if (prop_dictionary_set(dict, key, ps) == false) { 126 prop_object_release(ps); 127 return ENOMEM; 128 } 129 130 prop_object_release(ps); 131 return 0; 132 } 133 134 static int 135 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val) 136 { 137 prop_number_t pn; 138 139 KKASSERT(dict != NULL); 140 141 pn = prop_number_create_integer(val); 142 if (pn == NULL) 143 return ENOMEM; 144 145 if (prop_dictionary_set(dict, key, pn) == false) { 146 prop_object_release(pn); 147 return ENOMEM; 148 } 149 150 prop_object_release(pn); 151 return 0; 152 } 153 154 static int 155 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val) 156 { 157 prop_number_t pn; 158 159 KKASSERT(dict != NULL); 160 161 pn = prop_number_create_unsigned_integer(val); 162 if (pn == NULL) 163 return ENOMEM; 164 165 if (prop_dictionary_set(dict, key, pn) == false) { 166 prop_object_release(pn); 167 return ENOMEM; 168 } 169 170 prop_object_release(pn); 171 return 0; 172 } 173 174 static int 175 _udev_dict_delete_key(prop_dictionary_t dict, const char *key) 176 { 177 KKASSERT(dict != NULL); 178 179 prop_dictionary_remove(dict, key); 180 181 return 0; 182 } 183 184 /* 185 * Initialize an event dictionary, which contains three parameters to 186 * identify the device referred to (name, devnum, kptr) and the affected key. 187 */ 188 static prop_dictionary_t 189 udev_init_dict_event(cdev_t dev, const char *key) 190 { 191 prop_dictionary_t dict; 192 uint64_t kptr; 193 int error; 194 195 kptr = (uint64_t)(uintptr_t)dev; 196 KKASSERT(dev != NULL); 197 198 dict = prop_dictionary_create(); 199 if (dict == NULL) { 200 log(LOG_DEBUG, "udev_init_dict_event: prop_dictionary_create() failed\n"); 201 return NULL; 202 } 203 204 if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name))) 205 goto error_out; 206 if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode))) 207 goto error_out; 208 if ((error = _udev_dict_set_uint(dict, "kptr", kptr))) 209 goto error_out; 210 if ((error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key)))) 211 goto error_out; 212 213 error_out: 214 prop_object_release(dict); 215 return NULL; 216 } 217 218 int 219 udev_dict_set_cstr(cdev_t dev, const char *key, char *str) 220 { 221 prop_dictionary_t dict; 222 int error; 223 224 KKASSERT(dev != NULL); 225 226 /* Queue a key update event */ 227 dict = udev_init_dict_event(dev, key); 228 if (dict == NULL) 229 return ENOMEM; 230 if ((error = _udev_dict_set_cstr(dict, "value", str))) { 231 prop_object_release(dict); 232 return error; 233 } 234 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 235 prop_object_release(dict); 236 237 return _udev_dict_set_cstr(dev->si_dict, key, str); 238 } 239 240 int 241 udev_dict_set_int(cdev_t dev, const char *key, int64_t val) 242 { 243 prop_dictionary_t dict; 244 int error; 245 246 KKASSERT(dev != NULL); 247 248 /* Queue a key update event */ 249 dict = udev_init_dict_event(dev, key); 250 if (dict == NULL) 251 return ENOMEM; 252 if ((error = _udev_dict_set_int(dict, "value", val))) { 253 prop_object_release(dict); 254 return error; 255 } 256 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 257 prop_object_release(dict); 258 259 return _udev_dict_set_int(dev->si_dict, key, val); 260 } 261 262 int 263 udev_dict_set_uint(cdev_t dev, const char *key, uint64_t val) 264 { 265 prop_dictionary_t dict; 266 int error; 267 268 KKASSERT(dev != NULL); 269 270 /* Queue a key update event */ 271 dict = udev_init_dict_event(dev, key); 272 if (dict == NULL) 273 return ENOMEM; 274 if ((error = _udev_dict_set_uint(dict, "value", val))) { 275 prop_object_release(dict); 276 return error; 277 } 278 udev_event_insert(UDEV_EV_KEY_UPDATE, dict); 279 prop_object_release(dict); 280 281 return _udev_dict_set_uint(dev->si_dict, key, val); 282 } 283 284 int 285 udev_dict_delete_key(cdev_t dev, const char *key) 286 { 287 prop_dictionary_t dict; 288 289 KKASSERT(dev != NULL); 290 291 /* Queue a key removal event */ 292 dict = udev_init_dict_event(dev, key); 293 if (dict == NULL) 294 return ENOMEM; 295 udev_event_insert(UDEV_EV_KEY_REMOVE, dict); 296 prop_object_release(dict); 297 298 return _udev_dict_delete_key(dev->si_dict, key); 299 } 300 301 static int 302 udev_init_dict(cdev_t dev) 303 { 304 prop_dictionary_t dict; 305 uint64_t kptr; 306 int error; 307 308 kptr = (uint64_t)(uintptr_t)dev; 309 310 KKASSERT(dev != NULL); 311 dict = prop_dictionary_create(); 312 if (dict == NULL) { 313 log(LOG_DEBUG, "udev_init_dict: prop_dictionary_create() failed\n"); 314 return ENOMEM; 315 } 316 317 if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name))) 318 goto error_out; 319 if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode))) 320 goto error_out; 321 if ((error = _udev_dict_set_uint(dict, "kptr", kptr))) 322 goto error_out; 323 324 /* XXX: The next 3 are marginallly useful, if at all */ 325 if ((error = _udev_dict_set_uint(dict, "uid", dev->si_uid))) 326 goto error_out; 327 if ((error = _udev_dict_set_uint(dict, "gid", dev->si_gid))) 328 goto error_out; 329 if ((error = _udev_dict_set_int(dict, "mode", dev->si_perms))) 330 goto error_out; 331 332 if ((error = _udev_dict_set_int(dict, "major", umajor(dev->si_inode)))) 333 goto error_out; 334 if ((error = _udev_dict_set_int(dict, "minor", dev->si_uminor))) 335 goto error_out; 336 337 dev->si_dict = dict; 338 return 0; 339 340 error_out: 341 dev->si_dict = NULL; 342 prop_object_release(dict); 343 return error; 344 } 345 346 static int 347 udev_destroy_dict(cdev_t dev) 348 { 349 KKASSERT(dev != NULL); 350 351 if (dev->si_dict != NULL) { 352 prop_object_release(dev->si_dict); 353 dev->si_dict = NULL; 354 } 355 356 return 0; 357 } 358 359 static void 360 udev_event_insert(int ev_type, prop_dictionary_t dict) 361 { 362 struct udev_event_kernel *ev; 363 364 /* Only start queing events after client has initiated properly */ 365 if (!udevctx.initiated) 366 return; 367 368 /* XXX: use objcache eventually */ 369 ev = kmalloc(sizeof(*ev), M_UDEV, M_WAITOK); 370 ev->ev.ev_dict = prop_dictionary_copy(dict); 371 if (ev->ev.ev_dict == NULL) { 372 kfree(ev, M_UDEV); 373 return; 374 } 375 ev->ev.ev_type = ev_type; 376 377 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 378 TAILQ_INSERT_TAIL(&udevctx.ev_queue, ev, link); 379 ++udevctx.qlen; 380 lockmgr(&udevctx.lock, LK_RELEASE); 381 382 wakeup(&udevctx); 383 selwakeup(&udevctx.sel); 384 } 385 386 static struct udev_event_kernel * 387 udev_event_remove(void) 388 { 389 struct udev_event_kernel *ev; 390 391 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 392 if (TAILQ_EMPTY(&udevctx.ev_queue)) { 393 lockmgr(&udevctx.lock, LK_RELEASE); 394 return NULL; 395 } 396 397 ev = TAILQ_FIRST(&udevctx.ev_queue); 398 TAILQ_REMOVE(&udevctx.ev_queue, ev, link); 399 --udevctx.qlen; 400 lockmgr(&udevctx.lock, LK_RELEASE); 401 402 return ev; 403 } 404 405 static void 406 udev_event_free(struct udev_event_kernel *ev) 407 { 408 /* XXX: use objcache eventually */ 409 kfree(ev, M_UDEV); 410 } 411 412 static char * 413 udev_event_externalize(struct udev_event_kernel *ev) 414 { 415 prop_dictionary_t dict; 416 char *xml; 417 int error; 418 419 420 dict = prop_dictionary_create(); 421 if (dict == NULL) { 422 log(LOG_DEBUG, "udev_event_externalize: prop_dictionary_create() failed\n"); 423 return NULL; 424 } 425 426 if ((error = _udev_dict_set_int(dict, "evtype", ev->ev.ev_type))) { 427 prop_object_release(dict); 428 return NULL; 429 } 430 431 if (prop_dictionary_set(dict, "evdict", ev->ev.ev_dict) == false) { 432 prop_object_release(dict); 433 return NULL; 434 } 435 436 prop_object_release(ev->ev.ev_dict); 437 438 xml = prop_dictionary_externalize(dict); 439 440 prop_object_release(dict); 441 442 return xml; 443 } 444 445 int 446 udev_event_attach(cdev_t dev, char *name, int alias) 447 { 448 prop_dictionary_t dict; 449 int error; 450 451 KKASSERT(dev != NULL); 452 453 error = udev_init_dict(dev); 454 if (error) 455 goto error_out; 456 457 if (alias) { 458 dict = prop_dictionary_copy(dev->si_dict); 459 if (dict == NULL) 460 goto error_out; 461 462 if ((error = _udev_dict_set_cstr(dict, "name", name))) { 463 prop_object_release(dict); 464 goto error_out; 465 } 466 467 _udev_dict_set_int(dict, "alias", 1); 468 469 udev_event_insert(UDEV_EVENT_ATTACH, dict); 470 prop_object_release(dict); 471 } else { 472 _udev_dict_set_int(dev->si_dict, "alias", 0); 473 udev_event_insert(UDEV_EVENT_ATTACH, dev->si_dict); 474 } 475 476 error_out: 477 return error; 478 } 479 480 int 481 udev_event_detach(cdev_t dev, char *name, int alias) 482 { 483 prop_dictionary_t dict; 484 485 KKASSERT(dev != NULL); 486 487 if (alias) { 488 dict = prop_dictionary_copy(dev->si_dict); 489 if (dict == NULL) 490 goto error_out; 491 492 if (_udev_dict_set_cstr(dict, "name", name)) { 493 prop_object_release(dict); 494 goto error_out; 495 } 496 497 _udev_dict_set_int(dict, "alias", 1); 498 499 udev_event_insert(UDEV_EVENT_DETACH, dict); 500 prop_object_release(dict); 501 } else { 502 udev_event_insert(UDEV_EVENT_DETACH, dev->si_dict); 503 } 504 505 error_out: 506 udev_destroy_dict(dev); 507 508 return 0; 509 } 510 511 /* 512 * dev stuff 513 */ 514 static int 515 udev_dev_open(struct dev_open_args *ap) 516 { 517 if (udevctx.opened) 518 return EBUSY; 519 520 udevctx.opened = 1; 521 522 return 0; 523 } 524 525 static int 526 udev_dev_close(struct dev_close_args *ap) 527 { 528 udevctx.opened = 0; 529 udevctx.initiated = 0; 530 wakeup(&udevctx); 531 532 return 0; 533 } 534 535 static int 536 udev_dev_poll(struct dev_poll_args *ap) 537 { 538 int revents = 0; 539 540 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 541 if (ap->a_events & (POLLIN | POLLRDNORM)) { 542 if (!TAILQ_EMPTY(&udevctx.ev_queue)) 543 revents = ap->a_events & (POLLIN | POLLRDNORM); 544 else 545 selrecord(curthread, &udevctx.sel); 546 } 547 lockmgr(&udevctx.lock, LK_RELEASE); 548 549 ap->a_events = revents; 550 return 0; 551 } 552 553 static int 554 udev_dev_read(struct dev_read_args *ap) 555 { 556 struct udev_event_kernel *ev; 557 struct uio *uio = ap->a_uio; 558 char *xml; 559 size_t len; 560 int error; 561 562 563 lockmgr(&udevctx.lock, LK_EXCLUSIVE); 564 565 for (;;) { 566 if ((ev = udev_event_remove()) != NULL) { 567 if ((xml = udev_event_externalize(ev)) == NULL) { 568 lockmgr(&udevctx.lock, LK_RELEASE); 569 return ENOMEM; 570 } 571 572 len = strlen(xml) + 1; /* account for NULL-termination */ 573 if (uio->uio_resid < len) { 574 error = ENOMEM; 575 } else { 576 error = uiomove((caddr_t)xml, len, uio); 577 } 578 579 kfree(xml, M_TEMP); 580 udev_event_free(ev); 581 lockmgr(&udevctx.lock, LK_RELEASE); 582 return error; 583 } 584 585 if ((error = lksleep(&udevctx, &udevctx.lock, 0, "udevq", 0))) { 586 lockmgr(&udevctx.lock, LK_RELEASE); 587 return error; 588 } 589 } 590 591 lockmgr(&udevctx.lock, LK_RELEASE); 592 593 } 594 595 static int 596 udev_dev_ioctl(struct dev_ioctl_args *ap) 597 { 598 prop_dictionary_t dict; 599 prop_object_t po; 600 prop_string_t ps; 601 struct plistref *pref; 602 int i, error; 603 604 error = 0; 605 606 switch(ap->a_cmd) { 607 case UDEVPROP: 608 /* Use proplib(3) for userspace/kernel communication */ 609 pref = (struct plistref *)ap->a_data; 610 error = prop_dictionary_copyin_ioctl(pref, ap->a_cmd, &dict); 611 if (error) 612 return error; 613 614 po = prop_dictionary_get(dict, "command"); 615 if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) { 616 log(LOG_DEBUG, "udev: prop_dictionary_get() failed\n"); 617 prop_object_release(dict); 618 return EINVAL; 619 } 620 621 ps = po; 622 /* Handle cmd */ 623 for(i = 0; cmd_fn[i].cmd != NULL; i++) { 624 if (prop_string_equals_cstring(ps, cmd_fn[i].cmd)) 625 break; 626 } 627 628 if (cmd_fn[i].cmd != NULL) { 629 log(LOG_DEBUG, "udev: ioctl %s called\n", cmd_fn[i].cmd); 630 error = cmd_fn[i].fn(pref, ap->a_cmd, dict); 631 } else { 632 error = EINVAL; 633 } 634 635 //prop_object_release(po); 636 kprintf("foo\n"); 637 prop_object_release(dict); 638 break; 639 default: 640 error = ENOTTY; /* Inappropriate ioctl for device */ 641 break; 642 } 643 644 return(error); 645 } 646 647 static void 648 udev_getdevs_scan_callback(cdev_t cdev, void *arg) 649 { 650 struct udev_prop_ctx *ctx = arg; 651 652 KKASSERT(arg != NULL); 653 654 if (cdev->si_dict == NULL) 655 return; 656 657 if (prop_array_add(ctx->cdevs, cdev->si_dict) == false) { 658 ctx->error = EINVAL; 659 return; 660 } 661 } 662 663 static int 664 udev_getdevs_ioctl(struct plistref *pref, u_long cmd, prop_dictionary_t dict) 665 { 666 prop_dictionary_t odict; 667 struct udev_prop_ctx ctx; 668 int error; 669 670 ctx.error = 0; 671 ctx.cdevs = prop_array_create(); 672 if (ctx.cdevs == NULL) { 673 log(LOG_DEBUG, "udev_getdevs_ioctl: prop_array_create() failed\n"); 674 return EINVAL; 675 } 676 677 /* XXX: need devfs_scan_alias_callback() */ 678 devfs_scan_callback(udev_getdevs_scan_callback, &ctx); 679 680 if (ctx.error != 0) { 681 prop_object_release(ctx.cdevs); 682 return (ctx.error); 683 } 684 udevctx.initiated = 1; 685 686 odict = prop_dictionary_create(); 687 if (odict == NULL) { 688 return ENOMEM; 689 } 690 691 if ((prop_dictionary_set(odict, "array", ctx.cdevs)) == 0) { 692 log(LOG_DEBUG, "udev_getdevs_ioctl: prop_dictionary_set failed\n"); 693 prop_object_release(odict); 694 return ENOMEM; 695 } 696 697 error = prop_dictionary_copyout_ioctl(pref, cmd, odict); 698 699 /* XXX: need to release ctx.cdevs? */ 700 prop_object_release(odict); 701 return error; 702 } 703 704 705 /* 706 * SYSINIT stuff 707 */ 708 static void 709 udev_init(void) 710 { 711 lockinit(&udevctx.lock, "udevevq", 0, LK_CANRECURSE); 712 TAILQ_INIT(&udevctx.ev_queue); 713 } 714 715 static void 716 udev_uninit(void) 717 { 718 } 719 720 static void 721 udev_dev_init(void) 722 { 723 udev_dev = make_dev(&udev_dev_ops, 724 0, 725 UID_ROOT, 726 GID_WHEEL, 727 0600, 728 "udev"); 729 } 730 731 static void 732 udev_dev_uninit(void) 733 { 734 destroy_dev(udev_dev); 735 } 736 737 SYSINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY, udev_init, NULL); 738 SYSUNINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY, udev_uninit, NULL); 739 SYSINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY, udev_dev_init, NULL); 740 SYSUNINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY, udev_dev_uninit, NULL); 741