]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-core.c
sd-bus: the bus returned should be the first arg
[thirdparty/systemd.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 "logind.h"
36
37 int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
38 Device *d;
39
40 assert(m);
41 assert(sysfs);
42
43 d = hashmap_get(m->devices, sysfs);
44 if (d) {
45 if (_device)
46 *_device = d;
47
48 /* we support adding master-flags, but not removing them */
49 d->master = d->master || master;
50
51 return 0;
52 }
53
54 d = device_new(m, sysfs, master);
55 if (!d)
56 return -ENOMEM;
57
58 if (_device)
59 *_device = d;
60
61 return 0;
62 }
63
64 int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
65 Seat *s;
66
67 assert(m);
68 assert(id);
69
70 s = hashmap_get(m->seats, id);
71 if (s) {
72 if (_seat)
73 *_seat = s;
74
75 return 0;
76 }
77
78 s = seat_new(m, id);
79 if (!s)
80 return -ENOMEM;
81
82 if (_seat)
83 *_seat = s;
84
85 return 0;
86 }
87
88 int manager_add_session(Manager *m, const char *id, Session **_session) {
89 Session *s;
90
91 assert(m);
92 assert(id);
93
94 s = hashmap_get(m->sessions, id);
95 if (s) {
96 if (_session)
97 *_session = s;
98
99 return 0;
100 }
101
102 s = session_new(m, id);
103 if (!s)
104 return -ENOMEM;
105
106 if (_session)
107 *_session = s;
108
109 return 0;
110 }
111
112 int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
113 User *u;
114
115 assert(m);
116 assert(name);
117
118 u = hashmap_get(m->users, ULONG_TO_PTR((unsigned long) uid));
119 if (u) {
120 if (_user)
121 *_user = u;
122
123 return 0;
124 }
125
126 u = user_new(m, uid, gid, name);
127 if (!u)
128 return -ENOMEM;
129
130 if (_user)
131 *_user = u;
132
133 return 0;
134 }
135
136 int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
137 uid_t uid;
138 gid_t gid;
139 int r;
140
141 assert(m);
142 assert(name);
143
144 r = get_user_creds(&name, &uid, &gid, NULL, NULL);
145 if (r < 0)
146 return r;
147
148 return manager_add_user(m, uid, gid, name, _user);
149 }
150
151 int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
152 struct passwd *p;
153
154 assert(m);
155
156 errno = 0;
157 p = getpwuid(uid);
158 if (!p)
159 return errno ? -errno : -ENOENT;
160
161 return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
162 }
163
164 int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
165 Inhibitor *i;
166
167 assert(m);
168 assert(id);
169
170 i = hashmap_get(m->inhibitors, id);
171 if (i) {
172 if (_inhibitor)
173 *_inhibitor = i;
174
175 return 0;
176 }
177
178 i = inhibitor_new(m, id);
179 if (!i)
180 return -ENOMEM;
181
182 if (_inhibitor)
183 *_inhibitor = i;
184
185 return 0;
186 }
187
188 int manager_add_button(Manager *m, const char *name, Button **_button) {
189 Button *b;
190
191 assert(m);
192 assert(name);
193
194 b = hashmap_get(m->buttons, name);
195 if (b) {
196 if (_button)
197 *_button = b;
198
199 return 0;
200 }
201
202 b = button_new(m, name);
203 if (!b)
204 return -ENOMEM;
205
206 if (_button)
207 *_button = b;
208
209 return 0;
210 }
211
212 int manager_watch_busname(Manager *m, const char *name) {
213 char *n;
214 int r;
215
216 assert(m);
217 assert(name);
218
219 if (set_get(m->busnames, (char*) name))
220 return 0;
221
222 n = strdup(name);
223 if (!n)
224 return -ENOMEM;
225
226 r = set_put(m->busnames, n);
227 if (r < 0) {
228 free(n);
229 return r;
230 }
231
232 return 0;
233 }
234
235 void manager_drop_busname(Manager *m, const char *name) {
236 Session *session;
237 Iterator i;
238
239 assert(m);
240 assert(name);
241
242 /* keep it if the name still owns a controller */
243 HASHMAP_FOREACH(session, m->sessions, i)
244 if (session_is_controller(session, name))
245 return;
246
247 free(set_remove(m->busnames, (char*) name));
248 }
249
250 int manager_process_seat_device(Manager *m, struct udev_device *d) {
251 Device *device;
252 int r;
253
254 assert(m);
255
256 if (streq_ptr(udev_device_get_action(d), "remove")) {
257
258 device = hashmap_get(m->devices, udev_device_get_syspath(d));
259 if (!device)
260 return 0;
261
262 seat_add_to_gc_queue(device->seat);
263 device_free(device);
264
265 } else {
266 const char *sn;
267 Seat *seat = NULL;
268 bool master;
269
270 sn = udev_device_get_property_value(d, "ID_SEAT");
271 if (isempty(sn))
272 sn = "seat0";
273
274 if (!seat_name_is_valid(sn)) {
275 log_warning("Device with invalid seat name %s found, ignoring.", sn);
276 return 0;
277 }
278
279 /* ignore non-master devices for unknown seats */
280 master = udev_device_has_tag(d, "master-of-seat");
281 if (!master && !(seat = hashmap_get(m->seats, sn)))
282 return 0;
283
284 r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
285 if (r < 0)
286 return r;
287
288 if (!seat) {
289 r = manager_add_seat(m, sn, &seat);
290 if (r < 0) {
291 if (!device->seat)
292 device_free(device);
293
294 return r;
295 }
296 }
297
298 device_attach(device, seat);
299 seat_start(seat);
300 }
301
302 return 0;
303 }
304
305 int manager_process_button_device(Manager *m, struct udev_device *d) {
306 Button *b;
307
308 int r;
309
310 assert(m);
311
312 if (streq_ptr(udev_device_get_action(d), "remove")) {
313
314 b = hashmap_get(m->buttons, udev_device_get_sysname(d));
315 if (!b)
316 return 0;
317
318 button_free(b);
319
320 } else {
321 const char *sn;
322
323 r = manager_add_button(m, udev_device_get_sysname(d), &b);
324 if (r < 0)
325 return r;
326
327 sn = udev_device_get_property_value(d, "ID_SEAT");
328 if (isempty(sn))
329 sn = "seat0";
330
331 button_set_seat(b, sn);
332 button_open(b);
333 }
334
335 return 0;
336 }
337
338 int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
339 _cleanup_free_ char *unit = NULL;
340 Session *s;
341 int r;
342
343 assert(m);
344 assert(session);
345
346 if (pid < 1)
347 return -EINVAL;
348
349 r = cg_pid_get_unit(pid, &unit);
350 if (r < 0)
351 return 0;
352
353 s = hashmap_get(m->session_units, unit);
354 if (!s)
355 return 0;
356
357 *session = s;
358 return 1;
359 }
360
361 int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
362 _cleanup_free_ char *unit = NULL;
363 User *u;
364 int r;
365
366 assert(m);
367 assert(user);
368
369 if (pid < 1)
370 return -EINVAL;
371
372 r = cg_pid_get_slice(pid, &unit);
373 if (r < 0)
374 return 0;
375
376 u = hashmap_get(m->user_units, unit);
377 if (!u)
378 return 0;
379
380 *user = u;
381 return 1;
382 }
383
384 int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
385 Session *s;
386 bool idle_hint;
387 dual_timestamp ts = { 0, 0 };
388 Iterator i;
389
390 assert(m);
391
392 idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
393
394 HASHMAP_FOREACH(s, m->sessions, i) {
395 dual_timestamp k;
396 int ih;
397
398 ih = session_get_idle_hint(s, &k);
399 if (ih < 0)
400 return ih;
401
402 if (!ih) {
403 if (!idle_hint) {
404 if (k.monotonic < ts.monotonic)
405 ts = k;
406 } else {
407 idle_hint = false;
408 ts = k;
409 }
410 } else if (idle_hint) {
411
412 if (k.monotonic > ts.monotonic)
413 ts = k;
414 }
415 }
416
417 if (t)
418 *t = ts;
419
420 return idle_hint;
421 }
422
423 bool manager_shall_kill(Manager *m, const char *user) {
424 assert(m);
425 assert(user);
426
427 if (!m->kill_user_processes)
428 return false;
429
430 if (strv_contains(m->kill_exclude_users, user))
431 return false;
432
433 if (strv_isempty(m->kill_only_users))
434 return true;
435
436 return strv_contains(m->kill_only_users, user);
437 }
438
439 static int vt_is_busy(unsigned int vtnr) {
440 struct vt_stat vt_stat;
441 int r = 0, fd;
442
443 assert(vtnr >= 1);
444
445 /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
446 * we'd open the latter we'd open the foreground tty which
447 * hence would be unconditionally busy. By opening /dev/tty1
448 * we avoid this. Since tty1 is special and needs to be an
449 * explicitly loaded getty or DM this is safe. */
450
451 fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
452 if (fd < 0)
453 return -errno;
454
455 if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
456 r = -errno;
457 else
458 r = !!(vt_stat.v_state & (1 << vtnr));
459
460 close_nointr_nofail(fd);
461
462 return r;
463 }
464
465 int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
466 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
467 _cleanup_free_ char *name = NULL;
468 int r;
469
470 assert(m);
471 assert(vtnr >= 1);
472
473 if (vtnr > m->n_autovts &&
474 vtnr != m->reserve_vt)
475 return 0;
476
477 if (vtnr != m->reserve_vt) {
478 /* If this is the reserved TTY, we'll start the getty
479 * on it in any case, but otherwise only if it is not
480 * busy. */
481
482 r = vt_is_busy(vtnr);
483 if (r < 0)
484 return r;
485 else if (r > 0)
486 return -EBUSY;
487 }
488
489 if (asprintf(&name, "autovt@tty%u.service", vtnr) < 0)
490 return log_oom();
491
492 r = sd_bus_call_method(
493 m->bus,
494 "org.freedesktop.systemd1",
495 "/org/freedesktop/systemd1",
496 "org.freedesktop.systemd1.Manager",
497 "StartUnit",
498 &error,
499 NULL,
500 "ss", name, "fail");
501 if (r < 0)
502 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
503
504 return r;
505 }