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