chiark / gitweb /
Remove support for auto-spawning VTs
[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
35 int 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);
42         if (d)
43                 /* we support adding master-flags, but not removing them */
44                 d->master = d->master || master;
45         else {
46                 d = device_new(m, sysfs, master);
47                 if (!d)
48                         return -ENOMEM;
49         }
50
51         if (_device)
52                 *_device = d;
53
54         return 0;
55 }
56
57 int 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);
64         if (!s) {
65                 s = seat_new(m, id);
66                 if (!s)
67                         return -ENOMEM;
68         }
69
70         if (_seat)
71                 *_seat = s;
72
73         return 0;
74 }
75
76 int 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);
83         if (!s) {
84                 s = session_new(m, id);
85                 if (!s)
86                         return -ENOMEM;
87         }
88
89         if (_session)
90                 *_session = s;
91
92         return 0;
93 }
94
95 int 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
101         u = hashmap_get(m->users, UID_TO_PTR(uid));
102         if (!u) {
103                 u = user_new(m, uid, gid, name);
104                 if (!u)
105                         return -ENOMEM;
106         }
107
108         if (_user)
109                 *_user = u;
110
111         return 0;
112 }
113
114 int 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
129 int 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
142 int 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
166 int 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);
173         if (!b) {
174                 b = button_new(m, name);
175                 if (!b)
176                         return -ENOMEM;
177         }
178
179         if (_button)
180                 *_button = b;
181
182         return 0;
183 }
184
185 int manager_watch_busname(Manager *m, const char *name) {
186         char *n;
187         int r;
188
189         assert(m);
190         assert(name);
191
192         if (set_get(m->busnames, (char*) name))
193                 return 0;
194
195         n = strdup(name);
196         if (!n)
197                 return -ENOMEM;
198
199         r = set_put(m->busnames, n);
200         if (r < 0) {
201                 free(n);
202                 return r;
203         }
204
205         return 0;
206 }
207
208 void manager_drop_busname(Manager *m, const char *name) {
209         Session *session;
210         Iterator i;
211
212         assert(m);
213         assert(name);
214
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
220         free(set_remove(m->busnames, (char*) name));
221 }
222
223 int 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
252                 seat = hashmap_get(m->seats, sn);
253                 master = udev_device_has_tag(d, "master-of-seat");
254
255                 /* Ignore non-master devices for unknown seats */
256                 if (!master && !seat)
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
280 int 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
313 int 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)
326                 return 0;
327
328         s = hashmap_get(m->session_units, unit);
329         if (!s)
330                 return 0;
331
332         *session = s;
333         return 1;
334 }
335
336 int 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)
349                 return 0;
350
351         u = hashmap_get(m->user_units, unit);
352         if (!u)
353                 return 0;
354
355         *user = u;
356         return 1;
357 }
358
359 int 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
367         idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
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
398 bool 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
414 static int vt_is_busy(unsigned int vtnr) {
415         struct vt_stat vt_stat;
416         int r = 0;
417         _cleanup_close_ int fd;
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
436         return r;
437 }
438
439 bool manager_is_docked(Manager *m) {
440         Iterator i;
441         Button *b;
442
443         HASHMAP_FOREACH(b, m->buttons, i)
444                 if (b->docked)
445                         return true;
446
447         return false;
448 }
449
450 int manager_count_displays(Manager *m) {
451         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
452         struct udev_list_entry *item = NULL, *first = NULL;
453         int r;
454         int n = 0;
455
456         e = udev_enumerate_new(m->udev);
457         if (!e)
458                 return -ENOMEM;
459
460         r = udev_enumerate_add_match_subsystem(e, "drm");
461         if (r < 0)
462                 return r;
463
464         r = udev_enumerate_scan_devices(e);
465         if (r < 0)
466                 return r;
467
468         first = udev_enumerate_get_list_entry(e);
469         udev_list_entry_foreach(item, first) {
470                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
471                 struct udev_device *p;
472                 const char *status;
473
474                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
475                 if (!d)
476                         return -ENOMEM;
477
478                 p = udev_device_get_parent(d);
479                 if (!p)
480                         continue;
481
482                 /* If the parent shares the same subsystem as the
483                  * device we are looking at then it is a connector,
484                  * which is what we are interested in. */
485                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
486                         continue;
487
488                 /* We count any connector which is not explicitly
489                  * "disconnected" as connected. */
490                 status = udev_device_get_sysattr_value(d, "status");
491                 if (!streq_ptr(status, "disconnected"))
492                         n++;
493         }
494
495         return n;
496 }
497
498 bool manager_is_docked_or_multiple_displays(Manager *m) {
499         int n;
500
501         /* If we are docked don't react to lid closing */
502         if (manager_is_docked(m)) {
503                 log_debug("System is docked.");
504                 return true;
505         }
506
507         /* If we have more than one display connected,
508          * assume that we are docked. */
509         n = manager_count_displays(m);
510         if (n < 0)
511                 log_warning_errno(n, "Display counting failed: %m");
512         else if (n > 1) {
513                 log_debug("Multiple (%i) displays connected.", n);
514                 return true;
515         }
516
517         return false;
518 }