1 /*
2 * Copyright © 2013 David Herrmann
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #include "config.h"
27
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <signal.h>
31 #include <stdarg.h>
32 #include <stdbool.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <systemd/sd-login.h>
39 #include <unistd.h>
40
41 #include <libweston/libweston.h>
42 #include "backend.h"
43 #include "dbus.h"
44 #include "launcher-impl.h"
45
46 #define DRM_MAJOR 226
47
48 /* major()/minor() */
49 #ifdef MAJOR_IN_MKDEV
50 #include <sys/mkdev.h>
51 #endif
52 #ifdef MAJOR_IN_SYSMACROS
53 #include <sys/sysmacros.h>
54 #endif
55
56 struct launcher_logind {
57 struct weston_launcher base;
58 struct weston_compositor *compositor;
59 bool sync_drm;
60 char *seat;
61 char *sid;
62 unsigned int vtnr;
63 int vt;
64 int kb_mode;
65
66 DBusConnection *dbus;
67 struct wl_event_source *dbus_ctx;
68 char *spath;
69 DBusPendingCall *pending_active;
70 };
71
72 static int
launcher_logind_take_device(struct launcher_logind * wl,uint32_t major,uint32_t minor,bool * paused_out)73 launcher_logind_take_device(struct launcher_logind *wl, uint32_t major,
74 uint32_t minor, bool *paused_out)
75 {
76 DBusMessage *m, *reply;
77 bool b;
78 int r, fd;
79 dbus_bool_t paused;
80
81 m = dbus_message_new_method_call("org.freedesktop.login1",
82 wl->spath,
83 "org.freedesktop.login1.Session",
84 "TakeDevice");
85 if (!m)
86 return -ENOMEM;
87
88 b = dbus_message_append_args(m,
89 DBUS_TYPE_UINT32, &major,
90 DBUS_TYPE_UINT32, &minor,
91 DBUS_TYPE_INVALID);
92 if (!b) {
93 r = -ENOMEM;
94 goto err_unref;
95 }
96
97 reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
98 -1, NULL);
99 if (!reply) {
100 r = -ENODEV;
101 goto err_unref;
102 }
103
104 b = dbus_message_get_args(reply, NULL,
105 DBUS_TYPE_UNIX_FD, &fd,
106 DBUS_TYPE_BOOLEAN, &paused,
107 DBUS_TYPE_INVALID);
108 if (!b) {
109 r = -ENODEV;
110 goto err_reply;
111 }
112
113 r = fd;
114 if (paused_out)
115 *paused_out = paused;
116
117 err_reply:
118 dbus_message_unref(reply);
119 err_unref:
120 dbus_message_unref(m);
121 return r;
122 }
123
124 static void
launcher_logind_release_device(struct launcher_logind * wl,uint32_t major,uint32_t minor)125 launcher_logind_release_device(struct launcher_logind *wl, uint32_t major,
126 uint32_t minor)
127 {
128 DBusMessage *m;
129 bool b;
130
131 m = dbus_message_new_method_call("org.freedesktop.login1",
132 wl->spath,
133 "org.freedesktop.login1.Session",
134 "ReleaseDevice");
135 if (m) {
136 b = dbus_message_append_args(m,
137 DBUS_TYPE_UINT32, &major,
138 DBUS_TYPE_UINT32, &minor,
139 DBUS_TYPE_INVALID);
140 if (b)
141 dbus_connection_send(wl->dbus, m, NULL);
142 dbus_message_unref(m);
143 }
144 }
145
146 static void
launcher_logind_pause_device_complete(struct launcher_logind * wl,uint32_t major,uint32_t minor)147 launcher_logind_pause_device_complete(struct launcher_logind *wl, uint32_t major,
148 uint32_t minor)
149 {
150 DBusMessage *m;
151 bool b;
152
153 m = dbus_message_new_method_call("org.freedesktop.login1",
154 wl->spath,
155 "org.freedesktop.login1.Session",
156 "PauseDeviceComplete");
157 if (m) {
158 b = dbus_message_append_args(m,
159 DBUS_TYPE_UINT32, &major,
160 DBUS_TYPE_UINT32, &minor,
161 DBUS_TYPE_INVALID);
162 if (b)
163 dbus_connection_send(wl->dbus, m, NULL);
164 dbus_message_unref(m);
165 }
166 }
167
168 static int
launcher_logind_open(struct weston_launcher * launcher,const char * path,int flags)169 launcher_logind_open(struct weston_launcher *launcher, const char *path, int flags)
170 {
171 struct launcher_logind *wl = wl_container_of(launcher, wl, base);
172 struct stat st;
173 int fl, r, fd;
174
175 r = stat(path, &st);
176 if (r < 0)
177 return -1;
178 if (!S_ISCHR(st.st_mode)) {
179 errno = ENODEV;
180 return -1;
181 }
182
183 fd = launcher_logind_take_device(wl, major(st.st_rdev),
184 minor(st.st_rdev), NULL);
185 if (fd < 0)
186 return fd;
187
188 /* Compared to weston_launcher_open() we cannot specify the open-mode
189 * directly. Instead, logind passes us an fd with sane default modes.
190 * For DRM and evdev this means O_RDWR | O_CLOEXEC. If we want
191 * something else, we need to change it afterwards. We currently
192 * only support setting O_NONBLOCK. Changing access-modes is not
193 * possible so accept whatever logind passes us. */
194
195 fl = fcntl(fd, F_GETFL);
196 if (fl < 0) {
197 r = -errno;
198 goto err_close;
199 }
200
201 if (flags & O_NONBLOCK)
202 fl |= O_NONBLOCK;
203
204 r = fcntl(fd, F_SETFL, fl);
205 if (r < 0) {
206 r = -errno;
207 goto err_close;
208 }
209 return fd;
210
211 err_close:
212 close(fd);
213 launcher_logind_release_device(wl, major(st.st_rdev),
214 minor(st.st_rdev));
215 errno = -r;
216 return -1;
217 }
218
219 static void
launcher_logind_close(struct weston_launcher * launcher,int fd)220 launcher_logind_close(struct weston_launcher *launcher, int fd)
221 {
222 struct launcher_logind *wl = wl_container_of(launcher, wl, base);
223 struct stat st;
224 int r;
225
226 r = fstat(fd, &st);
227 close(fd);
228 if (r < 0) {
229 weston_log("logind: cannot fstat fd: %s\n", strerror(errno));
230 return;
231 }
232
233 if (!S_ISCHR(st.st_mode)) {
234 weston_log("logind: invalid device passed\n");
235 return;
236 }
237
238 launcher_logind_release_device(wl, major(st.st_rdev),
239 minor(st.st_rdev));
240 }
241
242 static int
launcher_logind_activate_vt(struct weston_launcher * launcher,int vt)243 launcher_logind_activate_vt(struct weston_launcher *launcher, int vt)
244 {
245 struct launcher_logind *wl = wl_container_of(launcher, wl, base);
246 DBusMessage *m;
247 bool b;
248 int r;
249
250 m = dbus_message_new_method_call("org.freedesktop.login1",
251 "/org/freedesktop/login1/seat/self",
252 "org.freedesktop.login1.Seat",
253 "SwitchTo");
254 if (!m)
255 return -ENOMEM;
256
257 b = dbus_message_append_args(m,
258 DBUS_TYPE_UINT32, &vt,
259 DBUS_TYPE_INVALID);
260 if (!b) {
261 r = -ENOMEM;
262 goto err_unref;
263 }
264
265 dbus_connection_send(wl->dbus, m, NULL);
266 r = 0;
267
268 err_unref:
269 dbus_message_unref(m);
270 return r;
271 }
272
273 static void
launcher_logind_set_active(struct launcher_logind * wl,bool active)274 launcher_logind_set_active(struct launcher_logind *wl, bool active)
275 {
276 if (wl->compositor->session_active == active)
277 return;
278
279 wl->compositor->session_active = active;
280
281 wl_signal_emit(&wl->compositor->session_signal,
282 wl->compositor);
283 }
284
285 static void
parse_active(struct launcher_logind * wl,DBusMessage * m,DBusMessageIter * iter)286 parse_active(struct launcher_logind *wl, DBusMessage *m, DBusMessageIter *iter)
287 {
288 DBusMessageIter sub;
289 dbus_bool_t b;
290
291 if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
292 return;
293
294 dbus_message_iter_recurse(iter, &sub);
295
296 if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
297 return;
298
299 dbus_message_iter_get_basic(&sub, &b);
300
301 /* If the backend requested DRM master-device synchronization, we only
302 * wake-up the compositor once the master-device is up and running. For
303 * other backends, we immediately forward the Active-change event. */
304 if (!wl->sync_drm || !b)
305 launcher_logind_set_active(wl, b);
306 }
307
308 static void
get_active_cb(DBusPendingCall * pending,void * data)309 get_active_cb(DBusPendingCall *pending, void *data)
310 {
311 struct launcher_logind *wl = data;
312 DBusMessageIter iter;
313 DBusMessage *m;
314 int type;
315
316 dbus_pending_call_unref(wl->pending_active);
317 wl->pending_active = NULL;
318
319 m = dbus_pending_call_steal_reply(pending);
320 if (!m)
321 return;
322
323 type = dbus_message_get_type(m);
324 if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
325 dbus_message_iter_init(m, &iter))
326 parse_active(wl, m, &iter);
327
328 dbus_message_unref(m);
329 }
330
331 static void
launcher_logind_get_active(struct launcher_logind * wl)332 launcher_logind_get_active(struct launcher_logind *wl)
333 {
334 DBusPendingCall *pending;
335 DBusMessage *m;
336 bool b;
337 const char *iface, *name;
338
339 m = dbus_message_new_method_call("org.freedesktop.login1",
340 wl->spath,
341 "org.freedesktop.DBus.Properties",
342 "Get");
343 if (!m)
344 return;
345
346 iface = "org.freedesktop.login1.Session";
347 name = "Active";
348 b = dbus_message_append_args(m,
349 DBUS_TYPE_STRING, &iface,
350 DBUS_TYPE_STRING, &name,
351 DBUS_TYPE_INVALID);
352 if (!b)
353 goto err_unref;
354
355 b = dbus_connection_send_with_reply(wl->dbus, m, &pending, -1);
356 if (!b)
357 goto err_unref;
358
359 b = dbus_pending_call_set_notify(pending, get_active_cb, wl, NULL);
360 if (!b) {
361 dbus_pending_call_cancel(pending);
362 dbus_pending_call_unref(pending);
363 goto err_unref;
364 }
365
366 if (wl->pending_active) {
367 dbus_pending_call_cancel(wl->pending_active);
368 dbus_pending_call_unref(wl->pending_active);
369 }
370 wl->pending_active = pending;
371 return;
372
373 err_unref:
374 dbus_message_unref(m);
375 }
376
377 static void
disconnected_dbus(struct launcher_logind * wl)378 disconnected_dbus(struct launcher_logind *wl)
379 {
380 weston_log("logind: dbus connection lost, exiting..\n");
381 exit(-1);
382 }
383
384 static void
session_removed(struct launcher_logind * wl,DBusMessage * m)385 session_removed(struct launcher_logind *wl, DBusMessage *m)
386 {
387 const char *name, *obj;
388 bool r;
389
390 r = dbus_message_get_args(m, NULL,
391 DBUS_TYPE_STRING, &name,
392 DBUS_TYPE_OBJECT_PATH, &obj,
393 DBUS_TYPE_INVALID);
394 if (!r) {
395 weston_log("logind: cannot parse SessionRemoved dbus signal\n");
396 return;
397 }
398
399 if (!strcmp(name, wl->sid)) {
400 weston_log("logind: our session got closed, exiting..\n");
401 exit(-1);
402 }
403 }
404
405 static void
property_changed(struct launcher_logind * wl,DBusMessage * m)406 property_changed(struct launcher_logind *wl, DBusMessage *m)
407 {
408 DBusMessageIter iter, sub, entry;
409 const char *interface, *name;
410
411 if (!dbus_message_iter_init(m, &iter) ||
412 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
413 goto error;
414
415 dbus_message_iter_get_basic(&iter, &interface);
416
417 if (!dbus_message_iter_next(&iter) ||
418 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
419 goto error;
420
421 dbus_message_iter_recurse(&iter, &sub);
422
423 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
424 dbus_message_iter_recurse(&sub, &entry);
425
426 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
427 goto error;
428
429 dbus_message_iter_get_basic(&entry, &name);
430 if (!dbus_message_iter_next(&entry))
431 goto error;
432
433 if (!strcmp(name, "Active")) {
434 parse_active(wl, m, &entry);
435 return;
436 }
437
438 dbus_message_iter_next(&sub);
439 }
440
441 if (!dbus_message_iter_next(&iter) ||
442 dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
443 goto error;
444
445 dbus_message_iter_recurse(&iter, &sub);
446
447 while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
448 dbus_message_iter_get_basic(&sub, &name);
449
450 if (!strcmp(name, "Active")) {
451 launcher_logind_get_active(wl);
452 return;
453 }
454
455 dbus_message_iter_next(&sub);
456 }
457
458 return;
459
460 error:
461 weston_log("logind: cannot parse PropertiesChanged dbus signal\n");
462 }
463
464 static void
device_paused(struct launcher_logind * wl,DBusMessage * m)465 device_paused(struct launcher_logind *wl, DBusMessage *m)
466 {
467 bool r;
468 const char *type;
469 uint32_t major, minor;
470
471 r = dbus_message_get_args(m, NULL,
472 DBUS_TYPE_UINT32, &major,
473 DBUS_TYPE_UINT32, &minor,
474 DBUS_TYPE_STRING, &type,
475 DBUS_TYPE_INVALID);
476 if (!r) {
477 weston_log("logind: cannot parse PauseDevice dbus signal\n");
478 return;
479 }
480
481 /* "pause" means synchronous pausing. Acknowledge it unconditionally
482 * as we support asynchronous device shutdowns, anyway.
483 * "force" means asynchronous pausing.
484 * "gone" means the device is gone. We handle it the same as "force" as
485 * a following udev event will be caught, too.
486 *
487 * If it's our main DRM device, tell the compositor to go asleep. */
488
489 if (!strcmp(type, "pause"))
490 launcher_logind_pause_device_complete(wl, major, minor);
491
492 if (wl->sync_drm && wl->compositor->backend->device_changed)
493 wl->compositor->backend->device_changed(wl->compositor,
494 makedev(major,minor),
495 false);
496 }
497
498 static void
device_resumed(struct launcher_logind * wl,DBusMessage * m)499 device_resumed(struct launcher_logind *wl, DBusMessage *m)
500 {
501 bool r;
502 uint32_t major, minor;
503
504 r = dbus_message_get_args(m, NULL,
505 DBUS_TYPE_UINT32, &major,
506 DBUS_TYPE_UINT32, &minor,
507 DBUS_TYPE_INVALID);
508 if (!r) {
509 weston_log("logind: cannot parse ResumeDevice dbus signal\n");
510 return;
511 }
512
513 /* DeviceResumed messages provide us a new file-descriptor for
514 * resumed devices. For DRM devices it's the same as before, for evdev
515 * devices it's a new open-file. As we reopen evdev devices, anyway,
516 * there is no need for us to handle this event for evdev. For DRM, we
517 * notify the compositor to wake up. */
518
519 if (wl->sync_drm && wl->compositor->backend->device_changed)
520 wl->compositor->backend->device_changed(wl->compositor,
521 makedev(major,minor),
522 true);
523 }
524
525 static DBusHandlerResult
filter_dbus(DBusConnection * c,DBusMessage * m,void * data)526 filter_dbus(DBusConnection *c, DBusMessage *m, void *data)
527 {
528 struct launcher_logind *wl = data;
529
530 if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
531 disconnected_dbus(wl);
532 } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Manager",
533 "SessionRemoved")) {
534 session_removed(wl, m);
535 } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties",
536 "PropertiesChanged")) {
537 property_changed(wl, m);
538 } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
539 "PauseDevice")) {
540 device_paused(wl, m);
541 } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
542 "ResumeDevice")) {
543 device_resumed(wl, m);
544 }
545
546 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
547 }
548
549 static int
launcher_logind_setup_dbus(struct launcher_logind * wl)550 launcher_logind_setup_dbus(struct launcher_logind *wl)
551 {
552 bool b;
553 int r;
554
555 r = asprintf(&wl->spath, "/org/freedesktop/login1/session/%s",
556 wl->sid);
557 if (r < 0)
558 return -ENOMEM;
559
560 b = dbus_connection_add_filter(wl->dbus, filter_dbus, wl, NULL);
561 if (!b) {
562 weston_log("logind: cannot add dbus filter\n");
563 r = -ENOMEM;
564 goto err_spath;
565 }
566
567 r = weston_dbus_add_match_signal(wl->dbus,
568 "org.freedesktop.login1",
569 "org.freedesktop.login1.Manager",
570 "SessionRemoved",
571 "/org/freedesktop/login1");
572 if (r < 0) {
573 weston_log("logind: cannot add dbus match\n");
574 goto err_spath;
575 }
576
577 r = weston_dbus_add_match_signal(wl->dbus,
578 "org.freedesktop.login1",
579 "org.freedesktop.login1.Session",
580 "PauseDevice",
581 wl->spath);
582 if (r < 0) {
583 weston_log("logind: cannot add dbus match\n");
584 goto err_spath;
585 }
586
587 r = weston_dbus_add_match_signal(wl->dbus,
588 "org.freedesktop.login1",
589 "org.freedesktop.login1.Session",
590 "ResumeDevice",
591 wl->spath);
592 if (r < 0) {
593 weston_log("logind: cannot add dbus match\n");
594 goto err_spath;
595 }
596
597 r = weston_dbus_add_match_signal(wl->dbus,
598 "org.freedesktop.login1",
599 "org.freedesktop.DBus.Properties",
600 "PropertiesChanged",
601 wl->spath);
602 if (r < 0) {
603 weston_log("logind: cannot add dbus match\n");
604 goto err_spath;
605 }
606
607 return 0;
608
609 err_spath:
610 /* don't remove any dbus-match as the connection is closed, anyway */
611 free(wl->spath);
612 return r;
613 }
614
615 static void
launcher_logind_destroy_dbus(struct launcher_logind * wl)616 launcher_logind_destroy_dbus(struct launcher_logind *wl)
617 {
618 /* don't remove any dbus-match as the connection is closed, anyway */
619 free(wl->spath);
620 }
621
622 static int
launcher_logind_take_control(struct launcher_logind * wl)623 launcher_logind_take_control(struct launcher_logind *wl)
624 {
625 DBusError err;
626 DBusMessage *m, *reply;
627 dbus_bool_t force;
628 bool b;
629 int r;
630
631 dbus_error_init(&err);
632
633 m = dbus_message_new_method_call("org.freedesktop.login1",
634 wl->spath,
635 "org.freedesktop.login1.Session",
636 "TakeControl");
637 if (!m)
638 return -ENOMEM;
639
640 force = false;
641 b = dbus_message_append_args(m,
642 DBUS_TYPE_BOOLEAN, &force,
643 DBUS_TYPE_INVALID);
644 if (!b) {
645 r = -ENOMEM;
646 goto err_unref;
647 }
648
649 reply = dbus_connection_send_with_reply_and_block(wl->dbus,
650 m, -1, &err);
651 if (!reply) {
652 if (dbus_error_has_name(&err, DBUS_ERROR_UNKNOWN_METHOD))
653 weston_log("logind: old systemd version detected\n");
654 else
655 weston_log("logind: cannot take control over session %s\n", wl->sid);
656
657 dbus_error_free(&err);
658 r = -EIO;
659 goto err_unref;
660 }
661
662 dbus_message_unref(reply);
663 dbus_message_unref(m);
664 return 0;
665
666 err_unref:
667 dbus_message_unref(m);
668 return r;
669 }
670
671 static void
launcher_logind_release_control(struct launcher_logind * wl)672 launcher_logind_release_control(struct launcher_logind *wl)
673 {
674 DBusMessage *m;
675
676 m = dbus_message_new_method_call("org.freedesktop.login1",
677 wl->spath,
678 "org.freedesktop.login1.Session",
679 "ReleaseControl");
680 if (m) {
681 dbus_connection_send(wl->dbus, m, NULL);
682 dbus_message_unref(m);
683 }
684 }
685
686 static int
weston_sd_session_get_vt(const char * sid,unsigned int * out)687 weston_sd_session_get_vt(const char *sid, unsigned int *out)
688 {
689 #ifdef HAVE_SYSTEMD_LOGIN_209
690 return sd_session_get_vt(sid, out);
691 #else
692 int r;
693 char *tty;
694
695 r = sd_session_get_tty(sid, &tty);
696 if (r < 0)
697 return r;
698
699 r = sscanf(tty, "tty%u", out);
700 free(tty);
701
702 if (r != 1)
703 return -EINVAL;
704
705 return 0;
706 #endif
707 }
708
709 static int
launcher_logind_activate(struct launcher_logind * wl)710 launcher_logind_activate(struct launcher_logind *wl)
711 {
712 DBusMessage *m;
713
714 m = dbus_message_new_method_call("org.freedesktop.login1",
715 wl->spath,
716 "org.freedesktop.login1.Session",
717 "Activate");
718 if (!m)
719 return -ENOMEM;
720
721 dbus_connection_send(wl->dbus, m, NULL);
722 return 0;
723 }
724
725 static int
launcher_logind_connect(struct weston_launcher ** out,struct weston_compositor * compositor,int tty,const char * seat_id,bool sync_drm)726 launcher_logind_connect(struct weston_launcher **out, struct weston_compositor *compositor,
727 int tty, const char *seat_id, bool sync_drm)
728 {
729 struct launcher_logind *wl;
730 struct wl_event_loop *loop;
731 char *t;
732 int r;
733
734 wl = zalloc(sizeof(*wl));
735 if (wl == NULL) {
736 r = -ENOMEM;
737 goto err_out;
738 }
739
740 wl->base.iface = &launcher_logind_iface;
741 wl->compositor = compositor;
742 wl->sync_drm = sync_drm;
743
744 wl->seat = strdup(seat_id);
745 if (!wl->seat) {
746 r = -ENOMEM;
747 goto err_wl;
748 }
749
750 r = sd_pid_get_session(getpid(), &wl->sid);
751 if (r < 0) {
752 weston_log("logind: not running in a systemd session\n");
753 goto err_seat;
754 }
755
756 t = NULL;
757 r = sd_session_get_seat(wl->sid, &t);
758 if (r < 0) {
759 weston_log("logind: failed to get session seat\n");
760 free(t);
761 goto err_session;
762 } else if (strcmp(seat_id, t)) {
763 weston_log("logind: weston's seat '%s' differs from session-seat '%s'\n",
764 seat_id, t);
765 r = -EINVAL;
766 free(t);
767 goto err_session;
768 }
769
770 r = strcmp(t, "seat0");
771 free(t);
772 if (r == 0) {
773 r = weston_sd_session_get_vt(wl->sid, &wl->vtnr);
774 if (r < 0) {
775 weston_log("logind: session not running on a VT\n");
776 goto err_session;
777 } else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
778 weston_log("logind: requested VT --tty=%d differs from real session VT %u\n",
779 tty, wl->vtnr);
780 r = -EINVAL;
781 goto err_session;
782 }
783 }
784
785 loop = wl_display_get_event_loop(compositor->wl_display);
786 r = weston_dbus_open(loop, DBUS_BUS_SYSTEM, &wl->dbus, &wl->dbus_ctx);
787 if (r < 0) {
788 weston_log("logind: cannot connect to system dbus\n");
789 goto err_session;
790 }
791
792 r = launcher_logind_setup_dbus(wl);
793 if (r < 0)
794 goto err_dbus;
795
796 r = launcher_logind_take_control(wl);
797 if (r < 0)
798 goto err_dbus_cleanup;
799
800 r = launcher_logind_activate(wl);
801 if (r < 0)
802 goto err_dbus_cleanup;
803
804 weston_log("logind: session control granted\n");
805 * (struct launcher_logind **) out = wl;
806 return 0;
807
808 err_dbus_cleanup:
809 launcher_logind_destroy_dbus(wl);
810 err_dbus:
811 weston_dbus_close(wl->dbus, wl->dbus_ctx);
812 err_session:
813 free(wl->sid);
814 err_seat:
815 free(wl->seat);
816 err_wl:
817 free(wl);
818 err_out:
819 weston_log("logind: cannot setup systemd-logind helper (%d), using legacy fallback\n", r);
820 errno = -r;
821 return -1;
822 }
823
824 static void
launcher_logind_destroy(struct weston_launcher * launcher)825 launcher_logind_destroy(struct weston_launcher *launcher)
826 {
827 struct launcher_logind *wl = wl_container_of(launcher, wl, base);
828
829 if (wl->pending_active) {
830 dbus_pending_call_cancel(wl->pending_active);
831 dbus_pending_call_unref(wl->pending_active);
832 }
833
834 launcher_logind_release_control(wl);
835 launcher_logind_destroy_dbus(wl);
836 weston_dbus_close(wl->dbus, wl->dbus_ctx);
837 free(wl->sid);
838 free(wl->seat);
839 free(wl);
840 }
841
842 static int
launcher_logind_get_vt(struct weston_launcher * launcher)843 launcher_logind_get_vt(struct weston_launcher *launcher)
844 {
845 struct launcher_logind *wl = wl_container_of(launcher, wl, base);
846 return wl->vtnr;
847 }
848
849 const struct launcher_interface launcher_logind_iface = {
850 .connect = launcher_logind_connect,
851 .destroy = launcher_logind_destroy,
852 .open = launcher_logind_open,
853 .close = launcher_logind_close,
854 .activate_vt = launcher_logind_activate_vt,
855 .get_vt = launcher_logind_get_vt,
856 };
857