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