blob: 7264f7e22d2ba86304c59337ee5757837ac9b738 [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
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
Benjamin Franzkebfeda132012-01-30 14:04:04 +010071 int signalfd;
72
73 pid_t child;
74 int verbose;
Kristian Høgsberg636156d2013-07-22 10:35:47 -070075 char *new_user;
Benjamin Franzkebfeda132012-01-30 14:04:04 +010076};
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{
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100193 if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, wl->sock) < 0)
194 error(1, errno, "socketpair failed");
195
196 fcntl(wl->sock[0], F_SETFD, O_CLOEXEC);
197
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100198 return 0;
199}
200
201static int
202setup_signals(struct weston_launch *wl)
203{
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100204 int ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100205 sigset_t mask;
206 struct sigaction sa;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100207
208 memset(&sa, 0, sizeof sa);
209 sa.sa_handler = SIG_DFL;
210 sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100211 ret = sigaction(SIGCHLD, &sa, NULL);
212 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100213
Kristian Høgsberg18684d42013-07-22 11:59:18 -0700214 sa.sa_handler = SIG_IGN;
215 sa.sa_flags = 0;
216 sigaction(SIGHUP, &sa, NULL);
217
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100218 ret = sigemptyset(&mask);
219 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100220 sigaddset(&mask, SIGCHLD);
221 sigaddset(&mask, SIGINT);
222 sigaddset(&mask, SIGTERM);
Philipp Brüschweilerff253122013-03-09 19:38:56 +0100223 ret = sigprocmask(SIG_BLOCK, &mask, NULL);
224 assert(ret == 0);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100225
226 wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
227 if (wl->signalfd < 0)
228 return -errno;
229
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100230 return 0;
231}
232
233static void
234setenv_fd(const char *env, int fd)
235{
236 char buf[32];
237
238 snprintf(buf, sizeof buf, "%d", fd);
239 setenv(env, buf, 1);
240}
241
242static int
243handle_setmaster(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
244{
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400245 int ret = -1;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100246 struct cmsghdr *cmsg;
247 struct weston_launcher_set_master *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400248 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100249
250 if (len != sizeof(*message)) {
251 error(0, 0, "missing value in setmaster request");
252 goto out;
253 }
254
255 message = msg->msg_iov->iov_base;
256
257 cmsg = CMSG_FIRSTHDR(msg);
258 if (!cmsg ||
259 cmsg->cmsg_level != SOL_SOCKET ||
260 cmsg->cmsg_type != SCM_RIGHTS) {
261 error(0, 0, "invalid control message");
262 goto out;
263 }
264
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400265 data = (union cmsg_data *) CMSG_DATA(cmsg);
266 if (data->fd == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100267 error(0, 0, "missing drm fd in socket request");
268 goto out;
269 }
270
271 if (message->set_master)
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400272 ret = drmSetMaster(data->fd);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100273 else
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400274 ret = drmDropMaster(data->fd);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100275
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400276 close(data->fd);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100277out:
278 do {
279 len = send(wl->sock[0], &ret, sizeof ret, 0);
280 } while (len < 0 && errno == EINTR);
281 if (len < 0)
282 return -1;
283
284 return 0;
285}
286
287static int
288handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
289{
290 int fd = -1, ret = -1;
291 char control[CMSG_SPACE(sizeof(fd))];
292 struct cmsghdr *cmsg;
293 struct stat s;
294 struct msghdr nmsg;
295 struct iovec iov;
296 struct weston_launcher_open *message;
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400297 union cmsg_data *data;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100298
299 message = msg->msg_iov->iov_base;
300 if ((size_t)len < sizeof(*message))
301 goto err0;
302
303 /* Ensure path is null-terminated */
304 ((char *) message)[len-1] = '\0';
305
306 if (stat(message->path, &s) < 0)
307 goto err0;
308
309 fd = open(message->path, message->flags);
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100310 if (fd < 0) {
311 fprintf(stderr, "Error opening device %s: %m\n",
312 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100313 goto err0;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100314 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100315
316 if (major(s.st_rdev) != INPUT_MAJOR) {
317 close(fd);
318 fd = -1;
Rob Bradfordd33f2b02013-05-20 16:55:10 +0100319 fprintf(stderr, "Device %s is not an input device\n",
320 message->path);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100321 goto err0;
322 }
323
324err0:
325 memset(&nmsg, 0, sizeof nmsg);
326 nmsg.msg_iov = &iov;
327 nmsg.msg_iovlen = 1;
328 if (fd != -1) {
329 nmsg.msg_control = control;
330 nmsg.msg_controllen = sizeof control;
331 cmsg = CMSG_FIRSTHDR(&nmsg);
332 cmsg->cmsg_level = SOL_SOCKET;
333 cmsg->cmsg_type = SCM_RIGHTS;
334 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
Kristian Høgsberg9e140912012-04-10 01:26:18 -0400335 data = (union cmsg_data *) CMSG_DATA(cmsg);
336 data->fd = fd;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100337 nmsg.msg_controllen = cmsg->cmsg_len;
338 ret = 0;
339 }
340 iov.iov_base = &ret;
341 iov.iov_len = sizeof ret;
342
343 if (wl->verbose)
344 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
345 message->path, ret, fd);
346 do {
347 len = sendmsg(wl->sock[0], &nmsg, 0);
348 } while (len < 0 && errno == EINTR);
349
350 if (len < 0)
351 return -1;
352
353 return 0;
354}
355
356static int
357handle_socket_msg(struct weston_launch *wl)
358{
359 char control[CMSG_SPACE(sizeof(int))];
360 char buf[BUFSIZ];
361 struct msghdr msg;
362 struct iovec iov;
363 int ret = -1;
364 ssize_t len;
365 struct weston_launcher_message *message;
366
367 memset(&msg, 0, sizeof(msg));
368 iov.iov_base = buf;
369 iov.iov_len = sizeof buf;
370 msg.msg_iov = &iov;
371 msg.msg_iovlen = 1;
372 msg.msg_control = control;
373 msg.msg_controllen = sizeof control;
374
375 do {
376 len = recvmsg(wl->sock[0], &msg, 0);
377 } while (len < 0 && errno == EINTR);
378
379 if (len < 1)
380 return -1;
381
382 message = (void *) buf;
383 switch (message->opcode) {
384 case WESTON_LAUNCHER_OPEN:
385 ret = handle_open(wl, &msg, len);
386 break;
387 case WESTON_LAUNCHER_DRM_SET_MASTER:
388 ret = handle_setmaster(wl, &msg, len);
389 break;
390 }
391
392 return ret;
393}
394
395static void
396quit(struct weston_launch *wl, int status)
397{
398 int err;
399
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100400 close(wl->signalfd);
401 close(wl->sock[0]);
402
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700403 if (wl->new_user) {
404 err = pam_close_session(wl->ph, 0);
405 if (err)
406 fprintf(stderr, "pam_close_session failed: %d: %s\n",
407 err, pam_strerror(wl->ph, err));
408 pam_end(wl->ph, err);
409 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100410
411 exit(status);
412}
413
414static int
415handle_signal(struct weston_launch *wl)
416{
417 struct signalfd_siginfo sig;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100418 int pid, status, ret;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100419
420 if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
421 error(0, errno, "reading signalfd failed");
422 return -1;
423 }
424
425 switch (sig.ssi_signo) {
426 case SIGCHLD:
427 pid = waitpid(-1, &status, 0);
428 if (pid == wl->child) {
429 wl->child = 0;
Philipp Brüschweiler7a3ec742013-03-10 15:14:01 +0100430 if (WIFEXITED(status))
431 ret = WEXITSTATUS(status);
432 else if (WIFSIGNALED(status))
433 /*
434 * If weston dies because of signal N, we
435 * return 10+N. This is distinct from
436 * weston-launch dying because of a signal
437 * (128+N).
438 */
439 ret = 10 + WTERMSIG(status);
440 else
441 ret = 0;
442 quit(wl, ret);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100443 }
444 break;
445 case SIGTERM:
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100446 case SIGINT:
447 if (wl->child)
Kristian Høgsberg1a81abb2013-06-17 15:23:20 -0400448 kill(wl->child, sig.ssi_signo);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100449 break;
450 default:
451 return -1;
452 }
453
454 return 0;
455}
456
457static int
458setup_tty(struct weston_launch *wl, const char *tty)
459{
460 struct stat buf;
461 char *t;
462
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700463 if (!wl->new_user) {
464 wl->tty = STDIN_FILENO;
465 } else if (tty) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100466 t = ttyname(STDIN_FILENO);
467 if (t && strcmp(t, tty) == 0)
468 wl->tty = STDIN_FILENO;
469 else
470 wl->tty = open(tty, O_RDWR | O_NOCTTY);
471 } else {
472 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
473 char filename[16];
474
475 if (tty0 < 0)
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300476 error(1, errno, "could not open tty0");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100477
478 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
479 error(1, errno, "failed to find non-opened console");
480
481 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
482 wl->tty = open(filename, O_RDWR | O_NOCTTY);
483 close(tty0);
484 }
485
486 if (wl->tty < 0)
487 error(1, errno, "failed to open tty");
488
489 if (tty) {
490 if (fstat(wl->tty, &buf) < 0)
491 error(1, errno, "stat %s failed", tty);
492
493 if (major(buf.st_rdev) != TTY_MAJOR)
494 error(1, 0, "invalid tty device: %s", tty);
495
496 wl->ttynr = minor(buf.st_rdev);
497 }
498
499 return 0;
500}
501
502static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700503setup_session(struct weston_launch *wl)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700504{
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700505 char **env;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700506 char *term;
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700507 int i;
508
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700509 if (wl->tty != STDIN_FILENO) {
510 if (setsid() < 0)
511 error(1, errno, "setsid failed");
512 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
513 error(1, errno, "TIOCSCTTY failed - tty is in use");
514 }
515
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700516 term = getenv("TERM");
517 clearenv();
Rob Bradford7ac9f732013-08-09 11:30:38 +0100518 if (term)
519 setenv("TERM", term, 1);
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700520 setenv("USER", wl->pw->pw_name, 1);
521 setenv("LOGNAME", wl->pw->pw_name, 1);
522 setenv("HOME", wl->pw->pw_dir, 1);
523 setenv("SHELL", wl->pw->pw_shell, 1);
524
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700525 env = pam_getenvlist(wl->ph);
526 if (env) {
527 for (i = 0; env[i]; ++i) {
528 if (putenv(env[i]) < 0)
529 error(0, 0, "putenv %s failed", env[i]);
530 }
531 free(env);
532 }
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700533}
534
535static void
Peter Hutterer34be0602013-08-06 12:10:09 +1000536drop_privileges(struct weston_launch *wl)
537{
538 if (setgid(wl->pw->pw_gid) < 0 ||
539#ifdef HAVE_INITGROUPS
540 initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
541#endif
542 setuid(wl->pw->pw_uid) < 0)
543 error(1, errno, "dropping privileges failed");
544}
545
546static void
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700547launch_compositor(struct weston_launch *wl, int argc, char *argv[])
548{
549 char *child_argv[MAX_ARGV_SIZE];
Eduardo Limad0357bb2013-07-30 10:43:41 -0700550 sigset_t mask;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700551 int i;
552
553 if (wl->verbose)
554 printf("weston-launch: spawned weston with pid: %d\n", getpid());
555 if (wl->new_user)
556 setup_session(wl);
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700557
Peter Hutterer34be0602013-08-06 12:10:09 +1000558 drop_privileges(wl);
559
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700560 if (wl->tty != STDIN_FILENO)
561 setenv_fd("WESTON_TTY_FD", wl->tty);
562
563 setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
564
565 unsetenv("DISPLAY");
566
Kristian Høgsberg73c60ab2013-07-30 09:45:04 -0700567 /* Do not give our signal mask to the new process. */
568 sigemptyset(&mask);
569 sigaddset(&mask, SIGTERM);
570 sigaddset(&mask, SIGCHLD);
571 sigaddset(&mask, SIGINT);
572 sigprocmask(SIG_UNBLOCK, &mask, NULL);
573
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700574 child_argv[0] = wl->pw->pw_shell;
575 child_argv[1] = "-l";
576 child_argv[2] = "-c";
577 child_argv[3] = BINDIR "/weston \"$@\"";
578 child_argv[4] = "weston";
579 for (i = 0; i < argc; ++i)
580 child_argv[5 + i] = argv[i];
581 child_argv[5 + i] = NULL;
582
583 execv(child_argv[0], child_argv);
584 error(1, errno, "exec failed");
585}
586
587static void
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100588help(const char *name)
589{
590 fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
591 fprintf(stderr, " -u, --user Start session as specified username\n");
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300592 fprintf(stderr, " -t, --tty Start session on alternative tty\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100593 fprintf(stderr, " -v, --verbose Be verbose\n");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100594 fprintf(stderr, " -h, --help Display this help message\n");
595}
596
597int
598main(int argc, char *argv[])
599{
600 struct weston_launch wl;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100601 int i, c;
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700602 char *tty = NULL;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100603 struct option opts[] = {
604 { "user", required_argument, NULL, 'u' },
605 { "tty", required_argument, NULL, 't' },
606 { "verbose", no_argument, NULL, 'v' },
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100607 { "help", no_argument, NULL, 'h' },
608 { 0, 0, NULL, 0 }
609 };
610
611 memset(&wl, 0, sizeof wl);
612
Kristian Høgsbergab499942013-07-19 21:26:24 -0700613 while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100614 switch (c) {
615 case 'u':
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700616 wl.new_user = optarg;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100617 if (getuid() != 0)
618 error(1, 0, "Permission denied. -u allowed for root only");
619 break;
620 case 't':
621 tty = optarg;
622 break;
623 case 'v':
624 wl.verbose = 1;
625 break;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100626 case 'h':
Scott Moreaucc9acfc2013-01-21 23:40:59 -0700627 help("weston-launch");
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530628 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100629 }
630 }
631
Ander Conselvan de Oliveira9bdfc482013-05-22 22:55:33 +0300632 if ((argc - optind) > (MAX_ARGV_SIZE - 6))
Quentin Glidicff323092013-05-17 16:20:37 +0200633 error(1, E2BIG, "Too many arguments to pass to weston");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100634
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700635 if (wl.new_user)
636 wl.pw = getpwnam(wl.new_user);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100637 else
638 wl.pw = getpwuid(getuid());
639 if (wl.pw == NULL)
640 error(1, errno, "failed to get username");
641
642 if (!weston_launch_allowed(&wl))
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300643 error(1, 0, "Permission denied. You should either:\n"
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100644#ifdef HAVE_SYSTEMD_LOGIN
645 " - run from an active and local (systemd) session.\n"
646#else
647 " - enable systemd session support for weston-launch.\n"
648#endif
Tiago Vignatti314db6e2012-04-17 20:10:11 +0300649 " - or add yourself to the 'weston-launch' group.");
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100650
651 if (setup_tty(&wl, tty) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530652 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100653
Kristian Høgsberg636156d2013-07-22 10:35:47 -0700654 if (wl.new_user && setup_pam(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530655 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100656
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100657 if (setup_launcher_socket(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530658 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100659
660 if (setup_signals(&wl) < 0)
Siddharth Heroord6be88b2013-03-12 02:36:52 +0530661 exit(EXIT_FAILURE);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100662
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700663 wl.child = fork();
664 if (wl.child == -1) {
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100665 error(1, errno, "fork failed");
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700666 exit(EXIT_FAILURE);
667 }
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100668
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700669 if (wl.child == 0)
670 launch_compositor(&wl, argc - optind, argv + optind);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100671
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700672 close(wl.sock[1]);
673 if (wl.tty != STDIN_FILENO)
674 close(wl.tty);
Quentin Glidic735302e2013-06-19 15:27:11 +0200675
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700676 while (1) {
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700677 struct pollfd fds[2];
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700678 int n;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100679
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700680 fds[0].fd = wl.sock[0];
681 fds[0].events = POLLIN;
682 fds[1].fd = wl.signalfd;
683 fds[1].events = POLLIN;
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100684
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700685 n = poll(fds, 2, -1);
686 if (n < 0)
687 error(0, errno, "poll failed");
688 if (fds[0].revents & POLLIN)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700689 handle_socket_msg(&wl);
Kristian Høgsbergf2807702013-07-23 11:43:03 -0700690 if (fds[1].revents)
Kristian Høgsbergca70f2f2013-07-19 21:25:20 -0700691 handle_signal(&wl);
Benjamin Franzkebfeda132012-01-30 14:04:04 +0100692 }
693
694 return 0;
695}