aboutsummaryrefslogtreecommitdiff
path: root/backend/drm/session.c
diff options
context:
space:
mode:
authorScott Anderson <ascent12@hotmail.com>2017-05-01 15:20:48 +1200
committerScott Anderson <ascent12@hotmail.com>2017-05-01 15:20:48 +1200
commitaca13320b3e6df8cb575f64db736dc38b8b30ed2 (patch)
treeb39f6b902ff1af637afbe959d49369f09bc105b6 /backend/drm/session.c
parent1aed98730194aa80b5954ae1d6370162041b56e2 (diff)
Inital commit of libotd.
Diffstat (limited to 'backend/drm/session.c')
-rw-r--r--backend/drm/session.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/backend/drm/session.c b/backend/drm/session.c
new file mode 100644
index 00000000..c845fb27
--- /dev/null
+++ b/backend/drm/session.c
@@ -0,0 +1,224 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <systemd/sd-bus.h>
+#include <systemd/sd-login.h>
+#include <unistd.h>
+#include <sys/sysmacros.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "session.h"
+#include "otd.h"
+
+int take_device(struct otd *restrict otd,
+ const char *restrict path,
+ bool *restrict paused_out)
+{
+ int ret;
+ int fd = -1;
+ sd_bus_message *msg = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ struct otd_session *s = &otd->session;
+
+ struct stat st;
+ if (stat(path, &st) < 0) {
+ fprintf(stderr, "Failed to stat '%s'\n", path);
+ return -1;
+ }
+
+ ret = sd_bus_call_method(s->bus,
+ "org.freedesktop.login1",
+ s->path,
+ "org.freedesktop.login1.Session",
+ "TakeDevice",
+ &error, &msg,
+ "uu", major(st.st_rdev), minor(st.st_rdev));
+ if (ret < 0) {
+ fprintf(stderr, "%s\n", error.message);
+ goto error;
+ }
+
+ int paused = 0;
+ ret = sd_bus_message_read(msg, "hb", &fd, &paused);
+ if (ret < 0) {
+ fprintf(stderr, "%s\n", strerror(-ret));
+ goto error;
+ }
+
+ // The original fd seem to be closed when the message is freed
+ // so we just clone it.
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
+
+ if (paused_out)
+ *paused_out = paused;
+
+error:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(msg);
+ return fd;
+}
+
+void release_device(struct otd *otd, int fd)
+{
+ int ret;
+ sd_bus_message *msg = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ struct otd_session *s = &otd->session;
+
+ struct stat st;
+ if (fstat(fd, &st) < 0) {
+ fprintf(stderr, "Could not stat fd %d\n", fd);
+ return;
+ }
+
+ ret = sd_bus_call_method(s->bus,
+ "org.freedesktop.login1",
+ s->path,
+ "org.freedesktop.login1.Session",
+ "ReleaseDevice",
+ &error, &msg,
+ "uu", major(st.st_rdev), minor(st.st_rdev));
+ if (ret < 0) {
+ /* Log something */;
+ }
+
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(msg);
+}
+
+static bool session_activate(struct otd *otd)
+{
+ int ret;
+ sd_bus_message *msg = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ struct otd_session *s = &otd->session;
+
+ ret = sd_bus_call_method(s->bus,
+ "org.freedesktop.login1",
+ s->path,
+ "org.freedesktop.login1.Session",
+ "Activate",
+ &error, &msg,
+ "");
+ if (ret < 0) {
+ fprintf(stderr, "%s\n", error.message);
+ }
+
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(msg);
+ return ret >= 0;
+}
+
+static bool take_control(struct otd *otd)
+{
+ int ret;
+ sd_bus_message *msg = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ struct otd_session *s = &otd->session;
+
+ ret = sd_bus_call_method(s->bus,
+ "org.freedesktop.login1",
+ s->path,
+ "org.freedesktop.login1.Session",
+ "TakeControl",
+ &error, &msg,
+ "b", false);
+ if (ret < 0) {
+ /* Log something */;
+ }
+
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(msg);
+ return ret >= 0;
+}
+
+static void release_control(struct otd *otd)
+{
+ int ret;
+ sd_bus_message *msg = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ struct otd_session *s = &otd->session;
+
+ ret = sd_bus_call_method(s->bus,
+ "org.freedesktop.login1",
+ s->path,
+ "org.freedesktop.login1.Session",
+ "ReleaseControl",
+ &error, &msg,
+ "");
+ if (ret < 0) {
+ /* Log something */;
+ }
+
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(msg);
+}
+
+void otd_close_session(struct otd *otd)
+{
+ release_device(otd, otd->fd);
+ release_control(otd);
+
+ sd_bus_unref(otd->session.bus);
+ free(otd->session.id);
+ free(otd->session.path);
+ free(otd->session.seat);
+}
+
+bool otd_new_session(struct otd *otd)
+{
+ int ret;
+ struct otd_session *s = &otd->session;
+
+ ret = sd_pid_get_session(getpid(), &s->id);
+ if (ret < 0) {
+ fprintf(stderr, "Could not get session\n");
+ goto error;
+ }
+
+ ret = sd_session_get_seat(s->id, &s->seat);
+ if (ret < 0) {
+ fprintf(stderr, "Could not get seat\n");
+ goto error;
+ }
+
+ // This could be done using asprintf, but I don't want to define _GNU_SOURCE
+
+ const char *fmt = "/org/freedesktop/login1/session/%s";
+ int len = snprintf(NULL, 0, fmt, s->id);
+
+ s->path = malloc(len + 1);
+ if (!s->path)
+ goto error;
+
+ sprintf(s->path, fmt, s->id);
+
+ ret = sd_bus_open_system(&s->bus);
+ if (ret < 0) {
+ fprintf(stderr, "Could not open bus\n");
+ goto error;
+ }
+
+ if (!session_activate(otd)) {
+ fprintf(stderr, "Could not activate session\n");
+ goto error_bus;
+ }
+
+ if (!take_control(otd)) {
+ fprintf(stderr, "Could not take control of session\n");
+ goto error_bus;
+ }
+
+ return true;
+
+error_bus:
+ sd_bus_unref(s->bus);
+
+error:
+ free(s->path);
+ free(s->id);
+ free(s->seat);
+ return false;
+}