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