aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvgeny Zinoviev <me@ch1p.com>2018-10-28 01:00:03 +0300
committerEvgeny Zinoviev <me@ch1p.com>2018-10-28 19:09:38 +0300
commit2a453f362d34674b2adfc9f29bb781a0ba7a69c2 (patch)
treeb38eabf030a59afed45b2d5ff2c5b311b4f8b56a
initial
-rw-r--r--Makefile26
-rw-r--r--README.md1
-rw-r--r--drm_master_util.c151
3 files changed, 178 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f69be8d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+CC = gcc
+CFLAGS = -O2 -Wall -W
+CFLAGS += `pkg-config --cflags libdrm`
+LDFLAGS = `pkg-config --libs libdrm`
+PROGRAM = drm_master_util
+INSTALL = /usr/bin/install
+PREFIX = /usr
+
+all: $(PROGRAM)
+
+$(PROGRAM): drm_master_util.o
+ $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
+
+install: $(PROGRAM)
+ $(INSTALL) $(PROGRAM) $(PREFIX)/bin
+ chmod u+s $(PREFIX)/bin/${PROGRAM}
+
+clean:
+ rm -f *.o $(PROGRAM)
+
+distclean: clean
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $^ -I. -o $@
+
+.PHONY: all install clean distclean
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..b923e75
--- /dev/null
+++ b/README.md
@@ -0,0 +1 @@
+# drm_master_util
diff --git a/drm_master_util.c b/drm_master_util.c
new file mode 100644
index 0000000..73884af
--- /dev/null
+++ b/drm_master_util.c
@@ -0,0 +1,151 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <errno.h>
+#include <xf86drm.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#define DRM_HACK_SOCKET_NAME "xorg_drm_master_util"
+
+int recv_fd(int sock)
+{
+ // This function does the arcane magic recving
+ // file descriptors over unix domain sockets
+ struct msghdr msg;
+ struct iovec iov[1];
+ struct cmsghdr *cmsg = NULL;
+ char ctrl_buf[CMSG_SPACE(sizeof(int))];
+ char data[1];
+
+ memset(&msg, 0, sizeof(struct msghdr));
+ memset(ctrl_buf, 0, CMSG_SPACE(sizeof(int)));
+
+ iov[0].iov_base = data;
+ iov[0].iov_len = sizeof(data);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = ctrl_buf;
+ msg.msg_controllen = CMSG_SPACE(sizeof(int));
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ recvmsg(sock, &msg, 0);
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+
+ return *((int *) CMSG_DATA(cmsg));
+}
+
+void usage(const char *name)
+{
+ printf("usage: %s\n", name);
+ printf("\n"
+ "-h, --help: print this help\n"
+ "-s, --set: drmSetMaster\n"
+ "-d, --drop: drmDropMaster\n"
+ "-t, --test: test\n"
+ "-r, --root: ensure i'm root\n"
+ "\n");
+}
+
+void check_error(char *prog, int err)
+{
+ if (err) {
+ fprintf(stderr, "%s: %s\n", prog, strerror(errno));
+ exit(err);
+ }
+}
+
+enum action {HELP, SET, DROP, TEST};
+
+int main(int argc, char *argv[])
+{
+ enum action act = HELP;
+ int opt, optindex = 0;
+ int ret = 0;
+ bool ensure_root = false;
+ static struct option longopts[] = {
+ {"help", 0, 0, 'h'},
+ {"set", 0, 0, 's'},
+ {"drop", 0, 0, 'd'},
+ {"test", 0, 0, 't'},
+ {"root", 0, 0, 'r'},
+ {0, 0, 0, 0}
+ };
+
+ if (argv[1] == NULL) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ while ((opt = getopt_long(argc, argv, "hsdtr",
+ longopts, &optindex)) != EOF) {
+ switch (opt) {
+ case 's': act = SET; break;
+ case 'd': act = DROP; break;
+ case 't': act = TEST; break;
+ case 'r': ensure_root = true; break;
+ }
+ }
+
+ if (optind < argc) {
+ fprintf(stderr, "Error: extra parameter found.\n");
+ exit(1);
+ }
+
+ if (ensure_root) {
+ uid_t uid = getuid();
+ uid_t euid = geteuid();
+
+ assert(euid == 0);
+
+ ret = setuid(euid);
+ check_error("setuid", ret);
+
+ uid = getuid();
+ euid = getuid();
+
+ assert(uid == 0);
+ }
+
+ if (act == HELP) {
+ usage(argv[0]);
+ exit(0);
+ }
+
+ struct sockaddr_un addr;
+ int sock;
+
+ // Create and connect a unix domain socket
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strcpy(&addr.sun_path[1], DRM_HACK_SOCKET_NAME);
+ connect(sock, (struct sockaddr *)&addr, sizeof(addr));
+
+ int fd = recv_fd(sock);
+ close(sock);
+
+ assert(fd != 0);
+
+ if (act == SET) {
+ ret = drmSetMaster(fd);
+ check_error("drmSetMaster", ret);
+ } else if (act == DROP) {
+ ret = drmDropMaster(fd);
+ check_error("drmDropMaster", ret);
+ } else if (act == TEST) {
+ printf("received fd: %d\n", fd);
+ dprintf(fd, "drm_master_util: writing to received fd ;)\n");
+ }
+
+ return 0;
+}