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