commit 5901d5a1ab47a9f11466a6a0b3984fed9d133d80
parent f57c76f5f4ffdb19cf2692f125f5e219ca27da64
Author: Michael Forney <mforney@mforney.org>
Date: Tue, 22 Oct 2013 13:47:46 -0700
Refactor launcher
* Move tty handling to launcher.
* Handle DRM master and evdev revoking in launcher.
* Make launcher a standalone program that can start arbitrary servers.
* Handle VT switching in launcher.
Diffstat:
16 files changed, 442 insertions(+), 481 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -28,5 +28,5 @@ Makefile.in
/libswc/libswc.la
/launch/liblaunch-protocol.la
-/launch/libswc-launch.la
+/launch/swc-launch
diff --git a/launch/Makefile.am b/launch/Makefile.am
@@ -2,16 +2,12 @@
AM_CFLAGS = $(drm_CFLAGS)
-lib_LTLIBRARIES = libswc-launch.la
+bin_PROGRAMS = swc-launch
noinst_LTLIBRARIES = liblaunch-protocol.la
-libswc_launch_la_SOURCES = \
- launch.c swc-launch.h
+swc_launch_SOURCES = launch.c
+swc_launch_LDADD = liblaunch-protocol.la $(drm_LIBS)
+swc_launch_LDFLAGS = -static
-libswc_launch_la_LIBADD = $(drm_LIBS) liblaunch-protocol.la
-
-liblaunch_protocol_la_SOURCES = \
- protocol.c protocol.h
-
-include_HEADERS = swc-launch.h
+liblaunch_protocol_la_SOURCES = protocol.c protocol.h
diff --git a/launch/launch.c b/launch/launch.c
@@ -1,4 +1,30 @@
-#include "swc-launch.h"
+/* swc: launch/launch.c
+ *
+ * Copyright (c) 2013 Michael Forney
+ *
+ * Based in part upon weston-launch.c from weston which is:
+ *
+ * Copyright © 2012 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
#include "protocol.h"
#include <stdlib.h>
@@ -8,35 +34,156 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
-#include <sys/epoll.h>
+#include <poll.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
+#include <linux/kd.h>
#include <linux/major.h>
#include <linux/vt.h>
#include <xf86drm.h>
-static void print_usage(const char * name, const char * compositor_name)
+#ifndef DRM_MAJOR
+# define DRM_MAJOR 226
+#endif
+#ifndef EVIOCREVOKE
+# define EVIOCREVOKE _IOW('E', 0x91, int)
+#endif
+
+#define ARRAY_LENGTH(array) (sizeof (array) / sizeof (array)[0])
+
+pid_t child_pid = -1;
+
+static struct
+{
+ int input_fds[128];
+ unsigned num_input_fds;
+ int drm_fds[16];
+ unsigned num_drm_fds;
+ int tty_fd;
+} launcher;
+
+static struct
+{
+ bool altered;
+ int vt;
+ long kb_mode;
+ long console_mode;
+} original_vt_state;
+
+static void __attribute__((noreturn)) usage(const char * name)
+{
+ fprintf(stderr, "Usage: %s [-h] [--] <server> [server arguments...]\n", name);
+ exit(EXIT_FAILURE);
+}
+
+static void start_devices()
+{
+ unsigned index;
+
+ for (index = 0; index < launcher.num_drm_fds; ++index)
+ drmSetMaster(launcher.drm_fds[index]);
+}
+
+static void stop_devices()
+{
+ unsigned index;
+
+ for (index = 0; index < launcher.num_drm_fds; ++index)
+ drmDropMaster(launcher.drm_fds[index]);
+
+ for (index = 0; index < launcher.num_input_fds; ++index)
+ {
+ if (ioctl(launcher.input_fds[index], EVIOCREVOKE, 1) == -1
+ && errno == EINVAL)
+ {
+ static bool warned = false;
+
+ if (!warned)
+ {
+ fprintf(stderr, "WARNING: Your kernel does not support EVIOCREVOKE; "
+ "input devices cannot be revoked\n");
+ warned = true;
+ }
+ }
+ close(launcher.input_fds[index]);
+ }
+ launcher.num_input_fds = 0;
+}
+
+static void cleanup()
+{
+ /* Cleanup VT */
+ if (original_vt_state.altered)
+ {
+ struct vt_mode mode = { .mode = VT_AUTO };
+
+ fprintf(stderr, "Restoring VT to original state\n");
+ ioctl(launcher.tty_fd, VT_SETMODE, &mode);
+ ioctl(launcher.tty_fd, KDSETMODE, original_vt_state.console_mode);
+ ioctl(launcher.tty_fd, KDSKBMODE, original_vt_state.kb_mode);
+ ioctl(launcher.tty_fd, VT_ACTIVATE, original_vt_state.vt);
+ }
+
+ stop_devices();
+}
+
+static void __attribute__((noreturn,format(printf,1,2)))
+ die(const char * format, ...)
{
- fprintf(stderr, "Usage: %s [-- [%s arguments]]\n",
- name, compositor_name);
+ va_list args;
+
+ fputs("FATAL: ", stderr);
+ va_start(args, format);
+ vfprintf(stderr, format, args);
+ va_end(args);
+
+ if (errno != 0)
+ fprintf(stderr, ": %s", strerror(errno));
+
+ fputc('\n', stderr);
+
+ if (child_pid)
+ cleanup();
+
+ exit(EXIT_FAILURE);
}
-static void catch_chld(int signal)
+static void handle_chld(int signal)
{
int status;
wait(&status);
- exit(status);
+ fprintf(stderr, "Server exited with status %d\n", WEXITSTATUS(status));
+ cleanup();
+ exit(WEXITSTATUS(status));
+}
+
+static void handle_usr1(int signal)
+{
+ stop_devices();
+ ioctl(launcher.tty_fd, VT_RELDISP, 1);
+}
+
+static void handle_usr2(int signal)
+{
+ start_devices();
+ ioctl(launcher.tty_fd, VT_RELDISP, VT_ACKACQ);
+}
+
+static void forward_signal(int signal)
+{
+ kill(child_pid, signal);
}
static void handle_socket_data(int socket)
{
char buffer[BUFSIZ];
struct swc_launch_request * request = (void *) &buffer;
- struct swc_launch_response response = { false };
+ struct swc_launch_response response;
int fd;
+ struct stat st;
ssize_t size;
size = receive_fd(socket, &fd, buffer, sizeof buffer);
@@ -46,30 +193,45 @@ static void handle_socket_data(int socket)
switch (request->type)
{
- case SWC_LAUNCH_REQUEST_DRM_MASTER:
- response.success = (request->set ? drmSetMaster(fd)
- : drmDropMaster(fd)) == 0;
- fd = -1;
- break;
- case SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE:
- {
- struct stat st;
-
+ case SWC_LAUNCH_REQUEST_OPEN_DEVICE:
if (request->path[size - __builtin_offsetof(typeof(*request),
- path)] != '\0')
+ path) - 1] != '\0')
{
fprintf(stderr, "Path is not NULL terminated\n");
goto fail;
}
- stat(request->path, &st);
-
- if (major(st.st_rdev) != INPUT_MAJOR)
+ if (stat(request->path, &st) == -1)
{
- fprintf(stderr, "Device is not an input device\n");
+ fprintf(stderr, "Could not stat %s\n", request->path);
goto fail;
}
+ switch (major(st.st_rdev))
+ {
+ case INPUT_MAJOR:
+ if (launcher.num_input_fds
+ == ARRAY_LENGTH(launcher.input_fds))
+ {
+ fprintf(stderr, "Too many input devices opened\n");
+ goto fail;
+ }
+ break;
+ case DRM_MAJOR:
+ if (launcher.num_drm_fds
+ == ARRAY_LENGTH(launcher.drm_fds))
+ {
+ fprintf(stderr, "Too many DRM devices opened\n");
+ goto fail;
+ }
+ break;
+ default:
+ fprintf(stderr, "Device is not an input device\n");
+ goto fail;
+ }
+
+ fprintf(stderr, "opening %s\n", request->path);
+
fd = open(request->path, request->flags);
if (fd == -1)
@@ -78,13 +240,35 @@ static void handle_socket_data(int socket)
goto fail;
}
+ switch (major(st.st_rdev))
+ {
+ case INPUT_MAJOR:
+ launcher.input_fds[launcher.num_input_fds++] = fd;
+ break;
+ case DRM_MAJOR:
+ if (drmSetMaster(fd) == -1)
+ {
+ perror("Could not become DRM master");
+ goto fail;
+ }
+ launcher.drm_fds[launcher.num_drm_fds++] = fd;
+ break;
+ }
+
+ break;
+ case SWC_LAUNCH_REQUEST_ACTIVATE_VT:
+ if (ioctl(launcher.tty_fd, VT_ACTIVATE, request->vt) == -1)
+ {
+ fprintf(stderr, "Could not activate VT %d: %s\n",
+ request->vt, strerror(errno));
+ }
break;
- }
default:
fprintf(stderr, "Unknown request %u\n", request->type);
goto fail;
}
+ response.success = true;
goto done;
fail:
@@ -94,23 +278,6 @@ static void handle_socket_data(int socket)
send_fd(socket, fd, &response, sizeof response);
}
-static void monitor_socket(int epoll_fd)
-{
- struct epoll_event event;
- int count;
-
- while (true)
- {
- printf("waiting\n");
- count = epoll_wait(epoll_fd, &event, 1, -1);
-
- if (count < 0)
- break;
-
- handle_socket_data(event.data.fd);
- }
-}
-
static int find_vt()
{
char * vt_string;
@@ -123,21 +290,17 @@ static int find_vt()
{
char * end;
vt = strtoul(vt_string, &end, 10);
- printf("vt: %d\n", vt);
if (*end == '\0')
goto done;
}
tty0_fd = open("/dev/tty0", O_RDWR);
-
if (ioctl(tty0_fd, VT_OPENQRY, &vt) != 0)
- {
- printf("could not find open vt\n");
- vt = 0;
- }
-
+ die("Could not find open VT");
close(tty0_fd);
+ fprintf(stderr, "Running on VT %d\n", vt);
+
done:
return vt;
}
@@ -162,107 +325,201 @@ static int open_tty(int vt)
fd = open(tty_name, O_RDWR | O_NOCTTY);
if (fd < 0)
- {
- fprintf(stderr, "FATAL: Could not open %s\n", tty_name);
- exit(EXIT_FAILURE);
- }
+ die("Could not open %s", tty_name);
return fd;
}
}
-int swc_launch(int argc, const char * argv[], const char * path)
+static void setup_tty(int fd)
{
- int sockets[2];
- int epoll_fd;
- struct epoll_event event;
+ struct stat st;
+ int vt;
+ struct vt_stat state;
+ struct vt_mode mode = {
+ .mode = VT_PROCESS,
+ .relsig = SIGUSR1,
+ .acqsig = SIGUSR2
+ };
+
+ if (fstat(fd, &st) == -1)
+ die("Could not stat TTY fd");
+
+ vt = minor(st.st_rdev);
+
+ if (major(st.st_rdev) != TTY_MAJOR || vt == 0)
+ die("Not a valid VT");
+
+ if (ioctl(fd, VT_GETSTATE, &state) == -1)
+ die("Could not get the current VT state");
+
+ original_vt_state.vt = state.v_active;
+
+ if (ioctl(fd, KDGKBMODE, &original_vt_state.kb_mode))
+ die("Could not get keyboard mode");
+
+ if (ioctl(fd, KDGETMODE, &original_vt_state.console_mode))
+ die("Could not get console mode");
- if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, sockets) == -1)
+ if (ioctl(fd, KDSKBMODE, K_OFF) == -1)
+ die("Could not set keyboard mode to K_OFF");
+
+ if (ioctl(fd, KDSETMODE, KD_GRAPHICS) == -1)
{
- fprintf(stderr, "FATAL: Could not create socket pair\n");
- return EXIT_FAILURE;
+ perror("Could not set console mode to KD_GRAPHICS");
+ goto error0;
}
- if (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1)
+ if (ioctl(fd, VT_SETMODE, &mode) == -1)
+ {
+ perror("Could not set VT mode");
+ goto error1;
+ }
+
+ if (ioctl(fd, VT_ACTIVATE, vt) == -1)
+ {
+ perror("Could not activate VT");
+ goto error2;
+ }
+
+ if (ioctl(fd, VT_WAITACTIVE, vt) == -1)
{
- fprintf(stderr, "FATAL: Could not set CLOEXEC on socket\n");
- return EXIT_FAILURE;
+ perror("Could not wait for VT to become active");
+ goto error2;
}
- epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ original_vt_state.altered = true;
- if (epoll_fd == -1)
+ return;
+
+ error2:
+ mode = (struct vt_mode) { .mode = VT_AUTO };
+ ioctl(fd, VT_SETMODE, &mode);
+ error1:
+ ioctl(fd, KDSETMODE, original_vt_state.console_mode);
+ error0:
+ ioctl(fd, KDSKBMODE, original_vt_state.kb_mode);
+ exit(EXIT_FAILURE);
+}
+
+int main(int argc, char * argv[])
+{
+ int option;
+ int sockets[2];
+ int vt;
+ struct sigaction action = { 0 };
+ sigset_t set;
+
+ while ((option = getopt(argc, argv, "h")) != -1)
{
- fprintf(stderr, "FATAL: Could not create epoll\n");
- return EXIT_FAILURE;
+ switch (option)
+ {
+ case 'h':
+ default:
+ usage(argv[0]);
+ }
}
- event.events = EPOLLIN;
- event.data.fd = sockets[0];
- epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockets[0], &event);
+ if (argc - optind < 1)
+ usage(argv[0]);
+
+ if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, sockets) == -1)
+ die("Could not create socket pair");
+
+ if (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1)
+ die("Could not set CLOEXEC on socket");
+
+ action.sa_handler = &handle_chld;
+ if (sigaction(SIGCHLD, &action, NULL) == -1)
+ die("Failed to register signal handler for SIGCHLD");
+
+ action.sa_handler = &handle_usr1;
+ if (sigaction(SIGUSR1, &action, NULL) == -1)
+ die("Failed to register signal handler for SIGUSR1");
+
+ action.sa_handler = &handle_usr2;
+ if (sigaction(SIGUSR2, &action, NULL) == -1)
+ die("Failed to register signal handler for SIGUSR2");
+
+ action.sa_handler = &forward_signal;
+ if (sigaction(SIGINT, &action, NULL) == -1)
+ die("Failed to register signal handler for SIGINT");
+ if (sigaction(SIGTERM, &action, NULL) == -1)
+ die("Failed to register signal handler for SIGTERM");
+
+ sigfillset(&set);
+ sigdelset(&set, SIGCHLD);
+ sigdelset(&set, SIGUSR1);
+ sigdelset(&set, SIGUSR2);
+ sigdelset(&set, SIGINT);
+ sigdelset(&set, SIGTERM);
+ sigprocmask(SIG_SETMASK, &set, NULL);
+
+ vt = find_vt();
+ launcher.tty_fd = open_tty(vt);
+ setup_tty(launcher.tty_fd);
+
+ child_pid = fork();
/* Child */
- if (fork() == 0)
+ if (child_pid == 0)
{
char string[64];
- int tty_fd;
- int vt;
uid_t uid;
gid_t gid;
- vt = find_vt();
- tty_fd = open_tty(vt);
-
- /* If the desired TTY is not the current TTY, start a new session, and
- * set it's controlling TTY appropriately. */
- if (tty_fd != STDIN_FILENO)
- {
- pid_t sid = setsid();
-
- if (ioctl(tty_fd, TIOCSCTTY, vt) != 0)
- {
- fprintf(stderr, "FATAL: Couldn't set controlling TTY to "
- "/dev/tty%u: %s\n", vt, strerror(errno));
- exit(EXIT_FAILURE);
- }
-
- //tcsetpgrp(tty_fd, sid);
- }
+ /* Reset signal handlers to defaults */
+ action.sa_handler = SIG_DFL;
+ if (sigaction(SIGCHLD, &action, NULL) == -1)
+ die("Failed to set default signal handler for SIGCHLD");
+ if (sigaction(SIGUSR1, &action, NULL) == -1)
+ die("Failed to set default signal handler for SIGUSR1");
+ if (sigaction(SIGUSR2, &action, NULL) == -1)
+ die("Failed to set default signal handler for SIGUSR2");
+ if (sigaction(SIGINT, &action, NULL) == -1)
+ die("Failed to set default signal handler for SIGINT");
+ if (sigaction(SIGTERM, &action, NULL) == -1)
+ die("Failed to set default signal handler for SIGTERM");
+
+ /* Set empty signal mask */
+ sigemptyset(&set);
+ sigprocmask(SIG_SETMASK, &set, NULL);
sprintf(string, "%d", sockets[1]);
setenv(SWC_LAUNCH_SOCKET_ENV, string, 1);
- sprintf(string, "%d", tty_fd);
+ sprintf(string, "%d", launcher.tty_fd);
setenv(SWC_LAUNCH_TTY_FD_ENV, string, 1);
- printf("dropping privileges\n");
setuid(getuid());
setgid(getgid());
- //execlp("valgrind", "valgrind", "-v", "--suppressions=drm.supp",
- // "--track-origins=yes", path, NULL);
- execlp("gdb", "gdb", path, NULL);
- //execl(path, path, NULL);
- printf("%s failed: %s\n", path, strerror(errno));
-
- exit(EXIT_FAILURE);
+ execvp(argv[optind], argv + optind);
+ die("Could not exec %s", argv[optind]);
}
/* Parent */
else
{
- struct sigaction action;
- sigset_t blocked_signals;
+ struct pollfd pollfd;
+ int ret;
+
+ pollfd.fd = sockets[0];
+ pollfd.events = POLLIN;
- action.sa_handler = &catch_chld;
- sigaction(SIGCHLD, &action, NULL);
+ while (true)
+ {
+ ret = poll(&pollfd, 1, -1);
- sigemptyset(&blocked_signals);
- sigaddset(&blocked_signals, SIGINT);
- sigaddset(&blocked_signals, SIGTERM);
- sigprocmask(SIG_BLOCK, &blocked_signals, NULL);
+ if (ret == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ die("Error while polling on socket fd");
+ }
- printf("monitoring socket\n");
- monitor_socket(epoll_fd);
+ handle_socket_data(pollfd.fd);
+ }
}
return EXIT_SUCCESS;
diff --git a/launch/protocol.c b/launch/protocol.c
@@ -3,13 +3,12 @@
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
-#include <errno.h>
-ssize_t send_fd(int socket, int fd, void * buffer, ssize_t buffer_size)
+ssize_t send_fd(int socket, int fd, const void * buffer, ssize_t buffer_size)
{
char control[CMSG_SPACE(sizeof(int))];
struct iovec iov = {
- .iov_base = buffer,
+ .iov_base = (void *) buffer,
.iov_len = buffer_size
};
struct msghdr message = {
diff --git a/launch/protocol.h b/launch/protocol.h
@@ -11,20 +11,20 @@ struct swc_launch_request
{
enum
{
- SWC_LAUNCH_REQUEST_DRM_MASTER,
- SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE
+ SWC_LAUNCH_REQUEST_OPEN_DEVICE,
+ SWC_LAUNCH_REQUEST_ACTIVATE_VT
} type;
union
{
- struct /* DRM_MASTER */
- {
- bool set;
- };
- struct /* OPEN_INPUT_DEVICE */
+ struct /* OPEN_DEVICE */
{
int flags;
char path[];
};
+ struct /* ACTIVATE_VT */
+ {
+ unsigned vt;
+ };
};
};
@@ -33,7 +33,7 @@ struct swc_launch_response
bool success;
};
-ssize_t send_fd(int socket, int fd, void * buffer, ssize_t buffer_size);
+ssize_t send_fd(int socket, int fd, const void * buffer, ssize_t buffer_size);
ssize_t receive_fd(int socket, int * fd, void * buffer,
ssize_t buffer_size);
diff --git a/launch/swc-launch.h b/launch/swc-launch.h
@@ -1,7 +0,0 @@
-#ifndef SWC_LAUNCH_H
-#define SWC_LAUNCH_H 1
-
-int swc_launch(int argc, const char * argv[], const char * path);
-
-#endif
-
diff --git a/libswc/Makefile.am b/libswc/Makefile.am
@@ -23,7 +23,6 @@ libswc_la_SOURCES = \
data_device.c data_device.h \
data.c data.h \
mode.c mode.h \
- tty.c tty.h \
evdev_device.c evdev_device.h \
xkb.c xkb.h \
drm.c drm.h \
diff --git a/libswc/compositor.c b/libswc/compositor.c
@@ -5,7 +5,6 @@
#include "compositor.h"
#include "compositor_surface.h"
#include "cursor_surface.h"
-#include "tty.h"
#include "output.h"
#include "surface.h"
#include "event.h"
@@ -249,25 +248,6 @@ struct swc_pointer_handler pointer_handler = {
.motion = &handle_motion
};
-/* XXX: maybe this should go in swc_drm */
-static void handle_tty_event(struct wl_listener * listener, void * data)
-{
- struct swc_event * event = data;
- struct swc_compositor * compositor;
-
- compositor = swc_container_of(listener, typeof(*compositor), tty_listener);
-
- switch (event->type)
- {
- case SWC_TTY_VT_ENTER:
- swc_drm_set_master(&compositor->drm);
- break;
- case SWC_TTY_VT_LEAVE:
- swc_drm_drop_master(&compositor->drm);
- break;
- }
-}
-
static void handle_drm_event(struct wl_listener * listener, void * data)
{
struct swc_event * event = data;
@@ -330,11 +310,9 @@ static void handle_terminate(uint32_t time, uint32_t value, void * data)
static void handle_switch_vt(uint32_t time, uint32_t value, void * data)
{
- struct swc_tty * tty = data;
uint8_t vt = value - XKB_KEY_XF86Switch_VT_1 + 1;
printf("handle switch vt%u\n", vt);
- if (vt != tty->vt)
- swc_tty_switch_vt(tty, vt);
+ swc_launch_activate_vt(vt);
}
static void create_surface(struct wl_client * client,
@@ -400,7 +378,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
xkb_keysym_t keysym;
compositor->display = display;
- compositor->tty_listener.notify = &handle_tty_event;
compositor->drm_listener.notify = &handle_drm_event;
compositor->pointer_listener.notify = &handle_pointer_event;
compositor->scheduled_updates = 0;
@@ -409,7 +386,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
= &swc_compositor_class_implementation;
compositor->cursor_class.interface = &swc_cursor_class_implementation;
-
compositor->udev = udev_new();
if (compositor->udev == NULL)
@@ -420,20 +396,11 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
event_loop = wl_display_get_event_loop(display);
- if (!swc_tty_initialize(&compositor->tty, event_loop, 2))
- {
- printf("could not initialize tty\n");
- goto error_udev;
- }
-
- wl_signal_add(&compositor->tty.event_signal, &compositor->tty_listener);
-
/* TODO: configurable seat */
- if (!swc_seat_initialize(&compositor->seat, compositor->udev,
- default_seat))
+ if (!swc_seat_initialize(&compositor->seat, compositor->udev, default_seat))
{
printf("could not initialize seat\n");
- goto error_tty;
+ goto error_udev;
}
swc_seat_add_event_sources(&compositor->seat, event_loop);
@@ -500,7 +467,7 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
++keysym)
{
swc_compositor_add_key_binding(compositor, SWC_MOD_ANY, keysym,
- &handle_switch_vt, &compositor->tty);
+ &handle_switch_vt, NULL);
}
@@ -512,8 +479,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
swc_drm_finish(&compositor->drm);
error_seat:
swc_seat_finish(&compositor->seat);
- error_tty:
- swc_tty_finish(&compositor->tty);
error_udev:
udev_unref(compositor->udev);
error_base:
@@ -536,7 +501,6 @@ void swc_compositor_finish(struct swc_compositor * compositor)
swc_drm_finish(&compositor->drm);
swc_seat_finish(&compositor->seat);
- swc_tty_finish(&compositor->tty);
udev_unref(compositor->udev);
}
diff --git a/libswc/compositor.h b/libswc/compositor.h
@@ -2,7 +2,6 @@
#define SWC_COMPOSITOR_H 1
#include "drm.h"
-#include "tty.h"
#include "seat.h"
#include "binding.h"
#include "renderer.h"
@@ -15,7 +14,6 @@ struct swc_compositor
struct udev * udev;
- struct swc_tty tty;
struct swc_seat seat;
struct swc_drm drm;
struct swc_renderer renderer;
@@ -42,7 +40,6 @@ struct swc_compositor
struct swc_surface_class compositor_class;
struct swc_surface_class cursor_class;
- struct wl_listener tty_listener;
struct wl_listener drm_listener;
struct wl_listener pointer_listener;
diff --git a/libswc/drm.c b/libswc/drm.c
@@ -312,7 +312,7 @@ bool swc_drm_initialize(struct swc_drm * drm, struct udev * udev,
drm->path = strdup(udev_device_get_devnode(drm_device));
udev_device_unref(drm_device);
- drm->fd = open(drm->path, O_RDWR | O_CLOEXEC);
+ drm->fd = swc_launch_open_device(drm->path, O_RDWR | O_CLOEXEC);
if (drm->fd == -1)
{
@@ -375,18 +375,6 @@ void swc_drm_add_globals(struct swc_drm * drm, struct wl_display * display)
wl_global_create(display, &wl_drm_interface, 2, drm, &bind_drm);
}
-void swc_drm_set_master(struct swc_drm * drm)
-{
- printf("setting drm master\n");
- drmSetMaster(drm->fd);
-}
-
-void swc_drm_drop_master(struct swc_drm * drm)
-{
- printf("dropping drm master\n");
- drmDropMaster(drm->fd);
-}
-
struct wl_list * swc_drm_create_outputs(struct swc_drm * drm)
{
drmModeRes * resources;
diff --git a/libswc/drm.h b/libswc/drm.h
@@ -44,10 +44,6 @@ void swc_drm_add_event_sources(struct swc_drm * drm,
void swc_drm_add_globals(struct swc_drm * drm, struct wl_display * display);
-void swc_drm_set_master(struct swc_drm * drm);
-
-void swc_drm_drop_master(struct swc_drm * drm);
-
struct wl_list * swc_drm_create_outputs(struct swc_drm * drm);
#endif
diff --git a/libswc/evdev_device.c b/libswc/evdev_device.c
@@ -2,6 +2,7 @@
#include "seat.h"
#include "event.h"
+#include "util.h"
#include <stdlib.h>
#include <stdio.h>
@@ -142,7 +143,7 @@ struct swc_evdev_device * swc_evdev_device_new
if (!(device = malloc(sizeof *device)))
goto error0;
- device->fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
+ device->fd = swc_launch_open_device(path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
if (device->fd == -1)
{
diff --git a/libswc/tty.c b/libswc/tty.c
@@ -1,216 +0,0 @@
-/* swc: tty.c
- *
- * Copyright © 2012 Michael Forney
- *
- * Based in part upon tty.c from weston, which is:
- *
- * Copyright © 2010 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <linux/kd.h>
-
-#include <wayland-server.h>
-
-#include "tty.h"
-#include "event.h"
-
-static void restore_tty(struct swc_tty * tty);
-static int handle_vt_signal(int signal_number, void * data);
-
-bool swc_tty_initialize(struct swc_tty * tty,
- struct wl_event_loop * event_loop,
- uint8_t tty_number)
-{
- struct vt_stat state;
- char tty_device[16];
- struct vt_mode mode;
-
- wl_signal_init(&tty->event_signal);
-
- if (tty_number == 0)
- {
- char * vt_string = getenv("XDG_VTNR");
- if (vt_string)
- {
- char * end;
- tty_number = strtoul(vt_string, &end, 10);
- if (*end != '\0')
- tty_number = 0;
- }
- }
-
- /* If we still don't have a VT number. */
- if (tty_number == 0)
- {
- printf("don't know which VT to run on\n");
- goto error_base;
- }
-
- snprintf(tty_device, sizeof(tty_device), "/dev/tty%u", tty_number);
-
- /* Open the TTY. */
- tty->fd = open(tty_device, O_RDWR | O_NOCTTY | O_CLOEXEC);
-
- if (tty->fd == -1)
- {
- printf("couldn't open tty\n");
- goto error_base;
- }
-
- tty->vt = tty_number;
-
- /* Determine the current VT state. */
- if (ioctl(tty->fd, VT_GETSTATE, &state) != 0)
- {
- printf("could not determine starting vt\n");
- goto error_tty;
- }
-
- tty->original_state.vt = state.v_active;
- printf("starting vt: %u\n", tty->original_state.vt);
-
- /* Switch to the new VT if necessary. */
- if (tty->original_state.vt != tty->vt)
- {
- if (ioctl(tty->fd, VT_ACTIVATE, tty->vt) != 0
- || ioctl(tty->fd, VT_WAITACTIVE, tty->vt) != 0)
- {
- printf("couldn't switch to vt%u\n", tty->vt);
- goto error_tty;
- }
- }
-
- tty->active = true;
-
- /* Save current kb_mode. */
- if (ioctl(tty->fd, KDGKBMODE, &tty->original_state.kb_mode) != 0)
- {
- printf("couldn't determine kb_mode of vt%u\n", tty->vt);
- goto error_tty;
- }
-
- /* Turn off keyboard, we will use evdev for input. */
- if (ioctl(tty->fd, KDSKBMODE, K_OFF) != 0)
- {
- printf("couldn't set kb_mode of vt%u to K_OFF\n", tty->vt);
- goto error_tty;
- }
-
- /* Set VT to graphics mode. */
- if (ioctl(tty->fd, KDSETMODE, KD_GRAPHICS) != 0)
- {
- printf("couldn't set mode of vt%u to KD_GRAPHICS\n", tty->vt);
- goto error_kdkbmode;
- }
-
- mode = (struct vt_mode) {
- .mode = VT_PROCESS,
- .relsig = SIGUSR1,
- .acqsig = SIGUSR1
- };
-
- /* Set up VT switching handler. */
- if (ioctl(tty->fd, VT_SETMODE, &mode) != 0)
- {
- printf("could not set VT mode on vt%u\n", tty->vt);
- goto error_kdmode;
- }
-
- tty->vt_source = wl_event_loop_add_signal(event_loop, SIGUSR1,
- &handle_vt_signal, tty);
-
- if (!tty->vt_source)
- {
- printf("could not create VT event source\n");
- goto error_vtmode;
- }
-
- return true;
-
- error_vtmode:
- mode = (struct vt_mode) { .mode = VT_AUTO };
- ioctl(tty->fd, VT_SETMODE, &mode);
- error_kdmode:
- ioctl(tty->fd, KDSETMODE, KD_TEXT);
- error_kdkbmode:
- ioctl(tty->fd, KDSKBMODE, tty->original_state.kb_mode);
- error_tty:
- close(tty->fd);
- error_base:
- return false;
-}
-
-void swc_tty_finish(struct swc_tty * tty)
-{
- wl_event_source_remove(tty->vt_source);
- restore_tty(tty);
- close(tty->fd);
-}
-
-void swc_tty_switch_vt(struct swc_tty * tty, uint32_t vt)
-{
- ioctl(tty->fd, VT_ACTIVATE, vt);
-}
-
-void restore_tty(struct swc_tty * tty)
-{
- struct vt_mode mode = { .mode = VT_AUTO };
-
- if (ioctl(tty->fd, KDSKBMODE, tty->original_state.kb_mode) != 0)
- printf("failed to restore keyboard mode\n");
- if (ioctl(tty->fd, KDSETMODE, KD_TEXT) != 0)
- printf("failed to set mode to KD_TEXT\n");
- if (ioctl(tty->fd, VT_SETMODE, &mode) != 0)
- printf("failed to restore VT handling\n");
- if (tty->vt != tty->original_state.vt
- && (ioctl(tty->fd, VT_ACTIVATE, tty->original_state.vt) != 0
- || ioctl(tty->fd, VT_WAITACTIVE, tty->original_state.vt) != 0))
- {
- printf("failed to restore VT\n");
- }
-}
-
-static int handle_vt_signal(int signal_number, void * data)
-{
- struct swc_tty * tty = data;
-
- if (tty->active)
- {
- swc_send_event(&tty->event_signal, SWC_TTY_VT_LEAVE, NULL);
- ioctl(tty->fd, VT_RELDISP, 1);
- tty->active = false;
- }
- else
- {
- ioctl(tty->fd, VT_RELDISP, VT_ACKACQ);
- tty->active = true;
- swc_send_event(&tty->event_signal, SWC_TTY_VT_ENTER, NULL);
- }
-
- return 1;
-}
-
diff --git a/libswc/tty.h b/libswc/tty.h
@@ -1,44 +0,0 @@
-#ifndef SWC_TTY_H
-#define SWC_TTY_H 1
-
-#include <stdint.h>
-#include <stdbool.h>
-#include <signal.h>
-
-enum swc_tty_event
-{
- SWC_TTY_VT_ENTER = 0,
- SWC_TTY_VT_LEAVE
-};
-
-struct swc_tty
-{
- int fd;
- uint8_t vt;
-
- bool active;
-
- /* The state of the VT the compositor was started on so we have a state to
- * restore to when the compositor closes. */
- struct
- {
- uint8_t vt;
- long kb_mode;
- } original_state;
-
- /* Receives events when switching from/to the VT the compositor is running on. */
- struct wl_event_source * vt_source;
-
- struct wl_signal event_signal;
-};
-
-bool swc_tty_initialize(struct swc_tty * tty,
- struct wl_event_loop * event_loop,
- uint8_t tty_number);
-
-void swc_tty_finish(struct swc_tty * tty);
-
-void swc_tty_switch_vt(struct swc_tty * tty, uint32_t vt);
-
-#endif
-
diff --git a/libswc/util.c b/libswc/util.c
@@ -12,51 +12,81 @@ void swc_remove_resource(struct wl_resource * resource)
wl_list_remove(wl_resource_get_link(resource));
}
-bool swc_launch_drm_master(int socket, int fd, bool set)
+static int get_launcher_socket()
{
- ssize_t size;
- struct swc_launch_request request;
- struct swc_launch_response response;
+ static int launcher_socket = -1;
- request.type = SWC_LAUNCH_REQUEST_DRM_MASTER;
- request.set = set;
+ if (launcher_socket == -1)
+ {
+ char * launcher_socket_name;
- size = send_fd(socket, fd, &request, sizeof request);
+ if ((launcher_socket_name = getenv(SWC_LAUNCH_SOCKET_ENV)))
+ {
+ char * end;
- if (size == -1)
- return false;
+ launcher_socket = strtol(launcher_socket_name, &end, 10);
+ if (*end != '\0')
+ launcher_socket = -1;
+ }
+ }
- size = recv(socket, &response, sizeof response, 0);
+ return launcher_socket;
+}
+
+static bool send_request(const struct swc_launch_request * request, size_t size,
+ struct swc_launch_response * response,
+ int out_fd, int * in_fd)
+{
+ int socket;
+ ssize_t ret;
- if (size == -1)
+ socket = get_launcher_socket();
+
+ if (send_fd(socket, out_fd, request, size) == -1)
+ return false;
+
+ if (receive_fd(socket, in_fd, &response, sizeof response) == -1)
return false;
return true;
}
-int swc_launch_open_input_device(int socket, const char * path, int flags)
+int swc_launch_open_device(const char * path, int flags)
{
size_t path_size = strlen(path);
char buffer[sizeof(struct swc_launch_request) + path_size + 1];
struct swc_launch_request * request = (void *) buffer;
struct swc_launch_response response;
- ssize_t size;
int fd;
+ int socket;
+
+ socket = get_launcher_socket();
- request->type = SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE;
+ request->type = SWC_LAUNCH_REQUEST_OPEN_DEVICE;
request->flags = flags;
strcpy(request->path, path);
- size = send(socket, buffer, sizeof buffer, 0);
-
- if (size == -1)
+ if (!send_request(request, sizeof buffer, &response, -1, &fd))
return -1;
- size = receive_fd(socket, &fd, &response, sizeof response);
+ return fd;
+}
- if (size == -1)
- return -1;
+bool swc_launch_activate_vt(unsigned vt)
+{
+ struct swc_launch_request request;
+ struct swc_launch_response response;
+ ssize_t size;
+ int socket;
- return fd;
+ socket = get_launcher_socket();
+
+ request.type = SWC_LAUNCH_REQUEST_ACTIVATE_VT;
+ request.vt = vt;
+
+ if (!send_request(&request, sizeof request, &response, -1, NULL))
+ return false;
+
+ return response.success;
}
diff --git a/libswc/util.h b/libswc/util.h
@@ -43,8 +43,9 @@ static inline bool swc_rectangle_overlap
< r1->height + r2->height);
}
-int swc_launch_open_input_device(int socket, const char * path, int flags);
-bool swc_launch_drm_master(int socket, int fd, bool set);
+/* Launch Utilities */
+int swc_launch_open_device(const char * path, int flags);
+bool swc_launch_activate_vt(unsigned vt);
/* Double Buffers */
struct swc_double_buffer