xref: /dragonfly/sys/kern/kern_udev.c (revision 3d33658b)
1 /*
2  * Copyright (c) 2010,2018 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/vnode.h>
42 #include <sys/malloc.h>
43 #include <sys/objcache.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 MALLOC_DEFINE(M_UDEV, "udev", "udev allocs");
51 static struct objcache *udev_event_kernel_cache;
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 static d_clone_t	udev_dev_clone;
62 
63 struct udev_prop_ctx {
64 	prop_array_t cdevs;
65 	int error;
66 };
67 
68 struct udev_event_kernel {
69 	struct udev_event ev;
70 	TAILQ_ENTRY(udev_event_kernel)	link;
71 };
72 
73 struct udev_softc {
74 	TAILQ_ENTRY(udev_softc) entry;
75 	int opened;
76 	int initiated;
77 	int unit;
78 	cdev_t dev;
79 
80 	struct udev_event_kernel marker;	/* udev_evq marker */
81 };
82 
83 struct cmd_function {
84 	const char *cmd;
85 	int  (*fn)(struct udev_softc *, struct plistref *,
86 		   u_long, prop_dictionary_t);
87 };
88 
89 static int _udev_dict_set_cstr(prop_dictionary_t, const char *, char *);
90 static int _udev_dict_set_int(prop_dictionary_t, const char *, int64_t);
91 static int _udev_dict_set_uint(prop_dictionary_t, const char *, uint64_t);
92 static int _udev_dict_delete_key(prop_dictionary_t, const char *);
93 static prop_dictionary_t udev_init_dict_event(cdev_t, const char *);
94 static int udev_init_dict(cdev_t);
95 static int udev_destroy_dict(cdev_t);
96 static void udev_event_insert(int, prop_dictionary_t);
97 static void udev_clean_events_locked(void);
98 static char *udev_event_externalize(struct udev_event_kernel *);
99 static void udev_getdevs_scan_callback(char *, cdev_t, bool, void *);
100 static int udev_getdevs_ioctl(struct udev_softc *, struct plistref *,
101 					u_long, prop_dictionary_t);
102 static void udev_dev_filter_detach(struct knote *);
103 static int udev_dev_filter_read(struct knote *, long);
104 
105 static struct dev_ops udev_dev_ops = {
106 	{ "udev", 0, 0 },
107 	.d_open = udev_dev_open,
108 	.d_close = udev_dev_close,
109 	.d_read = udev_dev_read,
110 	.d_kqfilter = udev_dev_kqfilter,
111 	.d_ioctl = udev_dev_ioctl
112 };
113 
114 static struct cmd_function cmd_fn[] = {
115 		{ .cmd = "getdevs", .fn = udev_getdevs_ioctl},
116 		{NULL, NULL}
117 };
118 
119 DEVFS_DEFINE_CLONE_BITMAP(udev);
120 
121 static TAILQ_HEAD(, udev_softc) udevq;
122 static TAILQ_HEAD(, udev_event_kernel) udev_evq;
123 static struct kqinfo udev_kq;
124 static struct lock udev_lk;
125 static int udev_evqlen;
126 static int udev_initiated_count;
127 static int udev_open_count;
128 static int udev_seqwait;
129 static int udev_seq;
130 static struct lock udev_dict_lk = LOCK_INITIALIZER("dict", 0, 0);
131 
132 /*
133  * Acquire the device's si_dict and lock the device's si_dict field.
134  * If the device does not have an attached dictionary, NULL is returned.
135  *
136  * This function must be matched by a udev_put_dict() call regardless of
137  * the return value.  The device field is STILL LOCKED even when NULL is
138  * returned.
139  *
140  * Currently a single global lock is implemented.
141  */
142 static prop_dictionary_t
143 udev_get_dict(cdev_t dev)
144 {
145 	prop_dictionary_t udict;
146 
147 	lockmgr(&udev_dict_lk, LK_EXCLUSIVE|LK_CANRECURSE);
148 	udict = dev->si_dict;
149 	if (udict)
150 		prop_object_retain(udict);
151 	return udict;
152 }
153 
154 /*
155  * Release the dictionary previously returned by udev_get_dict() and unlock
156  * the device's si_dict field.  udict may be NULL.
157  */
158 static void
159 udev_put_dict(cdev_t dev, prop_dictionary_t udict)
160 {
161 	if (udict)
162 		prop_object_release(udict);
163 	lockmgr(&udev_dict_lk, LK_RELEASE);
164 }
165 
166 static int
167 _udev_dict_set_cstr(prop_dictionary_t dict, const char *key, char *str)
168 {
169 	prop_string_t	ps;
170 
171 	KKASSERT(dict != NULL);
172 
173 	ps = prop_string_create_cstring(str);
174 	if (ps == NULL) {
175 		return ENOMEM;
176 	}
177 
178 	if (prop_dictionary_set(dict, key, ps) == false) {
179 		prop_object_release(ps);
180 		return ENOMEM;
181 	}
182 
183 	prop_object_release(ps);
184 	return 0;
185 }
186 
187 static int
188 _udev_dict_set_int(prop_dictionary_t dict, const char *key, int64_t val)
189 {
190 	prop_number_t	pn;
191 
192 	KKASSERT(dict != NULL);
193 
194 	pn = prop_number_create_integer(val);
195 	if (pn == NULL)
196 		return ENOMEM;
197 
198 	if (prop_dictionary_set(dict, key, pn) == false) {
199 		prop_object_release(pn);
200 		return ENOMEM;
201 	}
202 
203 	prop_object_release(pn);
204 	return 0;
205 }
206 
207 static int
208 _udev_dict_set_uint(prop_dictionary_t dict, const char *key, uint64_t val)
209 {
210 	prop_number_t	pn;
211 
212 	KKASSERT(dict != NULL);
213 
214 	pn = prop_number_create_unsigned_integer(val);
215 	if (pn == NULL)
216 		return ENOMEM;
217 
218 	if (prop_dictionary_set(dict, key, pn) == false) {
219 		prop_object_release(pn);
220 		return ENOMEM;
221 	}
222 
223 	prop_object_release(pn);
224 	return 0;
225 }
226 
227 static int
228 _udev_dict_delete_key(prop_dictionary_t dict, const char *key)
229 {
230 	KKASSERT(dict != NULL);
231 
232 	prop_dictionary_remove(dict, key);
233 
234 	return 0;
235 }
236 
237 /*
238  * Initialize an event dictionary, which contains three parameters to
239  * identify the device referred to (name, devnum, kptr) and the affected key.
240  */
241 static prop_dictionary_t
242 udev_init_dict_event(cdev_t dev, const char *key)
243 {
244 	prop_dictionary_t	dict;
245 	uint64_t	kptr;
246 	int error;
247 
248 	kptr = (uint64_t)(uintptr_t)dev;
249 	KKASSERT(dev != NULL);
250 
251 	dict = prop_dictionary_create();
252 	if (dict == NULL) {
253 		log(LOG_DEBUG, "udev_init_dict_event: prop_dictionary_create() failed\n");
254 		return NULL;
255 	}
256 
257 	if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name)))
258 		goto error_out;
259 	if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode)))
260 		goto error_out;
261 	if ((error = _udev_dict_set_uint(dict, "devtype", (dev_dflags(dev) & D_TYPEMASK))))
262 		goto error_out;
263 	if ((error = _udev_dict_set_uint(dict, "kptr", kptr)))
264 		goto error_out;
265 	if ((error = _udev_dict_set_cstr(dict, "key", __DECONST(char *, key))))
266 		goto error_out;
267 
268 	return dict;
269 
270 error_out:
271 	prop_object_release(dict);
272 	return NULL;
273 }
274 
275 int
276 udev_dict_set_cstr(cdev_t dev, const char *key, char *str)
277 {
278 	prop_dictionary_t dict;
279 	prop_dictionary_t udict;
280 	int error;
281 
282 	KKASSERT(dev != NULL);
283 
284 	while ((udict = udev_get_dict(dev)) == NULL) {
285 		error = udev_init_dict(dev);
286 		udev_put_dict(dev, udict);
287 		if (error)
288 			return -1;
289 	}
290 
291 	/* Queue a key update event */
292 	dict = udev_init_dict_event(dev, key);
293 	if (dict == NULL) {
294 		error = ENOMEM;
295 		goto errout;
296 	}
297 
298 	if ((error = _udev_dict_set_cstr(dict, "value", str))) {
299 		prop_object_release(dict);
300 		goto errout;
301 	}
302 	udev_event_insert(UDEV_EV_KEY_UPDATE, dict);
303 	prop_object_release(dict);
304 	error = _udev_dict_set_cstr(udict, key, str);
305 
306 errout:
307 	udev_put_dict(dev, udict);
308 
309 	return error;
310 }
311 
312 int
313 udev_dict_set_int(cdev_t dev, const char *key, int64_t val)
314 {
315 	prop_dictionary_t dict;
316 	prop_dictionary_t udict;
317 	int error;
318 
319 	KKASSERT(dev != NULL);
320 
321 	while ((udict = udev_get_dict(dev)) == NULL) {
322 		error = udev_init_dict(dev);
323 		udev_put_dict(dev, udict);
324 		if (error)
325 			return -1;
326 	}
327 
328 	/* Queue a key update event */
329 	dict = udev_init_dict_event(dev, key);
330 	if (dict == NULL) {
331 		error = ENOMEM;
332 		goto errout;
333 	}
334 	if ((error = _udev_dict_set_int(dict, "value", val))) {
335 		prop_object_release(dict);
336 		goto errout;
337 	}
338 	udev_event_insert(UDEV_EV_KEY_UPDATE, dict);
339 	prop_object_release(dict);
340 	error = _udev_dict_set_int(udict, key, val);
341 errout:
342 	udev_put_dict(dev, udict);
343 
344 	return error;
345 }
346 
347 int
348 udev_dict_set_uint(cdev_t dev, const char *key, uint64_t val)
349 {
350 	prop_dictionary_t dict;
351 	prop_dictionary_t udict;
352 	int error;
353 
354 	KKASSERT(dev != NULL);
355 
356 	while ((udict = udev_get_dict(dev)) == NULL) {
357 		error = udev_init_dict(dev);
358 		udev_put_dict(dev, udict);
359 		if (error)
360 			return -1;
361 	}
362 
363 	/* Queue a key update event */
364 	dict = udev_init_dict_event(dev, key);
365 	if (dict == NULL) {
366 		error = ENOMEM;
367 		goto errout;
368 	}
369 	if ((error = _udev_dict_set_uint(dict, "value", val))) {
370 		prop_object_release(dict);
371 		goto errout;
372 	}
373 	udev_event_insert(UDEV_EV_KEY_UPDATE, dict);
374 	prop_object_release(dict);
375 	error = _udev_dict_set_uint(udict, key, val);
376 errout:
377 	udev_put_dict(dev, udict);
378 
379 	return error;
380 }
381 
382 int
383 udev_dict_delete_key(cdev_t dev, const char *key)
384 {
385 	prop_dictionary_t dict;
386 	prop_dictionary_t udict;
387 	int error;
388 
389 	KKASSERT(dev != NULL);
390 	udict = udev_get_dict(dev);
391 	if (udict == NULL) {
392 		error = ENOMEM;
393 		goto errout;
394 	}
395 
396 	/* Queue a key removal event */
397 	dict = udev_init_dict_event(dev, key);
398 	if (dict == NULL) {
399 		error = ENOMEM;
400 		goto errout;
401 	}
402 	udev_event_insert(UDEV_EV_KEY_REMOVE, dict);
403 	prop_object_release(dict);
404 	error = _udev_dict_delete_key(udict, key);
405 errout:
406 	udev_put_dict(dev, udict);
407 
408 	return error;
409 }
410 
411 /*
412  * device dictionary access already locked
413  */
414 static int
415 udev_init_dict(cdev_t dev)
416 {
417 	prop_dictionary_t dict;
418 	uint64_t	kptr;
419 	int error;
420 
421 	kptr = (uint64_t)(uintptr_t)dev;
422 
423 	KKASSERT(dev != NULL);
424 
425 	if (dev->si_dict != NULL) {
426 		log(LOG_DEBUG,
427 		    "udev_init_dict: new dict for %s, but has "
428 		    "dict already (%p)!\n",
429 		    dev->si_name, dev->si_dict);
430 		return 0;
431 	}
432 
433 	dict = prop_dictionary_create();
434 	if (dict == NULL) {
435 		log(LOG_DEBUG,
436 		    "udev_init_dict: prop_dictionary_create() failed\n");
437 		return ENOMEM;
438 	}
439 
440 	if ((error = _udev_dict_set_cstr(dict, "name", dev->si_name)))
441 		goto error_out;
442 	if ((error = _udev_dict_set_uint(dict, "devnum", dev->si_inode)))
443 		goto error_out;
444 	if ((error = _udev_dict_set_uint(dict, "kptr", kptr)))
445 		goto error_out;
446 	if ((error = _udev_dict_set_uint(dict, "devtype",
447 					 (dev_dflags(dev) & D_TYPEMASK)))) {
448 		goto error_out;
449 	}
450 
451 	/* XXX: The next 3 are marginallly useful, if at all */
452 	if ((error = _udev_dict_set_uint(dict, "uid", dev->si_uid)))
453 		goto error_out;
454 	if ((error = _udev_dict_set_uint(dict, "gid", dev->si_gid)))
455 		goto error_out;
456 	if ((error = _udev_dict_set_int(dict, "mode", dev->si_perms)))
457 		goto error_out;
458 
459 	if ((error = _udev_dict_set_int(dict, "major", dev->si_umajor)))
460 		goto error_out;
461 	if ((error = _udev_dict_set_int(dict, "minor", dev->si_uminor)))
462 		goto error_out;
463 	if (dev->si_ops->head.name != NULL) {
464 		if ((error = _udev_dict_set_cstr(dict, "driver",
465 		    __DECONST(char *, dev->si_ops->head.name))))
466 			goto error_out;
467 	}
468 
469 	dev->si_dict = dict;
470 	return 0;
471 
472 error_out:
473 	dev->si_dict = NULL;
474 	prop_object_release(dict);
475 	return error;
476 }
477 
478 /*
479  * device dictionary access already locked
480  */
481 static int
482 udev_destroy_dict(cdev_t dev)
483 {
484 	prop_dictionary_t udict;
485 
486 	KKASSERT(dev != NULL);
487 	udict = udev_get_dict(dev);
488 
489 	/* field is now locked, use directly to handle races */
490 	if (dev->si_dict) {
491 		prop_object_release(dev->si_dict);
492 		dev->si_dict = NULL;
493 	}
494 	udev_put_dict(dev, udict);
495 
496 	return 0;
497 }
498 
499 static void
500 udev_event_insert(int ev_type, prop_dictionary_t dict)
501 {
502 	struct udev_event_kernel *ev;
503 	prop_dictionary_t dict_copy;
504 
505 	/* Only start queing events after client has initiated properly */
506 	if (udev_initiated_count) {
507 		dict_copy = prop_dictionary_copy(dict);
508 		if (dict_copy == NULL)
509 			return;
510 		ev = objcache_get(udev_event_kernel_cache, M_WAITOK);
511 		ev->ev.ev_dict = dict_copy;
512 		ev->ev.ev_type = ev_type;
513 
514 		lockmgr(&udev_lk, LK_EXCLUSIVE);
515 		TAILQ_INSERT_TAIL(&udev_evq, ev, link);
516 		++udev_evqlen;
517 		++udev_seq;
518 		if (udev_seqwait)
519 			wakeup(&udev_seqwait);
520 		lockmgr(&udev_lk, LK_RELEASE);
521 		wakeup(&udev_evq);
522 		KNOTE(&udev_kq.ki_note, 0);
523 	} else if (udev_open_count) {
524 		lockmgr(&udev_lk, LK_EXCLUSIVE);
525 		++udev_seq;
526 		if (udev_seqwait)
527 			wakeup(&udev_seqwait);
528 		lockmgr(&udev_lk, LK_RELEASE);
529 		KNOTE(&udev_kq.ki_note, 0);
530 	}
531 }
532 
533 static void
534 udev_clean_events_locked(void)
535 {
536 	struct udev_event_kernel *ev;
537 
538 	while ((ev = TAILQ_FIRST(&udev_evq)) &&
539 	       ev->ev.ev_dict != NULL) {
540 		TAILQ_REMOVE(&udev_evq, ev, link);
541 		objcache_put(udev_event_kernel_cache, ev);
542 		--udev_evqlen;
543 	}
544 }
545 
546 static char *
547 udev_event_externalize(struct udev_event_kernel *ev)
548 {
549 	prop_dictionary_t	dict;
550 	char *xml;
551 	int error;
552 
553 	dict = prop_dictionary_create();
554 	if (dict == NULL) {
555 		log(LOG_DEBUG,
556 		    "udev_event_externalize: prop_dictionary_create() failed\n");
557 		return NULL;
558 	}
559 
560 	if ((error = _udev_dict_set_int(dict, "evtype", ev->ev.ev_type))) {
561 		prop_object_release(dict);
562 		return NULL;
563 	}
564 
565 	if (prop_dictionary_set(dict, "evdict", ev->ev.ev_dict) == false) {
566 		prop_object_release(dict);
567 		return NULL;
568 	}
569 
570 	prop_object_release(ev->ev.ev_dict);
571 
572 	xml = prop_dictionary_externalize(dict);
573 
574 	prop_object_release(dict);
575 
576 	return xml;
577 }
578 
579 int
580 udev_event_attach(cdev_t dev, char *name, int alias)
581 {
582 	prop_dictionary_t dict;
583 	prop_dictionary_t udict;
584 	int error;
585 
586 	KKASSERT(dev != NULL);
587 
588 	error = ENOMEM;
589 
590 	udict = udev_get_dict(dev);
591 	if (alias) {
592 		if (udict == NULL)
593 			goto error_out;
594 		dict = prop_dictionary_copy(udict);
595 		if (dict == NULL)
596 			goto error_out;
597 
598 		if ((error = _udev_dict_set_cstr(dict, "name", name))) {
599 			prop_object_release(dict);
600 			goto error_out;
601 		}
602 
603 		_udev_dict_set_int(dict, "alias", 1);
604 
605 		udev_event_insert(UDEV_EVENT_ATTACH, dict);
606 		prop_object_release(dict);
607 	} else {
608 		while (udict == NULL) {
609 			error = udev_init_dict(dev);
610 			if (error)
611 				goto error_out;
612 			udev_put_dict(dev, udict);
613 			udict = udev_get_dict(dev);
614 		}
615 		_udev_dict_set_int(udict, "alias", 0);
616 		udev_event_insert(UDEV_EVENT_ATTACH, udict);
617 	}
618 error_out:
619 	udev_put_dict(dev, udict);
620 
621 	return error;
622 }
623 
624 int
625 udev_event_detach(cdev_t dev, char *name, int alias)
626 {
627 	prop_dictionary_t dict;
628 	prop_dictionary_t udict;
629 
630 	KKASSERT(dev != NULL);
631 
632 	udict = udev_get_dict(dev);
633 	if (alias) {
634 		dict = prop_dictionary_copy(udict);
635 		if (dict == NULL)
636 			goto error_out;
637 
638 		if (_udev_dict_set_cstr(dict, "name", name)) {
639 			prop_object_release(dict);
640 			goto error_out;
641 		}
642 
643 		_udev_dict_set_int(dict, "alias", 1);
644 
645 		udev_event_insert(UDEV_EVENT_DETACH, dict);
646 		prop_object_release(dict);
647 	} else {
648 		if (udict)
649 			udev_event_insert(UDEV_EVENT_DETACH, udict);
650 	}
651 
652 error_out:
653 	udev_destroy_dict(dev);
654 	udev_put_dict(dev, udict);
655 
656 	return 0;
657 }
658 
659 /*
660  * Allow multiple opens.  Each opener gets a different device.
661  * Messages are replicated to all devices using a marker system.
662  */
663 static int
664 udev_dev_clone(struct dev_clone_args *ap)
665 {
666 	struct udev_softc *softc;
667 	int unit;
668 
669 	unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(udev), 1000);
670 	if (unit < 0) {
671 		ap->a_dev = NULL;
672 		return 1;
673 	}
674 
675 	softc = kmalloc(sizeof(*softc), M_UDEV, M_WAITOK | M_ZERO);
676 	softc->unit = unit;
677 	lockmgr(&udev_lk, LK_EXCLUSIVE);
678 	TAILQ_INSERT_TAIL(&udevq, softc, entry);
679 	lockmgr(&udev_lk, LK_RELEASE);
680 
681 	softc->dev = make_only_dev(&udev_dev_ops, unit, ap->a_cred->cr_ruid,
682 				   0, 0600, "udevs/%d", unit);
683 	softc->dev->si_drv1 = softc;
684 	ap->a_dev = softc->dev;
685 	return 0;
686 }
687 
688 /*
689  * dev stuff
690  */
691 static int
692 udev_dev_open(struct dev_open_args *ap)
693 {
694 	struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
695 
696 	lockmgr(&udev_lk, LK_EXCLUSIVE);
697 	if (softc == NULL || softc->opened) {
698 		lockmgr(&udev_lk, LK_RELEASE);
699 		return EBUSY;
700 	}
701 	softc->opened = 1;
702 	++udev_open_count;
703 	lockmgr(&udev_lk, LK_RELEASE);
704 
705 	return 0;
706 }
707 
708 static int
709 udev_dev_close(struct dev_close_args *ap)
710 {
711 	struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
712 
713 	KKASSERT(softc->dev == ap->a_head.a_dev);
714 	KKASSERT(softc->opened == 1);
715 
716 	destroy_dev(ap->a_head.a_dev);
717 	lockmgr(&udev_lk, LK_EXCLUSIVE);
718 	TAILQ_REMOVE(&udevq, softc, entry);
719 
720 	if (softc->initiated) {
721 		TAILQ_REMOVE(&udev_evq, &softc->marker, link);
722 		softc->initiated = 0;
723 		--udev_initiated_count;
724 		udev_clean_events_locked();
725 	}
726 	softc->opened = 0;
727 	softc->dev = NULL;
728 	ap->a_head.a_dev->si_drv1 = NULL;
729 	--udev_open_count;
730 	lockmgr(&udev_lk, LK_RELEASE);
731 
732 	/*
733 	 * WARNING! devfs_clone_bitmap_put() interacts with the devfs
734 	 *	    thread, avoid deadlocks by ensuring we are unlocked
735 	 *	    before calling.
736 	 */
737 	devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(udev), softc->unit);
738 	wakeup(&udev_evq);
739 
740 	kfree(softc, M_UDEV);
741 
742 	return 0;
743 }
744 
745 static struct filterops udev_dev_read_filtops =
746 	{ FILTEROP_ISFD | FILTEROP_MPSAFE, NULL,
747 	  udev_dev_filter_detach, udev_dev_filter_read };
748 
749 static int
750 udev_dev_kqfilter(struct dev_kqfilter_args *ap)
751 {
752 	struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
753 	struct knote *kn = ap->a_kn;
754 	struct klist *klist;
755 
756 	ap->a_result = 0;
757 	lockmgr(&udev_lk, LK_EXCLUSIVE);
758 
759 	switch (kn->kn_filter) {
760 	case EVFILT_READ:
761 		kn->kn_fop = &udev_dev_read_filtops;
762 		kn->kn_hook = (caddr_t)softc;
763 		break;
764 	default:
765 		ap->a_result = EOPNOTSUPP;
766 	        lockmgr(&udev_lk, LK_RELEASE);
767 		return (0);
768 	}
769 
770 	klist = &udev_kq.ki_note;
771 	knote_insert(klist, kn);
772 
773         lockmgr(&udev_lk, LK_RELEASE);
774 
775 	return (0);
776 }
777 
778 static void
779 udev_dev_filter_detach(struct knote *kn)
780 {
781 	struct klist *klist;
782 
783 	lockmgr(&udev_lk, LK_EXCLUSIVE);
784 	klist = &udev_kq.ki_note;
785 	knote_remove(klist, kn);
786 	lockmgr(&udev_lk, LK_RELEASE);
787 }
788 
789 static int
790 udev_dev_filter_read(struct knote *kn, long hint)
791 {
792 	struct udev_softc *softc = (void *)kn->kn_hook;
793 	struct udev_event_kernel *ev;
794 	int ready = 0;
795 
796 	lockmgr(&udev_lk, LK_EXCLUSIVE);
797 	if (softc->initiated) {
798 		ev = TAILQ_NEXT(&softc->marker, link);
799 		while (ev && ev->ev.ev_dict == NULL)
800 			ev = TAILQ_NEXT(ev, link);
801 		if (ev)
802 			ready = 1;
803 	}
804 	lockmgr(&udev_lk, LK_RELEASE);
805 
806 	return (ready);
807 }
808 
809 static int
810 udev_dev_read(struct dev_read_args *ap)
811 {
812 	struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
813 	struct udev_event_kernel *ev;
814 	struct uio *uio = ap->a_uio;
815 	char	*xml;
816 	size_t	len;
817 	int	error;
818 
819 	lockmgr(&udev_lk, LK_EXCLUSIVE);
820 
821 	/*
822 	 * Automatically enable message collection if it has not already
823 	 * been enabled.
824 	 */
825 	if (softc->initiated == 0) {
826 		softc->initiated = 1;
827 		++udev_initiated_count;
828 		TAILQ_INSERT_HEAD(&udev_evq, &softc->marker, link);
829 	}
830 
831 	/*
832 	 * Loop, sleep interruptably until we get an event or signal.
833 	 */
834 	error = 0;
835 	for (;;) {
836 		if (softc->initiated) {
837 			ev = TAILQ_NEXT(&softc->marker, link);
838 			while (ev && ev->ev.ev_dict == NULL)
839 				ev = TAILQ_NEXT(ev, link);
840 			if (ev) {
841 				if ((xml = udev_event_externalize(ev)) == NULL) {
842 					error = ENOMEM;
843 					break;
844 				}
845 				len = strlen(xml) + 1; /* include terminator */
846 				if (uio->uio_resid < len)
847 					error = ENOMEM;
848 				else
849 					error = uiomove((caddr_t)xml, len, uio);
850 				kfree(xml, M_TEMP);
851 
852 				/*
853 				 * Move the marker
854 				 */
855 				TAILQ_REMOVE(&udev_evq, &softc->marker, link);
856 				TAILQ_INSERT_AFTER(&udev_evq,
857 						   ev, &softc->marker, link);
858 				udev_clean_events_locked();
859 				break;
860 			}
861 		}
862 		if (ap->a_ioflag & IO_NDELAY) {
863 			error = EWOULDBLOCK;
864 			break;
865 		}
866 		if ((error = lksleep(&udev_evq, &udev_lk, PCATCH, "udevq", 0)))
867 			break;
868 	}
869 
870 	lockmgr(&udev_lk, LK_RELEASE);
871 	return error;
872 }
873 
874 static int
875 udev_dev_ioctl(struct dev_ioctl_args *ap)
876 {
877 	struct udev_softc *softc = ap->a_head.a_dev->si_drv1;
878 	prop_dictionary_t dict;
879 	prop_object_t	po;
880 	prop_string_t	ps;
881 	struct plistref *pref;
882 	int i, error;
883 	int seq;
884 
885 	error = 0;
886 
887 	switch(ap->a_cmd) {
888 	case UDEVPROP:
889 		/* Use proplib(3) for userspace/kernel communication */
890 		pref = (struct plistref *)ap->a_data;
891 		error = prop_dictionary_copyin_ioctl(pref, ap->a_cmd, &dict);
892 		if (error)
893 			return error;
894 
895 		po = prop_dictionary_get(dict, "command");
896 		if (po == NULL || prop_object_type(po) != PROP_TYPE_STRING) {
897 			log(LOG_DEBUG, "udev: prop_dictionary_get() failed\n");
898 			prop_object_release(dict);
899 			return EINVAL;
900 		}
901 
902 		ps = po;
903 		/* Handle cmd */
904 		for(i = 0; cmd_fn[i].cmd != NULL; i++) {
905 			if (prop_string_equals_cstring(ps, cmd_fn[i].cmd))
906 				break;
907 		}
908 
909 		if (cmd_fn[i].cmd != NULL) {
910 			error = cmd_fn[i].fn(softc, pref, ap->a_cmd, dict);
911 		} else {
912 			error = EINVAL;
913 		}
914 
915 		//prop_object_release(po);
916 		prop_object_release(dict);
917 		break;
918 	case UDEVWAIT:
919 		/*
920 		 * Wait for events based on sequence number.  Updates
921 		 * sequence number for loop.
922 		 */
923 		lockmgr(&udev_lk, LK_EXCLUSIVE);
924 		seq = *(int *)ap->a_data;
925 		++udev_seqwait;
926 		while (seq == udev_seq) {
927 			error = lksleep(&udev_seqwait, &udev_lk,
928 					PCATCH, "udevw", 0);
929 			if (error)
930 				break;
931 		}
932 		--udev_seqwait;
933 		*(int *)ap->a_data = udev_seq;
934 		lockmgr(&udev_lk, LK_RELEASE);
935 		break;
936 	default:
937 		error = ENOTTY; /* Inappropriate ioctl for device */
938 		break;
939 	}
940 
941 	return(error);
942 }
943 
944 static void
945 udev_getdevs_scan_callback(char *name, cdev_t cdev, bool is_alias, void *arg)
946 {
947 	struct udev_prop_ctx *ctx = arg;
948 
949 	KKASSERT(arg != NULL);
950 
951 	if (cdev->si_dict == NULL)
952 		return;
953 
954 	if (prop_array_add(ctx->cdevs, cdev->si_dict) == false) {
955 		ctx->error = EINVAL;
956 		return;
957 	}
958 }
959 
960 static int
961 udev_getdevs_ioctl(struct udev_softc *softc, struct plistref *pref,
962 		   u_long cmd, prop_dictionary_t dict)
963 {
964 	prop_dictionary_t odict;
965 	struct udev_prop_ctx ctx;
966 	int error;
967 
968 	/*
969 	 * Ensure event notification is enabled before doing the devfs
970 	 * scan so nothing gets missed.
971 	 */
972 	lockmgr(&udev_lk, LK_EXCLUSIVE);
973 	if (softc->initiated == 0) {
974 		softc->initiated = 1;
975 		++udev_initiated_count;
976 		TAILQ_INSERT_HEAD(&udev_evq, &softc->marker, link);
977 	}
978 	lockmgr(&udev_lk, LK_RELEASE);
979 
980 	/*
981 	 * Devfs scan to build full dictionary.
982 	 */
983 	ctx.error = 0;
984 	ctx.cdevs = prop_array_create();
985 	if (ctx.cdevs == NULL) {
986 		log(LOG_DEBUG,
987 		    "udev_getdevs_ioctl: prop_array_create() failed\n");
988 		return EINVAL;
989 	}
990 
991 	devfs_scan_callback(udev_getdevs_scan_callback, &ctx);
992 
993 	if (ctx.error != 0) {
994 		prop_object_release(ctx.cdevs);
995 		return (ctx.error);
996 	}
997 
998 	odict = prop_dictionary_create();
999 	if (odict == NULL) {
1000 		return ENOMEM;
1001 	}
1002 
1003 	if ((prop_dictionary_set(odict, "array", ctx.cdevs)) == 0) {
1004 		log(LOG_DEBUG,
1005 		    "udev_getdevs_ioctl: prop_dictionary_set failed\n");
1006 		prop_object_release(odict);
1007 		return ENOMEM;
1008 	}
1009 
1010 	error = prop_dictionary_copyout_ioctl(pref, cmd, odict);
1011 
1012 	prop_object_release(odict);
1013 	return error;
1014 }
1015 
1016 
1017 /*
1018  * SYSINIT stuff
1019  */
1020 static void
1021 udev_init(void)
1022 {
1023 	lockinit(&udev_lk, "udevlk", 0, LK_CANRECURSE);
1024 	TAILQ_INIT(&udevq);
1025 	TAILQ_INIT(&udev_evq);
1026 	udev_event_kernel_cache = objcache_create_simple(M_UDEV, sizeof(struct udev_event_kernel));
1027 }
1028 
1029 static void
1030 udev_uninit(void)
1031 {
1032 	objcache_destroy(udev_event_kernel_cache);
1033 }
1034 
1035 static void
1036 udev_dev_init(void)
1037 {
1038 	udev_dev = make_autoclone_dev(&udev_dev_ops, &DEVFS_CLONE_BITMAP(udev),
1039 				      udev_dev_clone,
1040 				      UID_ROOT, GID_WHEEL, 0600, "udev");
1041 }
1042 
1043 static void
1044 udev_dev_uninit(void)
1045 {
1046 	destroy_dev(udev_dev);
1047 }
1048 
1049 SYSINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY,
1050 	udev_init, NULL);
1051 SYSUNINIT(subr_udev_register, SI_SUB_CREATE_INIT, SI_ORDER_ANY,
1052 	udev_uninit, NULL);
1053 SYSINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY,
1054 	udev_dev_init, NULL);
1055 SYSUNINIT(subr_udev_dev_register, SI_SUB_DRIVERS, SI_ORDER_ANY,
1056 	udev_dev_uninit, NULL);
1057