Implement select(2) in terms of kevent
[dragonfly.git] / sys / kern / kern_udev.c
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);