commit 61ab1cf
Michael Forney
·
2013-06-21 07:45:48 +0000 UTC
parent caa0f9f
Add swc-launch
7 files changed,
+432,
-2
+1,
-1
1@@ -29,5 +29,5 @@ libswc_la_LIBADD = $(wayland_server_LIBS) $(udev_LIBS) $(xkbcommon_LIBS) \
2 $(drm_LIBS) $(drm_intel_LIBS) $(gbm_LIBS) $(egl_LIBS) $(pixman_LIBS) \
3 intel/libintel.la
4
5-SUBDIRS = intel
6+SUBDIRS = launch intel
7
+1,
-1
1@@ -33,6 +33,6 @@ PKG_CHECK_MODULES([wayland_client], [wayland-client])
2 dnl }}}
3
4 #AC_CONFIG_HEADERS([config.h])
5-AC_CONFIG_FILES([Makefile intel/Makefile])
6+AC_CONFIG_FILES([Makefile intel/Makefile launch/Makefile])
7 AC_OUTPUT
8
+17,
-0
1@@ -0,0 +1,17 @@
2+# launch/Makefile.am
3+
4+AM_CFLAGS = $(drm_CFLAGS)
5+
6+lib_LTLIBRARIES = libswc-launch.la
7+noinst_LTLIBRARIES = liblaunch-protocol.la
8+
9+libswc_launch_la_SOURCES = \
10+ launch.c swc-launch.h
11+
12+libswc_launch_la_LIBADD = $(drm_LIBS) liblaunch-protocol.la
13+
14+liblaunch_protocol_la_SOURCES = \
15+ protocol.c protocol.h
16+
17+include_HEADERS = swc-launch.h
18+
+270,
-0
1@@ -0,0 +1,270 @@
2+#include "swc-launch.h"
3+#include "protocol.h"
4+
5+#include <stdlib.h>
6+#include <stdio.h>
7+#include <stdbool.h>
8+#include <string.h>
9+#include <unistd.h>
10+#include <errno.h>
11+#include <fcntl.h>
12+#include <sys/epoll.h>
13+#include <sys/socket.h>
14+#include <sys/stat.h>
15+#include <sys/wait.h>
16+#include <sys/ioctl.h>
17+#include <linux/major.h>
18+#include <linux/vt.h>
19+#include <xf86drm.h>
20+
21+static void print_usage(const char * name, const char * compositor_name)
22+{
23+ fprintf(stderr, "Usage: %s [-- [%s arguments]]\n",
24+ name, compositor_name);
25+}
26+
27+static void catch_chld(int signal)
28+{
29+ int status;
30+
31+ wait(&status);
32+ exit(status);
33+}
34+
35+static void handle_socket_data(int socket)
36+{
37+ char buffer[BUFSIZ];
38+ struct swc_launch_request * request = (void *) &buffer;
39+ struct swc_launch_response response = { false };
40+ int fd;
41+ ssize_t size;
42+
43+ size = receive_fd(socket, &fd, buffer, sizeof buffer);
44+
45+ if (size == -1 || size == 0)
46+ return;
47+
48+ switch (request->type)
49+ {
50+ case SWC_LAUNCH_REQUEST_DRM_MASTER:
51+ response.success = (request->set ? drmSetMaster(fd)
52+ : drmDropMaster(fd)) == 0;
53+ fd = -1;
54+ break;
55+ case SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE:
56+ {
57+ struct stat st;
58+
59+ if (request->path[size - __builtin_offsetof(typeof(*request),
60+ path)] != '\0')
61+ {
62+ fprintf(stderr, "Path is not NULL terminated\n");
63+ goto fail;
64+ }
65+
66+ stat(request->path, &st);
67+
68+ if (major(st.st_rdev) != INPUT_MAJOR)
69+ {
70+ fprintf(stderr, "Device is not an input device\n");
71+ goto fail;
72+ }
73+
74+ fd = open(request->path, request->flags);
75+
76+ if (fd == -1)
77+ {
78+ fprintf(stderr, "Could not open device %s\n", request->path);
79+ goto fail;
80+ }
81+
82+ break;
83+ }
84+ default:
85+ fprintf(stderr, "Unknown request %u\n", request->type);
86+ goto fail;
87+ }
88+
89+ goto done;
90+
91+ fail:
92+ response.success = false;
93+ fd = -1;
94+ done:
95+ send_fd(socket, fd, &response, sizeof response);
96+}
97+
98+static void monitor_socket(int epoll_fd)
99+{
100+ struct epoll_event event;
101+ int count;
102+
103+ while (true)
104+ {
105+ printf("waiting\n");
106+ count = epoll_wait(epoll_fd, &event, 1, -1);
107+
108+ if (count < 0)
109+ break;
110+
111+ handle_socket_data(event.data.fd);
112+ }
113+}
114+
115+static int find_vt()
116+{
117+ char * vt_string;
118+ int vt;
119+ int tty0_fd;
120+
121+ vt_string = getenv("XDG_VTNR");
122+
123+ if (vt_string)
124+ {
125+ char * end;
126+ vt = strtoul(vt_string, &end, 10);
127+ printf("vt: %d\n", vt);
128+ if (*end == '\0')
129+ goto done;
130+ }
131+
132+ tty0_fd = open("/dev/tty0", O_RDWR);
133+
134+ if (ioctl(tty0_fd, VT_OPENQRY, &vt) != 0)
135+ {
136+ printf("could not find open vt\n");
137+ vt = 0;
138+ }
139+
140+ close(tty0_fd);
141+
142+ done:
143+ return vt;
144+}
145+
146+static int open_tty(int vt)
147+{
148+ char * current_tty_name;
149+ char tty_name[64];
150+
151+ snprintf(tty_name, sizeof tty_name, "/dev/tty%d", vt);
152+
153+ /* Check if we are running on the desired VT */
154+ current_tty_name = ttyname(STDIN_FILENO);
155+
156+ if (strcmp(tty_name, current_tty_name) == 0)
157+ return STDIN_FILENO;
158+ else
159+ {
160+ int fd;
161+
162+ /* Open the new TTY. */
163+ fd = open(tty_name, O_RDWR | O_NOCTTY);
164+
165+ if (fd < 0)
166+ {
167+ fprintf(stderr, "FATAL: Could not open %s\n", tty_name);
168+ exit(EXIT_FAILURE);
169+ }
170+
171+ return fd;
172+ }
173+}
174+
175+int swc_launch(int argc, const char * argv[], const char * path)
176+{
177+ int sockets[2];
178+ int epoll_fd;
179+ struct epoll_event event;
180+
181+ if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, sockets) == -1)
182+ {
183+ fprintf(stderr, "FATAL: Could not create socket pair\n");
184+ return EXIT_FAILURE;
185+ }
186+
187+ if (fcntl(sockets[0], F_SETFD, FD_CLOEXEC) == -1)
188+ {
189+ fprintf(stderr, "FATAL: Could not set CLOEXEC on socket\n");
190+ return EXIT_FAILURE;
191+ }
192+
193+ epoll_fd = epoll_create1(EPOLL_CLOEXEC);
194+
195+ if (epoll_fd == -1)
196+ {
197+ fprintf(stderr, "FATAL: Could not create epoll\n");
198+ return EXIT_FAILURE;
199+ }
200+
201+ event.events = EPOLLIN;
202+ event.data.fd = sockets[0];
203+ epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockets[0], &event);
204+
205+ /* Child */
206+ if (fork() == 0)
207+ {
208+ char string[64];
209+ int tty_fd;
210+ int vt;
211+ uid_t uid;
212+ gid_t gid;
213+
214+ vt = find_vt();
215+ tty_fd = open_tty(vt);
216+
217+ /* If the desired TTY is not the current TTY, start a new session, and
218+ * set it's controlling TTY appropriately. */
219+ if (tty_fd != STDIN_FILENO)
220+ {
221+ pid_t sid = setsid();
222+
223+ if (ioctl(tty_fd, TIOCSCTTY, vt) != 0)
224+ {
225+ fprintf(stderr, "FATAL: Couldn't set controlling TTY to "
226+ "/dev/tty%u: %s\n", vt, strerror(errno));
227+ exit(EXIT_FAILURE);
228+ }
229+
230+ //tcsetpgrp(tty_fd, sid);
231+ }
232+
233+ sprintf(string, "%d", sockets[1]);
234+ setenv(SWC_LAUNCH_SOCKET_ENV, string, 1);
235+
236+ sprintf(string, "%d", tty_fd);
237+ setenv(SWC_LAUNCH_TTY_FD_ENV, string, 1);
238+
239+ printf("dropping privileges\n");
240+ setuid(getuid());
241+ setgid(getgid());
242+ //execlp("valgrind", "valgrind", "-v", "--suppressions=drm.supp",
243+ // "--track-origins=yes", path, NULL);
244+ execlp("gdb", "gdb", path, NULL);
245+ //execl(path, path, NULL);
246+
247+ printf("%s failed: %s\n", path, strerror(errno));
248+
249+ exit(EXIT_FAILURE);
250+ }
251+ /* Parent */
252+ else
253+ {
254+ struct sigaction action;
255+ sigset_t blocked_signals;
256+
257+ action.sa_handler = &catch_chld;
258+ sigaction(SIGCHLD, &action, NULL);
259+
260+ sigemptyset(&blocked_signals);
261+ sigaddset(&blocked_signals, SIGINT);
262+ sigaddset(&blocked_signals, SIGTERM);
263+ sigprocmask(SIG_BLOCK, &blocked_signals, NULL);
264+
265+ printf("monitoring socket\n");
266+ monitor_socket(epoll_fd);
267+ }
268+
269+ return EXIT_SUCCESS;
270+}
271+
+94,
-0
1@@ -0,0 +1,94 @@
2+#include "protocol.h"
3+
4+#include <sys/socket.h>
5+#include <stdio.h>
6+#include <string.h>
7+#include <errno.h>
8+
9+ssize_t send_fd(int socket, int fd, void * buffer, ssize_t buffer_size)
10+{
11+ char control[CMSG_SPACE(sizeof(int))];
12+ struct iovec iov = {
13+ .iov_base = buffer,
14+ .iov_len = buffer_size
15+ };
16+ struct msghdr message = {
17+ .msg_name = NULL,
18+ .msg_namelen = 0,
19+ .msg_iov = &iov,
20+ .msg_iovlen = 1,
21+ };
22+ struct cmsghdr * cmsg;
23+
24+ if (fd != -1)
25+ {
26+ message.msg_control = control,
27+ message.msg_controllen = sizeof control;
28+
29+ cmsg = CMSG_FIRSTHDR(&message);
30+ cmsg->cmsg_len = CMSG_LEN(sizeof fd);
31+ cmsg->cmsg_level = SOL_SOCKET;
32+ cmsg->cmsg_type = SCM_RIGHTS;
33+
34+ *((int *) CMSG_DATA(cmsg)) = fd;
35+ }
36+ else
37+ {
38+ message.msg_control = NULL;
39+ message.msg_controllen = 0;
40+ }
41+
42+ return sendmsg(socket, &message, 0);
43+}
44+
45+ssize_t receive_fd(int socket, int * fd, void * buffer,
46+ ssize_t buffer_size)
47+{
48+ ssize_t size;
49+
50+ if (fd)
51+ {
52+ char control[CMSG_SPACE(sizeof(int))];
53+ struct iovec iov = {
54+ .iov_base = buffer,
55+ .iov_len = buffer_size
56+ };
57+ struct msghdr message = {
58+ .msg_name = NULL,
59+ .msg_namelen = 0,
60+ .msg_iov = &iov,
61+ .msg_iovlen = 1,
62+ .msg_control = &control,
63+ .msg_controllen = sizeof control
64+ };
65+ struct cmsghdr * cmsg;
66+
67+ size = recvmsg(socket, &message, 0);
68+
69+ if (size < 0)
70+ goto nofd;
71+
72+ cmsg = CMSG_FIRSTHDR(&message);
73+
74+ if (!cmsg || cmsg->cmsg_len != CMSG_LEN(sizeof(int))
75+ || cmsg->cmsg_level != SOL_SOCKET
76+ || cmsg->cmsg_type != SCM_RIGHTS)
77+ {
78+ goto nofd;
79+ }
80+
81+ *fd = *((int *) CMSG_DATA(cmsg));
82+ }
83+ else
84+ {
85+ size = recv(socket, buffer, buffer_size, 0);
86+ }
87+
88+ goto done;
89+
90+ nofd:
91+ *fd = -1;
92+ done:
93+ return size;
94+}
95+
+42,
-0
1@@ -0,0 +1,42 @@
2+#ifndef SWC_LAUNCH_PROTOCOL_H
3+#define SWC_LAUNCH_PROTOCOL_H 1
4+
5+#include <stdbool.h>
6+#include <sys/types.h>
7+
8+#define SWC_LAUNCH_SOCKET_ENV "SWC_LAUNCH_SOCKET"
9+#define SWC_LAUNCH_TTY_FD_ENV "SWC_LAUNCH_TTY_FD"
10+
11+struct swc_launch_request
12+{
13+ enum
14+ {
15+ SWC_LAUNCH_REQUEST_DRM_MASTER,
16+ SWC_LAUNCH_REQUEST_OPEN_INPUT_DEVICE
17+ } type;
18+ union
19+ {
20+ struct /* DRM_MASTER */
21+ {
22+ bool set;
23+ };
24+ struct /* OPEN_INPUT_DEVICE */
25+ {
26+ int flags;
27+ char path[];
28+ };
29+ };
30+};
31+
32+struct swc_launch_response
33+{
34+ bool success;
35+};
36+
37+ssize_t send_fd(int socket, int fd, void * buffer, ssize_t buffer_size);
38+
39+ssize_t receive_fd(int socket, int * fd, void * buffer,
40+ ssize_t buffer_size);
41+
42+#endif
43+
+7,
-0
1@@ -0,0 +1,7 @@
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+