chiark / gitweb /
util: make malloc0 ask calloc for one block of size n
[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 static int vt_is_busy(unsigned int vtnr) {
378         struct vt_stat vt_stat;
379         int r = 0;
380         _cleanup_close_ int fd;
381
382         assert(vtnr >= 1);
383
384         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
385          * we'd open the latter we'd open the foreground tty which
386          * hence would be unconditionally busy. By opening /dev/tty1
387          * we avoid this. Since tty1 is special and needs to be an
388          * explicitly loaded getty or DM this is safe. */
389
390         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
391         if (fd < 0)
392                 return -errno;
393
394         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
395                 r = -errno;
396         else
397                 r = !!(vt_stat.v_state & (1 << vtnr));
398
399         return r;
400 }
401
402 int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
403         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
404         char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
405         int r;
406
407         assert(m);
408         assert(vtnr >= 1);
409
410         if (vtnr > m->n_autovts &&
411             vtnr != m->reserve_vt)
412                 return 0;
413
414         if (vtnr != m->reserve_vt) {
415                 /* If this is the reserved TTY, we'll start the getty
416                  * on it in any case, but otherwise only if it is not
417                  * busy. */
418
419                 r = vt_is_busy(vtnr);
420                 if (r < 0)
421                         return r;
422                 else if (r > 0)
423                         return -EBUSY;
424         }
425
426         snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
427         r = sd_bus_call_method(
428                         m->bus,
429                         "org.freedesktop.systemd1",
430                         "/org/freedesktop/systemd1",
431                         "org.freedesktop.systemd1.Manager",
432                         "StartUnit",
433                         &error,
434                         NULL,
435                         "ss", name, "fail");
436         if (r < 0)
437                 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
438
439         return r;
440 }
441
442 bool manager_is_docked(Manager *m) {
443         Iterator i;
444         Button *b;
445
446         HASHMAP_FOREACH(b, m->buttons, i)
447                 if (b->docked)
448                         return true;
449
450         return false;
451 }
452
453 int manager_count_displays(Manager *m) {
454         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
455         struct udev_list_entry *item = NULL, *first = NULL;
456         int r;
457         int n = 0;
458
459         e = udev_enumerate_new(m->udev);
460         if (!e)
461                 return -ENOMEM;
462
463         r = udev_enumerate_add_match_subsystem(e, "drm");
464         if (r < 0)
465                 return r;
466
467         r = udev_enumerate_scan_devices(e);
468         if (r < 0)
469                 return r;
470
471         first = udev_enumerate_get_list_entry(e);
472         udev_list_entry_foreach(item, first) {
473                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
474                 struct udev_device *p;
475                 const char *status;
476
477                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
478                 if (!d)
479                         return -ENOMEM;
480
481                 p = udev_device_get_parent(d);
482                 if (!p)
483                         continue;
484
485                 /* If the parent shares the same subsystem as the
486                  * device we are looking at then it is a connector,
487                  * which is what we are interested in. */
488                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
489                         continue;
490
491                 /* We count any connector which is not explicitly
492                  * "disconnected" as connected. */
493                 status = udev_device_get_sysattr_value(d, "status");
494                 if (!streq_ptr(status, "disconnected"))
495                         n++;
496         }
497
498         return n;
499 }
500
501 bool manager_is_docked_or_multiple_displays(Manager *m) {
502         int n;
503
504         /* If we are docked don't react to lid closing */
505         if (manager_is_docked(m)) {
506                 log_debug("System is docked.");
507                 return true;
508         }
509
510         /* If we have more than one display connected,
511          * assume that we are docked. */
512         n = manager_count_displays(m);
513         if (n < 0)
514                 log_warning_errno(n, "Display counting failed: %m");
515         else if (n > 1) {
516                 log_debug("Multiple (%i) displays connected.", n);
517                 return true;
518         }
519
520         return false;
521 }