]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind.c
manager: remove unavailable/redundant entries from default controllers list
[thirdparty/systemd.git] / src / login / logind.c
CommitLineData
20263082
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
20263082
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
20263082 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
20263082
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <errno.h>
23#include <pwd.h>
24#include <libudev.h>
25#include <fcntl.h>
26#include <string.h>
27#include <unistd.h>
28#include <sys/epoll.h>
5eda94dd
LP
29#include <sys/ioctl.h>
30#include <linux/vt.h>
20263082 31
81527be1
LP
32#include <systemd/sd-daemon.h>
33
20263082
LP
34#include "logind.h"
35#include "dbus-common.h"
36#include "dbus-loop.h"
193197e8
LP
37#include "strv.h"
38#include "conf-parser.h"
20263082 39
20263082
LP
40Manager *manager_new(void) {
41 Manager *m;
42
43 m = new0(Manager, 1);
44 if (!m)
45 return NULL;
46
47 m->console_active_fd = -1;
48 m->bus_fd = -1;
30ed21ce
LP
49 m->udev_seat_fd = -1;
50 m->udev_vcsa_fd = -1;
20263082
LP
51 m->epoll_fd = -1;
52 m->n_autovts = 6;
53
54 m->devices = hashmap_new(string_hash_func, string_compare_func);
55 m->seats = hashmap_new(string_hash_func, string_compare_func);
56 m->sessions = hashmap_new(string_hash_func, string_compare_func);
57 m->users = hashmap_new(trivial_hash_func, trivial_compare_func);
1713813d 58 m->cgroups = hashmap_new(string_hash_func, string_compare_func);
932e3ee7 59 m->fifo_fds = hashmap_new(trivial_hash_func, trivial_compare_func);
20263082 60
25d93491
LP
61 if (!m->devices || !m->seats || !m->sessions || !m->users || !m->cgroups || !m->fifo_fds) {
62 manager_free(m);
63 return NULL;
64 }
65
66 m->reset_controllers = strv_new("cpu", NULL);
67 m->kill_exclude_users = strv_new("root", NULL);
68 if (!m->reset_controllers || !m->kill_exclude_users) {
20263082
LP
69 manager_free(m);
70 return NULL;
71 }
72
73 m->udev = udev_new();
74 if (!m->udev) {
75 manager_free(m);
76 return NULL;
77 }
78
79 if (cg_get_user_path(&m->cgroup_path) < 0) {
80 manager_free(m);
81 return NULL;
82 }
83
84 return m;
85}
86
87void manager_free(Manager *m) {
88 Session *session;
89 User *u;
90 Device *d;
91 Seat *s;
92
93 assert(m);
94
95 while ((session = hashmap_first(m->sessions)))
96 session_free(session);
97
98 while ((u = hashmap_first(m->users)))
99 user_free(u);
100
101 while ((d = hashmap_first(m->devices)))
102 device_free(d);
103
104 while ((s = hashmap_first(m->seats)))
105 seat_free(s);
106
107 hashmap_free(m->sessions);
108 hashmap_free(m->users);
109 hashmap_free(m->devices);
110 hashmap_free(m->seats);
1713813d 111 hashmap_free(m->cgroups);
932e3ee7 112 hashmap_free(m->fifo_fds);
20263082
LP
113
114 if (m->console_active_fd >= 0)
115 close_nointr_nofail(m->console_active_fd);
116
30ed21ce
LP
117 if (m->udev_seat_monitor)
118 udev_monitor_unref(m->udev_seat_monitor);
119
120 if (m->udev_vcsa_monitor)
121 udev_monitor_unref(m->udev_vcsa_monitor);
20263082
LP
122
123 if (m->udev)
124 udev_unref(m->udev);
125
126 if (m->bus) {
127 dbus_connection_flush(m->bus);
128 dbus_connection_close(m->bus);
129 dbus_connection_unref(m->bus);
130 }
131
132 if (m->bus_fd >= 0)
133 close_nointr_nofail(m->bus_fd);
134
135 if (m->epoll_fd >= 0)
136 close_nointr_nofail(m->epoll_fd);
137
193197e8
LP
138 strv_free(m->controllers);
139 strv_free(m->reset_controllers);
140 strv_free(m->kill_only_users);
141 strv_free(m->kill_exclude_users);
142
20263082
LP
143 free(m->cgroup_path);
144 free(m);
145}
146
147int manager_add_device(Manager *m, const char *sysfs, Device **_device) {
148 Device *d;
149
150 assert(m);
151 assert(sysfs);
152
153 d = hashmap_get(m->devices, sysfs);
154 if (d) {
155 if (_device)
156 *_device = d;
157
158 return 0;
159 }
160
161 d = device_new(m, sysfs);
162 if (!d)
163 return -ENOMEM;
164
165 if (_device)
166 *_device = d;
167
168 return 0;
169}
170
171int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
172 Seat *s;
173
174 assert(m);
175 assert(id);
176
177 s = hashmap_get(m->seats, id);
178 if (s) {
179 if (_seat)
180 *_seat = s;
181
182 return 0;
183 }
184
185 s = seat_new(m, id);
186 if (!s)
187 return -ENOMEM;
188
189 if (_seat)
190 *_seat = s;
191
192 return 0;
193}
194
195int manager_add_session(Manager *m, User *u, const char *id, Session **_session) {
196 Session *s;
197
198 assert(m);
199 assert(id);
200
201 s = hashmap_get(m->sessions, id);
202 if (s) {
203 if (_session)
204 *_session = s;
205
206 return 0;
207 }
208
209 s = session_new(m, u, id);
210 if (!s)
211 return -ENOMEM;
212
213 if (_session)
214 *_session = s;
215
216 return 0;
217}
218
219int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
220 User *u;
20263082
LP
221
222 assert(m);
223 assert(name);
224
225 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
226 if (u) {
227 if (_user)
228 *_user = u;
229
230 return 0;
231 }
232
233 u = user_new(m, uid, gid, name);
234 if (!u)
235 return -ENOMEM;
236
14c3baca
LP
237 if (_user)
238 *_user = u;
20263082 239
14c3baca 240 return 0;
20263082
LP
241}
242
243int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
4b67834e
LP
244 uid_t uid;
245 gid_t gid;
246 int r;
20263082
LP
247
248 assert(m);
249 assert(name);
250
4b67834e
LP
251 r = get_user_creds(&name, &uid, &gid, NULL);
252 if (r < 0)
253 return r;
20263082 254
4b67834e 255 return manager_add_user(m, uid, gid, name, _user);
20263082
LP
256}
257
258int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
259 struct passwd *p;
260
261 assert(m);
262
263 errno = 0;
264 p = getpwuid(uid);
265 if (!p)
266 return errno ? -errno : -ENOENT;
267
268 return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
269}
270
30ed21ce 271int manager_process_seat_device(Manager *m, struct udev_device *d) {
20263082
LP
272 Device *device;
273 int r;
274
275 assert(m);
276
14c3baca 277 if (streq_ptr(udev_device_get_action(d), "remove")) {
20263082 278
3745b500 279 device = hashmap_get(m->devices, udev_device_get_syspath(d));
14c3baca
LP
280 if (!device)
281 return 0;
20263082 282
14c3baca
LP
283 seat_add_to_gc_queue(device->seat);
284 device_free(device);
285
286 } else {
287 const char *sn;
288 Seat *seat;
289
3f49d45a 290 sn = udev_device_get_property_value(d, "ID_SEAT");
53907215 291 if (isempty(sn))
14c3baca
LP
292 sn = "seat0";
293
3f49d45a
LP
294 if (!seat_name_is_valid(sn)) {
295 log_warning("Device with invalid seat name %s found, ignoring.", sn);
296 return 0;
297 }
14c3baca 298
3745b500 299 r = manager_add_device(m, udev_device_get_syspath(d), &device);
14c3baca
LP
300 if (r < 0)
301 return r;
302
303 r = manager_add_seat(m, sn, &seat);
304 if (r < 0) {
305 if (!device->seat)
306 device_free(device);
307
308 return r;
309 }
310
311 device_attach(device, seat);
3f49d45a 312 seat_start(seat);
14c3baca 313 }
20263082 314
20263082
LP
315 return 0;
316}
317
318int manager_enumerate_devices(Manager *m) {
319 struct udev_list_entry *item = NULL, *first = NULL;
320 struct udev_enumerate *e;
14c3baca 321 int r;
20263082
LP
322
323 assert(m);
324
325 /* Loads devices from udev and creates seats for them as
326 * necessary */
327
328 e = udev_enumerate_new(m->udev);
14c3baca
LP
329 if (!e) {
330 r = -ENOMEM;
5eda94dd 331 goto finish;
14c3baca 332 }
20263082 333
14c3baca
LP
334 r = udev_enumerate_add_match_subsystem(e, "graphics");
335 if (r < 0)
20263082
LP
336 goto finish;
337
14c3baca
LP
338 r = udev_enumerate_add_match_tag(e, "seat");
339 if (r < 0)
20263082
LP
340 goto finish;
341
14c3baca
LP
342 r = udev_enumerate_scan_devices(e);
343 if (r < 0)
20263082
LP
344 goto finish;
345
346 first = udev_enumerate_get_list_entry(e);
347 udev_list_entry_foreach(item, first) {
348 struct udev_device *d;
349 int k;
350
351 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
14c3baca
LP
352 if (!d) {
353 r = -ENOMEM;
20263082 354 goto finish;
14c3baca 355 }
20263082 356
30ed21ce 357 k = manager_process_seat_device(m, d);
20263082
LP
358 udev_device_unref(d);
359
360 if (k < 0)
361 r = k;
362 }
363
364finish:
365 if (e)
366 udev_enumerate_unref(e);
367
368 return r;
369}
370
371int manager_enumerate_seats(Manager *m) {
372 DIR *d;
373 struct dirent *de;
374 int r = 0;
375
376 assert(m);
377
378 /* This loads data about seats stored on disk, but does not
379 * actually create any seats. Removes data of seats that no
380 * longer exist. */
381
382 d = opendir("/run/systemd/seats");
383 if (!d) {
384 if (errno == ENOENT)
385 return 0;
386
387 log_error("Failed to open /run/systemd/seats: %m");
388 return -errno;
389 }
390
391 while ((de = readdir(d))) {
392 Seat *s;
393 int k;
394
395 if (!dirent_is_file(de))
396 continue;
397
398 s = hashmap_get(m->seats, de->d_name);
399 if (!s) {
400 unlinkat(dirfd(d), de->d_name, 0);
401 continue;
402 }
403
404 k = seat_load(s);
405 if (k < 0)
406 r = k;
407 }
408
409 closedir(d);
410
411 return r;
412}
413
414static int manager_enumerate_users_from_cgroup(Manager *m) {
415 int r = 0;
416 char *name;
417 DIR *d;
3e085b6c 418 int k;
20263082
LP
419
420 r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d);
421 if (r < 0) {
422 if (r == -ENOENT)
423 return 0;
424
425 log_error("Failed to open %s: %s", m->cgroup_path, strerror(-r));
426 return r;
427 }
428
3e085b6c 429 while ((k = cg_read_subgroup(d, &name)) > 0) {
20263082 430 User *user;
14c3baca
LP
431
432 k = manager_add_user_by_name(m, name, &user);
433 if (k < 0) {
434 free(name);
435 r = k;
436 continue;
437 }
438
439 user_add_to_gc_queue(user);
440
441 if (!user->cgroup_path)
442 if (asprintf(&user->cgroup_path, "%s/%s", m->cgroup_path, name) < 0) {
443 r = -ENOMEM;
444 free(name);
445 break;
446 }
20263082 447
20263082 448 free(name);
14c3baca
LP
449 }
450
3e085b6c
LP
451 if (r >= 0 && k < 0)
452 r = k;
453
14c3baca
LP
454 closedir(d);
455
456 return r;
457}
20263082 458
14c3baca
LP
459static int manager_enumerate_linger_users(Manager *m) {
460 DIR *d;
461 struct dirent *de;
462 int r = 0;
463
464 d = opendir("/var/lib/systemd/linger");
465 if (!d) {
466 if (errno == ENOENT)
467 return 0;
468
469 log_error("Failed to open /var/lib/systemd/linger/: %m");
470 return -errno;
471 }
472
473 while ((de = readdir(d))) {
474 int k;
475
476 if (!dirent_is_file(de))
20263082
LP
477 continue;
478
14c3baca
LP
479 k = manager_add_user_by_name(m, de->d_name, NULL);
480 if (k < 0) {
481 log_notice("Couldn't add lingering user %s: %s", de->d_name, strerror(-k));
482 r = k;
20263082
LP
483 }
484 }
485
14c3baca 486 closedir(d);
20263082
LP
487
488 return r;
489}
490
491int manager_enumerate_users(Manager *m) {
492 DIR *d;
493 struct dirent *de;
14c3baca 494 int r, k;
20263082
LP
495
496 assert(m);
497
14c3baca 498 /* First, enumerate user cgroups */
20263082
LP
499 r = manager_enumerate_users_from_cgroup(m);
500
14c3baca
LP
501 /* Second, add lingering users on top */
502 k = manager_enumerate_linger_users(m);
503 if (k < 0)
504 r = k;
505
506 /* Third, read in user data stored on disk */
20263082
LP
507 d = opendir("/run/systemd/users");
508 if (!d) {
509 if (errno == ENOENT)
510 return 0;
511
512 log_error("Failed to open /run/systemd/users: %m");
513 return -errno;
514 }
515
516 while ((de = readdir(d))) {
ddd88763 517 uid_t uid;
20263082 518 User *u;
20263082
LP
519
520 if (!dirent_is_file(de))
521 continue;
522
ddd88763 523 k = parse_uid(de->d_name, &uid);
20263082
LP
524 if (k < 0) {
525 log_error("Failed to parse file name %s: %s", de->d_name, strerror(-k));
526 continue;
527 }
528
ddd88763 529 u = hashmap_get(m->users, ULONG_TO_PTR(uid));
20263082
LP
530 if (!u) {
531 unlinkat(dirfd(d), de->d_name, 0);
532 continue;
533 }
534
535 k = user_load(u);
536 if (k < 0)
537 r = k;
538 }
539
540 closedir(d);
541
542 return r;
543}
544
545static int manager_enumerate_sessions_from_cgroup(Manager *m) {
546 User *u;
547 Iterator i;
548 int r = 0;
549
550 HASHMAP_FOREACH(u, m->users, i) {
551 DIR *d;
552 char *name;
553 int k;
554
14c3baca
LP
555 if (!u->cgroup_path)
556 continue;
557
20263082
LP
558 k = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &d);
559 if (k < 0) {
560 if (k == -ENOENT)
561 continue;
562
563 log_error("Failed to open %s: %s", u->cgroup_path, strerror(-k));
564 r = k;
565 continue;
566 }
567
568 while ((k = cg_read_subgroup(d, &name)) > 0) {
569 Session *session;
570
11896841
LP
571 if (streq(name, "shared"))
572 continue;
573
20263082 574 k = manager_add_session(m, u, name, &session);
14c3baca
LP
575 if (k < 0) {
576 free(name);
20263082 577 break;
14c3baca 578 }
20263082 579
14c3baca 580 session_add_to_gc_queue(session);
20263082 581
14c3baca
LP
582 if (!session->cgroup_path)
583 if (asprintf(&session->cgroup_path, "%s/%s", u->cgroup_path, name) < 0) {
584 k = -ENOMEM;
585 free(name);
586 break;
587 }
588
589 free(name);
20263082
LP
590 }
591
592 closedir(d);
593
594 if (k < 0)
595 r = k;
596 }
597
598 return r;
599}
600
601int manager_enumerate_sessions(Manager *m) {
602 DIR *d;
603 struct dirent *de;
604 int r = 0;
605
606 assert(m);
607
14c3baca 608 /* First enumerate session cgroups */
20263082
LP
609 r = manager_enumerate_sessions_from_cgroup(m);
610
14c3baca 611 /* Second, read in session data stored on disk */
20263082
LP
612 d = opendir("/run/systemd/sessions");
613 if (!d) {
614 if (errno == ENOENT)
615 return 0;
616
617 log_error("Failed to open /run/systemd/sessions: %m");
618 return -errno;
619 }
620
621 while ((de = readdir(d))) {
622 struct Session *s;
623 int k;
624
625 if (!dirent_is_file(de))
626 continue;
627
628 s = hashmap_get(m->sessions, de->d_name);
629 if (!s) {
630 unlinkat(dirfd(d), de->d_name, 0);
631 continue;
632 }
633
634 k = session_load(s);
635 if (k < 0)
636 r = k;
637 }
638
639 closedir(d);
640
641 return r;
642}
643
30ed21ce 644int manager_dispatch_seat_udev(Manager *m) {
20263082
LP
645 struct udev_device *d;
646 int r;
647
648 assert(m);
649
30ed21ce 650 d = udev_monitor_receive_device(m->udev_seat_monitor);
20263082
LP
651 if (!d)
652 return -ENOMEM;
653
30ed21ce
LP
654 r = manager_process_seat_device(m, d);
655 udev_device_unref(d);
656
657 return r;
658}
659
30ed21ce
LP
660int manager_dispatch_vcsa_udev(Manager *m) {
661 struct udev_device *d;
662 int r = 0;
663 const char *name;
664
665 assert(m);
666
667 d = udev_monitor_receive_device(m->udev_vcsa_monitor);
668 if (!d)
669 return -ENOMEM;
670
671 name = udev_device_get_sysname(d);
672
673 /* Whenever a VCSA device is removed try to reallocate our
674 * VTs, to make sure our auto VTs never go away. */
675
676 if (name && startswith(name, "vcsa") && streq_ptr(udev_device_get_action(d), "remove"))
677 r = seat_preallocate_vts(m->vtconsole);
678
20263082
LP
679 udev_device_unref(d);
680
681 return r;
682}
683
684int manager_dispatch_console(Manager *m) {
20263082
LP
685 assert(m);
686
20263082 687 if (m->vtconsole)
14c3baca 688 seat_read_active_vt(m->vtconsole);
20263082
LP
689
690 return 0;
691}
692
5eda94dd
LP
693static int vt_is_busy(int vtnr) {
694 struct vt_stat vt_stat;
695 int r = 0, fd;
696
697 assert(vtnr >= 1);
698
d0a522eb
LP
699 /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
700 * we'd open the latter we'd open the foreground tty which
701 * hence would be unconditionally busy. By opening /dev/tty1
702 * we avoid this. Since tty1 is special and needs to be an
703 * explicitly loaded getty or DM this is safe. */
704
705 fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
5eda94dd
LP
706 if (fd < 0)
707 return -errno;
708
709 if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
710 r = -errno;
711 else
712 r = !!(vt_stat.v_state & (1 << vtnr));
713
714 close_nointr_nofail(fd);
715
716 return r;
717}
718
20263082 719int manager_spawn_autovt(Manager *m, int vtnr) {
5eda94dd 720 int r;
d0a522eb
LP
721 DBusMessage *message = NULL, *reply = NULL;
722 char *name = NULL;
723 const char *mode = "fail";
724 DBusError error;
5eda94dd 725
20263082 726 assert(m);
30ed21ce 727 assert(vtnr >= 1);
20263082 728
d0a522eb
LP
729 dbus_error_init(&error);
730
30ed21ce 731 if ((unsigned) vtnr > m->n_autovts)
975fd867
LP
732 return 0;
733
5eda94dd 734 r = vt_is_busy(vtnr);
975fd867 735 if (r < 0)
5eda94dd 736 return r;
975fd867
LP
737 else if (r > 0)
738 return -EBUSY;
5eda94dd 739
d0a522eb
LP
740 message = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit");
741 if (!message) {
742 log_error("Could not allocate message.");
743 r = -ENOMEM;
744 goto finish;
745 }
5eda94dd 746
cd9e5d0a 747 if (asprintf(&name, "autovt@tty%i.service", vtnr) < 0) {
d0a522eb
LP
748 log_error("Could not allocate service name.");
749 r = -ENOMEM;
750 goto finish;
751 }
752
753 if (!dbus_message_append_args(message,
754 DBUS_TYPE_STRING, &name,
755 DBUS_TYPE_STRING, &mode,
756 DBUS_TYPE_INVALID)) {
757 log_error("Could not attach target and flag information to message.");
758 r = -ENOMEM;
759 goto finish;
760 }
761
762 reply = dbus_connection_send_with_reply_and_block(m->bus, message, -1, &error);
763 if (!reply) {
764 log_error("Failed to start unit: %s", bus_error_message(&error));
765 goto finish;
766 }
767
768 r = 0;
769
770finish:
771 free(name);
772
773 if (message)
774 dbus_message_unref(message);
775
776 if (reply)
777 dbus_message_unref(reply);
778
779 dbus_error_free(&error);
780
781 return r;
20263082
LP
782}
783
9b221b63 784int manager_get_session_by_cgroup(Manager *m, const char *cgroup, Session **session) {
acb14d31 785 Session *s;
1713813d
LP
786 char *p;
787
788 assert(m);
789 assert(cgroup);
9b221b63 790 assert(session);
1713813d 791
acb14d31
LP
792 s = hashmap_get(m->cgroups, cgroup);
793 if (s) {
794 *session = s;
795 return 1;
796 }
797
1713813d
LP
798 p = strdup(cgroup);
799 if (!p) {
800 log_error("Out of memory.");
9b221b63 801 return -ENOMEM;
1713813d
LP
802 }
803
804 for (;;) {
805 char *e;
20263082 806
acb14d31
LP
807 e = strrchr(p, '/');
808 if (!e || e == p) {
9b221b63
LP
809 free(p);
810 *session = NULL;
811 return 0;
812 }
1713813d 813
acb14d31
LP
814 *e = 0;
815
1713813d 816 s = hashmap_get(m->cgroups, p);
9b221b63
LP
817 if (s) {
818 free(p);
819 *session = s;
820 return 1;
821 }
1713813d 822 }
9b221b63
LP
823}
824
825int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
826 char *p;
827 int r;
828
829 assert(m);
830 assert(pid >= 1);
831 assert(session);
1713813d 832
9b221b63
LP
833 r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &p);
834 if (r < 0)
835 return r;
836
837 r = manager_get_session_by_cgroup(m, p, session);
1713813d 838 free(p);
9b221b63
LP
839
840 return r;
841}
842
843void manager_cgroup_notify_empty(Manager *m, const char *cgroup) {
844 Session *s;
845 int r;
846
847 r = manager_get_session_by_cgroup(m, cgroup, &s);
848 if (r <= 0)
849 return;
850
851 session_add_to_gc_queue(s);
20263082
LP
852}
853
31b79c2b
LP
854static void manager_pipe_notify_eof(Manager *m, int fd) {
855 Session *s;
856
857 assert_se(m);
858 assert_se(fd >= 0);
859
932e3ee7
LP
860 assert_se(s = hashmap_get(m->fifo_fds, INT_TO_PTR(fd + 1)));
861 assert(s->fifo_fd == fd);
862 session_remove_fifo(s);
31b79c2b 863
21308c65 864 session_stop(s);
31b79c2b
LP
865}
866
20263082 867static int manager_connect_bus(Manager *m) {
20263082
LP
868 DBusError error;
869 int r;
870 struct epoll_event ev;
871
872 assert(m);
873 assert(!m->bus);
874 assert(m->bus_fd < 0);
875
876 dbus_error_init(&error);
877
878 m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
879 if (!m->bus) {
a2e52832 880 log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
20263082
LP
881 r = -ECONNREFUSED;
882 goto fail;
883 }
884
3f49d45a
LP
885 if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/login1", &bus_manager_vtable, m) ||
886 !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/seat", &bus_seat_vtable, m) ||
887 !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/session", &bus_session_vtable, m) ||
888 !dbus_connection_register_fallback(m->bus, "/org/freedesktop/login1/user", &bus_user_vtable, m) ||
1713813d 889 !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
20263082
LP
890 log_error("Not enough memory");
891 r = -ENOMEM;
892 goto fail;
893 }
894
895 dbus_bus_add_match(m->bus,
896 "type='signal',"
897 "interface='org.freedesktop.systemd1.Agent',"
898 "member='Released',"
899 "path='/org/freedesktop/systemd1/agent'",
900 &error);
901
902 if (dbus_error_is_set(&error)) {
a2e52832 903 log_error("Failed to register match: %s", bus_error_message(&error));
20263082
LP
904 r = -EIO;
905 goto fail;
906 }
907
bafd4449
LP
908 r = dbus_bus_request_name(m->bus, "org.freedesktop.login1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
909 if (dbus_error_is_set(&error)) {
910 log_error("Failed to register name on bus: %s", bus_error_message(&error));
911 r = -EIO;
912 goto fail;
913 }
914
915 if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
916 log_error("Failed to acquire name.");
20263082
LP
917 r = -EEXIST;
918 goto fail;
919 }
920
921 m->bus_fd = bus_loop_open(m->bus);
922 if (m->bus_fd < 0) {
923 r = m->bus_fd;
924 goto fail;
925 }
926
927 zero(ev);
928 ev.events = EPOLLIN;
929 ev.data.u32 = FD_BUS;
930
931 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
932 goto fail;
933
934 return 0;
935
936fail:
937 dbus_error_free(&error);
938
939 return r;
940}
941
942static int manager_connect_console(Manager *m) {
943 struct epoll_event ev;
944
945 assert(m);
946 assert(m->console_active_fd < 0);
947
74afee9c
LP
948 /* On certain architectures (S390 and Xen, and containers),
949 /dev/tty0 does not exist, so don't fail if we can't open
950 it. */
951 if (access("/dev/tty0", F_OK) < 0) {
952 m->console_active_fd = -1;
953 return 0;
954 }
955
20263082
LP
956 m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
957 if (m->console_active_fd < 0) {
958 log_error("Failed to open /sys/class/tty/tty0/active: %m");
959 return -errno;
960 }
961
962 zero(ev);
14c3baca 963 ev.events = 0;
20263082
LP
964 ev.data.u32 = FD_CONSOLE;
965
966 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
967 return -errno;
968
969 return 0;
970}
971
972static int manager_connect_udev(Manager *m) {
973 struct epoll_event ev;
14c3baca 974 int r;
20263082
LP
975
976 assert(m);
30ed21ce
LP
977 assert(!m->udev_seat_monitor);
978 assert(!m->udev_vcsa_monitor);
20263082 979
30ed21ce
LP
980 m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
981 if (!m->udev_seat_monitor)
20263082
LP
982 return -ENOMEM;
983
30ed21ce 984 r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat");
14c3baca
LP
985 if (r < 0)
986 return r;
20263082 987
30ed21ce 988 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL);
14c3baca
LP
989 if (r < 0)
990 return r;
20263082 991
30ed21ce 992 r = udev_monitor_enable_receiving(m->udev_seat_monitor);
14c3baca
LP
993 if (r < 0)
994 return r;
20263082 995
30ed21ce 996 m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor);
20263082
LP
997
998 zero(ev);
999 ev.events = EPOLLIN;
30ed21ce 1000 ev.data.u32 = FD_SEAT_UDEV;
20263082 1001
976c088a
LP
1002 /* Don't bother watching VCSA devices, if nobody cares */
1003 if (m->n_autovts <= 0 || m->console_active_fd < 0)
30ed21ce
LP
1004 return 0;
1005
1006 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
1007 return -errno;
1008
1009 m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
1010 if (!m->udev_vcsa_monitor)
1011 return -ENOMEM;
1012
1013 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
1014 if (r < 0)
1015 return r;
1016
1017 r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
1018 if (r < 0)
1019 return r;
1020
1021 m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
1022
1023 zero(ev);
1024 ev.events = EPOLLIN;
1025 ev.data.u32 = FD_VCSA_UDEV;
1026
1027 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
20263082
LP
1028 return -errno;
1029
1030 return 0;
1031}
1032
4a4b033f 1033void manager_gc(Manager *m, bool drop_not_started) {
14c3baca
LP
1034 Seat *seat;
1035 Session *session;
1036 User *user;
1037
1038 assert(m);
1039
1040 while ((seat = m->seat_gc_queue)) {
1041 LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
1042 seat->in_gc_queue = false;
1043
4a4b033f 1044 if (seat_check_gc(seat, drop_not_started) == 0) {
14c3baca
LP
1045 seat_stop(seat);
1046 seat_free(seat);
1047 }
1048 }
1049
1050 while ((session = m->session_gc_queue)) {
1051 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
1052 session->in_gc_queue = false;
1053
4a4b033f 1054 if (session_check_gc(session, drop_not_started) == 0) {
14c3baca
LP
1055 session_stop(session);
1056 session_free(session);
1057 }
1058 }
1059
1060 while ((user = m->user_gc_queue)) {
1061 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
1062 user->in_gc_queue = false;
1063
4a4b033f 1064 if (user_check_gc(user, drop_not_started) == 0) {
14c3baca
LP
1065 user_stop(user);
1066 user_free(user);
1067 }
1068 }
1069}
1070
a185c5aa
LP
1071int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
1072 Session *s;
1073 bool idle_hint = true;
1074 dual_timestamp ts = { 0, 0 };
1075 Iterator i;
1076
1077 assert(m);
1078
1079 HASHMAP_FOREACH(s, m->sessions, i) {
1080 dual_timestamp k;
1081 int ih;
1082
1083 ih = session_get_idle_hint(s, &k);
1084 if (ih < 0)
1085 return ih;
1086
1087 if (!ih) {
1088 if (!idle_hint) {
1089 if (k.monotonic < ts.monotonic)
1090 ts = k;
1091 } else {
1092 idle_hint = false;
1093 ts = k;
1094 }
1095 } else if (idle_hint) {
1096
1097 if (k.monotonic > ts.monotonic)
1098 ts = k;
1099 }
1100 }
1101
1102 if (t)
1103 *t = ts;
1104
1105 return idle_hint;
1106}
1107
20263082
LP
1108int manager_startup(Manager *m) {
1109 int r;
14c3baca
LP
1110 Seat *seat;
1111 Session *session;
1112 User *user;
1113 Iterator i;
20263082
LP
1114
1115 assert(m);
1116 assert(m->epoll_fd <= 0);
1117
1118 m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
1119 if (m->epoll_fd < 0)
1120 return -errno;
1121
976c088a
LP
1122 /* Connect to console */
1123 r = manager_connect_console(m);
20263082
LP
1124 if (r < 0)
1125 return r;
1126
976c088a
LP
1127 /* Connect to udev */
1128 r = manager_connect_udev(m);
20263082
LP
1129 if (r < 0)
1130 return r;
1131
1132 /* Connect to the bus */
1133 r = manager_connect_bus(m);
1134 if (r < 0)
1135 return r;
1136
14c3baca
LP
1137 /* Instantiate magic seat 0 */
1138 r = manager_add_seat(m, "seat0", &m->vtconsole);
1139 if (r < 0)
1140 return r;
1141
20263082
LP
1142 /* Deserialize state */
1143 manager_enumerate_devices(m);
1144 manager_enumerate_seats(m);
1145 manager_enumerate_users(m);
1146 manager_enumerate_sessions(m);
1147
4a4b033f
LP
1148 /* Remove stale objects before we start them */
1149 manager_gc(m, false);
1150
14c3baca
LP
1151 /* And start everything */
1152 HASHMAP_FOREACH(seat, m->seats, i)
1153 seat_start(seat);
1154
1155 HASHMAP_FOREACH(user, m->users, i)
1156 user_start(user);
1157
1158 HASHMAP_FOREACH(session, m->sessions, i)
1159 session_start(session);
20263082
LP
1160
1161 return 0;
1162}
1163
1164int manager_run(Manager *m) {
1165 assert(m);
1166
1167 for (;;) {
1168 struct epoll_event event;
1169 int n;
1170
4a4b033f 1171 manager_gc(m, true);
14c3baca 1172
20263082
LP
1173 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
1174 continue;
1175
4a4b033f 1176 manager_gc(m, true);
1713813d 1177
20263082
LP
1178 n = epoll_wait(m->epoll_fd, &event, 1, -1);
1179 if (n < 0) {
3f49d45a
LP
1180 if (errno == EINTR || errno == EAGAIN)
1181 continue;
1182
20263082
LP
1183 log_error("epoll() failed: %m");
1184 return -errno;
1185 }
1186
1187 switch (event.data.u32) {
1188
30ed21ce
LP
1189 case FD_SEAT_UDEV:
1190 manager_dispatch_seat_udev(m);
1191 break;
1192
1193 case FD_VCSA_UDEV:
1194 manager_dispatch_vcsa_udev(m);
20263082
LP
1195 break;
1196
1197 case FD_CONSOLE:
1198 manager_dispatch_console(m);
1199 break;
1200
1201 case FD_BUS:
1202 bus_loop_dispatch(m->bus_fd);
1203 break;
31b79c2b
LP
1204
1205 default:
932e3ee7
LP
1206 if (event.data.u32 >= FD_FIFO_BASE)
1207 manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
20263082
LP
1208 }
1209 }
1210
1211 return 0;
1212}
1213
193197e8 1214static int manager_parse_config_file(Manager *m) {
193197e8
LP
1215 FILE *f;
1216 const char *fn;
1217 int r;
1218
1219 assert(m);
1220
18b754d3 1221 fn = "/etc/systemd/logind.conf";
193197e8
LP
1222 f = fopen(fn, "re");
1223 if (!f) {
1224 if (errno == ENOENT)
1225 return 0;
1226
1227 log_warning("Failed to open configuration file %s: %m", fn);
1228 return -errno;
1229 }
1230
f975e971 1231 r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m);
193197e8
LP
1232 if (r < 0)
1233 log_warning("Failed to parse configuration file: %s", strerror(-r));
1234
1235 fclose(f);
1236
1237 return r;
1238}
1239
20263082
LP
1240int main(int argc, char *argv[]) {
1241 Manager *m = NULL;
5eda94dd 1242 int r;
20263082
LP
1243
1244 log_set_target(LOG_TARGET_AUTO);
3eff4208 1245 log_set_facility(LOG_AUTH);
20263082
LP
1246 log_parse_environment();
1247 log_open();
1248
4c12626c
LP
1249 umask(0022);
1250
20263082
LP
1251 if (argc != 1) {
1252 log_error("This program takes no arguments.");
1253 r = -EINVAL;
1254 goto finish;
1255 }
1256
20263082
LP
1257 m = manager_new();
1258 if (!m) {
1259 log_error("Out of memory");
1260 r = -ENOMEM;
1261 goto finish;
1262 }
1263
193197e8
LP
1264 manager_parse_config_file(m);
1265
20263082
LP
1266 r = manager_startup(m);
1267 if (r < 0) {
1268 log_error("Failed to fully start up daemon: %s", strerror(-r));
1269 goto finish;
1270 }
1271
e6960940
LP
1272 log_debug("systemd-logind running as pid %lu", (unsigned long) getpid());
1273
1274 sd_notify(false,
1275 "READY=1\n"
1276 "STATUS=Processing requests...");
1277
20263082
LP
1278 r = manager_run(m);
1279
e6960940
LP
1280 log_debug("systemd-logind stopped as pid %lu", (unsigned long) getpid());
1281
20263082 1282finish:
e6960940
LP
1283 sd_notify(false,
1284 "STATUS=Shutting down...");
1285
20263082
LP
1286 if (m)
1287 manager_free(m);
1288
1289 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1290}