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