blob: ac786afa5d20cedc151fd84a3ef72ce2d9103c24 [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>
29#include <errno.h>
30
31#include <error.h>
32#include <getopt.h>
33
34#include <sys/types.h>
35#include <sys/ioctl.h>
36#include <sys/stat.h>
37#include <sys/wait.h>
38#include <sys/socket.h>
39#include <sys/epoll.h>
40#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
Quentin Glidicff323092013-05-17 16:20:37 +020061#define MAX_ARGV_SIZE 256
62
Benjamin Franzkebfeda132012-01-30 14:04:04 +010063struct weston_launch {
64 struct pam_conv pc;
65 pam_handle_t *ph;
66 int tty;
67 int ttynr;
68 int sock[2];
69 struct passwd *pw;
70
71 int epollfd;
72 int signalfd;
73
74 pid_t child;
75 int verbose;
76};
77
Kristian Høgsberg9e140912012-04-10 01:26:18 -040078union cmsg_data { unsigned char b[4]; int fd; };
79
Benjamin Franzkebfeda132012-01-30 14:04:04 +010080static gid_t *
81read_groups(void)
82{
83 int n;
84 gid_t *groups;
85
86 n = getgroups(0, NULL);
Rob Bradford40be7b42012-12-05 18:47:11 +000087
88 if (n < 0) {
89 fprintf(stderr, "Unable to retrieve groups: %m\n");
90 return NULL;
91 }
92
Benjamin Franzkebfeda132012-01-30 14:04:04 +010093 groups = malloc(n * sizeof(gid_t));
94 if (!groups)
95 return NULL;
96
97 if (getgroups(n, groups) < 0) {
Rob Bradford40be7b42012-12-05 18:47:11 +000098 fprintf(stderr, "Unable to retrieve groups: %m\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +010099 free(groups);
100 return NULL;
101 }
102 return groups;
103}
104
105static int
106weston_launch_allowed(struct weston_launch *wl)
107{
108 struct group *gr;
109 gid_t *groups;
110 int i;
111#ifdef HAVE_SYSTEMD_LOGIN
112 char *session, *seat;
113 int err;
114#endif
115
116 if (getuid() == 0)
117 return 1;
118
119 gr = getgrnam("weston-launch");
120 if (gr) {
121 groups = read_groups();
122 if (groups) {
123 for (i = 0; groups[i]; ++i) {
124 if (groups[i] == gr->gr_gid) {
125 free(groups);
126 return 1;
127 }
128 }
129 free(groups);
130 }
131 }
132
133#ifdef HAVE_SYSTEMD_LOGIN
134 err = sd_pid_get_session(getpid(), &session);
135 if (err == 0 && session) {
136 if (sd_session_is_active(session) &&
137 sd_session_get_seat(session, &seat) == 0) {
138 free(seat);
139 free(session);
140 return 1;
141 }
142 free(session);
143 }
144#endif
145
146 return 0;
147}
148
149static int
150pam_conversation_fn(int msg_count,
151 const struct pam_message **messages,
152 struct pam_response **responses,
153 void *user_data)
154{
155 return PAM_SUCCESS;
156}
157
158static int
159setup_pam(struct weston_launch *wl)
160{
161 int err;
162
163 wl->pc.conv = pam_conversation_fn;
164 wl->pc.appdata_ptr = wl;
165
166 err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
John Kåre Alsaker5b90d8f2012-10-12 12:25:05 +0200167 if (err != PAM_SUCCESS) {
168 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
169 err, pam_strerror(wl->ph, err));
170 return -1;
171 }
172
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100173 err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
174 if (err != PAM_SUCCESS) {
175 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
176 err, pam_strerror(wl->ph, err));
177 return -1;
178 }
179
180 err = pam_open_session(wl->ph, 0);
181 if (err != PAM_SUCCESS) {
182 fprintf(stderr, "failed to open pam session: %d: %s\n",
183 err, pam_strerror(wl->ph, err));
184 return -1;
185 }
186
187 return 0;
188}
189
190static int
191setup_launcher_socket(struct weston_launch *wl)
192{
193 struct epoll_event ev;
194
195 if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
196 error(1, errno, "socketpair failed");
197
198 fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
199
200 memset(&ev, 0, sizeof ev);
201 ev.events = EPOLLIN;
202 ev.data.fd = wl->sock[0];
203 if (epoll_ctl(wl->epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0)
204 return -errno;
205
206 return 0;
207}
208
209static int
210setup_signals(struct weston_launch *wl)
211{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100212 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100213 sigset_t mask;
214 struct sigaction sa;
215 struct epoll_event ev;
216
217 memset(&sa, 0, sizeof sa);
218 sa.sa_handler = SIG_DFL;
219 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100220 ret = sigaction(SIGCHLD, &sa, NULL);
221 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100222
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700223 sa.sa_handler = SIG_IGN;
224 sa.sa_flags = 0;
225 sigaction(SIGHUP, &sa, NULL);
226
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100227 ret = sigemptyset(&mask);
228 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100229 sigaddset(&mask, SIGCHLD);
230 sigaddset(&mask, SIGINT);
231 sigaddset(&mask, SIGTERM);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100232 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
233 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100234
235 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
236 if (wl->signalfd < 0)
237 return -errno;
238
239 memset(&ev, 0, sizeof ev);
240 ev.events = EPOLLIN;
241 ev.data.fd = wl->signalfd;
242 if (epoll_ctl(wl->epollfd, EPOLL_CTL_ADD, ev.data.fd, &ev) < 0)
243 return -errno;
244
245 return 0;
246}
247
248static void
249setenv_fd(const char *env, int fd)
250{
251 char buf[32];
252
253 snprintf(buf, sizeof buf, "%d", fd);
254 setenv(env, buf, 1);
255}
256
257static int
258handle_setmaster(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
259{
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400260 int ret = -1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100261 struct cmsghdr *cmsg;
262 struct weston_launcher_set_master *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400263 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100264
265 if (len != sizeof(*message)) {
266 error(0, 0, "missing value in setmaster request");
267 goto out;
268 }
269
270 message = msg->msg_iov->iov_base;
271
272 cmsg = CMSG_FIRSTHDR(msg);
273 if (!cmsg ||
274 cmsg->cmsg_level != SOL_SOCKET ||
275 cmsg->cmsg_type != SCM_RIGHTS) {
276 error(0, 0, "invalid control message");
277 goto out;
278 }
279
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400280 data = (union cmsg_data *) CMSG_DATA(cmsg);
281 if (data->fd == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100282 error(0, 0, "missing drm fd in socket request");
283 goto out;
284 }
285
286 if (message->set_master)
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400287 ret = drmSetMaster(data->fd);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100288 else
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400289 ret = drmDropMaster(data->fd);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100290
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400291 close(data->fd);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100292out:
293 do {
294 len = send(wl->sock[0], &ret, sizeof ret, 0);
295 } while (len < 0 && errno == EINTR);
296 if (len < 0)
297 return -1;
298
299 return 0;
300}
301
302static int
303handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
304{
305 int fd = -1, ret = -1;
306 char control[CMSG_SPACE(sizeof(fd))];
307 struct cmsghdr *cmsg;
308 struct stat s;
309 struct msghdr nmsg;
310 struct iovec iov;
311 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400312 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100313
314 message = msg->msg_iov->iov_base;
315 if ((size_t)len < sizeof(*message))
316 goto err0;
317
318 /* Ensure path is null-terminated */
319 ((char *) message)[len-1] = '\0';
320
321 if (stat(message->path, &s) < 0)
322 goto err0;
323
324 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100325 if (fd < 0) {
326 fprintf(stderr, "Error opening device %s: %m\n",
327 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100328 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100329 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100330
331 if (major(s.st_rdev) != INPUT_MAJOR) {
332 close(fd);
333 fd = -1;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100334 fprintf(stderr, "Device %s is not an input device\n",
335 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100336 goto err0;
337 }
338
339err0:
340 memset(&nmsg, 0, sizeof nmsg);
341 nmsg.msg_iov = &iov;
342 nmsg.msg_iovlen = 1;
343 if (fd != -1) {
344 nmsg.msg_control = control;
345 nmsg.msg_controllen = sizeof control;
346 cmsg = CMSG_FIRSTHDR(&nmsg);
347 cmsg->cmsg_level = SOL_SOCKET;
348 cmsg->cmsg_type = SCM_RIGHTS;
349 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400350 data = (union cmsg_data *) CMSG_DATA(cmsg);
351 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100352 nmsg.msg_controllen = cmsg->cmsg_len;
353 ret = 0;
354 }
355 iov.iov_base = &ret;
356 iov.iov_len = sizeof ret;
357
358 if (wl->verbose)
359 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
360 message->path, ret, fd);
361 do {
362 len = sendmsg(wl->sock[0], &nmsg, 0);
363 } while (len < 0 && errno == EINTR);
364
365 if (len < 0)
366 return -1;
367
368 return 0;
369}
370
371static int
372handle_socket_msg(struct weston_launch *wl)
373{
374 char control[CMSG_SPACE(sizeof(int))];
375 char buf[BUFSIZ];
376 struct msghdr msg;
377 struct iovec iov;
378 int ret = -1;
379 ssize_t len;
380 struct weston_launcher_message *message;
381
382 memset(&msg, 0, sizeof(msg));
383 iov.iov_base = buf;
384 iov.iov_len = sizeof buf;
385 msg.msg_iov = &iov;
386 msg.msg_iovlen = 1;
387 msg.msg_control = control;
388 msg.msg_controllen = sizeof control;
389
390 do {
391 len = recvmsg(wl->sock[0], &msg, 0);
392 } while (len < 0 && errno == EINTR);
393
394 if (len < 1)
395 return -1;
396
397 message = (void *) buf;
398 switch (message->opcode) {
399 case WESTON_LAUNCHER_OPEN:
400 ret = handle_open(wl, &msg, len);
401 break;
402 case WESTON_LAUNCHER_DRM_SET_MASTER:
403 ret = handle_setmaster(wl, &msg, len);
404 break;
405 }
406
407 return ret;
408}
409
410static void
411quit(struct weston_launch *wl, int status)
412{
413 int err;
414
415 close(wl->epollfd);
416 close(wl->signalfd);
417 close(wl->sock[0]);
418
419 err = pam_close_session(wl->ph, 0);
420 if (err)
421 fprintf(stderr, "pam_close_session failed: %d: %s\n",
422 err, pam_strerror(wl->ph, err));
423 pam_end(wl->ph, err);
424
425 exit(status);
426}
427
428static int
429handle_signal(struct weston_launch *wl)
430{
431 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100432 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100433
434 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
435 error(0, errno, "reading signalfd failed");
436 return -1;
437 }
438
439 switch (sig.ssi_signo) {
440 case SIGCHLD:
441 pid = waitpid(-1, &status, 0);
442 if (pid == wl->child) {
443 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100444 if (WIFEXITED(status))
445 ret = WEXITSTATUS(status);
446 else if (WIFSIGNALED(status))
447 /*
448 * If weston dies because of signal N, we
449 * return 10+N. This is distinct from
450 * weston-launch dying because of a signal
451 * (128+N).
452 */
453 ret = 10 + WTERMSIG(status);
454 else
455 ret = 0;
456 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100457 }
458 break;
459 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100460 case SIGINT:
461 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400462 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100463 break;
464 default:
465 return -1;
466 }
467
468 return 0;
469}
470
471static int
472setup_tty(struct weston_launch *wl, const char *tty)
473{
474 struct stat buf;
475 char *t;
476
477 if (tty) {
478 t = ttyname(STDIN_FILENO);
479 if (t && strcmp(t, tty) == 0)
480 wl->tty = STDIN_FILENO;
481 else
482 wl->tty = open(tty, O_RDWR | O_NOCTTY);
483 } else {
484 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
485 char filename[16];
486
487 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300488 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100489
490 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
491 error(1, errno, "failed to find non-opened console");
492
493 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
494 wl->tty = open(filename, O_RDWR | O_NOCTTY);
495 close(tty0);
496 }
497
498 if (wl->tty < 0)
499 error(1, errno, "failed to open tty");
500
501 if (tty) {
502 if (fstat(wl->tty, &buf) < 0)
503 error(1, errno, "stat %s failed", tty);
504
505 if (major(buf.st_rdev) != TTY_MAJOR)
506 error(1, 0, "invalid tty device: %s", tty);
507
508 wl->ttynr = minor(buf.st_rdev);
509 }
510
511 return 0;
512}
513
514static void
515help(const char *name)
516{
517 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
518 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300519 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100520 fprintf(stderr, " -v, --verbose Be verbose\n");
521 fprintf(stderr, " -s, --sleep Sleep specified amount of time before exec\n");
522 fprintf(stderr, " -h, --help Display this help message\n");
523}
524
525int
526main(int argc, char *argv[])
527{
528 struct weston_launch wl;
529 char **env;
530 int i, c;
Quentin Glidicff323092013-05-17 16:20:37 +0200531 char *child_argv[MAX_ARGV_SIZE];
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100532 char *tty = NULL, *new_user = NULL;
Quentin Glidicff323092013-05-17 16:20:37 +0200533 char *term;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100534 int sleep_fork = 0;
535 struct option opts[] = {
536 { "user", required_argument, NULL, 'u' },
537 { "tty", required_argument, NULL, 't' },
538 { "verbose", no_argument, NULL, 'v' },
539 { "sleep", optional_argument, NULL, 's' },
540 { "help", no_argument, NULL, 'h' },
541 { 0, 0, NULL, 0 }
542 };
543
544 memset(&wl, 0, sizeof wl);
545
546 while ((c = getopt_long(argc, argv, "u:t:s::vh", opts, &i)) != -1) {
547 switch (c) {
548 case 'u':
549 new_user = optarg;
550 if (getuid() != 0)
551 error(1, 0, "Permission denied. -u allowed for root only");
552 break;
553 case 't':
554 tty = optarg;
555 break;
556 case 'v':
557 wl.verbose = 1;
558 break;
559 case 's':
560 if (optarg)
561 sleep_fork = atoi(optarg);
562 else
563 sleep_fork = 10;
564 break;
565 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700566 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530567 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100568 }
569 }
570
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300571 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200572 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100573
574 if (new_user)
575 wl.pw = getpwnam(new_user);
576 else
577 wl.pw = getpwuid(getuid());
578 if (wl.pw == NULL)
579 error(1, errno, "failed to get username");
580
Quentin Glidicff323092013-05-17 16:20:37 +0200581 child_argv[0] = wl.pw->pw_shell;
582 child_argv[1] = "-l";
583 child_argv[2] = "-c";
584 child_argv[3] = BINDIR "/weston \"$@\"";
585 child_argv[4] = "weston";
586 for (i = 0; i < (argc - optind); ++i)
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300587 child_argv[5 + i] = argv[optind + i];
588 child_argv[5 + i] = NULL;
Quentin Glidicff323092013-05-17 16:20:37 +0200589
590 term = getenv("TERM");
Kristian Høgsberg272d2432013-01-29 14:14:06 -0500591 clearenv();
Quentin Glidicff323092013-05-17 16:20:37 +0200592 setenv("TERM", term, 1);
Kristian Høgsberg272d2432013-01-29 14:14:06 -0500593 setenv("USER", wl.pw->pw_name, 1);
594 setenv("LOGNAME", wl.pw->pw_name, 1);
595 setenv("HOME", wl.pw->pw_dir, 1);
596 setenv("SHELL", wl.pw->pw_shell, 1);
597
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100598 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300599 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100600#ifdef HAVE_SYSTEMD_LOGIN
601 " - run from an active and local (systemd) session.\n"
602#else
603 " - enable systemd session support for weston-launch.\n"
604#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300605 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100606
607 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530608 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100609
610 if (setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530611 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100612
613 wl.epollfd = epoll_create1(EPOLL_CLOEXEC);
614 if (wl.epollfd < 0)
615 error(1, errno, "epoll create failed");
616
617 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530618 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100619
620 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530621 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100622
623 switch ((wl.child = fork())) {
624 case -1:
625 error(1, errno, "fork failed");
626 break;
627 case 0:
628 if (wl.verbose)
629 printf("weston-launch: spawned weston with pid: %d\n", getpid());
630 if (wl.tty != STDIN_FILENO) {
631 if (setsid() < 0)
632 error(1, errno, "setsid failed");
633 if (ioctl(wl.tty, TIOCSCTTY, 0) < 0)
634 error(1, errno, "TIOCSCTTY failed - tty is in use");
635 }
636
637 if (setgid(wl.pw->pw_gid) < 0 ||
Quentin Glidic735302e2013-06-19 15:27:11 +0200638#ifdef HAVE_INITGROUPS
639 initgroups(wl.pw->pw_name, wl.pw->pw_gid) < 0 ||
640#endif
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100641 setuid(wl.pw->pw_uid) < 0)
Kristian Høgsberg07d48a32013-07-08 14:34:53 -0400642 error(1, errno, "dropping privileges failed");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100643
Quentin Glidic735302e2013-06-19 15:27:11 +0200644
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100645 if (sleep_fork) {
646 if (wl.verbose)
647 printf("weston-launch: waiting %d seconds\n", sleep_fork);
648 sleep(sleep_fork);
649 }
650
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100651 env = pam_getenvlist(wl.ph);
652 if (env) {
653 for (i = 0; env[i]; ++i) {
654 if (putenv(env[i]) < 0)
655 error(0, 0, "putenv %s failed", env[i]);
656 }
657 free(env);
658 }
659
660 if (wl.tty != STDIN_FILENO)
661 setenv_fd("WESTON_TTY_FD", wl.tty);
662
663 setenv_fd("WESTON_LAUNCHER_SOCK", wl.sock[1]);
664
665 unsetenv("DISPLAY");
666
667 execv(child_argv[0], child_argv);
668 error(1, errno, "exec failed");
669 break;
670 default:
671 close(wl.sock[1]);
672 if (wl.tty != STDIN_FILENO)
673 close(wl.tty);
674
675 while (1) {
676 struct epoll_event ev;
677 int n;
678
679 n = epoll_wait(wl.epollfd, &ev, 1, -1);
680 if (n < 0)
681 error(0, errno, "epoll_wait failed");
682 if (n != 1)
683 continue;
684
685 if (ev.data.fd == wl.sock[0])
686 handle_socket_msg(&wl);
687 else if (ev.data.fd == wl.signalfd)
688 handle_signal(&wl);
689 }
690 break;
691 }
692
693 return 0;
694}