blob: 96ac25adec7c1b6037948a1562edcb849647b9cd [file] [log] [blame]
Jasper St. Pierre72dea062015-09-23 10:46:47 -07001/*
2 * Copyright © 2012 Benjamin Franzke
3 * Copyright © 2013 Intel Corporation
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
24#include "config.h"
25
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030026#include <stdint.h>
Jasper St. Pierre72dea062015-09-23 10:46:47 -070027#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include <errno.h>
32#include <signal.h>
33#include <sys/socket.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <sys/uio.h>
37#include <sys/ioctl.h>
38#include <fcntl.h>
39#include <unistd.h>
40#include <linux/vt.h>
41#include <linux/kd.h>
42#include <linux/major.h>
43
44#include "compositor.h"
45#include "weston-launch.h"
46#include "launcher-impl.h"
47
48#define DRM_MAJOR 226
49
50#ifndef KDSKBMUTE
51#define KDSKBMUTE 0x4B51
52#endif
53
54#ifdef HAVE_LIBDRM
55
56#include <xf86drm.h>
57
58static inline int
59is_drm_master(int drm_fd)
60{
61 drm_magic_t magic;
62
63 return drmGetMagic(drm_fd, &magic) == 0 &&
64 drmAuthMagic(drm_fd, magic) == 0;
65}
66
67#else
68
69static inline int
70drmDropMaster(int drm_fd)
71{
72 return 0;
73}
74
75static inline int
76drmSetMaster(int drm_fd)
77{
78 return 0;
79}
80
81static inline int
82is_drm_master(int drm_fd)
83{
84 return 0;
85}
86
87#endif
88
89
90union cmsg_data { unsigned char b[4]; int fd; };
91
92struct launcher_weston_launch {
93 struct weston_launcher base;
94 struct weston_compositor *compositor;
95 struct wl_event_loop *loop;
96 int fd;
97 struct wl_event_source *source;
98
99 int kb_mode, tty, drm_fd;
Jasper St. Pierre72dea062015-09-23 10:46:47 -0700100};
101
102static int
103launcher_weston_launch_open(struct weston_launcher *launcher_base,
104 const char *path, int flags)
105{
106 struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
107 int n, ret;
108 struct msghdr msg;
109 struct cmsghdr *cmsg;
110 struct iovec iov;
111 union cmsg_data *data;
112 char control[CMSG_SPACE(sizeof data->fd)];
113 ssize_t len;
114 struct weston_launcher_open *message;
115
116 n = sizeof(*message) + strlen(path) + 1;
117 message = malloc(n);
118 if (!message)
119 return -1;
120
121 message->header.opcode = WESTON_LAUNCHER_OPEN;
122 message->flags = flags;
123 strcpy(message->path, path);
124
125 do {
126 len = send(launcher->fd, message, n, 0);
127 } while (len < 0 && errno == EINTR);
128 free(message);
129
130 memset(&msg, 0, sizeof msg);
131 iov.iov_base = &ret;
132 iov.iov_len = sizeof ret;
133 msg.msg_iov = &iov;
134 msg.msg_iovlen = 1;
135 msg.msg_control = control;
136 msg.msg_controllen = sizeof control;
137
138 do {
139 len = recvmsg(launcher->fd, &msg, MSG_CMSG_CLOEXEC);
140 } while (len < 0 && errno == EINTR);
141
142 if (len != sizeof ret ||
143 ret < 0)
144 return -1;
145
146 cmsg = CMSG_FIRSTHDR(&msg);
147 if (!cmsg ||
148 cmsg->cmsg_level != SOL_SOCKET ||
149 cmsg->cmsg_type != SCM_RIGHTS) {
150 fprintf(stderr, "invalid control message\n");
151 return -1;
152 }
153
154 data = (union cmsg_data *) CMSG_DATA(cmsg);
155 if (data->fd == -1) {
156 fprintf(stderr, "missing drm fd in socket request\n");
157 return -1;
158 }
159
160 return data->fd;
161}
162
163static void
164launcher_weston_launch_close(struct weston_launcher *launcher_base, int fd)
165{
166 close(fd);
167}
168
169static void
170launcher_weston_launch_restore(struct weston_launcher *launcher_base)
171{
172 struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
173 struct vt_mode mode = { 0 };
174
175 if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
176 ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
177 weston_log("failed to restore kb mode: %m\n");
178
179 if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
180 weston_log("failed to set KD_TEXT mode on tty: %m\n");
181
182 /* We have to drop master before we switch the VT back in
183 * VT_AUTO, so we don't risk switching to a VT with another
184 * display server, that will then fail to set drm master. */
185 drmDropMaster(launcher->drm_fd);
186
187 mode.mode = VT_AUTO;
188 if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
189 weston_log("could not reset vt handling\n");
190}
191
192static int
193launcher_weston_launch_data(int fd, uint32_t mask, void *data)
194{
195 struct launcher_weston_launch *launcher = data;
196 int len, ret;
197
198 if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
199 weston_log("launcher socket closed, exiting\n");
200 /* Normally the weston-launch will reset the tty, but
201 * in this case it died or something, so do it here so
202 * we don't end up with a stuck vt. */
203 launcher_weston_launch_restore(&launcher->base);
204 exit(-1);
205 }
206
207 do {
208 len = recv(launcher->fd, &ret, sizeof ret, 0);
209 } while (len < 0 && errno == EINTR);
210
211 switch (ret) {
212 case WESTON_LAUNCHER_ACTIVATE:
213 launcher->compositor->session_active = 1;
214 wl_signal_emit(&launcher->compositor->session_signal,
215 launcher->compositor);
216 break;
217 case WESTON_LAUNCHER_DEACTIVATE:
218 launcher->compositor->session_active = 0;
219 wl_signal_emit(&launcher->compositor->session_signal,
220 launcher->compositor);
221 break;
222 default:
223 weston_log("unexpected event from weston-launch\n");
224 break;
225 }
226
227 return 1;
228}
229
230static int
231launcher_weston_launch_activate_vt(struct weston_launcher *launcher_base, int vt)
232{
233 struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
234 return ioctl(launcher->tty, VT_ACTIVATE, vt);
235}
236
237static int
238launcher_weston_launch_connect(struct weston_launcher **out, struct weston_compositor *compositor,
239 int tty, const char *seat_id, bool sync_drm)
240{
241 struct launcher_weston_launch *launcher;
242 struct wl_event_loop *loop;
243
244 launcher = malloc(sizeof *launcher);
245 if (launcher == NULL)
246 return -ENOMEM;
247
248 launcher->base.iface = &launcher_weston_launch_iface;
249 * (struct launcher_weston_launch **) out = launcher;
250 launcher->compositor = compositor;
251 launcher->drm_fd = -1;
Derek Foremane7d868a2015-09-24 14:30:38 -0500252 launcher->fd = weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
Jasper St. Pierre72dea062015-09-23 10:46:47 -0700253 if (launcher->fd != -1) {
254 launcher->tty = weston_environment_get_fd("WESTON_TTY_FD");
255 /* We don't get a chance to read out the original kb
256 * mode for the tty, so just hard code K_UNICODE here
257 * in case we have to clean if weston-launch dies. */
258 launcher->kb_mode = K_UNICODE;
259
260 loop = wl_display_get_event_loop(compositor->wl_display);
261 launcher->source = wl_event_loop_add_fd(loop, launcher->fd,
262 WL_EVENT_READABLE,
263 launcher_weston_launch_data,
264 launcher);
265 if (launcher->source == NULL) {
266 free(launcher);
267 return -ENOMEM;
268 }
269
270 return 0;
271 } else {
272 return -1;
273 }
274}
275
276static void
277launcher_weston_launch_destroy(struct weston_launcher *launcher_base)
278{
279 struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
280
281 if (launcher->fd != -1) {
282 close(launcher->fd);
283 wl_event_source_remove(launcher->source);
284 } else {
285 launcher_weston_launch_restore(&launcher->base);
Jasper St. Pierre72dea062015-09-23 10:46:47 -0700286 }
287
288 if (launcher->tty >= 0)
289 close(launcher->tty);
290
291 free(launcher);
292}
293
294struct launcher_interface launcher_weston_launch_iface = {
295 launcher_weston_launch_connect,
296 launcher_weston_launch_destroy,
297 launcher_weston_launch_open,
298 launcher_weston_launch_close,
299 launcher_weston_launch_activate_vt,
300 launcher_weston_launch_restore,
301};