blob: 0ff99a448ccdbb8e8e00b781f2c4bd0b59108801 [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
26#include "compositor.h"
27
28#include <errno.h>
29#include <fcntl.h>
30#include <unistd.h>
31#include <signal.h>
32#include <sys/stat.h>
33#include <sys/ioctl.h>
34#include <linux/vt.h>
35#include <linux/kd.h>
36#include <linux/major.h>
37
38#include "launcher-impl.h"
39
40#define DRM_MAJOR 226
41
42#ifndef KDSKBMUTE
43#define KDSKBMUTE 0x4B51
44#endif
45
46#ifdef HAVE_LIBDRM
47
48#include <xf86drm.h>
49
50static inline int
51is_drm_master(int drm_fd)
52{
53 drm_magic_t magic;
54
55 return drmGetMagic(drm_fd, &magic) == 0 &&
56 drmAuthMagic(drm_fd, magic) == 0;
57}
58
59#else
60
61static inline int
62drmDropMaster(int drm_fd)
63{
64 return 0;
65}
66
67static inline int
68drmSetMaster(int drm_fd)
69{
70 return 0;
71}
72
73static inline int
74is_drm_master(int drm_fd)
75{
76 return 0;
77}
78
79#endif
80
81struct launcher_direct {
82 struct weston_launcher base;
83 struct weston_compositor *compositor;
84 int kb_mode, tty, drm_fd;
85 struct wl_event_source *vt_source;
86};
87
88static int
89vt_handler(int signal_number, void *data)
90{
91 struct launcher_direct *launcher = data;
92 struct weston_compositor *compositor = launcher->compositor;
93
94 if (compositor->session_active) {
95 compositor->session_active = 0;
96 wl_signal_emit(&compositor->session_signal, compositor);
97 drmDropMaster(launcher->drm_fd);
98 ioctl(launcher->tty, VT_RELDISP, 1);
99 } else {
100 ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
101 drmSetMaster(launcher->drm_fd);
102 compositor->session_active = 1;
103 wl_signal_emit(&compositor->session_signal, compositor);
104 }
105
106 return 1;
107}
108
109static int
110setup_tty(struct launcher_direct *launcher, int tty)
111{
112 struct wl_event_loop *loop;
113 struct vt_mode mode = { 0 };
114 struct stat buf;
115 char tty_device[32] ="<stdin>";
116 int ret, kd_mode;
117
118 if (tty == 0) {
119 launcher->tty = dup(tty);
120 if (launcher->tty == -1) {
121 weston_log("couldn't dup stdin: %m\n");
122 return -1;
123 }
124 } else {
125 snprintf(tty_device, sizeof tty_device, "/dev/tty%d", tty);
126 launcher->tty = open(tty_device, O_RDWR | O_CLOEXEC);
127 if (launcher->tty == -1) {
128 weston_log("couldn't open tty %s: %m\n", tty_device);
129 return -1;
130 }
131 }
132
133 if (fstat(launcher->tty, &buf) == -1 ||
134 major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
135 weston_log("%s not a vt\n", tty_device);
136 weston_log("if running weston from ssh, "
137 "use --tty to specify a tty\n");
138 goto err_close;
139 }
140
141 ret = ioctl(launcher->tty, KDGETMODE, &kd_mode);
142 if (ret) {
143 weston_log("failed to get VT mode: %m\n");
144 return -1;
145 }
146 if (kd_mode != KD_TEXT) {
147 weston_log("%s is already in graphics mode, "
148 "is another display server running?\n", tty_device);
149 goto err_close;
150 }
151
152 ioctl(launcher->tty, VT_ACTIVATE, minor(buf.st_rdev));
153 ioctl(launcher->tty, VT_WAITACTIVE, minor(buf.st_rdev));
154
155 if (ioctl(launcher->tty, KDGKBMODE, &launcher->kb_mode)) {
156 weston_log("failed to read keyboard mode: %m\n");
157 goto err_close;
158 }
159
160 if (ioctl(launcher->tty, KDSKBMUTE, 1) &&
161 ioctl(launcher->tty, KDSKBMODE, K_OFF)) {
162 weston_log("failed to set K_OFF keyboard mode: %m\n");
163 goto err_close;
164 }
165
166 ret = ioctl(launcher->tty, KDSETMODE, KD_GRAPHICS);
167 if (ret) {
168 weston_log("failed to set KD_GRAPHICS mode on tty: %m\n");
169 goto err_close;
170 }
171
172 /*
173 * SIGRTMIN is used as global VT-acquire+release signal. Note that
174 * SIGRT* must be tested on runtime, as their exact values are not
175 * known at compile-time. POSIX requires 32 of them to be available.
176 */
177 if (SIGRTMIN > SIGRTMAX) {
178 weston_log("not enough RT signals available: %u-%u\n",
179 SIGRTMIN, SIGRTMAX);
180 ret = -EINVAL;
181 goto err_close;
182 }
183
184 mode.mode = VT_PROCESS;
185 mode.relsig = SIGRTMIN;
186 mode.acqsig = SIGRTMIN;
187 if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0) {
188 weston_log("failed to take control of vt handling\n");
189 goto err_close;
190 }
191
192 loop = wl_display_get_event_loop(launcher->compositor->wl_display);
193 launcher->vt_source =
194 wl_event_loop_add_signal(loop, SIGRTMIN, vt_handler, launcher);
195 if (!launcher->vt_source)
196 goto err_close;
197
198 return 0;
199
200 err_close:
201 close(launcher->tty);
202 return -1;
203}
204
205static int
206launcher_direct_open(struct weston_launcher *launcher_base, const char *path, int flags)
207{
208 struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
209 struct stat s;
210 int fd;
211
212 fd = open(path, flags | O_CLOEXEC);
213 if (fd == -1)
214 return -1;
215
216 if (fstat(fd, &s) == -1) {
217 close(fd);
218 return -1;
219 }
220
221 if (major(s.st_rdev) == DRM_MAJOR) {
222 launcher->drm_fd = fd;
223 if (!is_drm_master(fd)) {
224 weston_log("drm fd not master\n");
225 close(fd);
226 return -1;
227 }
228 }
229
230 return fd;
231}
232
233static void
234launcher_direct_close(struct weston_launcher *launcher_base, int fd)
235{
236 close(fd);
237}
238
239static void
240launcher_direct_restore(struct weston_launcher *launcher_base)
241{
242 struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
243 struct vt_mode mode = { 0 };
244
245 if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
246 ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
247 weston_log("failed to restore kb mode: %m\n");
248
249 if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
250 weston_log("failed to set KD_TEXT mode on tty: %m\n");
251
252 /* We have to drop master before we switch the VT back in
253 * VT_AUTO, so we don't risk switching to a VT with another
254 * display server, that will then fail to set drm master. */
255 drmDropMaster(launcher->drm_fd);
256
257 mode.mode = VT_AUTO;
258 if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
259 weston_log("could not reset vt handling\n");
260}
261
262static int
263launcher_direct_activate_vt(struct weston_launcher *launcher_base, int vt)
264{
265 struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
266 return ioctl(launcher->tty, VT_ACTIVATE, vt);
267}
268
269static int
270launcher_direct_connect(struct weston_launcher **out, struct weston_compositor *compositor,
271 int tty, const char *seat_id, bool sync_drm)
272{
273 struct launcher_direct *launcher;
274
275 if (geteuid() != 0)
276 return -EINVAL;
277
278 launcher = zalloc(sizeof(*launcher));
279 if (launcher == NULL)
280 return -ENOMEM;
281
282 launcher->base.iface = &launcher_direct_iface;
283 launcher->compositor = compositor;
284
285 if (setup_tty(launcher, tty) == -1) {
286 free(launcher);
287 return -1;
288 }
289
290 * (struct launcher_direct **) out = launcher;
291 return 0;
292}
293
294static void
295launcher_direct_destroy(struct weston_launcher *launcher_base)
296{
297 struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
298
299 launcher_direct_restore(&launcher->base);
300 wl_event_source_remove(launcher->vt_source);
301
302 if (launcher->tty >= 0)
303 close(launcher->tty);
304
305 free(launcher);
306}
307
Giulio Camuffoa32986e2016-12-05 14:50:36 +0100308static int
309launcher_direct_get_vt(struct weston_launcher *base)
310{
311 struct launcher_direct *launcher = wl_container_of(base, launcher, base);
312 struct stat s;
313 if (fstat(launcher->tty, &s) < 0)
314 return -1;
315
316 return minor(s.st_rdev);
317}
318
Jasper St. Pierre72dea062015-09-23 10:46:47 -0700319struct launcher_interface launcher_direct_iface = {
320 launcher_direct_connect,
321 launcher_direct_destroy,
322 launcher_direct_open,
323 launcher_direct_close,
324 launcher_direct_activate_vt,
325 launcher_direct_restore,
Giulio Camuffoa32986e2016-12-05 14:50:36 +0100326 launcher_direct_get_vt,
Jasper St. Pierre72dea062015-09-23 10:46:47 -0700327};