blob: 87f46417cce1d4c96865c9b24853181e3ab69328 [file] [log] [blame]
Benjamin Franzkebfeda132012-01-30 14:04:04 +01001/*
2 * Copyright © 2012 Benjamin Franzke
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 */
22
Benjamin Franzkebfeda132012-01-30 14:04:04 +010023#include "config.h"
24
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <assert.h>
Kristian Høgsbergf2807702013-07-23 11:43:03 -070029#include <poll.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010030#include <errno.h>
31
32#include <error.h>
33#include <getopt.h>
34
35#include <sys/types.h>
36#include <sys/ioctl.h>
37#include <sys/stat.h>
38#include <sys/wait.h>
39#include <sys/socket.h>
Benjamin Franzkebfeda132012-01-30 14:04:04 +010040#include <sys/signalfd.h>
41#include <signal.h>
42#include <unistd.h>
43#include <fcntl.h>
44
45#include <termios.h>
46#include <linux/vt.h>
47#include <linux/major.h>
48
49#include <pwd.h>
50#include <grp.h>
51#include <security/pam_appl.h>
52
53#include <xf86drm.h>
54
55#ifdef HAVE_SYSTEMD_LOGIN
56#include <systemd/sd-login.h>
57#endif
58
59#include "weston-launch.h"
60
Kristian Høgsberg1ff51092013-09-17 14:03:42 -070061#define DRM_MAJOR 226
62
Quentin Glidicff323092013-05-17 16:20:37 +020063#define MAX_ARGV_SIZE 256
64
Benjamin Franzkebfeda132012-01-30 14:04:04 +010065struct weston_launch {
66 struct pam_conv pc;
67 pam_handle_t *ph;
68 int tty;
69 int ttynr;
70 int sock[2];
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -070071 int drm_fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010072 struct passwd *pw;
73
Benjamin Franzkebfeda132012-01-30 14:04:04 +010074 int signalfd;
75
76 pid_t child;
77 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -070078 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010079};
80
Kristian Høgsberg9e140912012-04-10 01:26:18 -040081union cmsg_data { unsigned char b[4]; int fd; };
82
Benjamin Franzkebfeda132012-01-30 14:04:04 +010083static gid_t *
84read_groups(void)
85{
86 int n;
87 gid_t *groups;
88
89 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +000090
91 if (n < 0) {
92 fprintf(stderr, "Unable to retrieve groups: %m\n");
93 return NULL;
94 }
95
Benjamin Franzkebfeda132012-01-30 14:04:04 +010096 groups = malloc(n * sizeof(gid_t));
97 if (!groups)
98 return NULL;
99
100 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +0000101 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100102 free(groups);
103 return NULL;
104 }
105 return groups;
106}
107
108static int
109weston_launch_allowed(struct weston_launch *wl)
110{
111 struct group *gr;
112 gid_t *groups;
113 int i;
114#ifdef HAVE_SYSTEMD_LOGIN
115 char *session, *seat;
116 int err;
117#endif
118
119 if (getuid() == 0)
120 return 1;
121
122 gr = getgrnam("weston-launch");
123 if (gr) {
124 groups = read_groups();
125 if (groups) {
126 for (i = 0; groups[i]; ++i) {
127 if (groups[i] == gr->gr_gid) {
128 free(groups);
129 return 1;
130 }
131 }
132 free(groups);
133 }
134 }
135
136#ifdef HAVE_SYSTEMD_LOGIN
137 err = sd_pid_get_session(getpid(), &session);
138 if (err == 0 && session) {
139 if (sd_session_is_active(session) &&
140 sd_session_get_seat(session, &seat) == 0) {
141 free(seat);
142 free(session);
143 return 1;
144 }
145 free(session);
146 }
147#endif
148
149 return 0;
150}
151
152static int
153pam_conversation_fn(int msg_count,
154 const struct pam_message **messages,
155 struct pam_response **responses,
156 void *user_data)
157{
158 return PAM_SUCCESS;
159}
160
161static int
162setup_pam(struct weston_launch *wl)
163{
164 int err;
165
166 wl->pc.conv = pam_conversation_fn;
167 wl->pc.appdata_ptr = wl;
168
169 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200170 if (err != PAM_SUCCESS) {
171 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
172 err, pam_strerror(wl->ph, err));
173 return -1;
174 }
175
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100176 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
177 if (err != PAM_SUCCESS) {
178 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
179 err, pam_strerror(wl->ph, err));
180 return -1;
181 }
182
183 err = pam_open_session(wl->ph, 0);
184 if (err != PAM_SUCCESS) {
185 fprintf(stderr, "failed to open pam session: %d: %s\n",
186 err, pam_strerror(wl->ph, err));
187 return -1;
188 }
189
190 return 0;
191}
192
193static int
194setup_launcher_socket(struct weston_launch *wl)
195{
Kristian Høgsbergbf3c3742013-09-18 11:01:48 -0700196 if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100197 error(1, errno, "socketpair failed");
198
Kristian Høgsbergf45b1e82013-09-18 11:00:56 -0700199 if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
200 error(1, errno, "fcntl failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100201
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100202 return 0;
203}
204
205static int
206setup_signals(struct weston_launch *wl)
207{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100208 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100209 sigset_t mask;
210 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100211
212 memset(&sa, 0, sizeof sa);
213 sa.sa_handler = SIG_DFL;
214 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100215 ret = sigaction(SIGCHLD, &sa, NULL);
216 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100217
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700218 sa.sa_handler = SIG_IGN;
219 sa.sa_flags = 0;
220 sigaction(SIGHUP, &sa, NULL);
221
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100222 ret = sigemptyset(&mask);
223 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100224 sigaddset(&mask, SIGCHLD);
225 sigaddset(&mask, SIGINT);
226 sigaddset(&mask, SIGTERM);
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700227 sigaddset(&mask, SIGUSR1);
228 sigaddset(&mask, SIGUSR2);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100229 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
230 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100231
232 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
233 if (wl->signalfd < 0)
234 return -errno;
235
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100236 return 0;
237}
238
239static void
240setenv_fd(const char *env, int fd)
241{
242 char buf[32];
243
244 snprintf(buf, sizeof buf, "%d", fd);
245 setenv(env, buf, 1);
246}
247
248static int
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700249send_reply(struct weston_launch *wl, int reply)
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100250{
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700251 int len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100252
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100253 do {
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700254 len = send(wl->sock[0], &reply, sizeof reply, 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100255 } while (len < 0 && errno == EINTR);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100256
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700257 return len;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100258}
259
260static int
261handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
262{
263 int fd = -1, ret = -1;
264 char control[CMSG_SPACE(sizeof(fd))];
265 struct cmsghdr *cmsg;
266 struct stat s;
267 struct msghdr nmsg;
268 struct iovec iov;
269 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400270 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100271
272 message = msg->msg_iov->iov_base;
273 if ((size_t)len < sizeof(*message))
274 goto err0;
275
276 /* Ensure path is null-terminated */
277 ((char *) message)[len-1] = '\0';
278
279 if (stat(message->path, &s) < 0)
280 goto err0;
281
282 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100283 if (fd < 0) {
284 fprintf(stderr, "Error opening device %s: %m\n",
285 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100286 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100287 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100288
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700289 if (major(s.st_rdev) != INPUT_MAJOR &&
290 major(s.st_rdev) != DRM_MAJOR) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100291 close(fd);
292 fd = -1;
Kristian Høgsberg1ff51092013-09-17 14:03:42 -0700293 fprintf(stderr, "Device %s is not an input or drm device\n",
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100294 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100295 goto err0;
296 }
297
298err0:
299 memset(&nmsg, 0, sizeof nmsg);
300 nmsg.msg_iov = &iov;
301 nmsg.msg_iovlen = 1;
302 if (fd != -1) {
303 nmsg.msg_control = control;
304 nmsg.msg_controllen = sizeof control;
305 cmsg = CMSG_FIRSTHDR(&nmsg);
306 cmsg->cmsg_level = SOL_SOCKET;
307 cmsg->cmsg_type = SCM_RIGHTS;
308 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400309 data = (union cmsg_data *) CMSG_DATA(cmsg);
310 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100311 nmsg.msg_controllen = cmsg->cmsg_len;
312 ret = 0;
313 }
314 iov.iov_base = &ret;
315 iov.iov_len = sizeof ret;
316
317 if (wl->verbose)
318 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
319 message->path, ret, fd);
320 do {
321 len = sendmsg(wl->sock[0], &nmsg, 0);
322 } while (len < 0 && errno == EINTR);
323
324 if (len < 0)
325 return -1;
326
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700327 if (major(s.st_rdev) == DRM_MAJOR)
328 wl->drm_fd = fd;
329
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100330 return 0;
331}
332
333static int
334handle_socket_msg(struct weston_launch *wl)
335{
336 char control[CMSG_SPACE(sizeof(int))];
337 char buf[BUFSIZ];
338 struct msghdr msg;
339 struct iovec iov;
340 int ret = -1;
341 ssize_t len;
342 struct weston_launcher_message *message;
343
344 memset(&msg, 0, sizeof(msg));
345 iov.iov_base = buf;
346 iov.iov_len = sizeof buf;
347 msg.msg_iov = &iov;
348 msg.msg_iovlen = 1;
349 msg.msg_control = control;
350 msg.msg_controllen = sizeof control;
351
352 do {
353 len = recvmsg(wl->sock[0], &msg, 0);
354 } while (len < 0 && errno == EINTR);
355
356 if (len < 1)
357 return -1;
358
359 message = (void *) buf;
360 switch (message->opcode) {
361 case WESTON_LAUNCHER_OPEN:
362 ret = handle_open(wl, &msg, len);
363 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100364 }
365
366 return ret;
367}
368
369static void
370quit(struct weston_launch *wl, int status)
371{
372 int err;
373
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100374 close(wl->signalfd);
375 close(wl->sock[0]);
376
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700377 if (wl->new_user) {
378 err = pam_close_session(wl->ph, 0);
379 if (err)
380 fprintf(stderr, "pam_close_session failed: %d: %s\n",
381 err, pam_strerror(wl->ph, err));
382 pam_end(wl->ph, err);
383 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100384
385 exit(status);
386}
387
388static int
389handle_signal(struct weston_launch *wl)
390{
391 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100392 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100393
394 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
395 error(0, errno, "reading signalfd failed");
396 return -1;
397 }
398
399 switch (sig.ssi_signo) {
400 case SIGCHLD:
401 pid = waitpid(-1, &status, 0);
402 if (pid == wl->child) {
403 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100404 if (WIFEXITED(status))
405 ret = WEXITSTATUS(status);
406 else if (WIFSIGNALED(status))
407 /*
408 * If weston dies because of signal N, we
409 * return 10+N. This is distinct from
410 * weston-launch dying because of a signal
411 * (128+N).
412 */
413 ret = 10 + WTERMSIG(status);
414 else
415 ret = 0;
416 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100417 }
418 break;
419 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100420 case SIGINT:
421 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400422 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100423 break;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700424 case SIGUSR1:
425 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
426 drmDropMaster(wl->drm_fd);
427 ioctl(wl->tty, VT_RELDISP, 1);
428 break;
429 case SIGUSR2:
430 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
431 drmSetMaster(wl->drm_fd);
432 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
433 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100434 default:
435 return -1;
436 }
437
438 return 0;
439}
440
441static int
442setup_tty(struct weston_launch *wl, const char *tty)
443{
444 struct stat buf;
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700445 struct vt_mode mode = { 0 };
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100446 char *t;
447
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700448 if (!wl->new_user) {
449 wl->tty = STDIN_FILENO;
450 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100451 t = ttyname(STDIN_FILENO);
452 if (t && strcmp(t, tty) == 0)
453 wl->tty = STDIN_FILENO;
454 else
455 wl->tty = open(tty, O_RDWR | O_NOCTTY);
456 } else {
457 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
458 char filename[16];
459
460 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300461 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100462
463 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
464 error(1, errno, "failed to find non-opened console");
465
466 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
467 wl->tty = open(filename, O_RDWR | O_NOCTTY);
468 close(tty0);
469 }
470
471 if (wl->tty < 0)
472 error(1, errno, "failed to open tty");
473
474 if (tty) {
475 if (fstat(wl->tty, &buf) < 0)
476 error(1, errno, "stat %s failed", tty);
477
478 if (major(buf.st_rdev) != TTY_MAJOR)
479 error(1, 0, "invalid tty device: %s", tty);
480
481 wl->ttynr = minor(buf.st_rdev);
482 }
483
Kristian Høgsberg1eb482d2013-09-17 22:15:37 -0700484 mode.mode = VT_PROCESS;
485 mode.relsig = SIGUSR1;
486 mode.acqsig = SIGUSR2;
487 if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
488 error(1, errno, "failed to take control of vt handling\n");
489
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100490 return 0;
491}
492
493static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700494setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700495{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700496 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700497 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700498 int i;
499
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700500 if (wl->tty != STDIN_FILENO) {
501 if (setsid() < 0)
502 error(1, errno, "setsid failed");
503 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
504 error(1, errno, "TIOCSCTTY failed - tty is in use");
505 }
506
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700507 term = getenv("TERM");
508 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100509 if (term)
510 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700511 setenv("USER", wl->pw->pw_name, 1);
512 setenv("LOGNAME", wl->pw->pw_name, 1);
513 setenv("HOME", wl->pw->pw_dir, 1);
514 setenv("SHELL", wl->pw->pw_shell, 1);
515
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700516 env = pam_getenvlist(wl->ph);
517 if (env) {
518 for (i = 0; env[i]; ++i) {
519 if (putenv(env[i]) < 0)
520 error(0, 0, "putenv %s failed", env[i]);
521 }
522 free(env);
523 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700524}
525
526static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000527drop_privileges(struct weston_launch *wl)
528{
529 if (setgid(wl->pw->pw_gid) < 0 ||
530#ifdef HAVE_INITGROUPS
531 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
532#endif
533 setuid(wl->pw->pw_uid) < 0)
534 error(1, errno, "dropping privileges failed");
535}
536
537static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700538launch_compositor(struct weston_launch *wl, int argc, char *argv[])
539{
540 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700541 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700542 int i;
543
544 if (wl->verbose)
545 printf("weston-launch: spawned weston with pid: %d\n", getpid());
546 if (wl->new_user)
547 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700548
Peter Hutterer34be0602013-08-06 12:10:09 +1000549 drop_privileges(wl);
550
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700551 if (wl->tty != STDIN_FILENO)
552 setenv_fd("WESTON_TTY_FD", wl->tty);
553
554 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
555
556 unsetenv("DISPLAY");
557
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700558 /* Do not give our signal mask to the new process. */
559 sigemptyset(&mask);
560 sigaddset(&mask, SIGTERM);
561 sigaddset(&mask, SIGCHLD);
562 sigaddset(&mask, SIGINT);
563 sigprocmask(SIG_UNBLOCK, &mask, NULL);
564
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700565 child_argv[0] = wl->pw->pw_shell;
566 child_argv[1] = "-l";
567 child_argv[2] = "-c";
568 child_argv[3] = BINDIR "/weston \"$@\"";
569 child_argv[4] = "weston";
570 for (i = 0; i < argc; ++i)
571 child_argv[5 + i] = argv[i];
572 child_argv[5 + i] = NULL;
573
574 execv(child_argv[0], child_argv);
575 error(1, errno, "exec failed");
576}
577
578static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100579help(const char *name)
580{
581 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
582 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300583 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100584 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100585 fprintf(stderr, " -h, --help Display this help message\n");
586}
587
588int
589main(int argc, char *argv[])
590{
591 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100592 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700593 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100594 struct option opts[] = {
595 { "user", required_argument, NULL, 'u' },
596 { "tty", required_argument, NULL, 't' },
597 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100598 { "help", no_argument, NULL, 'h' },
599 { 0, 0, NULL, 0 }
600 };
601
602 memset(&wl, 0, sizeof wl);
603
Kristian Høgsbergab499942013-07-19 21:26:24 -0700604 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100605 switch (c) {
606 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700607 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100608 if (getuid() != 0)
609 error(1, 0, "Permission denied. -u allowed for root only");
610 break;
611 case 't':
612 tty = optarg;
613 break;
614 case 'v':
615 wl.verbose = 1;
616 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100617 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700618 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530619 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100620 }
621 }
622
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300623 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200624 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100625
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700626 if (wl.new_user)
627 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100628 else
629 wl.pw = getpwuid(getuid());
630 if (wl.pw == NULL)
631 error(1, errno, "failed to get username");
632
633 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300634 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100635#ifdef HAVE_SYSTEMD_LOGIN
636 " - run from an active and local (systemd) session.\n"
637#else
638 " - enable systemd session support for weston-launch.\n"
639#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300640 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100641
642 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530643 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100644
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700645 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530646 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100647
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100648 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530649 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100650
651 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530652 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100653
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700654 wl.child = fork();
655 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100656 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700657 exit(EXIT_FAILURE);
658 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100659
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700660 if (wl.child == 0)
661 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100662
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700663 close(wl.sock[1]);
664 if (wl.tty != STDIN_FILENO)
665 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200666
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700667 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700668 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700669 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100670
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700671 fds[0].fd = wl.sock[0];
672 fds[0].events = POLLIN;
673 fds[1].fd = wl.signalfd;
674 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100675
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700676 n = poll(fds, 2, -1);
677 if (n < 0)
678 error(0, errno, "poll failed");
679 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700680 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700681 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700682 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100683 }
684
685 return 0;
686}