]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-core.c
treewide: auto-convert the simple cases to log_*_errno()
[thirdparty/systemd.git] / src / login / logind-core.c
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
30 #include "strv.h"
31 #include "cgroup-util.h"
32 #include "audit.h"
33 #include "bus-util.h"
34 #include "bus-error.h"
35 #include "udev-util.h"
36 #include "logind.h"
37
38 int 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);
45 if (d)
46 /* we support adding master-flags, but not removing them */
47 d->master = d->master || master;
48 else {
49 d = device_new(m, sysfs, master);
50 if (!d)
51 return -ENOMEM;
52 }
53
54 if (_device)
55 *_device = d;
56
57 return 0;
58 }
59
60 int 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);
67 if (!s) {
68 s = seat_new(m, id);
69 if (!s)
70 return -ENOMEM;
71 }
72
73 if (_seat)
74 *_seat = s;
75
76 return 0;
77 }
78
79 int 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);
86 if (!s) {
87 s = session_new(m, id);
88 if (!s)
89 return -ENOMEM;
90 }
91
92 if (_session)
93 *_session = s;
94
95 return 0;
96 }
97
98 int 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));
105 if (!u) {
106 u = user_new(m, uid, gid, name);
107 if (!u)
108 return -ENOMEM;
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;
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
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 ? -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_watch_busname(Manager *m, const char *name) {
189 char *n;
190 int r;
191
192 assert(m);
193 assert(name);
194
195 if (set_get(m->busnames, (char*) name))
196 return 0;
197
198 n = strdup(name);
199 if (!n)
200 return -ENOMEM;
201
202 r = set_put(m->busnames, n);
203 if (r < 0) {
204 free(n);
205 return r;
206 }
207
208 return 0;
209 }
210
211 void manager_drop_busname(Manager *m, const char *name) {
212 Session *session;
213 Iterator i;
214
215 assert(m);
216 assert(name);
217
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
223 free(set_remove(m->busnames, (char*) name));
224 }
225
226 int 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
255 seat = hashmap_get(m->seats, sn);
256 master = udev_device_has_tag(d, "master-of-seat");
257
258 /* Ignore non-master devices for unknown seats */
259 if (!master && !seat)
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
283 int 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
316 int 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)
329 return 0;
330
331 s = hashmap_get(m->session_units, unit);
332 if (!s)
333 return 0;
334
335 *session = s;
336 return 1;
337 }
338
339 int 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)
352 return 0;
353
354 u = hashmap_get(m->user_units, unit);
355 if (!u)
356 return 0;
357
358 *user = u;
359 return 1;
360 }
361
362 int 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
370 idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
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
401 bool 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
417 static int vt_is_busy(unsigned int vtnr) {
418 struct vt_stat vt_stat;
419 int r = 0;
420 _cleanup_close_ int fd;
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
439 return r;
440 }
441
442 int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
443 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
444 char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
445 int r;
446
447 assert(m);
448 assert(vtnr >= 1);
449
450 if (vtnr > m->n_autovts &&
451 vtnr != m->reserve_vt)
452 return 0;
453
454 if (vtnr != m->reserve_vt) {
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
466 snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
467 r = sd_bus_call_method(
468 m->bus,
469 "org.freedesktop.systemd1",
470 "/org/freedesktop/systemd1",
471 "org.freedesktop.systemd1.Manager",
472 "StartUnit",
473 &error,
474 NULL,
475 "ss", name, "fail");
476 if (r < 0)
477 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
478
479 return r;
480 }
481
482 bool 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 }
492
493 int 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)
523 continue;
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 }
540
541 bool 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)
554 log_warning_errno(-n, "Display counting failed: %m");
555 else if (n > 1) {
556 log_debug("Multiple (%i) displays connected.", n);
557 return true;
558 }
559
560 return false;
561 }