swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

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:
M.gitignore | 2+-
Mlaunch/Makefile.am | 14+++++---------
Mlaunch/launch.c | 473+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mlaunch/protocol.c | 5++---
Mlaunch/protocol.h | 16++++++++--------
Dlaunch/swc-launch.h | 7-------
Mlibswc/Makefile.am | 1-
Mlibswc/compositor.c | 44++++----------------------------------------
Mlibswc/compositor.h | 3---
Mlibswc/drm.c | 14+-------------
Mlibswc/drm.h | 4----
Mlibswc/evdev_device.c | 3++-
Dlibswc/tty.c | 216-------------------------------------------------------------------------------
Dlibswc/tty.h | 44--------------------------------------------
Mlibswc/util.c | 72+++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mlibswc/util.h | 5+++--
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