2 * kmscon - Character-Device Session
4 * Copyright (c) 2012 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 * Character-Device Session
30 #define FUSE_USE_VERSION 29
35 #include <linux/major.h>
41 #include <sys/epoll.h>
45 #include "kmscon_cdev.h"
46 #include "kmscon_seat.h"
47 #include "shl_array.h"
48 #include "shl_dlist.h"
51 #include "tsm_screen.h"
53 #include "uterm_input.h"
55 #include <fuse/fuse.h>
56 #include <fuse/fuse_common.h>
57 #include <fuse/fuse_lowlevel.h>
58 #include <fuse/fuse_opt.h>
59 #include <fuse/cuse_lowlevel.h>
61 #define LOG_SUBSYSTEM "cdev"
64 struct kmscon_seat *seat;
65 struct ev_eloop *eloop;
66 struct uterm_input *input;
67 struct kmscon_session *s;
71 struct fuse_session *session;
73 struct fuse_chan *channel;
78 struct shl_dlist clients;
83 struct shl_dlist list;
84 struct kmscon_cdev *cdev;
87 struct tsm_screen *screen;
91 struct kmscon_session *s;
93 struct fuse_pollhandle *ph;
94 struct shl_ring *ring;
95 struct shl_dlist readers;
100 struct vt_mode vtmode;
101 struct fuse_ctx user;
104 struct shl_dlist waiters;
108 struct shl_dlist list;
115 struct shl_dlist list;
120 static pthread_mutex_t cdev_lock = PTHREAD_MUTEX_INITIALIZER;
121 static struct shl_array *cdev_ids = NULL;
123 static int cdev_allocate_id(void)
125 static const bool init = true;
128 pthread_mutex_lock(&cdev_lock);
131 ret = shl_array_new(&cdev_ids, sizeof(bool), 4);
136 len = shl_array_get_length(cdev_ids);
137 for (i = 0; i < len; ++i)
138 if (!*SHL_ARRAY_AT(cdev_ids, bool, i))
142 ret = shl_array_push(cdev_ids, &init);
147 *SHL_ARRAY_AT(cdev_ids, bool, i) = true;
152 pthread_mutex_unlock(&cdev_lock);
153 return (ret < 0) ? ret : (ret + 16384);
158 * As opposed to kernel VTs, we only provide one single char-dev per seat and
159 * each client that opens it is managed separately. Hence, it is not possible to
160 * use such a VT shared by two clients except if you pass the FD between the
161 * clients. This has several advantages and avoids many bugs in the kernel VT
163 * For every user opening a /dev/ttyF<seat> device, a separate cdev_client is
164 * created. A cdev_client emulates a single kernel VT but is managed as a
165 * dedicated kmscon_session on its seat. We start a kmscon_terminal as backend
166 * so you actually can run "agetty" on this fake-VT. When set into graphical
167 * mode, the terminal is suspended and you can run an XServer on it. We emulate
168 * the VT-switching signal-API, too. We release all DRM devices if a fake-VT is
169 * active and reacquire them afterwards. This allows the clients to actually
170 * implement graphical terminals. However, if you fail to release the DRM
171 * devices, we actually try to kill the fake-VT so we can get access again.
174 static void reader_interrupt(fuse_req_t req, void *data)
176 struct cdev_reader *reader = data;
181 reader->killed = true;
184 static int reader_new(struct cdev_reader **out, struct cdev_client *client,
187 struct cdev_reader *reader;
189 if (fuse_req_interrupted(req))
192 reader = malloc(sizeof(*reader));
195 memset(reader, 0, sizeof(*reader));
197 fuse_req_interrupt_func(req, reader_interrupt, reader);
198 if (reader->killed) {
199 fuse_req_interrupt_func(req, NULL, NULL);
204 shl_dlist_link_tail(&client->readers, &reader->list);
209 static void reader_free(struct cdev_reader *reader, int error)
211 shl_dlist_unlink(&reader->list);
213 fuse_req_interrupt_func(reader->req, NULL, NULL);
214 fuse_reply_err(reader->req, -error);
219 static int reader_release(struct cdev_reader *reader, const char *buf,
224 fuse_req_interrupt_func(reader->req, NULL, NULL);
225 ret = fuse_reply_buf(reader->req, buf, len);
227 reader_free(reader, 0);
231 static void waiter_interrupt(fuse_req_t req, void *data)
233 struct cdev_waiter *waiter = data;
238 waiter->killed = true;
241 static int waiter_new(struct cdev_waiter **out, struct cdev_client *client,
244 struct cdev_waiter *waiter;
246 if (fuse_req_interrupted(req))
249 waiter = malloc(sizeof(*waiter));
252 memset(waiter, 0, sizeof(*waiter));
254 fuse_req_interrupt_func(req, waiter_interrupt, waiter);
255 if (waiter->killed) {
256 fuse_req_interrupt_func(req, NULL, NULL);
261 shl_dlist_link_tail(&client->waiters, &waiter->list);
266 static void waiter_free(struct cdev_waiter *waiter, int error)
268 shl_dlist_unlink(&waiter->list);
270 fuse_req_interrupt_func(waiter->req, NULL, NULL);
271 fuse_reply_err(waiter->req, -error);
276 static int waiter_release(struct cdev_waiter *waiter)
280 fuse_req_interrupt_func(waiter->req, NULL, NULL);
281 ret = fuse_reply_ioctl(waiter->req, 0, NULL, 0);
283 waiter_free(waiter, 0);
287 static void client_vte_event(struct tsm_vte *vte, const char *u8, size_t len,
290 struct cdev_client *client = data;
291 struct cdev_reader *reader;
297 /* TODO: we should have a maximum buffer size here */
298 was_empty = shl_ring_is_empty(client->ring);
299 ret = shl_ring_write(client->ring, u8, len);
301 log_warning("cannot resize buffer for cdev client: %d", ret);
303 if (shl_ring_is_empty(client->ring))
306 if (was_empty && client->ph) {
307 fuse_notify_poll(client->ph);
308 fuse_pollhandle_destroy(client->ph);
312 while (!shl_dlist_empty(&client->readers)) {
313 reader = shl_dlist_entry(client->readers.next,
314 struct cdev_reader, list);
318 /* TODO: fix filling the whole buffer instead of returning
319 * partial buffers when the ring data is split */
320 buf = shl_ring_peek(client->ring, &size, 0);
323 if (size > reader->len)
326 ret = reader_release(reader, buf, size);
329 shl_ring_drop(client->ring, size);
333 static void client_input_event(struct uterm_input *input,
334 struct uterm_input_event *ev,
337 struct cdev_client *client = data;
339 if (!client->active || ev->handled)
342 /* we drop all input in K_OFF mode */
343 if (client->kbmode == K_OFF)
346 /* TODO: see kmscon_terminal on how this is special. We need to fix this
347 * when xkbcommon provides the first multi-sym events. */
348 if (ev->num_syms > 1)
351 if (tsm_vte_handle_keyboard(client->vte, ev->keysyms[0], ev->ascii,
352 ev->mods, ev->codepoints[0])) {
353 tsm_screen_sb_reset(client->screen);
358 static int client_activate(struct cdev_client *client)
361 struct cdev_waiter *waiter;
363 /* TODO: Check whether we have CAP_KILL capability during startup */
364 if (client->vtmode.mode == VT_PROCESS && client->vtmode.acqsig) {
365 ret = kill(client->user.pid, client->vtmode.acqsig);
367 log_warning("cannot send activation signal to process %d of cdev client %p (%d): %m",
368 client->user.pid, client, errno);
371 while (!shl_dlist_empty(&client->waiters)) {
372 waiter = shl_dlist_entry(client->waiters.next,
373 struct cdev_waiter, list);
375 waiter_free(waiter, 0);
377 waiter_release(waiter);
380 client->active = true;
384 static int client_deactivate(struct cdev_client *client)
388 if (client->vtmode.mode == VT_PROCESS && client->vtmode.relsig) {
389 ret = kill(client->user.pid, client->vtmode.relsig);
391 log_warning("cannot send deactivation signal to process %d of cdev client %p (%d): %m",
392 client->user.pid, client, errno);
393 client->pending_switch = true;
397 client->active = false;
401 static void client_kill(struct cdev_client *client)
403 struct cdev_reader *reader;
404 struct cdev_waiter *waiter;
407 log_error("killing already dead client");
411 log_debug("kill fake TTY client %p", client);
416 fuse_notify_poll(client->ph);
417 fuse_pollhandle_destroy(client->ph);
420 while (!shl_dlist_empty(&client->readers)) {
421 reader = shl_dlist_entry(client->readers.next,
422 struct cdev_reader, list);
423 reader_free(reader, -EPIPE);
426 while (!shl_dlist_empty(&client->waiters)) {
427 waiter = shl_dlist_entry(client->waiters.next,
428 struct cdev_waiter, list);
429 waiter_free(waiter, -EPIPE);
432 uterm_input_unregister_cb(client->cdev->input, client_input_event,
434 tsm_vte_unref(client->vte);
435 tsm_screen_unref(client->screen);
436 shl_ring_free(client->ring);
439 static int client_session_event(struct kmscon_session *s,
440 struct kmscon_session_event *ev,
443 struct cdev_client *client = data;
446 case KMSCON_SESSION_ACTIVATE:
447 return client_activate(client);
448 case KMSCON_SESSION_DEACTIVATE:
449 return client_deactivate(client);
450 case KMSCON_SESSION_UNREGISTER:
458 static int client_new(struct cdev_client **out, struct kmscon_cdev *cdev)
460 struct cdev_client *client;
463 client = malloc(sizeof(*client));
466 memset(client, 0, sizeof(*client));
468 client->kdmode = KD_TEXT;
469 client->kbmode = K_UNICODE;
470 client->vtmode.mode = VT_AUTO;
471 shl_dlist_init(&client->readers);
472 shl_dlist_init(&client->waiters);
474 log_debug("new fake TTY client %p", client);
476 ret = shl_ring_new(&client->ring);
478 log_error("cannot create ring buffer for new cdev client: %d",
483 /* TODO: Share the terminal-handling with the terminal-session. We
484 * currently just create the screen/vte objects here to get meaningful
485 * parsers. However, we should also correctly handled the terminal as is
486 * and draw it to the screen if in text-mode.
487 * This is nearly identical to the terminal-session so we should share
488 * the implementation between both instead of doing everything ourself
491 ret = tsm_screen_new(&client->screen, log_llog, NULL);
493 log_error("cannot create TSM screen for new cdev client: %d",
498 ret = tsm_vte_new(&client->vte, client->screen, client_vte_event,
499 client, log_llog, NULL);
501 log_error("cannot create TSM VTE for new cdev client: %d",
506 ret = uterm_input_register_cb(cdev->input, client_input_event, client);
508 log_error("cannot register input callback for cdev client: %d",
513 ret = kmscon_seat_register_session(cdev->seat, &client->s,
514 client_session_event, client);
516 log_error("cannot register session for cdev client: %d", ret);
520 shl_dlist_link(&cdev->clients, &client->list);
525 uterm_input_unregister_cb(cdev->input, client_input_event, client);
527 tsm_vte_unref(client->vte);
529 tsm_screen_unref(client->screen);
531 shl_ring_free(client->ring);
537 static void client_destroy(struct cdev_client *client)
539 log_debug("destroy client %p", client);
542 kmscon_session_unregister(client->s);
543 shl_dlist_unlink(&client->list);
547 /* This must be called after each event dispatch round. It cleans up all
548 * interrupted/killed readers. The readers cannot be released right away due to
549 * heavy locking inside of FUSE. We have to delay these tasks and clean up after
550 * each dispatch round. */
551 static void client_cleanup(struct cdev_client *client)
553 struct shl_dlist *i, *tmp;
554 struct cdev_reader *reader;
555 struct cdev_waiter *waiter;
557 shl_dlist_for_each_safe(i, tmp, &client->readers) {
558 reader = shl_dlist_entry(i, struct cdev_reader, list);
560 reader_free(reader, -ENOENT);
563 shl_dlist_for_each_safe(i, tmp, &client->waiters) {
564 waiter = shl_dlist_entry(i, struct cdev_waiter, list);
566 waiter_free(waiter, -ENOENT);
572 * This implements all the file-system operations on the character-device. It is
573 * important that we handle interrupts correctly (ENOENT) and never loose any
574 * data. This is all single threaded as it is not performance critical at all.
577 static void ll_open(fuse_req_t req, struct fuse_file_info *fi)
579 struct kmscon_cdev *cdev = fuse_req_userdata(req);
580 struct cdev_client *client;
583 ret = client_new(&client, cdev);
587 fi->fh = (long)client;
590 ret = fuse_reply_open(req, fi);
592 client_destroy(client);
594 kmscon_session_enable(client->s);
599 fuse_reply_err(req, -ret);
602 static void ll_release(fuse_req_t req, struct fuse_file_info *fi)
604 struct cdev_client *client = (void*)fi->fh;
607 fuse_reply_err(req, EINVAL);
611 client_destroy(client);
612 fuse_reply_err(req, 0);
615 static void ll_read(fuse_req_t req, size_t size, off_t off,
616 struct fuse_file_info *fi)
618 struct cdev_client *client = (void*)fi->fh;
619 struct cdev_reader *reader;
625 fuse_reply_err(req, EINVAL);
630 fuse_reply_err(req, EPIPE);
635 fuse_reply_err(req, EINVAL);
640 fuse_reply_buf(req, "", 0);
644 /* TODO: use a proper intermediate buffer as this might return only
646 buf = shl_ring_peek(client->ring, &len, 0);
648 if (fi->flags & O_NONBLOCK) {
649 fuse_reply_err(req, EAGAIN);
653 ret = reader_new(&reader, client, req);
655 fuse_reply_err(req, -ret);
665 ret = fuse_reply_buf(req, buf, len);
668 shl_ring_drop(client->ring, len);
671 static void ll_write(fuse_req_t req, const char *buf, size_t size, off_t off,
672 struct fuse_file_info *fi)
674 struct cdev_client *client = (void*)fi->fh;
678 fuse_reply_err(req, EINVAL);
683 fuse_reply_err(req, EPIPE);
687 ret = fuse_reply_write(req, size);
690 tsm_vte_input(client->vte, buf, size);
693 static void ll_poll(fuse_req_t req, struct fuse_file_info *fi,
694 struct fuse_pollhandle *ph)
696 struct cdev_client *client = (void*)fi->fh;
700 fuse_reply_err(req, EINVAL);
706 fuse_pollhandle_destroy(ph);
707 fuse_reply_poll(req, EPOLLHUP | EPOLLIN | EPOLLOUT |
708 EPOLLWRNORM | EPOLLRDNORM);
713 fuse_pollhandle_destroy(client->ph);
716 flags = EPOLLOUT | EPOLLWRNORM;
717 if (!shl_ring_is_empty(client->ring))
718 flags |= EPOLLIN | EPOLLRDNORM;
720 fuse_reply_poll(req, flags);
723 static void ioctl_TCFLSH(struct cdev_client *client, fuse_req_t req, int val)
727 shl_ring_flush(client->ring);
730 shl_ring_flush(client->ring);
733 /* nothing to do; we have no output queue */
736 fuse_reply_err(req, EINVAL);
740 fuse_reply_ioctl(req, 0, NULL, 0);
743 static void ioctl_VT_ACTIVATE(struct cdev_client *client, fuse_req_t req,
746 unsigned short target, id;
748 id = client->cdev->minor;
752 kmscon_session_schedule(client->s);
754 kmscon_seat_schedule(client->cdev->seat, target);
757 fuse_reply_ioctl(req, 0, NULL, 0);
760 static void ioctl_VT_WAITACTIVE(struct cdev_client *client, fuse_req_t req,
764 struct cdev_waiter *waiter;
766 if (client->active) {
767 fuse_reply_ioctl(req, 0, NULL, 0);
771 ret = waiter_new(&waiter, client, req);
773 fuse_reply_err(req, -ret);
778 static void ioctl_VT_GETSTATE(struct cdev_client *client, fuse_req_t req)
783 id = client->cdev->minor;
784 if (id == 0 || id == 1)
787 memset(&buf, 0, sizeof(buf));
788 buf.v_active = client->active ? id : 1;
792 fuse_reply_ioctl(req, 0, &buf, sizeof(buf));
795 static void ioctl_VT_GETMODE(struct cdev_client *client, fuse_req_t req)
797 fuse_reply_ioctl(req, 0, &client->vtmode, sizeof(client->vtmode));
800 static void ioctl_VT_SETMODE(struct cdev_client *client, fuse_req_t req,
801 struct vt_mode *mode)
805 proc = mode->mode == VT_PROCESS;
807 /* TODO: implement "waitv" logic */
809 fuse_reply_err(req, EINVAL);
814 log_debug("cdev client uses non-zero 'frsig' in VT_SETMODE: %d",
817 if (mode->mode != VT_AUTO && mode->mode != VT_PROCESS) {
818 fuse_reply_err(req, EINVAL);
822 if (proc && (mode->relsig > SIGRTMAX || mode->acqsig > SIGRTMAX ||
823 mode->relsig < 0 || mode->acqsig < 0)) {
824 fuse_reply_err(req, EINVAL);
828 memcpy(&client->vtmode, mode, sizeof(*mode));
829 memcpy(&client->user, fuse_req_ctx(req), sizeof(client->user));
830 fuse_reply_ioctl(req, 0, NULL, 0);
833 static void ioctl_VT_RELDISP(struct cdev_client *client, fuse_req_t req,
836 if (client->pending_switch) {
837 client->pending_switch = false;
839 client->active = false;
840 kmscon_session_notify_deactivated(client->s);
844 fuse_reply_ioctl(req, 0, NULL, 0);
847 static void ioctl_KDGETMODE(struct cdev_client *client, fuse_req_t req)
849 fuse_reply_ioctl(req, 0, &client->kdmode, sizeof(long));
852 static void ioctl_KDSETMODE(struct cdev_client *client, fuse_req_t req,
859 ret = kmscon_session_set_foreground(client->s);
861 fuse_reply_err(req, -ret);
864 client->kdmode = KD_TEXT;
867 ret = kmscon_session_set_background(client->s);
869 fuse_reply_err(req, -ret);
872 client->kdmode = KD_GRAPHICS;
875 fuse_reply_err(req, EINVAL);
879 fuse_reply_ioctl(req, 0, NULL, 0);
882 static void ioctl_KDGKBMODE(struct cdev_client *client, fuse_req_t req)
884 fuse_reply_ioctl(req, 0, &client->kbmode, sizeof(long));
887 static void ioctl_KDSKBMODE(struct cdev_client *client, fuse_req_t req,
894 /* TODO: we handle K_RAW/K_UNICODE the same way as it is unclear
895 * what K_RAW should do? */
896 client->kbmode = val;
897 fuse_reply_ioctl(req, 0, NULL, 0);
901 /* TODO: what do these do? */
902 fuse_reply_err(req, EOPNOTSUPP);
905 fuse_reply_err(req, EINVAL);
910 static bool ioctl_param(fuse_req_t req, void *arg, size_t in_want,
911 size_t in_have, size_t out_want, size_t out_have)
914 struct iovec in, out;
915 size_t in_num, out_num;
918 memset(&in, 0, sizeof(in));
920 memset(&out, 0, sizeof(out));
926 } else if (in_have < in_want) {
927 fuse_reply_err(req, EFAULT);
932 in.iov_len = in_want;
938 } else if (out_have < out_want) {
939 fuse_reply_err(req, EFAULT);
944 out.iov_len = out_want;
949 fuse_reply_ioctl_retry(req, in_num ? &in : NULL, in_num,
950 out_num ? &out : NULL, out_num);
954 static void ll_ioctl(fuse_req_t req, int cmd, void *arg,
955 struct fuse_file_info *fi, unsigned int flags,
956 const void *in_buf, size_t in_bufsz, size_t out_bufsz)
958 struct cdev_client *client = (void*)fi->fh;
962 fuse_reply_err(req, EINVAL);
967 fuse_reply_err(req, EPIPE);
971 /* TODO: fix compat-ioctls */
972 compat = !!(flags & FUSE_IOCTL_COMPAT);
974 fuse_reply_err(req, EOPNOTSUPP);
980 if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
982 ioctl_TCFLSH(client, req, (long)arg);
985 if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
987 ioctl_VT_ACTIVATE(client, req, (long)arg);
990 if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
992 ioctl_VT_WAITACTIVE(client, req, (long)arg);
995 if (ioctl_param(req, arg, 0, in_bufsz,
996 sizeof(struct vt_stat), out_bufsz))
998 ioctl_VT_GETSTATE(client, req);
1001 if (ioctl_param(req, arg, 0, in_bufsz,
1002 sizeof(int), out_bufsz))
1004 fuse_reply_err(req, EOPNOTSUPP);
1007 if (ioctl_param(req, arg, 0, in_bufsz,
1008 sizeof(struct vt_mode), out_bufsz))
1010 ioctl_VT_GETMODE(client, req);
1013 if (ioctl_param(req, arg, sizeof(struct vt_mode), in_bufsz,
1016 ioctl_VT_SETMODE(client, req, (struct vt_mode*)in_buf);
1019 if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
1021 ioctl_VT_RELDISP(client, req, (long)arg);
1024 if (ioctl_param(req, arg, 0, in_bufsz,
1025 sizeof(long), out_bufsz))
1027 ioctl_KDGETMODE(client, req);
1030 if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
1032 ioctl_KDSETMODE(client, req, (long)arg);
1035 if (ioctl_param(req, arg, 0, in_bufsz,
1036 sizeof(long), out_bufsz))
1038 ioctl_KDGKBMODE(client, req);
1041 if (ioctl_param(req, arg, 0, in_bufsz, 0, out_bufsz))
1043 ioctl_KDSKBMODE(client, req, (long)arg);
1046 if (ioctl_param(req, arg, 0, in_bufsz,
1047 sizeof(struct termios), out_bufsz))
1049 fuse_reply_err(req, EOPNOTSUPP);
1052 if (ioctl_param(req, arg, sizeof(struct termios), in_bufsz,
1055 fuse_reply_err(req, EOPNOTSUPP);
1058 if (ioctl_param(req, arg, sizeof(struct termios), in_bufsz,
1061 fuse_reply_err(req, EOPNOTSUPP);
1064 if (ioctl_param(req, arg, sizeof(struct termios), in_bufsz,
1067 fuse_reply_err(req, EOPNOTSUPP);
1070 fuse_reply_err(req, EINVAL);
1075 static void ll_destroy(void *data) {
1076 struct kmscon_cdev *cdev = data;
1077 struct cdev_client *client;
1079 /* on unexpected shutdown this releases all currently open clients */
1080 while (!shl_dlist_empty(&cdev->clients)) {
1081 client = shl_dlist_entry(cdev->clients.next,
1082 struct cdev_client, list);
1083 client_destroy(client);
1087 static const struct cuse_lowlevel_ops ll_ops = {
1089 .destroy = ll_destroy,
1091 .release = ll_release,
1102 * The connection to the FUSE kernel module is done via a file-descriptor.
1103 * Writing to it is synchronous, so the commands that we write are _immediately_
1104 * executed and return the result to us. Furthermore, write() is always
1105 * non-blocking and always succeeds so no reason to watch for EAGAIN.
1106 * Reading from the FD, on the other hand, may block if there is no data
1107 * available. However, we only read if the FD was signaled readable so we can
1108 * use a blocking FD to avoid any side-effects. The kernel maintains an
1109 * event-queue that we read from. So there may be pending events that we haven't
1110 * read but which affect the calls that we write to the kernel. This is
1111 * important when handling interrupts.
1112 * chan_receive() and chan_send() handle I/O to the kernel module and are hooked
1113 * up into a fuse-channel.
1116 static int chan_receive(struct fuse_chan **chp, char *buf, size_t size)
1118 struct fuse_chan *ch = *chp;
1119 struct kmscon_cdev *cdev = fuse_chan_data(ch);
1120 struct fuse_session *se = fuse_chan_session(ch);
1121 int fd = fuse_chan_fd(ch);
1131 if (fuse_session_exited(se))
1134 res = read(fd, buf, size);
1136 /* EOF on cuse file */
1137 log_error("fuse channel shut down");
1138 fuse_session_exit(se);
1140 } else if (res < 0) {
1141 /* ENOENT is returned if the operation was interrupted, it's
1142 * safe to restart */
1143 if (errno == ENOENT)
1146 /* ENODEV is returned if the FS got unmounted. This shouldn't
1147 * occur for CUSE devices. Anyway, exit if this happens. */
1148 if (errno == ENODEV) {
1149 fuse_session_exit(se);
1153 /* EINTR and EAGAIN are simply forwarded to the caller. */
1154 if (errno == EINTR || errno == EAGAIN)
1157 cdev->error = -errno;
1158 log_error("fuse channel read error (%d): %m", errno);
1159 fuse_session_exit(se);
1166 static int chan_send(struct fuse_chan *ch, const struct iovec iov[],
1169 struct kmscon_cdev *cdev = fuse_chan_data(ch);
1170 struct fuse_session *se = fuse_chan_session(ch);
1171 int fd = fuse_chan_fd(ch);
1179 ret = writev(fd, iov, count);
1181 /* ENOENT is returned on interruptions */
1182 if (!fuse_session_exited(se) && errno != ENOENT) {
1183 cdev->error = -errno;
1184 log_error("cannot write to fuse-channel (%d): %m",
1186 fuse_session_exit(se);
1194 static const struct fuse_chan_ops chan_ops = {
1195 .receive = chan_receive,
1202 * This creates the high-level character-device driver and registers a
1203 * fake-session that is used to control each fake-VT session.
1204 * channel_event() is a callback when I/O is possible on the FUSE FD and
1205 * performs all outstanding tasks.
1206 * On error, the fake-session is unregistered and deleted which also destroys
1207 * _all_ client fake-sessions.
1210 static void channel_event(struct ev_fd *fd, int mask, void *data)
1212 struct kmscon_cdev *cdev = data;
1214 struct fuse_buf buf;
1215 struct fuse_chan *ch;
1216 struct shl_dlist *i;
1217 struct cdev_client *client;
1219 if (mask & (EV_HUP | EV_ERR)) {
1220 log_error("HUP/ERR on fuse channel");
1221 cdev->error = -EPIPE;
1222 kmscon_session_unregister(cdev->s);
1226 if (!(mask & EV_READABLE))
1229 memset(&buf, 0, sizeof(buf));
1230 buf.mem = cdev->buf;
1231 buf.size = cdev->bufsize;
1233 ret = fuse_session_receive_buf(cdev->session, &buf, &ch);
1234 if (ret == -EINTR || ret == -EAGAIN) {
1236 } else if (ret < 0) {
1237 log_error("fuse channel read error: %d", ret);
1239 kmscon_session_unregister(cdev->s);
1243 fuse_session_process_buf(cdev->session, &buf, ch);
1244 if (fuse_session_exited(cdev->session)) {
1245 log_error("fuse session exited");
1247 cdev->error = -EFAULT;
1248 kmscon_session_unregister(cdev->s);
1252 /* Readers can get interrupted asynchronously. Due to heavy locking
1253 * inside of FUSE, we cannot release them right away. So cleanup all
1254 * killed readers after we processed all buffers. */
1255 shl_dlist_for_each(i, &cdev->clients) {
1256 client = shl_dlist_entry(i, struct cdev_client, list);
1257 client_cleanup(client);
1261 static int kmscon_cdev_init(struct kmscon_cdev *cdev)
1263 static const char prefix[] = "DEVNAME=";
1264 static const char fname[] = "/dev/cuse";
1267 struct cuse_info ci;
1268 const char *dev_info_argv[1];
1271 /* TODO: libfuse makes sure that fd 0, 1 and 2 are available as standard
1272 * streams, otherwise they fail. This is awkward and we should check
1273 * whether this is really needed and _why_?
1274 * If it is needed, fix upstream to stop that crazy! */
1276 shl_dlist_init(&cdev->clients);
1278 ret = asprintf(&name, "%sttyF%s", prefix,
1279 kmscon_seat_get_name(cdev->seat));
1281 log_error("cannot allocate memory for fuse-devname");
1285 log_info("initializing fake VT TTY device /dev/%s",
1286 &name[sizeof(prefix) - 1]);
1288 id = cdev_allocate_id();
1290 log_error("cannot allocate new cdev TTY id: %d", id);
1296 dev_info_argv[0] = name;
1297 memset(&ci, 0, sizeof(ci));
1298 ci.dev_major = TTY_MAJOR;
1299 ci.dev_minor = cdev->minor;
1300 ci.dev_info_argc = 1;
1301 ci.dev_info_argv = dev_info_argv;
1302 ci.flags = CUSE_UNRESTRICTED_IOCTL;
1304 cdev->session = cuse_lowlevel_new(NULL, &ci, &ll_ops, cdev);
1307 if (!cdev->session) {
1308 log_error("cannot create fuse-ll session");
1312 cdev->fd = open(fname, O_RDWR | O_CLOEXEC);
1314 log_error("cannot open %s (%d): %m", fname, errno);
1319 bufsize = getpagesize() + 0x1000;
1320 if (bufsize < 0x21000)
1323 cdev->bufsize = bufsize;
1324 cdev->buf = malloc(bufsize);
1326 log_error("cannot allocate memory for buffer of size %zu",
1332 /* Argh! libfuse does not use "const" for the "chan_ops" pointer so we
1333 * actually have to cast it. Their implementation does not write into it
1334 * so we can safely use a constant storage for it.
1335 * TODO: Fix libfuse upstream! */
1336 cdev->channel = fuse_chan_new((void*)&chan_ops, cdev->fd, bufsize,
1338 if (!cdev->channel) {
1339 log_error("cannot allocate fuse-channel");
1344 ret = ev_eloop_new_fd(cdev->eloop, &cdev->efd, cdev->fd, EV_READABLE,
1345 channel_event, cdev);
1347 log_error("cannot create fd-object in eloop: %d", ret);
1351 fuse_session_add_chan(cdev->session, cdev->channel);
1355 fuse_chan_destroy(cdev->channel);
1361 fuse_session_destroy(cdev->session);
1365 void kmscon_cdev_destroy(struct kmscon_cdev *cdev)
1371 log_warning("cdev module failed with error %d (maybe another kmscon process is already running?)",
1374 fuse_session_destroy(cdev->session);
1375 ev_eloop_rm_fd(cdev->efd);
1380 static int session_event(struct kmscon_session *session,
1381 struct kmscon_session_event *ev, void *data)
1383 struct kmscon_cdev *cdev = data;
1386 case KMSCON_SESSION_UNREGISTER:
1387 log_debug("destroy cdev session");
1388 kmscon_cdev_destroy(cdev);
1396 int kmscon_cdev_register(struct kmscon_session **out,
1397 struct kmscon_seat *seat)
1399 struct kmscon_cdev *cdev;
1405 cdev = malloc(sizeof(*cdev));
1408 memset(cdev, 0, sizeof(*cdev));
1410 cdev->eloop = kmscon_seat_get_eloop(seat);
1411 cdev->input = kmscon_seat_get_input(seat);
1413 ret = kmscon_cdev_init(cdev);
1417 ret = kmscon_seat_register_session(seat, &cdev->s, session_event, cdev);
1419 log_error("cannot register session for cdev: %d", ret);
1427 kmscon_cdev_destroy(cdev);