]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind.c
relicense to LGPLv2.1 (with exceptions)
[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
948 m->console_active_fd = open("/sys/class/tty/tty0/active", O_RDONLY|O_NOCTTY|O_CLOEXEC);
949 if (m->console_active_fd < 0) {
addedec4
LP
950
951 /* On certain architectures (S390 and Xen), /dev/tty0
952 does not exist, so don't fail if we can't open it.*/
953 if (errno == ENOENT)
954 return 0;
955
20263082
LP
956 log_error("Failed to open /sys/class/tty/tty0/active: %m");
957 return -errno;
958 }
959
960 zero(ev);
14c3baca 961 ev.events = 0;
20263082
LP
962 ev.data.u32 = FD_CONSOLE;
963
964 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->console_active_fd, &ev) < 0)
965 return -errno;
966
967 return 0;
968}
969
970static int manager_connect_udev(Manager *m) {
971 struct epoll_event ev;
14c3baca 972 int r;
20263082
LP
973
974 assert(m);
30ed21ce
LP
975 assert(!m->udev_seat_monitor);
976 assert(!m->udev_vcsa_monitor);
20263082 977
30ed21ce
LP
978 m->udev_seat_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
979 if (!m->udev_seat_monitor)
20263082
LP
980 return -ENOMEM;
981
30ed21ce 982 r = udev_monitor_filter_add_match_tag(m->udev_seat_monitor, "seat");
14c3baca
LP
983 if (r < 0)
984 return r;
20263082 985
30ed21ce 986 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_seat_monitor, "graphics", NULL);
14c3baca
LP
987 if (r < 0)
988 return r;
20263082 989
30ed21ce 990 r = udev_monitor_enable_receiving(m->udev_seat_monitor);
14c3baca
LP
991 if (r < 0)
992 return r;
20263082 993
30ed21ce 994 m->udev_seat_fd = udev_monitor_get_fd(m->udev_seat_monitor);
20263082
LP
995
996 zero(ev);
997 ev.events = EPOLLIN;
30ed21ce 998 ev.data.u32 = FD_SEAT_UDEV;
20263082 999
976c088a
LP
1000 /* Don't bother watching VCSA devices, if nobody cares */
1001 if (m->n_autovts <= 0 || m->console_active_fd < 0)
30ed21ce
LP
1002 return 0;
1003
1004 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_seat_fd, &ev) < 0)
1005 return -errno;
1006
1007 m->udev_vcsa_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
1008 if (!m->udev_vcsa_monitor)
1009 return -ENOMEM;
1010
1011 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_vcsa_monitor, "vc", NULL);
1012 if (r < 0)
1013 return r;
1014
1015 r = udev_monitor_enable_receiving(m->udev_vcsa_monitor);
1016 if (r < 0)
1017 return r;
1018
1019 m->udev_vcsa_fd = udev_monitor_get_fd(m->udev_vcsa_monitor);
1020
1021 zero(ev);
1022 ev.events = EPOLLIN;
1023 ev.data.u32 = FD_VCSA_UDEV;
1024
1025 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_vcsa_fd, &ev) < 0)
20263082
LP
1026 return -errno;
1027
1028 return 0;
1029}
1030
4a4b033f 1031void manager_gc(Manager *m, bool drop_not_started) {
14c3baca
LP
1032 Seat *seat;
1033 Session *session;
1034 User *user;
1035
1036 assert(m);
1037
1038 while ((seat = m->seat_gc_queue)) {
1039 LIST_REMOVE(Seat, gc_queue, m->seat_gc_queue, seat);
1040 seat->in_gc_queue = false;
1041
4a4b033f 1042 if (seat_check_gc(seat, drop_not_started) == 0) {
14c3baca
LP
1043 seat_stop(seat);
1044 seat_free(seat);
1045 }
1046 }
1047
1048 while ((session = m->session_gc_queue)) {
1049 LIST_REMOVE(Session, gc_queue, m->session_gc_queue, session);
1050 session->in_gc_queue = false;
1051
4a4b033f 1052 if (session_check_gc(session, drop_not_started) == 0) {
14c3baca
LP
1053 session_stop(session);
1054 session_free(session);
1055 }
1056 }
1057
1058 while ((user = m->user_gc_queue)) {
1059 LIST_REMOVE(User, gc_queue, m->user_gc_queue, user);
1060 user->in_gc_queue = false;
1061
4a4b033f 1062 if (user_check_gc(user, drop_not_started) == 0) {
14c3baca
LP
1063 user_stop(user);
1064 user_free(user);
1065 }
1066 }
1067}
1068
a185c5aa
LP
1069int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
1070 Session *s;
1071 bool idle_hint = true;
1072 dual_timestamp ts = { 0, 0 };
1073 Iterator i;
1074
1075 assert(m);
1076
1077 HASHMAP_FOREACH(s, m->sessions, i) {
1078 dual_timestamp k;
1079 int ih;
1080
1081 ih = session_get_idle_hint(s, &k);
1082 if (ih < 0)
1083 return ih;
1084
1085 if (!ih) {
1086 if (!idle_hint) {
1087 if (k.monotonic < ts.monotonic)
1088 ts = k;
1089 } else {
1090 idle_hint = false;
1091 ts = k;
1092 }
1093 } else if (idle_hint) {
1094
1095 if (k.monotonic > ts.monotonic)
1096 ts = k;
1097 }
1098 }
1099
1100 if (t)
1101 *t = ts;
1102
1103 return idle_hint;
1104}
1105
20263082
LP
1106int manager_startup(Manager *m) {
1107 int r;
14c3baca
LP
1108 Seat *seat;
1109 Session *session;
1110 User *user;
1111 Iterator i;
20263082
LP
1112
1113 assert(m);
1114 assert(m->epoll_fd <= 0);
1115
1116 m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
1117 if (m->epoll_fd < 0)
1118 return -errno;
1119
976c088a
LP
1120 /* Connect to console */
1121 r = manager_connect_console(m);
20263082
LP
1122 if (r < 0)
1123 return r;
1124
976c088a
LP
1125 /* Connect to udev */
1126 r = manager_connect_udev(m);
20263082
LP
1127 if (r < 0)
1128 return r;
1129
1130 /* Connect to the bus */
1131 r = manager_connect_bus(m);
1132 if (r < 0)
1133 return r;
1134
14c3baca
LP
1135 /* Instantiate magic seat 0 */
1136 r = manager_add_seat(m, "seat0", &m->vtconsole);
1137 if (r < 0)
1138 return r;
1139
20263082
LP
1140 /* Deserialize state */
1141 manager_enumerate_devices(m);
1142 manager_enumerate_seats(m);
1143 manager_enumerate_users(m);
1144 manager_enumerate_sessions(m);
1145
4a4b033f
LP
1146 /* Remove stale objects before we start them */
1147 manager_gc(m, false);
1148
14c3baca
LP
1149 /* And start everything */
1150 HASHMAP_FOREACH(seat, m->seats, i)
1151 seat_start(seat);
1152
1153 HASHMAP_FOREACH(user, m->users, i)
1154 user_start(user);
1155
1156 HASHMAP_FOREACH(session, m->sessions, i)
1157 session_start(session);
20263082
LP
1158
1159 return 0;
1160}
1161
1162int manager_run(Manager *m) {
1163 assert(m);
1164
1165 for (;;) {
1166 struct epoll_event event;
1167 int n;
1168
4a4b033f 1169 manager_gc(m, true);
14c3baca 1170
20263082
LP
1171 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
1172 continue;
1173
4a4b033f 1174 manager_gc(m, true);
1713813d 1175
20263082
LP
1176 n = epoll_wait(m->epoll_fd, &event, 1, -1);
1177 if (n < 0) {
3f49d45a
LP
1178 if (errno == EINTR || errno == EAGAIN)
1179 continue;
1180
20263082
LP
1181 log_error("epoll() failed: %m");
1182 return -errno;
1183 }
1184
1185 switch (event.data.u32) {
1186
30ed21ce
LP
1187 case FD_SEAT_UDEV:
1188 manager_dispatch_seat_udev(m);
1189 break;
1190
1191 case FD_VCSA_UDEV:
1192 manager_dispatch_vcsa_udev(m);
20263082
LP
1193 break;
1194
1195 case FD_CONSOLE:
1196 manager_dispatch_console(m);
1197 break;
1198
1199 case FD_BUS:
1200 bus_loop_dispatch(m->bus_fd);
1201 break;
31b79c2b
LP
1202
1203 default:
932e3ee7
LP
1204 if (event.data.u32 >= FD_FIFO_BASE)
1205 manager_pipe_notify_eof(m, event.data.u32 - FD_FIFO_BASE);
20263082
LP
1206 }
1207 }
1208
1209 return 0;
1210}
1211
193197e8 1212static int manager_parse_config_file(Manager *m) {
193197e8
LP
1213 FILE *f;
1214 const char *fn;
1215 int r;
1216
1217 assert(m);
1218
18b754d3 1219 fn = "/etc/systemd/logind.conf";
193197e8
LP
1220 f = fopen(fn, "re");
1221 if (!f) {
1222 if (errno == ENOENT)
1223 return 0;
1224
1225 log_warning("Failed to open configuration file %s: %m", fn);
1226 return -errno;
1227 }
1228
f975e971 1229 r = config_parse(fn, f, "Login\0", config_item_perf_lookup, (void*) logind_gperf_lookup, false, m);
193197e8
LP
1230 if (r < 0)
1231 log_warning("Failed to parse configuration file: %s", strerror(-r));
1232
1233 fclose(f);
1234
1235 return r;
1236}
1237
20263082
LP
1238int main(int argc, char *argv[]) {
1239 Manager *m = NULL;
5eda94dd 1240 int r;
20263082
LP
1241
1242 log_set_target(LOG_TARGET_AUTO);
3eff4208 1243 log_set_facility(LOG_AUTH);
20263082
LP
1244 log_parse_environment();
1245 log_open();
1246
4c12626c
LP
1247 umask(0022);
1248
20263082
LP
1249 if (argc != 1) {
1250 log_error("This program takes no arguments.");
1251 r = -EINVAL;
1252 goto finish;
1253 }
1254
20263082
LP
1255 m = manager_new();
1256 if (!m) {
1257 log_error("Out of memory");
1258 r = -ENOMEM;
1259 goto finish;
1260 }
1261
193197e8
LP
1262 manager_parse_config_file(m);
1263
20263082
LP
1264 r = manager_startup(m);
1265 if (r < 0) {
1266 log_error("Failed to fully start up daemon: %s", strerror(-r));
1267 goto finish;
1268 }
1269
e6960940
LP
1270 log_debug("systemd-logind running as pid %lu", (unsigned long) getpid());
1271
1272 sd_notify(false,
1273 "READY=1\n"
1274 "STATUS=Processing requests...");
1275
20263082
LP
1276 r = manager_run(m);
1277
e6960940
LP
1278 log_debug("systemd-logind stopped as pid %lu", (unsigned long) getpid());
1279
20263082 1280finish:
e6960940
LP
1281 sd_notify(false,
1282 "STATUS=Shutting down...");
1283
20263082
LP
1284 if (m)
1285 manager_free(m);
1286
1287 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1288}