chiark / gitweb /
shared: fix a misspelling of "journalctl"
[elogind.git] / src / login / logind-core.c
1 /***
2   This file is part of systemd.
3
4   Copyright 2011 Lennart Poettering
5
6   systemd is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   systemd is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <fcntl.h>
21 #include <pwd.h>
22 #include <sys/ioctl.h>
23 #include <sys/types.h>
24 #include <linux/vt.h>
25
26 #include "alloc-util.h"
27 #include "bus-error.h"
28 #include "bus-util.h"
29 #include "cgroup-util.h"
30 #include "fd-util.h"
31 #include "logind.h"
32 #include "strv.h"
33 #include "terminal-util.h"
34 #include "udev-util.h"
35 #include "user-util.h"
36
37 int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
38         Device *d;
39
40         assert(m);
41         assert(sysfs);
42
43         d = hashmap_get(m->devices, sysfs);
44         if (d)
45                 /* we support adding master-flags, but not removing them */
46                 d->master = d->master || master;
47         else {
48                 d = device_new(m, sysfs, master);
49                 if (!d)
50                         return -ENOMEM;
51         }
52
53         if (_device)
54                 *_device = d;
55
56         return 0;
57 }
58
59 int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
60         Seat *s;
61
62         assert(m);
63         assert(id);
64
65         s = hashmap_get(m->seats, id);
66         if (!s) {
67                 s = seat_new(m, id);
68                 if (!s)
69                         return -ENOMEM;
70         }
71
72         if (_seat)
73                 *_seat = s;
74
75         return 0;
76 }
77
78 int manager_add_session(Manager *m, const char *id, Session **_session) {
79         Session *s;
80
81         assert(m);
82         assert(id);
83
84         s = hashmap_get(m->sessions, id);
85         if (!s) {
86                 s = session_new(m, id);
87                 if (!s)
88                         return -ENOMEM;
89         }
90
91         if (_session)
92                 *_session = s;
93
94         return 0;
95 }
96
97 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
98         User *u;
99         int r;
100
101         assert(m);
102         assert(name);
103
104         u = hashmap_get(m->users, UID_TO_PTR(uid));
105         if (!u) {
106                 r = user_new(&u, m, uid, gid, name);
107                 if (r < 0)
108                         return r;
109         }
110
111         if (_user)
112                 *_user = u;
113
114         return 0;
115 }
116
117 int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
118         uid_t uid = 1000;
119         gid_t gid = 1000;
120         int r;
121
122         assert(m);
123         assert(name);
124
125         r = get_user_creds(&name, &uid, &gid, NULL, NULL);
126         if (r < 0)
127                 return r;
128
129         return manager_add_user(m, uid, gid, name, _user);
130 }
131
132 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
133         struct passwd *p;
134
135         assert(m);
136
137         errno = 0;
138         p = getpwuid(uid);
139         if (!p)
140                 return errno > 0 ? -errno : -ENOENT;
141
142         return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
143 }
144
145 int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
146         Inhibitor *i;
147
148         assert(m);
149         assert(id);
150
151         i = hashmap_get(m->inhibitors, id);
152         if (i) {
153                 if (_inhibitor)
154                         *_inhibitor = i;
155
156                 return 0;
157         }
158
159         i = inhibitor_new(m, id);
160         if (!i)
161                 return -ENOMEM;
162
163         if (_inhibitor)
164                 *_inhibitor = i;
165
166         return 0;
167 }
168
169 int manager_add_button(Manager *m, const char *name, Button **_button) {
170         Button *b;
171
172         assert(m);
173         assert(name);
174
175         b = hashmap_get(m->buttons, name);
176         if (!b) {
177                 b = button_new(m, name);
178                 if (!b)
179                         return -ENOMEM;
180         }
181
182         if (_button)
183                 *_button = b;
184
185         return 0;
186 }
187
188 int manager_process_seat_device(Manager *m, struct udev_device *d) {
189         Device *device;
190         int r;
191
192         assert(m);
193
194         if (streq_ptr(udev_device_get_action(d), "remove")) {
195
196                 device = hashmap_get(m->devices, udev_device_get_syspath(d));
197                 if (!device)
198                         return 0;
199
200                 seat_add_to_gc_queue(device->seat);
201                 device_free(device);
202
203         } else {
204                 const char *sn;
205                 Seat *seat = NULL;
206                 bool master;
207
208                 sn = udev_device_get_property_value(d, "ID_SEAT");
209                 if (isempty(sn))
210                         sn = "seat0";
211
212                 if (!seat_name_is_valid(sn)) {
213                         log_warning("Device with invalid seat name %s found, ignoring.", sn);
214                         return 0;
215                 }
216
217                 seat = hashmap_get(m->seats, sn);
218                 master = udev_device_has_tag(d, "master-of-seat");
219
220                 /* Ignore non-master devices for unknown seats */
221                 if (!master && !seat)
222                         return 0;
223
224                 r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
225                 if (r < 0)
226                         return r;
227
228                 if (!seat) {
229                         r = manager_add_seat(m, sn, &seat);
230                         if (r < 0) {
231                                 if (!device->seat)
232                                         device_free(device);
233
234                                 return r;
235                         }
236                 }
237
238                 device_attach(device, seat);
239                 seat_start(seat);
240         }
241
242         return 0;
243 }
244
245 int manager_process_button_device(Manager *m, struct udev_device *d) {
246         Button *b;
247
248         int r;
249
250         assert(m);
251
252         if (streq_ptr(udev_device_get_action(d), "remove")) {
253
254                 b = hashmap_get(m->buttons, udev_device_get_sysname(d));
255                 if (!b)
256                         return 0;
257
258                 button_free(b);
259
260         } else {
261                 const char *sn;
262
263                 r = manager_add_button(m, udev_device_get_sysname(d), &b);
264                 if (r < 0)
265                         return r;
266
267                 sn = udev_device_get_property_value(d, "ID_SEAT");
268                 if (isempty(sn))
269                         sn = "seat0";
270
271                 button_set_seat(b, sn);
272                 button_open(b);
273         }
274
275         return 0;
276 }
277
278 int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
279 #if 0 /// elogind does not support systemd units, but its own session system
280         _cleanup_free_ char *unit = NULL;
281 #else
282         _cleanup_free_ char *session_name = NULL;
283 #endif // 0
284         Session *s;
285         int r;
286
287         assert(m);
288
289         if (pid < 1)
290                 return -EINVAL;
291
292 #if 0 /// elogind does not support systemd units, but its own session system
293         r = cg_pid_get_unit(pid, &unit);
294         if (r < 0)
295                 return 0;
296
297         s = hashmap_get(m->session_units, unit);
298 #else
299         log_debug_elogind("Searching session for PID %u", pid);
300         r = cg_pid_get_session(pid, &session_name);
301         if (r < 0)
302                 return 0;
303
304         s = hashmap_get(m->sessions, session_name);
305         log_debug_elogind("Session Name \"%s\" -> Session \"%s\"",
306                           session_name, s && s->id ? s->id : "NULL");
307 #endif // 0
308         if (!s)
309                 return 0;
310
311         if (session)
312                 *session = s;
313         return 1;
314 }
315
316 int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
317 #if 0 /// elogind does not support systemd units, but its own session system
318         _cleanup_free_ char *unit = NULL;
319         User *u;
320 #else
321         Session *s;
322 #endif // 0
323         int r;
324
325         assert(m);
326         assert(user);
327
328         if (pid < 1)
329                 return -EINVAL;
330
331 #if 0 /// elogind does not support systemd units, but its own session system
332         r = cg_pid_get_slice(pid, &unit);
333         if (r < 0)
334                 return 0;
335
336         u = hashmap_get(m->user_units, unit);
337         if (!u)
338                 return 0;
339
340         *user = u;
341 #else
342         r = manager_get_session_by_pid (m, pid, &s);
343         if (r <= 0)
344                 return r;
345
346         *user = s->user;
347 #endif // 0
348
349         return 1;
350 }
351
352 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
353         Session *s;
354         bool idle_hint;
355         dual_timestamp ts = DUAL_TIMESTAMP_NULL;
356         Iterator i;
357
358         assert(m);
359
360         idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
361
362         HASHMAP_FOREACH(s, m->sessions, i) {
363                 dual_timestamp k;
364                 int ih;
365
366                 ih = session_get_idle_hint(s, &k);
367                 if (ih < 0)
368                         return ih;
369
370                 if (!ih) {
371                         if (!idle_hint) {
372                                 if (k.monotonic < ts.monotonic)
373                                         ts = k;
374                         } else {
375                                 idle_hint = false;
376                                 ts = k;
377                         }
378                 } else if (idle_hint) {
379
380                         if (k.monotonic > ts.monotonic)
381                                 ts = k;
382                 }
383         }
384
385         if (t)
386                 *t = ts;
387
388         return idle_hint;
389 }
390
391 bool manager_shall_kill(Manager *m, const char *user) {
392         assert(m);
393         assert(user);
394
395         if (!m->kill_user_processes)
396                 return false;
397
398         if (strv_contains(m->kill_exclude_users, user))
399                 return false;
400
401         if (strv_isempty(m->kill_only_users))
402                 return true;
403
404         return strv_contains(m->kill_only_users, user);
405 }
406
407 #if 0 /// UNNEEDED by elogind
408 static int vt_is_busy(unsigned int vtnr) {
409         struct vt_stat vt_stat;
410         int r = 0;
411         _cleanup_close_ int fd;
412
413         assert(vtnr >= 1);
414
415         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
416          * we'd open the latter we'd open the foreground tty which
417          * hence would be unconditionally busy. By opening /dev/tty1
418          * we avoid this. Since tty1 is special and needs to be an
419          * explicitly loaded getty or DM this is safe. */
420
421         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
422         if (fd < 0)
423                 return -errno;
424
425         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
426                 r = -errno;
427         else
428                 r = !!(vt_stat.v_state & (1 << vtnr));
429
430         return r;
431 }
432
433 int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
434         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
435         char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
436         int r;
437
438         assert(m);
439         assert(vtnr >= 1);
440
441         if (vtnr > m->n_autovts &&
442             vtnr != m->reserve_vt)
443                 return 0;
444
445         if (vtnr != m->reserve_vt) {
446                 /* If this is the reserved TTY, we'll start the getty
447                  * on it in any case, but otherwise only if it is not
448                  * busy. */
449
450                 r = vt_is_busy(vtnr);
451                 if (r < 0)
452                         return r;
453                 else if (r > 0)
454                         return -EBUSY;
455         }
456
457         snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
458         r = sd_bus_call_method(
459                         m->bus,
460                         "org.freedesktop.systemd1",
461                         "/org/freedesktop/systemd1",
462                         "org.freedesktop.systemd1.Manager",
463                         "StartUnit",
464                         &error,
465                         NULL,
466                         "ss", name, "fail");
467         if (r < 0)
468                 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
469
470         return r;
471 }
472 #endif // 0
473
474 static bool manager_is_docked(Manager *m) {
475         Iterator i;
476         Button *b;
477
478         HASHMAP_FOREACH(b, m->buttons, i)
479                 if (b->docked)
480                         return true;
481
482         return false;
483 }
484
485 static int manager_count_external_displays(Manager *m) {
486         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
487         struct udev_list_entry *item = NULL, *first = NULL;
488         int r;
489         int n = 0;
490
491         e = udev_enumerate_new(m->udev);
492         if (!e)
493                 return -ENOMEM;
494
495         r = udev_enumerate_add_match_subsystem(e, "drm");
496         if (r < 0)
497                 return r;
498
499         r = udev_enumerate_scan_devices(e);
500         if (r < 0)
501                 return r;
502
503         first = udev_enumerate_get_list_entry(e);
504         udev_list_entry_foreach(item, first) {
505                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
506                 struct udev_device *p;
507                 const char *status, *enabled, *dash, *nn, *i;
508                 bool external = false;
509
510                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
511                 if (!d)
512                         return -ENOMEM;
513
514                 p = udev_device_get_parent(d);
515                 if (!p)
516                         continue;
517
518                 /* If the parent shares the same subsystem as the
519                  * device we are looking at then it is a connector,
520                  * which is what we are interested in. */
521                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
522                         continue;
523
524                 nn = udev_device_get_sysname(d);
525                 if (!nn)
526                         continue;
527
528                 /* Ignore internal displays: the type is encoded in
529                  * the sysfs name, as the second dash seperated item
530                  * (the first is the card name, the last the connector
531                  * number). We implement a whitelist of external
532                  * displays here, rather than a whitelist, to ensure
533                  * we don't block suspends too eagerly. */
534                 dash = strchr(nn, '-');
535                 if (!dash)
536                         continue;
537
538                 dash++;
539                 FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
540                                "Composite-", "SVIDEO-", "Component-",
541                                "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
542
543                         if (startswith(dash, i)) {
544                                 external = true;
545                                 break;
546                         }
547                 }
548                 if (!external)
549                         continue;
550
551                 /* Ignore ports that are not enabled */
552                 enabled = udev_device_get_sysattr_value(d, "enabled");
553                 if (!enabled)
554                         continue;
555                 if (!streq_ptr(enabled, "enabled"))
556                         continue;
557
558                 /* We count any connector which is not explicitly
559                  * "disconnected" as connected. */
560                 status = udev_device_get_sysattr_value(d, "status");
561                 if (!streq_ptr(status, "disconnected"))
562                         n++;
563         }
564
565         return n;
566 }
567
568 bool manager_is_docked_or_external_displays(Manager *m) {
569         int n;
570
571         /* If we are docked don't react to lid closing */
572         if (manager_is_docked(m)) {
573                 log_debug("System is docked.");
574                 return true;
575         }
576
577         /* If we have more than one display connected,
578          * assume that we are docked. */
579         n = manager_count_external_displays(m);
580         if (n < 0)
581                 log_warning_errno(n, "Display counting failed: %m");
582         else if (n >= 1) {
583                 log_debug("External (%i) displays connected.", n);
584                 return true;
585         }
586
587         return false;
588 }