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.
This commit is contained in:
sghctoma 2018-08-30 11:15:39 +02:00
parent 633663cdde
commit 2bd6fbf20e
2 changed files with 55 additions and 8 deletions

View file

@ -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);
}

View file

@ -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;
}