chiark / gitweb /
Stop sessions on ReleaseSession
[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_process_seat_device(Manager *m, struct udev_device *d) {
187         Device *device;
188         int r;
189
190         assert(m);
191
192         if (streq_ptr(udev_device_get_action(d), "remove")) {
193
194                 device = hashmap_get(m->devices, udev_device_get_syspath(d));
195                 if (!device)
196                         return 0;
197
198                 seat_add_to_gc_queue(device->seat);
199                 device_free(device);
200
201         } else {
202                 const char *sn;
203                 Seat *seat = NULL;
204                 bool master;
205
206                 sn = udev_device_get_property_value(d, "ID_SEAT");
207                 if (isempty(sn))
208                         sn = "seat0";
209
210                 if (!seat_name_is_valid(sn)) {
211                         log_warning("Device with invalid seat name %s found, ignoring.", sn);
212                         return 0;
213                 }
214
215                 seat = hashmap_get(m->seats, sn);
216                 master = udev_device_has_tag(d, "master-of-seat");
217
218                 /* Ignore non-master devices for unknown seats */
219                 if (!master && !seat)
220                         return 0;
221
222                 r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
223                 if (r < 0)
224                         return r;
225
226                 if (!seat) {
227                         r = manager_add_seat(m, sn, &seat);
228                         if (r < 0) {
229                                 if (!device->seat)
230                                         device_free(device);
231
232                                 return r;
233                         }
234                 }
235
236                 device_attach(device, seat);
237                 seat_start(seat);
238         }
239
240         return 0;
241 }
242
243 int manager_process_button_device(Manager *m, struct udev_device *d) {
244         Button *b;
245
246         int r;
247
248         assert(m);
249
250         if (streq_ptr(udev_device_get_action(d), "remove")) {
251
252                 b = hashmap_get(m->buttons, udev_device_get_sysname(d));
253                 if (!b)
254                         return 0;
255
256                 button_free(b);
257
258         } else {
259                 const char *sn;
260
261                 r = manager_add_button(m, udev_device_get_sysname(d), &b);
262                 if (r < 0)
263                         return r;
264
265                 sn = udev_device_get_property_value(d, "ID_SEAT");
266                 if (isempty(sn))
267                         sn = "seat0";
268
269                 button_set_seat(b, sn);
270                 button_open(b);
271         }
272
273         return 0;
274 }
275
276 int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
277         _cleanup_free_ char *unit = NULL;
278         Session *s;
279         int r;
280
281         assert(m);
282         assert(session);
283
284         if (pid < 1)
285                 return -EINVAL;
286
287         r = cg_pid_get_unit(pid, &unit);
288         if (r < 0)
289                 return 0;
290
291         s = hashmap_get(m->session_units, unit);
292         if (!s)
293                 return 0;
294
295         *session = s;
296         return 1;
297 }
298
299 int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
300         _cleanup_free_ char *unit = NULL;
301         User *u;
302         int r;
303
304         assert(m);
305         assert(user);
306
307         if (pid < 1)
308                 return -EINVAL;
309
310         r = cg_pid_get_slice(pid, &unit);
311         if (r < 0)
312                 return 0;
313
314         u = hashmap_get(m->user_units, unit);
315         if (!u)
316                 return 0;
317
318         *user = u;
319         return 1;
320 }
321
322 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
323         Session *s;
324         bool idle_hint;
325         dual_timestamp ts = { 0, 0 };
326         Iterator i;
327
328         assert(m);
329
330         idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
331
332         HASHMAP_FOREACH(s, m->sessions, i) {
333                 dual_timestamp k;
334                 int ih;
335
336                 ih = session_get_idle_hint(s, &k);
337                 if (ih < 0)
338                         return ih;
339
340                 if (!ih) {
341                         if (!idle_hint) {
342                                 if (k.monotonic < ts.monotonic)
343                                         ts = k;
344                         } else {
345                                 idle_hint = false;
346                                 ts = k;
347                         }
348                 } else if (idle_hint) {
349
350                         if (k.monotonic > ts.monotonic)
351                                 ts = k;
352                 }
353         }
354
355         if (t)
356                 *t = ts;
357
358         return idle_hint;
359 }
360
361 bool manager_shall_kill(Manager *m, const char *user) {
362         assert(m);
363         assert(user);
364
365         if (!m->kill_user_processes)
366                 return false;
367
368         if (strv_contains(m->kill_exclude_users, user))
369                 return false;
370
371         if (strv_isempty(m->kill_only_users))
372                 return true;
373
374         return strv_contains(m->kill_only_users, user);
375 }
376
377 /// UNNEEDED by elogind
378 #if 0
379 static int vt_is_busy(unsigned int vtnr) {
380         struct vt_stat vt_stat;
381         int r = 0;
382         _cleanup_close_ int fd;
383
384         assert(vtnr >= 1);
385
386         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
387          * we'd open the latter we'd open the foreground tty which
388          * hence would be unconditionally busy. By opening /dev/tty1
389          * we avoid this. Since tty1 is special and needs to be an
390          * explicitly loaded getty or DM this is safe. */
391
392         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
393         if (fd < 0)
394                 return -errno;
395
396         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
397                 r = -errno;
398         else
399                 r = !!(vt_stat.v_state & (1 << vtnr));
400
401         return r;
402 }
403
404 int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
405         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
406         char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
407         int r;
408
409         assert(m);
410         assert(vtnr >= 1);
411
412         if (vtnr > m->n_autovts &&
413             vtnr != m->reserve_vt)
414                 return 0;
415
416         if (vtnr != m->reserve_vt) {
417                 /* If this is the reserved TTY, we'll start the getty
418                  * on it in any case, but otherwise only if it is not
419                  * busy. */
420
421                 r = vt_is_busy(vtnr);
422                 if (r < 0)
423                         return r;
424                 else if (r > 0)
425                         return -EBUSY;
426         }
427
428         snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
429         r = sd_bus_call_method(
430                         m->bus,
431                         "org.freedesktop.systemd1",
432                         "/org/freedesktop/systemd1",
433                         "org.freedesktop.systemd1.Manager",
434                         "StartUnit",
435                         &error,
436                         NULL,
437                         "ss", name, "fail");
438         if (r < 0)
439                 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
440
441         return r;
442 }
443 #endif // 0
444
445 bool manager_is_docked(Manager *m) {
446         Iterator i;
447         Button *b;
448
449         HASHMAP_FOREACH(b, m->buttons, i)
450                 if (b->docked)
451                         return true;
452
453         return false;
454 }
455
456 int manager_count_displays(Manager *m) {
457         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
458         struct udev_list_entry *item = NULL, *first = NULL;
459         int r;
460         int n = 0;
461
462         e = udev_enumerate_new(m->udev);
463         if (!e)
464                 return -ENOMEM;
465
466         r = udev_enumerate_add_match_subsystem(e, "drm");
467         if (r < 0)
468                 return r;
469
470         r = udev_enumerate_scan_devices(e);
471         if (r < 0)
472                 return r;
473
474         first = udev_enumerate_get_list_entry(e);
475         udev_list_entry_foreach(item, first) {
476                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
477                 struct udev_device *p;
478                 const char *status;
479
480                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
481                 if (!d)
482                         return -ENOMEM;
483
484                 p = udev_device_get_parent(d);
485                 if (!p)
486                         continue;
487
488                 /* If the parent shares the same subsystem as the
489                  * device we are looking at then it is a connector,
490                  * which is what we are interested in. */
491                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
492                         continue;
493
494                 /* We count any connector which is not explicitly
495                  * "disconnected" as connected. */
496                 status = udev_device_get_sysattr_value(d, "status");
497                 if (!streq_ptr(status, "disconnected"))
498                         n++;
499         }
500
501         return n;
502 }
503
504 bool manager_is_docked_or_multiple_displays(Manager *m) {
505         int n;
506
507         /* If we are docked don't react to lid closing */
508         if (manager_is_docked(m)) {
509                 log_debug("System is docked.");
510                 return true;
511         }
512
513         /* If we have more than one display connected,
514          * assume that we are docked. */
515         n = manager_count_displays(m);
516         if (n < 0)
517                 log_warning_errno(n, "Display counting failed: %m");
518         else if (n > 1) {
519                 log_debug("Multiple (%i) displays connected.", n);
520                 return true;
521         }
522
523         return false;
524 }