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