chiark / gitweb /
nspawn: fix getent fallback
[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/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                         return -ENOMEM;
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 }