From 2bd6fbf20ebb055d4871ffb8eedefa7d7aa60ee8 Mon Sep 17 00:00:00 2001 From: sghctoma Date: Thu, 30 Aug 2018 11:15:39 +0200 Subject: [PATCH] Fix that major(st_rdev) have no meaning on FreeBSD The major device number does not indicate the device type on FreeBSD, and AFAIK the only way to differentiate between DRM, input, and other devices is checking the fd path. This commit implements that. The drmDropmaster and drmSetmaster calls are necessary, because the implicit drop (that should occur when the DRM fd is closed) seems not to be working in some scenarios (e.g. if you have a tmux session running - maybe the fd is retained somehow by tmux?). This is a problem, because once you exit the compositor, you can't start it (or any other program that wants to be DRM master) again until you close all your tmux sessions. --- backend/session/direct-freebsd.c | 42 +++++++++++++++++++++++++++----- backend/session/direct-ipc.c | 21 ++++++++++++++-- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/backend/session/direct-freebsd.c b/backend/session/direct-freebsd.c index 63e1be01..1ef76f7a 100644 --- a/backend/session/direct-freebsd.c +++ b/backend/session/direct-freebsd.c @@ -40,12 +40,6 @@ static int direct_session_open(struct wlr_session *base, const char *path) { return fd; } - struct stat st; - if (fstat(fd, &st) < 0) { - close(fd); - return -errno; - } - return fd; } @@ -59,6 +53,20 @@ static void direct_session_close(struct wlr_session *base, int fd) { return; } + char *name; + name = devname(st.st_rdev, S_IFCHR); + if (name == NULL) { + wlr_log_errno(WLR_ERROR, "Failed to get device name"); + close(fd); + return; + } + + if (strncmp(name, "drm/", 4) == 0) { + direct_ipc_dropmaster(session->sock, fd); + } else if (strncmp(name, "input/event", 11)) { + ioctl(fd, EVIOCREVOKE, 0); + } + close(fd); } @@ -79,6 +87,8 @@ static void direct_session_destroy(struct wlr_session *base) { ioctl(session->tty_fd, KDSETMODE, KD_TEXT); ioctl(session->tty_fd, VT_SETMODE, &mode); + ioctl(session->tty_fd, VT_ACTIVATE, 1); + if (errno) { wlr_log(WLR_ERROR, "Failed to restore tty"); } @@ -97,9 +107,29 @@ static int vt_handler(int signo, void *data) { if (session->base.active) { session->base.active = false; wlr_signal_emit_safe(&session->base.session_signal, session); + + char *name; + struct wlr_device *dev; + wl_list_for_each(dev, &session->base.devices, link) { + name = devname(dev->dev, S_IFCHR); + if (name != NULL && strncmp(name, "drm/", 4) == 0) { + direct_ipc_dropmaster(session->sock, dev->fd); + } + } + ioctl(session->tty_fd, VT_RELDISP, 1); } else { ioctl(session->tty_fd, VT_RELDISP, VT_ACKACQ); + + char *name; + struct wlr_device *dev; + wl_list_for_each(dev, &session->base.devices, link) { + name = devname(dev->dev, S_IFCHR); + if (name != NULL && strncmp(name, "drm/", 4) == 0) { + direct_ipc_setmaster(session->sock, dev->fd); + } + } + session->base.active = true; wlr_signal_emit_safe(&session->base.session_signal, session); } diff --git a/backend/session/direct-ipc.c b/backend/session/direct-ipc.c index 5fdb95ac..99ffcb1b 100644 --- a/backend/session/direct-ipc.c +++ b/backend/session/direct-ipc.c @@ -142,6 +142,7 @@ static void communicate(int sock) { goto error; } +#ifndef __FreeBSD__ struct stat st; if (fstat(fd, &st) < 0) { ret = errno; @@ -157,6 +158,19 @@ static void communicate(int sock) { if (maj == DRM_MAJOR && drmSetMaster(fd)) { ret = errno; } +#else + if (strncmp(msg.path, "/dev/drm/", 9) && + strncmp(msg.path, "/dev/input/event", 16)) { + + ret = ENOTSUP; + goto error; + } + + if (strncmp(msg.path, "/dev/drm/", 9) == 0 && drmSetMaster(fd)) { + ret = errno; + } +#endif + error: send_msg(sock, ret ? -1 : fd, &ret, sizeof(ret)); if (fd >= 0) { @@ -193,8 +207,11 @@ int direct_ipc_open(int sock, const char *path) { send_msg(sock, -1, &msg, sizeof(msg)); - int fd, err; - recv_msg(sock, &fd, &err, sizeof(err)); + int fd, err, ret; + int retry = 0; + do { + ret = recv_msg(sock, &fd, &err, sizeof(err)); + } while (ret == 0 && retry++ < 3); return err ? -err : fd; }