commit 5901d5a

Michael Forney  ·  2013-10-22 20:47:46 +0000 UTC
parent f57c76f
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.
16 files changed,  +442, -481
+1, -1
1@@ -28,5 +28,5 @@ Makefile.in
2 
3 /libswc/libswc.la
4 /launch/liblaunch-protocol.la
5-/launch/libswc-launch.la
6+/launch/swc-launch
7 
+5, -9
 1@@ -2,16 +2,12 @@
 2 
 3 AM_CFLAGS = $(drm_CFLAGS)
 4 
 5-lib_LTLIBRARIES = libswc-launch.la
 6+bin_PROGRAMS = swc-launch
 7 noinst_LTLIBRARIES = liblaunch-protocol.la
 8 
 9-libswc_launch_la_SOURCES = \
10-	launch.c swc-launch.h
11+swc_launch_SOURCES = launch.c
12+swc_launch_LDADD = liblaunch-protocol.la $(drm_LIBS)
13+swc_launch_LDFLAGS = -static
14 
15-libswc_launch_la_LIBADD = $(drm_LIBS) liblaunch-protocol.la
16-
17-liblaunch_protocol_la_SOURCES = \
18-	protocol.c protocol.h
19-
20-include_HEADERS = swc-launch.h
21+liblaunch_protocol_la_SOURCES = protocol.c protocol.h
22 
+365, -108
  1@@ -1,4 +1,30 @@
  2-#include "swc-launch.h"
  3+/* swc: launch/launch.c
  4+ *
  5+ * Copyright (c) 2013 Michael Forney
  6+ *
  7+ * Based in part upon weston-launch.c from weston which is:
  8+ *
  9+ *     Copyright © 2012 Benjamin Franzke
 10+ *
 11+ * Permission is hereby granted, free of charge, to any person obtaining a copy
 12+ * of this software and associated documentation files (the "Software"), to deal
 13+ * in the Software without restriction, including without limitation the rights
 14+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 15+ * copies of the Software, and to permit persons to whom the Software is
 16+ * furnished to do so, subject to the following conditions:
 17+ *
 18+ * The above copyright notice and this permission notice shall be included in
 19+ * all copies or substantial portions of the Software.
 20+ *
 21+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 22+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 23+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 24+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 25+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 26+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 27+ * SOFTWARE.
 28+ */
 29+
 30 #include "protocol.h"
 31 
 32 #include <stdlib.h>
 33@@ -8,35 +34,156 @@
 34 #include <unistd.h>
 35 #include <errno.h>
 36 #include <fcntl.h>
 37-#include <sys/epoll.h>
 38+#include <poll.h>
 39 #include <sys/socket.h>
 40 #include <sys/stat.h>
 41 #include <sys/wait.h>
 42 #include <sys/ioctl.h>
 43+#include <linux/kd.h>
 44 #include <linux/major.h>
 45 #include <linux/vt.h>
 46 #include <xf86drm.h>
 47 
 48-static void print_usage(const char * name, const char * compositor_name)
 49+#ifndef DRM_MAJOR
 50+# define DRM_MAJOR 226
 51+#endif
 52+#ifndef EVIOCREVOKE
 53+# define EVIOCREVOKE _IOW('E', 0x91, int)
 54+#endif
 55+
 56+#define ARRAY_LENGTH(array) (sizeof (array) / sizeof (array)[0])
 57+
 58+pid_t child_pid = -1;
 59+
 60+static struct
 61+{
 62+    int input_fds[128];
 63+    unsigned num_input_fds;
 64+    int drm_fds[16];
 65+    unsigned num_drm_fds;
 66+    int tty_fd;
 67+} launcher;
 68+
 69+static struct
 70+{
 71+    bool altered;
 72+    int vt;
 73+    long kb_mode;
 74+    long console_mode;
 75+} original_vt_state;
 76+
 77+static void __attribute__((noreturn)) usage(const char * name)
 78+{
 79+    fprintf(stderr, "Usage: %s [-h] [--] <server> [server arguments...]\n", name);
 80+    exit(EXIT_FAILURE);
 81+}
 82+
 83+static void start_devices()
 84+{
 85+    unsigned index;
 86+
 87+    for (index = 0; index < launcher.num_drm_fds; ++index)
 88+        drmSetMaster(launcher.drm_fds[index]);
 89+}
 90+
 91+static void stop_devices()
 92+{
 93+    unsigned index;
 94+
 95+    for (index = 0; index < launcher.num_drm_fds; ++index)
 96+        drmDropMaster(launcher.drm_fds[index]);
 97+
 98+    for (index = 0; index < launcher.num_input_fds; ++index)
 99+    {
100+        if (ioctl(launcher.input_fds[index], EVIOCREVOKE, 1) == -1
101+            && errno == EINVAL)
102+        {
103+            static bool warned = false;
104+
105+            if (!warned)
106+            {
107+                fprintf(stderr, "WARNING: Your kernel does not support EVIOCREVOKE; "
108+                                "input devices cannot be revoked\n");
109+                warned = true;
110+            }
111+        }
112+        close(launcher.input_fds[index]);
113+    }
114+    launcher.num_input_fds = 0;
115+}
116+
117+static void cleanup()
118+{
119+    /* Cleanup VT */
120+    if (original_vt_state.altered)
121+    {
122+        struct vt_mode mode = { .mode = VT_AUTO };
123+
124+        fprintf(stderr, "Restoring VT to original state\n");
125+        ioctl(launcher.tty_fd, VT_SETMODE, &mode);
126+        ioctl(launcher.tty_fd, KDSETMODE, original_vt_state.console_mode);
127+        ioctl(launcher.tty_fd, KDSKBMODE, original_vt_state.kb_mode);
128+        ioctl(launcher.tty_fd, VT_ACTIVATE, original_vt_state.vt);
129+    }
130+
131+    stop_devices();
132+}
133+
134+static void __attribute__((noreturn,format(printf,1,2)))
135+    die(const char * format, ...)
136 {
137-    fprintf(stderr, "Usage: %s [-- [%s arguments]]\n",
138-            name, compositor_name);
139+    va_list args;
140+
141+    fputs("FATAL: ", stderr);
142+    va_start(args, format);
143+    vfprintf(stderr, format, args);
144+    va_end(args);
145+
146+    if (errno != 0)
147+        fprintf(stderr, ": %s", strerror(errno));
148+
149+    fputc('\n', stderr);
150+
151+    if (child_pid)
152+        cleanup();
153+
154+    exit(EXIT_FAILURE);
155 }
156 
157-static void catch_chld(int signal)
158+static void handle_chld(int signal)
159 {
160     int status;
161 
162     wait(&status);
163-    exit(status);
164+    fprintf(stderr, "Server exited with status %d\n", WEXITSTATUS(status));
165+    cleanup();
166+    exit(WEXITSTATUS(status));
167+}
168+
169+static void handle_usr1(int signal)
170+{
171+    stop_devices();
172+    ioctl(launcher.tty_fd, VT_RELDISP, 1);
173+}
174+
175+static void handle_usr2(int signal)
176+{
177+    start_devices();
178+    ioctl(launcher.tty_fd, VT_RELDISP, VT_ACKACQ);
179+}
180+
181+static void forward_signal(int signal)
182+{
183+    kill(child_pid, signal);
184 }
185 
186 static void handle_socket_data(int socket)
187 {
188     char buffer[BUFSIZ];
189     struct swc_launch_request * request = (void *) &buffer;
190-    struct swc_launch_response response = { false };
191+    struct swc_launch_response response;
192     int fd;
193+    struct stat st;
194     ssize_t size;
195 
196     size = receive_fd(socket, &fd, buffer, sizeof buffer);
197@@ -46,30 +193,45 @@ static void handle_socket_data(int socket)
198 
199     switch (request->type)
200     {
201-        case SWC_LAUNCH_REQUEST_DRM_MASTER:
202-            response.success = (request->set ? drmSetMaster(fd)
203-                                             : drmDropMaster(fd)) == 0;
204-            fd = -1;
205-            break;
206-        case SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE:
207-        {
208-            struct stat st;
209-
210+        case SWC_LAUNCH_REQUEST_OPEN_DEVICE:
211             if (request->path[size - __builtin_offsetof(typeof(*request),
212-                                                        path)] != '\0')
213+                                                        path) - 1] != '\0')
214             {
215                 fprintf(stderr, "Path is not NULL terminated\n");
216                 goto fail;
217             }
218 
219-            stat(request->path, &st);
220-
221-            if (major(st.st_rdev) != INPUT_MAJOR)
222+            if (stat(request->path, &st) == -1)
223             {
224-                fprintf(stderr, "Device is not an input device\n");
225+                fprintf(stderr, "Could not stat %s\n", request->path);
226                 goto fail;
227             }
228 
229+            switch (major(st.st_rdev))
230+            {
231+                case INPUT_MAJOR:
232+                    if (launcher.num_input_fds
233+                        == ARRAY_LENGTH(launcher.input_fds))
234+                    {
235+                        fprintf(stderr, "Too many input devices opened\n");
236+                        goto fail;
237+                    }
238+                    break;
239+                case DRM_MAJOR:
240+                    if (launcher.num_drm_fds
241+                        == ARRAY_LENGTH(launcher.drm_fds))
242+                    {
243+                        fprintf(stderr, "Too many DRM devices opened\n");
244+                        goto fail;
245+                    }
246+                    break;
247+                default:
248+                    fprintf(stderr, "Device is not an input device\n");
249+                    goto fail;
250+            }
251+
252+            fprintf(stderr, "opening %s\n", request->path);
253+
254             fd = open(request->path, request->flags);
255 
256             if (fd == -1)
257@@ -78,13 +240,35 @@ static void handle_socket_data(int socket)
258                 goto fail;
259             }
260 
261+            switch (major(st.st_rdev))
262+            {
263+                case INPUT_MAJOR:
264+                    launcher.input_fds[launcher.num_input_fds++] = fd;
265+                    break;
266+                case DRM_MAJOR:
267+                    if (drmSetMaster(fd) == -1)
268+                    {
269+                        perror("Could not become DRM master");
270+                        goto fail;
271+                    }
272+                    launcher.drm_fds[launcher.num_drm_fds++] = fd;
273+                    break;
274+            }
275+
276+            break;
277+        case SWC_LAUNCH_REQUEST_ACTIVATE_VT:
278+            if (ioctl(launcher.tty_fd, VT_ACTIVATE, request->vt) == -1)
279+            {
280+                fprintf(stderr, "Could not activate VT %d: %s\n",
281+                        request->vt, strerror(errno));
282+            }
283             break;
284-        }
285         default:
286             fprintf(stderr, "Unknown request %u\n", request->type);
287             goto fail;
288     }
289 
290+    response.success = true;
291     goto done;
292 
293   fail:
294@@ -94,23 +278,6 @@ static void handle_socket_data(int socket)
295     send_fd(socket, fd, &response, sizeof response);
296 }
297 
298-static void monitor_socket(int epoll_fd)
299-{
300-    struct epoll_event event;
301-    int count;
302-
303-    while (true)
304-    {
305-        printf("waiting\n");
306-        count = epoll_wait(epoll_fd, &event, 1, -1);
307-
308-        if (count < 0)
309-            break;
310-
311-        handle_socket_data(event.data.fd);
312-    }
313-}
314-
315 static int find_vt()
316 {
317     char * vt_string;
318@@ -123,21 +290,17 @@ static int find_vt()
319     {
320         char * end;
321         vt = strtoul(vt_string, &end, 10);
322-        printf("vt: %d\n", vt);
323         if (*end == '\0')
324             goto done;
325     }
326 
327     tty0_fd = open("/dev/tty0", O_RDWR);
328-
329     if (ioctl(tty0_fd, VT_OPENQRY, &vt) != 0)
330-    {
331-        printf("could not find open vt\n");
332-        vt = 0;
333-    }
334-
335+        die("Could not find open VT");
336     close(tty0_fd);
337 
338+    fprintf(stderr, "Running on VT %d\n", vt);
339+
340   done:
341     return vt;
342 }
343@@ -162,107 +325,201 @@ static int open_tty(int vt)
344         fd = open(tty_name, O_RDWR | O_NOCTTY);
345 
346         if (fd < 0)
347-        {
348-            fprintf(stderr, "FATAL: Could not open %s\n", tty_name);
349-            exit(EXIT_FAILURE);
350-        }
351+            die("Could not open %s", tty_name);
352 
353         return fd;
354     }
355 }
356 
357-int swc_launch(int argc, const char * argv[], const char * path)
358+static void setup_tty(int fd)
359 {
360-    int sockets[2];
361-    int epoll_fd;
362-    struct epoll_event event;
363+    struct stat st;
364+    int vt;
365+    struct vt_stat state;
366+    struct vt_mode mode = {
367+        .mode = VT_PROCESS,
368+        .relsig = SIGUSR1,
369+        .acqsig = SIGUSR2
370+    };
371+
372+    if (fstat(fd, &st) == -1)
373+        die("Could not stat TTY fd");
374+
375+    vt = minor(st.st_rdev);
376+
377+    if (major(st.st_rdev) != TTY_MAJOR || vt == 0)
378+        die("Not a valid VT");
379+
380+    if (ioctl(fd, VT_GETSTATE, &state) == -1)
381+        die("Could not get the current VT state");
382+
383+    original_vt_state.vt = state.v_active;
384+
385+    if (ioctl(fd, KDGKBMODE, &original_vt_state.kb_mode))
386+        die("Could not get keyboard mode");
387+
388+    if (ioctl(fd, KDGETMODE, &original_vt_state.console_mode))
389+        die("Could not get console mode");
390 
391-    if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, sockets) == -1)
392+    if (ioctl(fd, KDSKBMODE, K_OFF) == -1)
393+        die("Could not set keyboard mode to K_OFF");
394+
395+    if (ioctl(fd, KDSETMODE, KD_GRAPHICS) == -1)
396     {
397-        fprintf(stderr, "FATAL: Could not create socket pair\n");
398-        return EXIT_FAILURE;
399+        perror("Could not set console mode to KD_GRAPHICS");
400+        goto error0;
401     }
402 
403-    if (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1)
404+    if (ioctl(fd, VT_SETMODE, &mode) == -1)
405+    {
406+        perror("Could not set VT mode");
407+        goto error1;
408+    }
409+
410+    if (ioctl(fd, VT_ACTIVATE, vt) == -1)
411+    {
412+        perror("Could not activate VT");
413+        goto error2;
414+    }
415+
416+    if (ioctl(fd, VT_WAITACTIVE, vt) == -1)
417     {
418-        fprintf(stderr, "FATAL: Could not set CLOEXEC on socket\n");
419-        return EXIT_FAILURE;
420+        perror("Could not wait for VT to become active");
421+        goto error2;
422     }
423 
424-    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
425+    original_vt_state.altered = true;
426 
427-    if (epoll_fd == -1)
428+    return;
429+
430+  error2:
431+    mode = (struct vt_mode) { .mode = VT_AUTO };
432+    ioctl(fd, VT_SETMODE, &mode);
433+  error1:
434+    ioctl(fd, KDSETMODE, original_vt_state.console_mode);
435+  error0:
436+    ioctl(fd, KDSKBMODE, original_vt_state.kb_mode);
437+    exit(EXIT_FAILURE);
438+}
439+
440+int main(int argc, char * argv[])
441+{
442+    int option;
443+    int sockets[2];
444+    int vt;
445+    struct sigaction action = { 0 };
446+    sigset_t set;
447+
448+    while ((option = getopt(argc, argv, "h")) != -1)
449     {
450-        fprintf(stderr, "FATAL: Could not create epoll\n");
451-        return EXIT_FAILURE;
452+        switch (option)
453+        {
454+            case 'h':
455+            default:
456+                usage(argv[0]);
457+        }
458     }
459 
460-    event.events = EPOLLIN;
461-    event.data.fd = sockets[0];
462-    epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockets[0], &event);
463+    if (argc - optind < 1)
464+        usage(argv[0]);
465+
466+    if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, sockets) == -1)
467+        die("Could not create socket pair");
468+
469+    if (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1)
470+        die("Could not set CLOEXEC on socket");
471+
472+    action.sa_handler = &handle_chld;
473+    if (sigaction(SIGCHLD, &action, NULL) == -1)
474+        die("Failed to register signal handler for SIGCHLD");
475+
476+    action.sa_handler = &handle_usr1;
477+    if (sigaction(SIGUSR1, &action, NULL) == -1)
478+        die("Failed to register signal handler for SIGUSR1");
479+
480+    action.sa_handler = &handle_usr2;
481+    if (sigaction(SIGUSR2, &action, NULL) == -1)
482+        die("Failed to register signal handler for SIGUSR2");
483+
484+    action.sa_handler = &forward_signal;
485+    if (sigaction(SIGINT, &action, NULL) == -1)
486+        die("Failed to register signal handler for SIGINT");
487+    if (sigaction(SIGTERM, &action, NULL) == -1)
488+        die("Failed to register signal handler for SIGTERM");
489+
490+    sigfillset(&set);
491+    sigdelset(&set, SIGCHLD);
492+    sigdelset(&set, SIGUSR1);
493+    sigdelset(&set, SIGUSR2);
494+    sigdelset(&set, SIGINT);
495+    sigdelset(&set, SIGTERM);
496+    sigprocmask(SIG_SETMASK, &set, NULL);
497+
498+    vt = find_vt();
499+    launcher.tty_fd = open_tty(vt);
500+    setup_tty(launcher.tty_fd);
501+
502+    child_pid = fork();
503 
504     /* Child */
505-    if (fork() == 0)
506+    if (child_pid == 0)
507     {
508         char string[64];
509-        int tty_fd;
510-        int vt;
511         uid_t uid;
512         gid_t gid;
513 
514-        vt = find_vt();
515-        tty_fd = open_tty(vt);
516-
517-        /* If the desired TTY is not the current TTY, start a new session, and
518-         * set it's controlling TTY appropriately. */
519-        if (tty_fd != STDIN_FILENO)
520-        {
521-            pid_t sid = setsid();
522-
523-            if (ioctl(tty_fd, TIOCSCTTY, vt) != 0)
524-            {
525-                fprintf(stderr, "FATAL: Couldn't set controlling TTY to "
526-                                "/dev/tty%u: %s\n", vt, strerror(errno));
527-                exit(EXIT_FAILURE);
528-            }
529-
530-            //tcsetpgrp(tty_fd, sid);
531-        }
532+        /* Reset signal handlers to defaults */
533+        action.sa_handler = SIG_DFL;
534+        if (sigaction(SIGCHLD, &action, NULL) == -1)
535+            die("Failed to set default signal handler for SIGCHLD");
536+        if (sigaction(SIGUSR1, &action, NULL) == -1)
537+            die("Failed to set default signal handler for SIGUSR1");
538+        if (sigaction(SIGUSR2, &action, NULL) == -1)
539+            die("Failed to set default signal handler for SIGUSR2");
540+        if (sigaction(SIGINT, &action, NULL) == -1)
541+            die("Failed to set default signal handler for SIGINT");
542+        if (sigaction(SIGTERM, &action, NULL) == -1)
543+            die("Failed to set default signal handler for SIGTERM");
544+
545+        /* Set empty signal mask */
546+        sigemptyset(&set);
547+        sigprocmask(SIG_SETMASK, &set, NULL);
548 
549         sprintf(string, "%d", sockets[1]);
550         setenv(SWC_LAUNCH_SOCKET_ENV, string, 1);
551 
552-        sprintf(string, "%d", tty_fd);
553+        sprintf(string, "%d", launcher.tty_fd);
554         setenv(SWC_LAUNCH_TTY_FD_ENV, string, 1);
555 
556-        printf("dropping privileges\n");
557         setuid(getuid());
558         setgid(getgid());
559-        //execlp("valgrind", "valgrind", "-v", "--suppressions=drm.supp",
560-        //       "--track-origins=yes", path, NULL);
561-        execlp("gdb", "gdb", path, NULL);
562-        //execl(path, path, NULL);
563 
564-        printf("%s failed: %s\n", path, strerror(errno));
565-
566-        exit(EXIT_FAILURE);
567+        execvp(argv[optind], argv + optind);
568+        die("Could not exec %s", argv[optind]);
569     }
570     /* Parent */
571     else
572     {
573-        struct sigaction action;
574-        sigset_t blocked_signals;
575+        struct pollfd pollfd;
576+        int ret;
577+
578+        pollfd.fd = sockets[0];
579+        pollfd.events = POLLIN;
580 
581-        action.sa_handler = &catch_chld;
582-        sigaction(SIGCHLD, &action, NULL);
583+        while (true)
584+        {
585+            ret = poll(&pollfd, 1, -1);
586 
587-        sigemptyset(&blocked_signals);
588-        sigaddset(&blocked_signals, SIGINT);
589-        sigaddset(&blocked_signals, SIGTERM);
590-        sigprocmask(SIG_BLOCK, &blocked_signals, NULL);
591+            if (ret == -1)
592+            {
593+                if (errno == EINTR)
594+                    continue;
595+                else
596+                    die("Error while polling on socket fd");
597+            }
598 
599-        printf("monitoring socket\n");
600-        monitor_socket(epoll_fd);
601+            handle_socket_data(pollfd.fd);
602+        }
603     }
604 
605     return EXIT_SUCCESS;
+2, -3
 1@@ -3,13 +3,12 @@
 2 #include <sys/socket.h>
 3 #include <stdio.h>
 4 #include <string.h>
 5-#include <errno.h>
 6 
 7-ssize_t send_fd(int socket, int fd, void * buffer, ssize_t buffer_size)
 8+ssize_t send_fd(int socket, int fd, const void * buffer, ssize_t buffer_size)
 9 {
10     char control[CMSG_SPACE(sizeof(int))];
11     struct iovec iov = {
12-        .iov_base = buffer,
13+        .iov_base = (void *) buffer,
14         .iov_len = buffer_size
15     };
16     struct msghdr message = {
+8, -8
 1@@ -11,20 +11,20 @@ struct swc_launch_request
 2 {
 3     enum
 4     {
 5-        SWC_LAUNCH_REQUEST_DRM_MASTER,
 6-        SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE
 7+        SWC_LAUNCH_REQUEST_OPEN_DEVICE,
 8+        SWC_LAUNCH_REQUEST_ACTIVATE_VT
 9     } type;
10     union
11     {
12-        struct /* DRM_MASTER */
13-        {
14-            bool set;
15-        };
16-        struct /* OPEN_INPUT_DEVICE */
17+        struct /* OPEN_DEVICE */
18         {
19             int flags;
20             char path[];
21         };
22+        struct /* ACTIVATE_VT */
23+        {
24+            unsigned vt;
25+        };
26     };
27 };
28 
29@@ -33,7 +33,7 @@ struct swc_launch_response
30     bool success;
31 };
32 
33-ssize_t send_fd(int socket, int fd, void * buffer, ssize_t buffer_size);
34+ssize_t send_fd(int socket, int fd, const void * buffer, ssize_t buffer_size);
35 
36 ssize_t receive_fd(int socket, int * fd, void * buffer,
37                    ssize_t buffer_size);
+0, -7
1@@ -1,7 +0,0 @@
2-#ifndef SWC_LAUNCH_H
3-#define SWC_LAUNCH_H 1
4-
5-int swc_launch(int argc, const char * argv[], const char * path);
6-
7-#endif
8-
+0, -1
1@@ -23,7 +23,6 @@ libswc_la_SOURCES = \
2     data_device.c data_device.h \
3     data.c data.h \
4     mode.c mode.h \
5-    tty.c tty.h \
6     evdev_device.c evdev_device.h \
7     xkb.c xkb.h \
8     drm.c drm.h \
+4, -40
  1@@ -5,7 +5,6 @@
  2 #include "compositor.h"
  3 #include "compositor_surface.h"
  4 #include "cursor_surface.h"
  5-#include "tty.h"
  6 #include "output.h"
  7 #include "surface.h"
  8 #include "event.h"
  9@@ -249,25 +248,6 @@ struct swc_pointer_handler pointer_handler = {
 10     .motion = &handle_motion
 11 };
 12 
 13-/* XXX: maybe this should go in swc_drm */
 14-static void handle_tty_event(struct wl_listener * listener, void * data)
 15-{
 16-    struct swc_event * event = data;
 17-    struct swc_compositor * compositor;
 18-
 19-    compositor = swc_container_of(listener, typeof(*compositor), tty_listener);
 20-
 21-    switch (event->type)
 22-    {
 23-        case SWC_TTY_VT_ENTER:
 24-            swc_drm_set_master(&compositor->drm);
 25-            break;
 26-        case SWC_TTY_VT_LEAVE:
 27-            swc_drm_drop_master(&compositor->drm);
 28-            break;
 29-    }
 30-}
 31-
 32 static void handle_drm_event(struct wl_listener * listener, void * data)
 33 {
 34     struct swc_event * event = data;
 35@@ -330,11 +310,9 @@ static void handle_terminate(uint32_t time, uint32_t value, void * data)
 36 
 37 static void handle_switch_vt(uint32_t time, uint32_t value, void * data)
 38 {
 39-    struct swc_tty * tty = data;
 40     uint8_t vt = value - XKB_KEY_XF86Switch_VT_1 + 1;
 41     printf("handle switch vt%u\n", vt);
 42-    if (vt != tty->vt)
 43-        swc_tty_switch_vt(tty, vt);
 44+    swc_launch_activate_vt(vt);
 45 }
 46 
 47 static void create_surface(struct wl_client * client,
 48@@ -400,7 +378,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
 49     xkb_keysym_t keysym;
 50 
 51     compositor->display = display;
 52-    compositor->tty_listener.notify = &handle_tty_event;
 53     compositor->drm_listener.notify = &handle_drm_event;
 54     compositor->pointer_listener.notify = &handle_pointer_event;
 55     compositor->scheduled_updates = 0;
 56@@ -409,7 +386,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
 57         = &swc_compositor_class_implementation;
 58     compositor->cursor_class.interface = &swc_cursor_class_implementation;
 59 
 60-
 61     compositor->udev = udev_new();
 62 
 63     if (compositor->udev == NULL)
 64@@ -420,20 +396,11 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
 65 
 66     event_loop = wl_display_get_event_loop(display);
 67 
 68-    if (!swc_tty_initialize(&compositor->tty, event_loop, 2))
 69-    {
 70-        printf("could not initialize tty\n");
 71-        goto error_udev;
 72-    }
 73-
 74-    wl_signal_add(&compositor->tty.event_signal, &compositor->tty_listener);
 75-
 76     /* TODO: configurable seat */
 77-    if (!swc_seat_initialize(&compositor->seat, compositor->udev,
 78-                             default_seat))
 79+    if (!swc_seat_initialize(&compositor->seat, compositor->udev, default_seat))
 80     {
 81         printf("could not initialize seat\n");
 82-        goto error_tty;
 83+        goto error_udev;
 84     }
 85 
 86     swc_seat_add_event_sources(&compositor->seat, event_loop);
 87@@ -500,7 +467,7 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
 88          ++keysym)
 89     {
 90         swc_compositor_add_key_binding(compositor, SWC_MOD_ANY, keysym,
 91-                                       &handle_switch_vt, &compositor->tty);
 92+                                       &handle_switch_vt, NULL);
 93     }
 94 
 95 
 96@@ -512,8 +479,6 @@ bool swc_compositor_initialize(struct swc_compositor * compositor,
 97     swc_drm_finish(&compositor->drm);
 98   error_seat:
 99     swc_seat_finish(&compositor->seat);
100-  error_tty:
101-    swc_tty_finish(&compositor->tty);
102   error_udev:
103     udev_unref(compositor->udev);
104   error_base:
105@@ -536,7 +501,6 @@ void swc_compositor_finish(struct swc_compositor * compositor)
106 
107     swc_drm_finish(&compositor->drm);
108     swc_seat_finish(&compositor->seat);
109-    swc_tty_finish(&compositor->tty);
110     udev_unref(compositor->udev);
111 }
112 
+0, -3
 1@@ -2,7 +2,6 @@
 2 #define SWC_COMPOSITOR_H 1
 3 
 4 #include "drm.h"
 5-#include "tty.h"
 6 #include "seat.h"
 7 #include "binding.h"
 8 #include "renderer.h"
 9@@ -15,7 +14,6 @@ struct swc_compositor
10 
11     struct udev * udev;
12 
13-    struct swc_tty tty;
14     struct swc_seat seat;
15     struct swc_drm drm;
16     struct swc_renderer renderer;
17@@ -42,7 +40,6 @@ struct swc_compositor
18     struct swc_surface_class compositor_class;
19     struct swc_surface_class cursor_class;
20 
21-    struct wl_listener tty_listener;
22     struct wl_listener drm_listener;
23     struct wl_listener pointer_listener;
24 
+1, -13
 1@@ -312,7 +312,7 @@ bool swc_drm_initialize(struct swc_drm * drm, struct udev * udev,
 2 
 3     drm->path = strdup(udev_device_get_devnode(drm_device));
 4     udev_device_unref(drm_device);
 5-    drm->fd = open(drm->path, O_RDWR | O_CLOEXEC);
 6+    drm->fd = swc_launch_open_device(drm->path, O_RDWR | O_CLOEXEC);
 7 
 8     if (drm->fd == -1)
 9     {
10@@ -375,18 +375,6 @@ void swc_drm_add_globals(struct swc_drm * drm, struct wl_display * display)
11     wl_global_create(display, &wl_drm_interface, 2, drm, &bind_drm);
12 }
13 
14-void swc_drm_set_master(struct swc_drm * drm)
15-{
16-    printf("setting drm master\n");
17-    drmSetMaster(drm->fd);
18-}
19-
20-void swc_drm_drop_master(struct swc_drm * drm)
21-{
22-    printf("dropping drm master\n");
23-    drmDropMaster(drm->fd);
24-}
25-
26 struct wl_list * swc_drm_create_outputs(struct swc_drm * drm)
27 {
28     drmModeRes * resources;
+0, -4
 1@@ -44,10 +44,6 @@ void swc_drm_add_event_sources(struct swc_drm * drm,
 2 
 3 void swc_drm_add_globals(struct swc_drm * drm, struct wl_display * display);
 4 
 5-void swc_drm_set_master(struct swc_drm * drm);
 6-
 7-void swc_drm_drop_master(struct swc_drm * drm);
 8-
 9 struct wl_list * swc_drm_create_outputs(struct swc_drm * drm);
10 
11 #endif
+2, -1
 1@@ -2,6 +2,7 @@
 2 
 3 #include "seat.h"
 4 #include "event.h"
 5+#include "util.h"
 6 
 7 #include <stdlib.h>
 8 #include <stdio.h>
 9@@ -142,7 +143,7 @@ struct swc_evdev_device * swc_evdev_device_new
10     if (!(device = malloc(sizeof *device)))
11         goto error0;
12 
13-    device->fd = open(path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
14+    device->fd = swc_launch_open_device(path, O_RDWR | O_NONBLOCK | O_CLOEXEC);
15 
16     if (device->fd == -1)
17     {
+0, -216
  1@@ -1,216 +0,0 @@
  2-/* swc: tty.c
  3- *
  4- * Copyright © 2012 Michael Forney
  5- *
  6- * Based in part upon tty.c from weston, which is:
  7- *
  8- *      Copyright © 2010 Intel Corporation
  9- *
 10- * Permission is hereby granted, free of charge, to any person obtaining a copy
 11- * of this software and associated documentation files (the "Software"), to
 12- * deal in the Software without restriction, including without limitation the
 13- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 14- * sell copies of the Software, and to permit persons to whom the Software is
 15- * furnished to do so, subject to the following conditions:
 16- *
 17- * The above copyright notice and this permission notice shall be included in
 18- * all copies or substantial portions of the Software.
 19- *
 20- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 21- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 22- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 23- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 24- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 25- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 26- * IN THE SOFTWARE.
 27- */
 28-
 29-#include <stdlib.h>
 30-#include <stdio.h>
 31-#include <unistd.h>
 32-#include <fcntl.h>
 33-#include <sys/ioctl.h>
 34-#include <linux/vt.h>
 35-#include <linux/kd.h>
 36-
 37-#include <wayland-server.h>
 38-
 39-#include "tty.h"
 40-#include "event.h"
 41-
 42-static void restore_tty(struct swc_tty * tty);
 43-static int handle_vt_signal(int signal_number, void * data);
 44-
 45-bool swc_tty_initialize(struct swc_tty * tty,
 46-                        struct wl_event_loop * event_loop,
 47-                        uint8_t tty_number)
 48-{
 49-    struct vt_stat state;
 50-    char tty_device[16];
 51-    struct vt_mode mode;
 52-
 53-    wl_signal_init(&tty->event_signal);
 54-
 55-    if (tty_number == 0)
 56-    {
 57-        char * vt_string = getenv("XDG_VTNR");
 58-        if (vt_string)
 59-        {
 60-            char * end;
 61-            tty_number = strtoul(vt_string, &end, 10);
 62-            if (*end != '\0')
 63-                tty_number = 0;
 64-        }
 65-    }
 66-
 67-    /* If we still don't have a VT number. */
 68-    if (tty_number == 0)
 69-    {
 70-        printf("don't know which VT to run on\n");
 71-        goto error_base;
 72-    }
 73-
 74-    snprintf(tty_device, sizeof(tty_device), "/dev/tty%u", tty_number);
 75-
 76-    /* Open the TTY. */
 77-    tty->fd = open(tty_device, O_RDWR | O_NOCTTY | O_CLOEXEC);
 78-
 79-    if (tty->fd == -1)
 80-    {
 81-        printf("couldn't open tty\n");
 82-        goto error_base;
 83-    }
 84-
 85-    tty->vt = tty_number;
 86-
 87-    /* Determine the current VT state. */
 88-    if (ioctl(tty->fd, VT_GETSTATE, &state) != 0)
 89-    {
 90-        printf("could not determine starting vt\n");
 91-        goto error_tty;
 92-    }
 93-
 94-    tty->original_state.vt = state.v_active;
 95-    printf("starting vt: %u\n", tty->original_state.vt);
 96-
 97-    /* Switch to the new VT if necessary. */
 98-    if (tty->original_state.vt != tty->vt)
 99-    {
100-        if (ioctl(tty->fd, VT_ACTIVATE, tty->vt) != 0
101-            || ioctl(tty->fd, VT_WAITACTIVE, tty->vt) != 0)
102-        {
103-            printf("couldn't switch to vt%u\n", tty->vt);
104-            goto error_tty;
105-        }
106-    }
107-
108-    tty->active = true;
109-
110-    /* Save current kb_mode. */
111-    if (ioctl(tty->fd, KDGKBMODE, &tty->original_state.kb_mode) != 0)
112-    {
113-        printf("couldn't determine kb_mode of vt%u\n", tty->vt);
114-        goto error_tty;
115-    }
116-
117-    /* Turn off keyboard, we will use evdev for input. */
118-    if (ioctl(tty->fd, KDSKBMODE, K_OFF) != 0)
119-    {
120-        printf("couldn't set kb_mode of vt%u to K_OFF\n", tty->vt);
121-        goto error_tty;
122-    }
123-
124-    /* Set VT to graphics mode. */
125-    if (ioctl(tty->fd, KDSETMODE, KD_GRAPHICS) != 0)
126-    {
127-        printf("couldn't set mode of vt%u to KD_GRAPHICS\n", tty->vt);
128-        goto error_kdkbmode;
129-    }
130-
131-    mode = (struct vt_mode) {
132-        .mode = VT_PROCESS,
133-        .relsig = SIGUSR1,
134-        .acqsig = SIGUSR1
135-    };
136-
137-    /* Set up VT switching handler. */
138-    if (ioctl(tty->fd, VT_SETMODE, &mode) != 0)
139-    {
140-        printf("could not set VT mode on vt%u\n", tty->vt);
141-        goto error_kdmode;
142-    }
143-
144-    tty->vt_source = wl_event_loop_add_signal(event_loop, SIGUSR1,
145-                                              &handle_vt_signal, tty);
146-
147-    if (!tty->vt_source)
148-    {
149-        printf("could not create VT event source\n");
150-        goto error_vtmode;
151-    }
152-
153-    return true;
154-
155-  error_vtmode:
156-    mode = (struct vt_mode) { .mode = VT_AUTO };
157-    ioctl(tty->fd, VT_SETMODE, &mode);
158-  error_kdmode:
159-    ioctl(tty->fd, KDSETMODE, KD_TEXT);
160-  error_kdkbmode:
161-    ioctl(tty->fd, KDSKBMODE, tty->original_state.kb_mode);
162-  error_tty:
163-    close(tty->fd);
164-  error_base:
165-    return false;
166-}
167-
168-void swc_tty_finish(struct swc_tty * tty)
169-{
170-    wl_event_source_remove(tty->vt_source);
171-    restore_tty(tty);
172-    close(tty->fd);
173-}
174-
175-void swc_tty_switch_vt(struct swc_tty * tty, uint32_t vt)
176-{
177-    ioctl(tty->fd, VT_ACTIVATE, vt);
178-}
179-
180-void restore_tty(struct swc_tty * tty)
181-{
182-    struct vt_mode mode = { .mode = VT_AUTO };
183-
184-    if (ioctl(tty->fd, KDSKBMODE, tty->original_state.kb_mode) != 0)
185-        printf("failed to restore keyboard mode\n");
186-    if (ioctl(tty->fd, KDSETMODE, KD_TEXT) != 0)
187-        printf("failed to set mode to KD_TEXT\n");
188-    if (ioctl(tty->fd, VT_SETMODE, &mode) != 0)
189-        printf("failed to restore VT handling\n");
190-    if (tty->vt != tty->original_state.vt
191-        && (ioctl(tty->fd, VT_ACTIVATE, tty->original_state.vt) != 0
192-            || ioctl(tty->fd, VT_WAITACTIVE, tty->original_state.vt) != 0))
193-    {
194-        printf("failed to restore VT\n");
195-    }
196-}
197-
198-static int handle_vt_signal(int signal_number, void * data)
199-{
200-    struct swc_tty * tty = data;
201-
202-    if (tty->active)
203-    {
204-        swc_send_event(&tty->event_signal, SWC_TTY_VT_LEAVE, NULL);
205-        ioctl(tty->fd, VT_RELDISP, 1);
206-        tty->active = false;
207-    }
208-    else
209-    {
210-        ioctl(tty->fd, VT_RELDISP, VT_ACKACQ);
211-        tty->active = true;
212-        swc_send_event(&tty->event_signal, SWC_TTY_VT_ENTER, NULL);
213-    }
214-
215-    return 1;
216-}
217-
+0, -44
 1@@ -1,44 +0,0 @@
 2-#ifndef SWC_TTY_H
 3-#define SWC_TTY_H 1
 4-
 5-#include <stdint.h>
 6-#include <stdbool.h>
 7-#include <signal.h>
 8-
 9-enum swc_tty_event
10-{
11-    SWC_TTY_VT_ENTER = 0,
12-    SWC_TTY_VT_LEAVE
13-};
14-
15-struct swc_tty
16-{
17-    int fd;
18-    uint8_t vt;
19-
20-    bool active;
21-
22-    /* The state of the VT the compositor was started on so we have a state to
23-     * restore to when the compositor closes. */
24-    struct
25-    {
26-        uint8_t vt;
27-        long kb_mode;
28-    } original_state;
29-
30-    /* Receives events when switching from/to the VT the compositor is running on. */
31-    struct wl_event_source * vt_source;
32-
33-    struct wl_signal event_signal;
34-};
35-
36-bool swc_tty_initialize(struct swc_tty * tty,
37-                        struct wl_event_loop * event_loop,
38-                        uint8_t tty_number);
39-
40-void swc_tty_finish(struct swc_tty * tty);
41-
42-void swc_tty_switch_vt(struct swc_tty * tty, uint32_t vt);
43-
44-#endif
45-
+51, -21
  1@@ -12,51 +12,81 @@ void swc_remove_resource(struct wl_resource * resource)
  2     wl_list_remove(wl_resource_get_link(resource));
  3 }
  4 
  5-bool swc_launch_drm_master(int socket, int fd, bool set)
  6+static int get_launcher_socket()
  7 {
  8-    ssize_t size;
  9-    struct swc_launch_request request;
 10-    struct swc_launch_response response;
 11+    static int launcher_socket = -1;
 12 
 13-    request.type = SWC_LAUNCH_REQUEST_DRM_MASTER;
 14-    request.set = set;
 15+    if (launcher_socket == -1)
 16+    {
 17+        char * launcher_socket_name;
 18 
 19-    size = send_fd(socket, fd, &request, sizeof request);
 20+        if ((launcher_socket_name = getenv(SWC_LAUNCH_SOCKET_ENV)))
 21+        {
 22+            char * end;
 23 
 24-    if (size == -1)
 25-        return false;
 26+            launcher_socket = strtol(launcher_socket_name, &end, 10);
 27+            if (*end != '\0')
 28+                launcher_socket = -1;
 29+        }
 30+    }
 31 
 32-    size = recv(socket, &response, sizeof response, 0);
 33+    return launcher_socket;
 34+}
 35+
 36+static bool send_request(const struct swc_launch_request * request, size_t size,
 37+                         struct swc_launch_response * response,
 38+                         int out_fd, int * in_fd)
 39+{
 40+    int socket;
 41+    ssize_t ret;
 42 
 43-    if (size == -1)
 44+    socket = get_launcher_socket();
 45+
 46+    if (send_fd(socket, out_fd, request, size) == -1)
 47+        return false;
 48+
 49+    if (receive_fd(socket, in_fd, &response, sizeof response) == -1)
 50         return false;
 51 
 52     return true;
 53 }
 54 
 55-int swc_launch_open_input_device(int socket, const char * path, int flags)
 56+int swc_launch_open_device(const char * path, int flags)
 57 {
 58     size_t path_size = strlen(path);
 59     char buffer[sizeof(struct swc_launch_request) + path_size + 1];
 60     struct swc_launch_request * request = (void *) buffer;
 61     struct swc_launch_response response;
 62-    ssize_t size;
 63     int fd;
 64+    int socket;
 65+
 66+    socket = get_launcher_socket();
 67 
 68-    request->type = SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE;
 69+    request->type = SWC_LAUNCH_REQUEST_OPEN_DEVICE;
 70     request->flags = flags;
 71     strcpy(request->path, path);
 72 
 73-    size = send(socket, buffer, sizeof buffer, 0);
 74-
 75-    if (size == -1)
 76+    if (!send_request(request, sizeof buffer, &response, -1, &fd))
 77         return -1;
 78 
 79-    size = receive_fd(socket, &fd, &response, sizeof response);
 80+    return fd;
 81+}
 82 
 83-    if (size == -1)
 84-        return -1;
 85+bool swc_launch_activate_vt(unsigned vt)
 86+{
 87+    struct swc_launch_request request;
 88+    struct swc_launch_response response;
 89+    ssize_t size;
 90+    int socket;
 91 
 92-    return fd;
 93+    socket = get_launcher_socket();
 94+
 95+    request.type = SWC_LAUNCH_REQUEST_ACTIVATE_VT;
 96+    request.vt = vt;
 97+
 98+    if (!send_request(&request, sizeof request, &response, -1, NULL))
 99+        return false;
100+
101+    return response.success;
102 }
103 
+3, -2
 1@@ -43,8 +43,9 @@ static inline bool swc_rectangle_overlap
 2             < r1->height + r2->height);
 3 }
 4 
 5-int swc_launch_open_input_device(int socket, const char * path, int flags);
 6-bool swc_launch_drm_master(int socket, int fd, bool set);
 7+/* Launch Utilities */
 8+int swc_launch_open_device(const char * path, int flags);
 9+bool swc_launch_activate_vt(unsigned vt);
10 
11 /* Double Buffers */
12 struct swc_double_buffer