chiark / gitweb /
logind: apply selinux label to XDG_RUNTIME_DIR
[elogind.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/ioctl.h>
24 #include <fcntl.h>
25 #include <pwd.h>
26 #include <linux/vt.h>
27
28 #include "strv.h"
29 #include "cgroup-util.h"
30 #include "bus-util.h"
31 #include "bus-error.h"
32 #include "udev-util.h"
33 #include "logind.h"
34 #include "terminal-util.h"
35
36 int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
37         Device *d;
38
39         assert(m);
40         assert(sysfs);
41
42         d = hashmap_get(m->devices, sysfs);
43         if (d)
44                 /* we support adding master-flags, but not removing them */
45                 d->master = d->master || master;
46         else {
47                 d = device_new(m, sysfs, master);
48                 if (!d)
49                         return -ENOMEM;
50         }
51
52         if (_device)
53                 *_device = d;
54
55         return 0;
56 }
57
58 int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
59         Seat *s;
60
61         assert(m);
62         assert(id);
63
64         s = hashmap_get(m->seats, id);
65         if (!s) {
66                 s = seat_new(m, id);
67                 if (!s)
68                         return -ENOMEM;
69         }
70
71         if (_seat)
72                 *_seat = s;
73
74         return 0;
75 }
76
77 int manager_add_session(Manager *m, const char *id, Session **_session) {
78         Session *s;
79
80         assert(m);
81         assert(id);
82
83         s = hashmap_get(m->sessions, id);
84         if (!s) {
85                 s = session_new(m, id);
86                 if (!s)
87                         return -ENOMEM;
88         }
89
90         if (_session)
91                 *_session = s;
92
93         return 0;
94 }
95
96 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
97         User *u;
98
99         assert(m);
100         assert(name);
101
102         u = hashmap_get(m->users, UID_TO_PTR(uid));
103         if (!u) {
104                 u = user_new(m, uid, gid, name);
105                 if (!u)
106                         return -ENOMEM;
107         }
108
109         if (_user)
110                 *_user = u;
111
112         return 0;
113 }
114
115 int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
116         uid_t uid;
117         gid_t gid;
118         int r;
119
120         assert(m);
121         assert(name);
122
123         r = get_user_creds(&name, &uid, &gid, NULL, NULL);
124         if (r < 0)
125                 return r;
126
127         return manager_add_user(m, uid, gid, name, _user);
128 }
129
130 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
131         struct passwd *p;
132
133         assert(m);
134
135         errno = 0;
136         p = getpwuid(uid);
137         if (!p)
138                 return errno ? -errno : -ENOENT;
139
140         return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
141 }
142
143 int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
144         Inhibitor *i;
145
146         assert(m);
147         assert(id);
148
149         i = hashmap_get(m->inhibitors, id);
150         if (i) {
151                 if (_inhibitor)
152                         *_inhibitor = i;
153
154                 return 0;
155         }
156
157         i = inhibitor_new(m, id);
158         if (!i)
159                 return -ENOMEM;
160
161         if (_inhibitor)
162                 *_inhibitor = i;
163
164         return 0;
165 }
166
167 int manager_add_button(Manager *m, const char *name, Button **_button) {
168         Button *b;
169
170         assert(m);
171         assert(name);
172
173         b = hashmap_get(m->buttons, name);
174         if (!b) {
175                 b = button_new(m, name);
176                 if (!b)
177                         return -ENOMEM;
178         }
179
180         if (_button)
181                 *_button = b;
182
183         return 0;
184 }
185
186 int manager_watch_busname(Manager *m, const char *name) {
187         char *n;
188         int r;
189
190         assert(m);
191         assert(name);
192
193         if (set_get(m->busnames, (char*) name))
194                 return 0;
195
196         n = strdup(name);
197         if (!n)
198                 return -ENOMEM;
199
200         r = set_put(m->busnames, n);
201         if (r < 0) {
202                 free(n);
203                 return r;
204         }
205
206         return 0;
207 }
208
209 void manager_drop_busname(Manager *m, const char *name) {
210         Session *session;
211         Iterator i;
212
213         assert(m);
214         assert(name);
215
216         /* keep it if the name still owns a controller */
217         HASHMAP_FOREACH(session, m->sessions, i)
218                 if (session_is_controller(session, name))
219                         return;
220
221         free(set_remove(m->busnames, (char*) name));
222 }
223
224 int manager_process_seat_device(Manager *m, struct udev_device *d) {
225         Device *device;
226         int r;
227
228         assert(m);
229
230         if (streq_ptr(udev_device_get_action(d), "remove")) {
231
232                 device = hashmap_get(m->devices, udev_device_get_syspath(d));
233                 if (!device)
234                         return 0;
235
236                 seat_add_to_gc_queue(device->seat);
237                 device_free(device);
238
239         } else {
240                 const char *sn;
241                 Seat *seat = NULL;
242                 bool master;
243
244                 sn = udev_device_get_property_value(d, "ID_SEAT");
245                 if (isempty(sn))
246                         sn = "seat0";
247
248                 if (!seat_name_is_valid(sn)) {
249                         log_warning("Device with invalid seat name %s found, ignoring.", sn);
250                         return 0;
251                 }
252
253                 seat = hashmap_get(m->seats, sn);
254                 master = udev_device_has_tag(d, "master-of-seat");
255
256                 /* Ignore non-master devices for unknown seats */
257                 if (!master && !seat)
258                         return 0;
259
260                 r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
261                 if (r < 0)
262                         return r;
263
264                 if (!seat) {
265                         r = manager_add_seat(m, sn, &seat);
266                         if (r < 0) {
267                                 if (!device->seat)
268                                         device_free(device);
269
270                                 return r;
271                         }
272                 }
273
274                 device_attach(device, seat);
275                 seat_start(seat);
276         }
277
278         return 0;
279 }
280
281 int manager_process_button_device(Manager *m, struct udev_device *d) {
282         Button *b;
283
284         int r;
285
286         assert(m);
287
288         if (streq_ptr(udev_device_get_action(d), "remove")) {
289
290                 b = hashmap_get(m->buttons, udev_device_get_sysname(d));
291                 if (!b)
292                         return 0;
293
294                 button_free(b);
295
296         } else {
297                 const char *sn;
298
299                 r = manager_add_button(m, udev_device_get_sysname(d), &b);
300                 if (r < 0)
301                         return r;
302
303                 sn = udev_device_get_property_value(d, "ID_SEAT");
304                 if (isempty(sn))
305                         sn = "seat0";
306
307                 button_set_seat(b, sn);
308                 button_open(b);
309         }
310
311         return 0;
312 }
313
314 int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
315         _cleanup_free_ char *session_name = NULL;
316         Session *s;
317         int r;
318
319         assert(m);
320         assert(session);
321
322         if (pid < 1)
323                 return -EINVAL;
324
325         r = cg_pid_get_session(pid, &session_name);
326         if (r < 0)
327                 return 0;
328
329         s = hashmap_get(m->sessions, session_name);
330         if (!s)
331                 return 0;
332
333         *session = s;
334         return 1;
335 }
336
337 int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
338         Session *s;
339         int r;
340
341         assert(m);
342         assert(user);
343
344         r = manager_get_session_by_pid (m, pid, &s);
345         if (r <= 0)
346                 return r;
347
348         *user = s->user;
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 static int vt_is_busy(unsigned int vtnr) {
408         struct vt_stat vt_stat;
409         int r = 0;
410         _cleanup_close_ int fd;
411
412         assert(vtnr >= 1);
413
414         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
415          * we'd open the latter we'd open the foreground tty which
416          * hence would be unconditionally busy. By opening /dev/tty1
417          * we avoid this. Since tty1 is special and needs to be an
418          * explicitly loaded getty or DM this is safe. */
419
420         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
421         if (fd < 0)
422                 return -errno;
423
424         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
425                 r = -errno;
426         else
427                 r = !!(vt_stat.v_state & (1 << vtnr));
428
429         return r;
430 }
431
432 static bool manager_is_docked(Manager *m) {
433         Iterator i;
434         Button *b;
435
436         HASHMAP_FOREACH(b, m->buttons, i)
437                 if (b->docked)
438                         return true;
439
440         return false;
441 }
442
443 static int manager_count_external_displays(Manager *m) {
444         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
445         struct udev_list_entry *item = NULL, *first = NULL;
446         int r;
447         int n = 0;
448
449         e = udev_enumerate_new(m->udev);
450         if (!e)
451                 return -ENOMEM;
452
453         r = udev_enumerate_add_match_subsystem(e, "drm");
454         if (r < 0)
455                 return r;
456
457         r = udev_enumerate_scan_devices(e);
458         if (r < 0)
459                 return r;
460
461         first = udev_enumerate_get_list_entry(e);
462         udev_list_entry_foreach(item, first) {
463                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
464                 struct udev_device *p;
465                 const char *status, *enabled, *dash, *nn, *i;
466                 bool external = false;
467
468                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
469                 if (!d)
470                         return -ENOMEM;
471
472                 p = udev_device_get_parent(d);
473                 if (!p)
474                         continue;
475
476                 /* If the parent shares the same subsystem as the
477                  * device we are looking at then it is a connector,
478                  * which is what we are interested in. */
479                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
480                         continue;
481
482                 nn = udev_device_get_sysname(d);
483                 if (!nn)
484                         continue;
485
486                 /* Ignore internal displays: the type is encoded in
487                  * the sysfs name, as the second dash seperated item
488                  * (the first is the card name, the last the connector
489                  * number). We implement a whitelist of external
490                  * displays here, rather than a whitelist, to ensure
491                  * we don't block suspends too eagerly. */
492                 dash = strchr(nn, '-');
493                 if (!dash)
494                         continue;
495
496                 dash++;
497                 FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
498                                "Composite-", "SVIDEO-", "Component-",
499                                "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
500
501                         if (startswith(dash, i)) {
502                                 external = true;
503                                 break;
504                         }
505                 }
506                 if (!external)
507                         continue;
508
509                 /* Ignore ports that are not enabled */
510                 enabled = udev_device_get_sysattr_value(d, "enabled");
511                 if (!enabled)
512                         continue;
513                 if (!streq_ptr(enabled, "enabled"))
514                         continue;
515
516                 /* We count any connector which is not explicitly
517                  * "disconnected" as connected. */
518                 status = udev_device_get_sysattr_value(d, "status");
519                 if (!streq_ptr(status, "disconnected"))
520                         n++;
521         }
522
523         return n;
524 }
525
526 bool manager_is_docked_or_external_displays(Manager *m) {
527         int n;
528
529         /* If we are docked don't react to lid closing */
530         if (manager_is_docked(m)) {
531                 log_debug("System is docked.");
532                 return true;
533         }
534
535         /* If we have more than one display connected,
536          * assume that we are docked. */
537         n = manager_count_external_displays(m);
538         if (n < 0)
539                 log_warning_errno(n, "Display counting failed: %m");
540         else if (n >= 1) {
541                 log_debug("External (%i) displays connected.", n);
542                 return true;
543         }
544
545         return false;
546 }