compositor: quick fix for sub-surface mapping
[profile/ivi/weston-ivi-shell.git] / src / weston-launch.c
1 /*
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
23 #include "config.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <poll.h>
30 #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>
40 #include <sys/signalfd.h>
41 #include <signal.h>
42 #include <unistd.h>
43 #include <fcntl.h>
44
45 #include <linux/vt.h>
46 #include <linux/major.h>
47 #include <linux/kd.h>
48
49 #include <pwd.h>
50 #include <grp.h>
51 #include <security/pam_appl.h>
52
53 #ifdef HAVE_SYSTEMD_LOGIN
54 #include <systemd/sd-login.h>
55 #endif
56
57 #include "weston-launch.h"
58
59 #define DRM_MAJOR 226
60
61 #ifndef KDSKBMUTE
62 #define KDSKBMUTE       0x4B51
63 #endif
64
65 #ifndef EVIOCREVOKE
66 #define EVIOCREVOKE _IOW('E', 0x91, int)
67 #endif
68
69 #define MAX_ARGV_SIZE 256
70
71 #ifdef HAVE_LIBDRM
72
73 #include <xf86drm.h>
74
75 #else
76
77 static inline int
78 drmDropMaster(int drm_fd)
79 {
80         return 0;
81 }
82
83 static inline int
84 drmSetMaster(int drm_fd)
85 {
86         return 0;
87 }
88
89 #endif
90
91 struct weston_launch {
92         struct pam_conv pc;
93         pam_handle_t *ph;
94         int tty;
95         int ttynr;
96         int sock[2];
97         int drm_fd;
98         int last_input_fd;
99         int kb_mode;
100         struct passwd *pw;
101
102         int signalfd;
103
104         pid_t child;
105         int verbose;
106         char *new_user;
107 };
108
109 union cmsg_data { unsigned char b[4]; int fd; };
110
111 static gid_t *
112 read_groups(void)
113 {
114         int n;
115         gid_t *groups;
116         
117         n = getgroups(0, NULL);
118
119         if (n < 0) {
120                 fprintf(stderr, "Unable to retrieve groups: %m\n");
121                 return NULL;
122         }
123
124         groups = malloc(n * sizeof(gid_t));
125         if (!groups)
126                 return NULL;
127
128         if (getgroups(n, groups) < 0) {
129                 fprintf(stderr, "Unable to retrieve groups: %m\n");
130                 free(groups);
131                 return NULL;
132         }
133         return groups;
134 }
135
136 static int
137 weston_launch_allowed(struct weston_launch *wl)
138 {
139         struct group *gr;
140         gid_t *groups;
141         int i;
142 #ifdef HAVE_SYSTEMD_LOGIN
143         char *session, *seat;
144         int err;
145 #endif
146
147         if (getuid() == 0)
148                 return 1;
149
150         gr = getgrnam("weston-launch");
151         if (gr) {
152                 groups = read_groups();
153                 if (groups) {
154                         for (i = 0; groups[i]; ++i) {
155                                 if (groups[i] == gr->gr_gid) {
156                                         free(groups);
157                                         return 1;
158                                 }
159                         }
160                         free(groups);
161                 }
162         }
163
164 #ifdef HAVE_SYSTEMD_LOGIN
165         err = sd_pid_get_session(getpid(), &session);
166         if (err == 0 && session) {
167                 if (sd_session_is_active(session) &&
168                     sd_session_get_seat(session, &seat) == 0) {
169                         free(seat);
170                         free(session);
171                         return 1;
172                 }
173                 free(session);
174         }
175 #endif
176         
177         return 0;
178 }
179
180 static int
181 pam_conversation_fn(int msg_count,
182                     const struct pam_message **messages,
183                     struct pam_response **responses,
184                     void *user_data)
185 {
186         return PAM_SUCCESS;
187 }
188
189 static int
190 setup_pam(struct weston_launch *wl)
191 {
192         int err;
193
194         wl->pc.conv = pam_conversation_fn;
195         wl->pc.appdata_ptr = wl;
196
197         err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
198         if (err != PAM_SUCCESS) {
199                 fprintf(stderr, "failed to start pam transaction: %d: %s\n",
200                         err, pam_strerror(wl->ph, err));
201                 return -1;
202         }
203
204         err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
205         if (err != PAM_SUCCESS) {
206                 fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
207                         err, pam_strerror(wl->ph, err));
208                 return -1;
209         }
210
211         err = pam_open_session(wl->ph, 0);
212         if (err != PAM_SUCCESS) {
213                 fprintf(stderr, "failed to open pam session: %d: %s\n",
214                         err, pam_strerror(wl->ph, err));
215                 return -1;
216         }
217
218         return 0;
219 }
220
221 static int
222 setup_launcher_socket(struct weston_launch *wl)
223 {
224         if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
225                 error(1, errno, "socketpair failed");
226         
227         if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
228                 error(1, errno, "fcntl failed");
229
230         return 0;
231 }
232
233 static int
234 setup_signals(struct weston_launch *wl)
235 {
236         int ret;
237         sigset_t mask;
238         struct sigaction sa;
239
240         memset(&sa, 0, sizeof sa);
241         sa.sa_handler = SIG_DFL;
242         sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
243         ret = sigaction(SIGCHLD, &sa, NULL);
244         assert(ret == 0);
245
246         sa.sa_handler = SIG_IGN;
247         sa.sa_flags = 0;
248         sigaction(SIGHUP, &sa, NULL);
249
250         ret = sigemptyset(&mask);
251         assert(ret == 0);
252         sigaddset(&mask, SIGCHLD);
253         sigaddset(&mask, SIGINT);
254         sigaddset(&mask, SIGTERM);
255         sigaddset(&mask, SIGUSR1);
256         sigaddset(&mask, SIGUSR2);
257         ret = sigprocmask(SIG_BLOCK, &mask, NULL);
258         assert(ret == 0);
259
260         wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
261         if (wl->signalfd < 0)
262                 return -errno;
263
264         return 0;
265 }
266
267 static void
268 setenv_fd(const char *env, int fd)
269 {
270         char buf[32];
271
272         snprintf(buf, sizeof buf, "%d", fd);
273         setenv(env, buf, 1);
274 }
275
276 static int
277 send_reply(struct weston_launch *wl, int reply)
278 {
279         int len;
280
281         do {
282                 len = send(wl->sock[0], &reply, sizeof reply, 0);
283         } while (len < 0 && errno == EINTR);
284
285         return len;
286 }
287
288 static int
289 handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
290 {
291         int fd = -1, ret = -1;
292         char control[CMSG_SPACE(sizeof(fd))];
293         struct cmsghdr *cmsg;
294         struct stat s;
295         struct msghdr nmsg;
296         struct iovec iov;
297         struct weston_launcher_open *message;
298         union cmsg_data *data;
299
300         message = msg->msg_iov->iov_base;
301         if ((size_t)len < sizeof(*message))
302                 goto err0;
303
304         /* Ensure path is null-terminated */
305         ((char *) message)[len-1] = '\0';
306
307         fd = open(message->path, message->flags);
308         if (fd < 0) {
309                 fprintf(stderr, "Error opening device %s: %m\n",
310                         message->path);
311                 goto err0;
312         }
313
314         if (fstat(fd, &s) < 0) {
315                 close(fd);
316                 fd = -1;
317                 fprintf(stderr, "Failed to stat %s\n", message->path);
318                 goto err0;
319         }
320
321         if (major(s.st_rdev) != INPUT_MAJOR &&
322             major(s.st_rdev) != DRM_MAJOR) {
323                 close(fd);
324                 fd = -1;
325                 fprintf(stderr, "Device %s is not an input or drm device\n",
326                         message->path);
327                 goto err0;
328         }
329
330 err0:
331         memset(&nmsg, 0, sizeof nmsg);
332         nmsg.msg_iov = &iov;
333         nmsg.msg_iovlen = 1;
334         if (fd != -1) {
335                 nmsg.msg_control = control;
336                 nmsg.msg_controllen = sizeof control;
337                 cmsg = CMSG_FIRSTHDR(&nmsg);
338                 cmsg->cmsg_level = SOL_SOCKET;
339                 cmsg->cmsg_type = SCM_RIGHTS;
340                 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
341                 data = (union cmsg_data *) CMSG_DATA(cmsg);
342                 data->fd = fd;
343                 nmsg.msg_controllen = cmsg->cmsg_len;
344                 ret = 0;
345         }
346         iov.iov_base = &ret;
347         iov.iov_len = sizeof ret;
348
349         if (wl->verbose)
350                 fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
351                         message->path, ret, fd);
352         do {
353                 len = sendmsg(wl->sock[0], &nmsg, 0);
354         } while (len < 0 && errno == EINTR);
355
356         if (len < 0)
357                 return -1;
358
359         if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
360                 wl->drm_fd = fd;
361         if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
362             wl->last_input_fd < fd)
363                 wl->last_input_fd = fd;
364
365         return 0;
366 }
367
368 static int
369 handle_socket_msg(struct weston_launch *wl)
370 {
371         char control[CMSG_SPACE(sizeof(int))];
372         char buf[BUFSIZ];
373         struct msghdr msg;
374         struct iovec iov;
375         int ret = -1;
376         ssize_t len;
377         struct weston_launcher_message *message;
378
379         memset(&msg, 0, sizeof(msg));
380         iov.iov_base = buf;
381         iov.iov_len  = sizeof buf;
382         msg.msg_iov = &iov;
383         msg.msg_iovlen = 1;
384         msg.msg_control = control;
385         msg.msg_controllen = sizeof control;
386
387         do {
388                 len = recvmsg(wl->sock[0], &msg, 0);
389         } while (len < 0 && errno == EINTR);
390
391         if (len < 1)
392                 return -1;
393
394         message = (void *) buf;
395         switch (message->opcode) {
396         case WESTON_LAUNCHER_OPEN:
397                 ret = handle_open(wl, &msg, len);
398                 break;
399         }
400
401         return ret;
402 }
403
404 static void
405 quit(struct weston_launch *wl, int status)
406 {
407         struct vt_mode mode = { 0 };
408         int err;
409
410         close(wl->signalfd);
411         close(wl->sock[0]);
412
413         if (wl->new_user) {
414                 err = pam_close_session(wl->ph, 0);
415                 if (err)
416                         fprintf(stderr, "pam_close_session failed: %d: %s\n",
417                                 err, pam_strerror(wl->ph, err));
418                 pam_end(wl->ph, err);
419         }
420
421         if (ioctl(wl->tty, KDSKBMUTE, 0) &&
422             ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
423                 fprintf(stderr, "failed to restore keyboard mode: %m\n");
424
425         if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
426                 fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
427
428         /* We have to drop master before we switch the VT back in
429          * VT_AUTO, so we don't risk switching to a VT with another
430          * display server, that will then fail to set drm master. */
431         drmDropMaster(wl->drm_fd);
432
433         mode.mode = VT_AUTO;
434         if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
435                 fprintf(stderr, "could not reset vt handling\n");
436
437         exit(status);
438 }
439
440 static void
441 close_input_fds(struct weston_launch *wl)
442 {
443         struct stat s;
444         int fd;
445
446         for (fd = 3; fd <= wl->last_input_fd; fd++) {
447                 if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
448                         /* EVIOCREVOKE may fail if the kernel doesn't
449                          * support it, but all we can do is ignore it. */
450                         ioctl(fd, EVIOCREVOKE, 0);
451                         close(fd);
452                 }
453         }
454 }
455
456 static int
457 handle_signal(struct weston_launch *wl)
458 {
459         struct signalfd_siginfo sig;
460         int pid, status, ret;
461
462         if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
463                 error(0, errno, "reading signalfd failed");
464                 return -1;
465         }
466
467         switch (sig.ssi_signo) {
468         case SIGCHLD:
469                 pid = waitpid(-1, &status, 0);
470                 if (pid == wl->child) {
471                         wl->child = 0;
472                         if (WIFEXITED(status))
473                                 ret = WEXITSTATUS(status);
474                         else if (WIFSIGNALED(status))
475                                 /*
476                                  * If weston dies because of signal N, we
477                                  * return 10+N. This is distinct from
478                                  * weston-launch dying because of a signal
479                                  * (128+N).
480                                  */
481                                 ret = 10 + WTERMSIG(status);
482                         else
483                                 ret = 0;
484                         quit(wl, ret);
485                 }
486                 break;
487         case SIGTERM:
488         case SIGINT:
489                 if (wl->child)
490                         kill(wl->child, sig.ssi_signo);
491                 break;
492         case SIGUSR1:
493                 send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
494                 close_input_fds(wl);
495                 drmDropMaster(wl->drm_fd);
496                 ioctl(wl->tty, VT_RELDISP, 1);
497                 break;
498         case SIGUSR2:
499                 ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
500                 drmSetMaster(wl->drm_fd);
501                 send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
502                 break;
503         default:
504                 return -1;
505         }
506
507         return 0;
508 }
509
510 static int
511 setup_tty(struct weston_launch *wl, const char *tty)
512 {
513         struct stat buf;
514         struct vt_mode mode = { 0 };
515         char *t;
516
517         if (!wl->new_user) {
518                 wl->tty = STDIN_FILENO;
519         } else if (tty) {
520                 t = ttyname(STDIN_FILENO);
521                 if (t && strcmp(t, tty) == 0)
522                         wl->tty = STDIN_FILENO;
523                 else
524                         wl->tty = open(tty, O_RDWR | O_NOCTTY);
525         } else {
526                 int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
527                 char filename[16];
528
529                 if (tty0 < 0)
530                         error(1, errno, "could not open tty0");
531
532                 if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
533                         error(1, errno, "failed to find non-opened console"); 
534
535                 snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
536                 wl->tty = open(filename, O_RDWR | O_NOCTTY);
537                 close(tty0);
538         }
539
540         if (wl->tty < 0)
541                 error(1, errno, "failed to open tty");
542
543         if (fstat(wl->tty, &buf) == -1 ||
544             major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
545                 error(1, 0, "weston-launch must be run from a virtual terminal");
546
547         if (tty) {
548                 if (fstat(wl->tty, &buf) < 0)
549                         error(1, errno, "stat %s failed", tty);
550
551                 if (major(buf.st_rdev) != TTY_MAJOR)
552                         error(1, 0, "invalid tty device: %s", tty);
553
554                 wl->ttynr = minor(buf.st_rdev);
555         }
556
557         if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
558                 error(1, errno, "failed to get current keyboard mode: %m\n");
559
560         if (ioctl(wl->tty, KDSKBMUTE, 1) &&
561             ioctl(wl->tty, KDSKBMODE, K_OFF))
562                 error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
563
564         if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
565                 error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
566
567         mode.mode = VT_PROCESS;
568         mode.relsig = SIGUSR1;
569         mode.acqsig = SIGUSR2;
570         if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
571                 error(1, errno, "failed to take control of vt handling\n");
572
573         return 0;
574 }
575
576 static void
577 setup_session(struct weston_launch *wl)
578 {
579         char **env;
580         char *term;
581         int i;
582
583         if (wl->tty != STDIN_FILENO) {
584                 if (setsid() < 0)
585                         error(1, errno, "setsid failed");
586                 if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
587                         error(1, errno, "TIOCSCTTY failed - tty is in use");
588         }
589
590         term = getenv("TERM");
591         clearenv();
592         if (term)
593                 setenv("TERM", term, 1);
594         setenv("USER", wl->pw->pw_name, 1);
595         setenv("LOGNAME", wl->pw->pw_name, 1);
596         setenv("HOME", wl->pw->pw_dir, 1);
597         setenv("SHELL", wl->pw->pw_shell, 1);
598
599         env = pam_getenvlist(wl->ph);
600         if (env) {
601                 for (i = 0; env[i]; ++i) {
602                         if (putenv(env[i]) < 0)
603                                 error(0, 0, "putenv %s failed", env[i]);
604                 }
605                 free(env);
606         }
607 }
608
609 static void
610 drop_privileges(struct weston_launch *wl)
611 {
612         if (setgid(wl->pw->pw_gid) < 0 ||
613 #ifdef HAVE_INITGROUPS
614             initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
615 #endif
616             setuid(wl->pw->pw_uid) < 0)
617                 error(1, errno, "dropping privileges failed");
618 }
619
620 static void
621 launch_compositor(struct weston_launch *wl, int argc, char *argv[])
622 {
623         char *child_argv[MAX_ARGV_SIZE];
624         sigset_t mask;
625         int i;
626
627         if (wl->verbose)
628                 printf("weston-launch: spawned weston with pid: %d\n", getpid());
629         if (wl->new_user)
630                 setup_session(wl);
631
632         if (geteuid() == 0)
633                 drop_privileges(wl);
634
635         setenv_fd("WESTON_TTY_FD", wl->tty);
636         setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
637
638         unsetenv("DISPLAY");
639
640         /* Do not give our signal mask to the new process. */
641         sigemptyset(&mask);
642         sigaddset(&mask, SIGTERM);
643         sigaddset(&mask, SIGCHLD);
644         sigaddset(&mask, SIGINT);
645         sigprocmask(SIG_UNBLOCK, &mask, NULL);
646
647         child_argv[0] = "/bin/sh";
648         child_argv[1] = "-l";
649         child_argv[2] = "-c";
650         child_argv[3] = BINDIR "/weston \"$@\"";
651         child_argv[4] = "weston";
652         for (i = 0; i < argc; ++i)
653                 child_argv[5 + i] = argv[i];
654         child_argv[5 + i] = NULL;
655
656         execv(child_argv[0], child_argv);
657         error(1, errno, "exec failed");
658 }
659
660 static void
661 help(const char *name)
662 {
663         fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
664         fprintf(stderr, "  -u, --user      Start session as specified username\n");
665         fprintf(stderr, "  -t, --tty       Start session on alternative tty\n");
666         fprintf(stderr, "  -v, --verbose   Be verbose\n");
667         fprintf(stderr, "  -h, --help      Display this help message\n");
668 }
669
670 int
671 main(int argc, char *argv[])
672 {
673         struct weston_launch wl;
674         int i, c;
675         char *tty = NULL;
676         struct option opts[] = {
677                 { "user",    required_argument, NULL, 'u' },
678                 { "tty",     required_argument, NULL, 't' },
679                 { "verbose", no_argument,       NULL, 'v' },
680                 { "help",    no_argument,       NULL, 'h' },
681                 { 0,         0,                 NULL,  0  }
682         };      
683
684         memset(&wl, 0, sizeof wl);
685
686         while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
687                 switch (c) {
688                 case 'u':
689                         wl.new_user = optarg;
690                         if (getuid() != 0)
691                                 error(1, 0, "Permission denied. -u allowed for root only");
692                         break;
693                 case 't':
694                         tty = optarg;
695                         break;
696                 case 'v':
697                         wl.verbose = 1;
698                         break;
699                 case 'h':
700                         help("weston-launch");
701                         exit(EXIT_FAILURE);
702                 }
703         }
704
705         if ((argc - optind) > (MAX_ARGV_SIZE - 6))
706                 error(1, E2BIG, "Too many arguments to pass to weston");
707
708         if (wl.new_user)
709                 wl.pw = getpwnam(wl.new_user);
710         else
711                 wl.pw = getpwuid(getuid());
712         if (wl.pw == NULL)
713                 error(1, errno, "failed to get username");
714
715         if (!weston_launch_allowed(&wl))
716                 error(1, 0, "Permission denied. You should either:\n"
717 #ifdef HAVE_SYSTEMD_LOGIN
718                       " - run from an active and local (systemd) session.\n"
719 #else
720                       " - enable systemd session support for weston-launch.\n"
721 #endif
722                       " - or add yourself to the 'weston-launch' group.");
723
724         if (setup_tty(&wl, tty) < 0)
725                 exit(EXIT_FAILURE);
726
727         if (wl.new_user && setup_pam(&wl) < 0)
728                 exit(EXIT_FAILURE);
729
730         if (setup_launcher_socket(&wl) < 0)
731                 exit(EXIT_FAILURE);
732
733         if (setup_signals(&wl) < 0)
734                 exit(EXIT_FAILURE);
735
736         wl.child = fork();
737         if (wl.child == -1) {
738                 error(1, errno, "fork failed");
739                 exit(EXIT_FAILURE);
740         }
741
742         if (wl.child == 0)
743                 launch_compositor(&wl, argc - optind, argv + optind);
744
745         close(wl.sock[1]);
746         if (wl.tty != STDIN_FILENO)
747                 close(wl.tty);
748
749         while (1) {
750                 struct pollfd fds[2];
751                 int n;
752
753                 fds[0].fd = wl.sock[0];
754                 fds[0].events = POLLIN;
755                 fds[1].fd = wl.signalfd;
756                 fds[1].events = POLLIN;
757
758                 n = poll(fds, 2, -1);
759                 if (n < 0)
760                         error(0, errno, "poll failed");
761                 if (fds[0].revents & POLLIN)
762                         handle_socket_msg(&wl);
763                 if (fds[1].revents)
764                         handle_signal(&wl);
765         }
766
767         return 0;
768 }