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