]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/logind-user.c
logind: always kill session when termination is requested
[thirdparty/systemd.git] / src / login / logind-user.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 <string.h>
23 #include <unistd.h>
24 #include <errno.h>
25
26 #include "util.h"
27 #include "mkdir.h"
28 #include "hashmap.h"
29 #include "strv.h"
30 #include "fileio.h"
31 #include "special.h"
32 #include "unit-name.h"
33 #include "bus-util.h"
34 #include "bus-error.h"
35 #include "logind-user.h"
36
37 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
38 User *u;
39
40 assert(m);
41 assert(name);
42
43 u = new0(User, 1);
44 if (!u)
45 return NULL;
46
47 u->name = strdup(name);
48 if (!u->name)
49 goto fail;
50
51 if (asprintf(&u->state_file, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
52 goto fail;
53
54 if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0)
55 goto fail;
56
57 u->manager = m;
58 u->uid = uid;
59 u->gid = gid;
60
61 return u;
62
63 fail:
64 free(u->state_file);
65 free(u->name);
66 free(u);
67
68 return NULL;
69 }
70
71 void user_free(User *u) {
72 assert(u);
73
74 if (u->in_gc_queue)
75 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
76
77 while (u->sessions)
78 session_free(u->sessions);
79
80 if (u->slice) {
81 hashmap_remove(u->manager->user_units, u->slice);
82 free(u->slice);
83 }
84
85 if (u->service) {
86 hashmap_remove(u->manager->user_units, u->service);
87 free(u->service);
88 }
89
90 free(u->slice_job);
91 free(u->service_job);
92
93 free(u->runtime_path);
94
95 hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
96
97 free(u->name);
98 free(u->state_file);
99 free(u);
100 }
101
102 int user_save(User *u) {
103 _cleanup_free_ char *temp_path = NULL;
104 _cleanup_fclose_ FILE *f = NULL;
105 int r;
106
107 assert(u);
108 assert(u->state_file);
109
110 if (!u->started)
111 return 0;
112
113 r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
114 if (r < 0)
115 goto finish;
116
117 r = fopen_temporary(u->state_file, &f, &temp_path);
118 if (r < 0)
119 goto finish;
120
121 fchmod(fileno(f), 0644);
122
123 fprintf(f,
124 "# This is private data. Do not parse.\n"
125 "NAME=%s\n"
126 "STATE=%s\n",
127 u->name,
128 user_state_to_string(user_get_state(u)));
129
130 if (u->runtime_path)
131 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
132
133 if (u->service)
134 fprintf(f, "SERVICE=%s\n", u->service);
135 if (u->service_job)
136 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
137
138 if (u->slice)
139 fprintf(f, "SLICE=%s\n", u->slice);
140 if (u->slice_job)
141 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
142
143 if (u->display)
144 fprintf(f, "DISPLAY=%s\n", u->display->id);
145
146 if (dual_timestamp_is_set(&u->timestamp))
147 fprintf(f,
148 "REALTIME="USEC_FMT"\n"
149 "MONOTONIC="USEC_FMT"\n",
150 u->timestamp.realtime,
151 u->timestamp.monotonic);
152
153 if (u->sessions) {
154 Session *i;
155 bool first;
156
157 fputs("SESSIONS=", f);
158 first = true;
159 LIST_FOREACH(sessions_by_user, i, u->sessions) {
160 if (first)
161 first = false;
162 else
163 fputc(' ', f);
164
165 fputs(i->id, f);
166 }
167
168 fputs("\nSEATS=", f);
169 first = true;
170 LIST_FOREACH(sessions_by_user, i, u->sessions) {
171 if (!i->seat)
172 continue;
173
174 if (first)
175 first = false;
176 else
177 fputc(' ', f);
178
179 fputs(i->seat->id, f);
180 }
181
182 fputs("\nACTIVE_SESSIONS=", f);
183 first = true;
184 LIST_FOREACH(sessions_by_user, i, u->sessions) {
185 if (!session_is_active(i))
186 continue;
187
188 if (first)
189 first = false;
190 else
191 fputc(' ', f);
192
193 fputs(i->id, f);
194 }
195
196 fputs("\nONLINE_SESSIONS=", f);
197 first = true;
198 LIST_FOREACH(sessions_by_user, i, u->sessions) {
199 if (session_get_state(i) == SESSION_CLOSING)
200 continue;
201
202 if (first)
203 first = false;
204 else
205 fputc(' ', f);
206
207 fputs(i->id, f);
208 }
209
210 fputs("\nACTIVE_SEATS=", f);
211 first = true;
212 LIST_FOREACH(sessions_by_user, i, u->sessions) {
213 if (!session_is_active(i) || !i->seat)
214 continue;
215
216 if (first)
217 first = false;
218 else
219 fputc(' ', f);
220
221 fputs(i->seat->id, f);
222 }
223
224 fputs("\nONLINE_SEATS=", f);
225 first = true;
226 LIST_FOREACH(sessions_by_user, i, u->sessions) {
227 if (session_get_state(i) == SESSION_CLOSING || !i->seat)
228 continue;
229
230 if (first)
231 first = false;
232 else
233 fputc(' ', f);
234
235 fputs(i->seat->id, f);
236 }
237 fputc('\n', f);
238 }
239
240 fflush(f);
241
242 if (ferror(f) || rename(temp_path, u->state_file) < 0) {
243 r = -errno;
244 unlink(u->state_file);
245 unlink(temp_path);
246 }
247
248 finish:
249 if (r < 0)
250 log_error("Failed to save user data %s: %s", u->state_file, strerror(-r));
251
252 return r;
253 }
254
255 int user_load(User *u) {
256 _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
257 Session *s = NULL;
258 int r;
259
260 assert(u);
261
262 r = parse_env_file(u->state_file, NEWLINE,
263 "RUNTIME", &u->runtime_path,
264 "SERVICE", &u->service,
265 "SERVICE_JOB", &u->service_job,
266 "SLICE", &u->slice,
267 "SLICE_JOB", &u->slice_job,
268 "DISPLAY", &display,
269 "REALTIME", &realtime,
270 "MONOTONIC", &monotonic,
271 NULL);
272 if (r < 0) {
273 if (r == -ENOENT)
274 return 0;
275
276 log_error("Failed to read %s: %s", u->state_file, strerror(-r));
277 return r;
278 }
279
280 if (display)
281 s = hashmap_get(u->manager->sessions, display);
282
283 if (s && s->display && display_is_local(s->display))
284 u->display = s;
285
286 if (realtime) {
287 unsigned long long l;
288 if (sscanf(realtime, "%llu", &l) > 0)
289 u->timestamp.realtime = l;
290 }
291
292 if (monotonic) {
293 unsigned long long l;
294 if (sscanf(monotonic, "%llu", &l) > 0)
295 u->timestamp.monotonic = l;
296 }
297
298 return r;
299 }
300
301 static int user_mkdir_runtime_path(User *u) {
302 char *p;
303 int r;
304
305 assert(u);
306
307 r = mkdir_safe_label("/run/user", 0755, 0, 0);
308 if (r < 0) {
309 log_error("Failed to create /run/user: %s", strerror(-r));
310 return r;
311 }
312
313 if (!u->runtime_path) {
314 if (asprintf(&p, "/run/user/%lu", (unsigned long) u->uid) < 0)
315 return log_oom();
316 } else
317 p = u->runtime_path;
318
319 r = mkdir_safe_label(p, 0700, u->uid, u->gid);
320 if (r < 0) {
321 log_error("Failed to create runtime directory %s: %s", p, strerror(-r));
322 free(p);
323 u->runtime_path = NULL;
324 return r;
325 }
326
327 u->runtime_path = p;
328 return 0;
329 }
330
331 static int user_start_slice(User *u) {
332 char *job;
333 int r;
334
335 assert(u);
336
337 if (!u->slice) {
338 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
339 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *slice;
340 sprintf(lu, "%lu", (unsigned long) u->uid);
341
342 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
343 if (r < 0)
344 return r;
345
346 r = manager_start_unit(u->manager, slice, &error, &job);
347 if (r < 0) {
348 log_error("Failed to start user slice: %s", bus_error_message(&error, r));
349 free(slice);
350 } else {
351 u->slice = slice;
352
353 free(u->slice_job);
354 u->slice_job = job;
355 }
356 }
357
358 if (u->slice)
359 hashmap_put(u->manager->user_units, u->slice, u);
360
361 return 0;
362 }
363
364 static int user_start_service(User *u) {
365 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
366 char *job;
367 int r;
368
369 assert(u);
370
371 if (!u->service) {
372 char lu[DECIMAL_STR_MAX(unsigned long) + 1], *service;
373 sprintf(lu, "%lu", (unsigned long) u->uid);
374
375 service = unit_name_build("user", lu, ".service");
376 if (!service)
377 return log_oom();
378
379 r = manager_start_unit(u->manager, service, &error, &job);
380 if (r < 0) {
381 log_error("Failed to start user service: %s", bus_error_message(&error, r));
382 free(service);
383 } else {
384 u->service = service;
385
386 free(u->service_job);
387 u->service_job = job;
388 }
389 }
390
391 if (u->service)
392 hashmap_put(u->manager->user_units, u->service, u);
393
394 return 0;
395 }
396
397 int user_start(User *u) {
398 int r;
399
400 assert(u);
401
402 if (u->started)
403 return 0;
404
405 log_debug("New user %s logged in.", u->name);
406
407 /* Make XDG_RUNTIME_DIR */
408 r = user_mkdir_runtime_path(u);
409 if (r < 0)
410 return r;
411
412 /* Create cgroup */
413 r = user_start_slice(u);
414 if (r < 0)
415 return r;
416
417 /* Spawn user systemd */
418 r = user_start_service(u);
419 if (r < 0)
420 return r;
421
422 if (!dual_timestamp_is_set(&u->timestamp))
423 dual_timestamp_get(&u->timestamp);
424
425 u->started = true;
426
427 /* Save new user data */
428 user_save(u);
429
430 user_send_signal(u, true);
431
432 return 0;
433 }
434
435 static int user_stop_slice(User *u) {
436 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
437 char *job;
438 int r;
439
440 assert(u);
441
442 if (!u->slice)
443 return 0;
444
445 r = manager_stop_unit(u->manager, u->slice, &error, &job);
446 if (r < 0) {
447 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
448 return r;
449 }
450
451 free(u->slice_job);
452 u->slice_job = job;
453
454 return r;
455 }
456
457 static int user_stop_service(User *u) {
458 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
459 char *job;
460 int r;
461
462 assert(u);
463
464 if (!u->service)
465 return 0;
466
467 r = manager_stop_unit(u->manager, u->service, &error, &job);
468 if (r < 0) {
469 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
470 return r;
471 }
472
473 free(u->service_job);
474 u->service_job = job;
475
476 return r;
477 }
478
479 static int user_remove_runtime_path(User *u) {
480 int r;
481
482 assert(u);
483
484 if (!u->runtime_path)
485 return 0;
486
487 r = rm_rf(u->runtime_path, false, true, false);
488 if (r < 0)
489 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
490
491 free(u->runtime_path);
492 u->runtime_path = NULL;
493
494 return r;
495 }
496
497 int user_stop(User *u, bool force) {
498 Session *s;
499 int r = 0, k;
500 assert(u);
501
502 LIST_FOREACH(sessions_by_user, s, u->sessions) {
503 k = session_stop(s, force);
504 if (k < 0)
505 r = k;
506 }
507
508 /* Kill systemd */
509 k = user_stop_service(u);
510 if (k < 0)
511 r = k;
512
513 /* Kill cgroup */
514 k = user_stop_slice(u);
515 if (k < 0)
516 r = k;
517
518 u->stopping = true;
519
520 user_save(u);
521
522 return r;
523 }
524
525 int user_finalize(User *u) {
526 Session *s;
527 int r = 0, k;
528
529 assert(u);
530
531 if (u->started)
532 log_debug("User %s logged out.", u->name);
533
534 LIST_FOREACH(sessions_by_user, s, u->sessions) {
535 k = session_finalize(s);
536 if (k < 0)
537 r = k;
538 }
539
540 /* Kill XDG_RUNTIME_DIR */
541 k = user_remove_runtime_path(u);
542 if (k < 0)
543 r = k;
544
545 unlink(u->state_file);
546 user_add_to_gc_queue(u);
547
548 if (u->started) {
549 user_send_signal(u, false);
550 u->started = false;
551 }
552
553 return r;
554 }
555
556 int user_get_idle_hint(User *u, dual_timestamp *t) {
557 Session *s;
558 bool idle_hint = true;
559 dual_timestamp ts = { 0, 0 };
560
561 assert(u);
562
563 LIST_FOREACH(sessions_by_user, s, u->sessions) {
564 dual_timestamp k;
565 int ih;
566
567 ih = session_get_idle_hint(s, &k);
568 if (ih < 0)
569 return ih;
570
571 if (!ih) {
572 if (!idle_hint) {
573 if (k.monotonic < ts.monotonic)
574 ts = k;
575 } else {
576 idle_hint = false;
577 ts = k;
578 }
579 } else if (idle_hint) {
580
581 if (k.monotonic > ts.monotonic)
582 ts = k;
583 }
584 }
585
586 if (t)
587 *t = ts;
588
589 return idle_hint;
590 }
591
592 int user_check_linger_file(User *u) {
593 _cleanup_free_ char *cc = NULL;
594 char *p = NULL;
595
596 cc = cescape(u->name);
597 if (!cc)
598 return -ENOMEM;
599
600 p = strappenda("/var/lib/systemd/linger/", cc);
601
602 return access(p, F_OK) >= 0;
603 }
604
605 bool user_check_gc(User *u, bool drop_not_started) {
606 assert(u);
607
608 if (drop_not_started && !u->started)
609 return false;
610
611 if (u->sessions)
612 return true;
613
614 if (user_check_linger_file(u) > 0)
615 return true;
616
617 if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
618 return true;
619
620 if (u->service_job && manager_job_is_active(u->manager, u->service_job))
621 return true;
622
623 return false;
624 }
625
626 void user_add_to_gc_queue(User *u) {
627 assert(u);
628
629 if (u->in_gc_queue)
630 return;
631
632 LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
633 u->in_gc_queue = true;
634 }
635
636 UserState user_get_state(User *u) {
637 Session *i;
638
639 assert(u);
640
641 if (u->stopping)
642 return USER_CLOSING;
643
644 if (u->slice_job || u->service_job)
645 return USER_OPENING;
646
647 if (u->sessions) {
648 bool all_closing = true;
649
650 LIST_FOREACH(sessions_by_user, i, u->sessions) {
651 SessionState state;
652
653 state = session_get_state(i);
654 if (state == SESSION_ACTIVE)
655 return USER_ACTIVE;
656 if (state != SESSION_CLOSING)
657 all_closing = false;
658 }
659
660 return all_closing ? USER_CLOSING : USER_ONLINE;
661 }
662
663 if (user_check_linger_file(u) > 0)
664 return USER_LINGERING;
665
666 return USER_CLOSING;
667 }
668
669 int user_kill(User *u, int signo) {
670 assert(u);
671
672 if (!u->slice)
673 return -ESRCH;
674
675 return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
676 }
677
678 static const char* const user_state_table[_USER_STATE_MAX] = {
679 [USER_OFFLINE] = "offline",
680 [USER_OPENING] = "opening",
681 [USER_LINGERING] = "lingering",
682 [USER_ONLINE] = "online",
683 [USER_ACTIVE] = "active",
684 [USER_CLOSING] = "closing"
685 };
686
687 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);