chiark / gitweb /
login: Allow calling org.freedesktop.login1.Seat.SwitchTo
[elogind.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         /* Stop jobs have already been queued */
503         if (u->stopping) {
504                 user_save(u);
505                 return r;
506         }
507
508         LIST_FOREACH(sessions_by_user, s, u->sessions) {
509                 k = session_stop(s, force);
510                 if (k < 0)
511                         r = k;
512         }
513
514         /* Kill systemd */
515         k = user_stop_service(u);
516         if (k < 0)
517                 r = k;
518
519         /* Kill cgroup */
520         k = user_stop_slice(u);
521         if (k < 0)
522                 r = k;
523
524         u->stopping = true;
525
526         user_save(u);
527
528         return r;
529 }
530
531 int user_finalize(User *u) {
532         Session *s;
533         int r = 0, k;
534
535         assert(u);
536
537         if (u->started)
538                 log_debug("User %s logged out.", u->name);
539
540         LIST_FOREACH(sessions_by_user, s, u->sessions) {
541                 k = session_finalize(s);
542                 if (k < 0)
543                         r = k;
544         }
545
546         /* Kill XDG_RUNTIME_DIR */
547         k = user_remove_runtime_path(u);
548         if (k < 0)
549                 r = k;
550
551         unlink(u->state_file);
552         user_add_to_gc_queue(u);
553
554         if (u->started) {
555                 user_send_signal(u, false);
556                 u->started = false;
557         }
558
559         return r;
560 }
561
562 int user_get_idle_hint(User *u, dual_timestamp *t) {
563         Session *s;
564         bool idle_hint = true;
565         dual_timestamp ts = { 0, 0 };
566
567         assert(u);
568
569         LIST_FOREACH(sessions_by_user, s, u->sessions) {
570                 dual_timestamp k;
571                 int ih;
572
573                 ih = session_get_idle_hint(s, &k);
574                 if (ih < 0)
575                         return ih;
576
577                 if (!ih) {
578                         if (!idle_hint) {
579                                 if (k.monotonic < ts.monotonic)
580                                         ts = k;
581                         } else {
582                                 idle_hint = false;
583                                 ts = k;
584                         }
585                 } else if (idle_hint) {
586
587                         if (k.monotonic > ts.monotonic)
588                                 ts = k;
589                 }
590         }
591
592         if (t)
593                 *t = ts;
594
595         return idle_hint;
596 }
597
598 int user_check_linger_file(User *u) {
599         _cleanup_free_ char *cc = NULL;
600         char *p = NULL;
601
602         cc = cescape(u->name);
603         if (!cc)
604                 return -ENOMEM;
605
606         p = strappenda("/var/lib/systemd/linger/", cc);
607
608         return access(p, F_OK) >= 0;
609 }
610
611 bool user_check_gc(User *u, bool drop_not_started) {
612         assert(u);
613
614         if (drop_not_started && !u->started)
615                 return false;
616
617         if (u->sessions)
618                 return true;
619
620         if (user_check_linger_file(u) > 0)
621                 return true;
622
623         if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
624                 return true;
625
626         if (u->service_job && manager_job_is_active(u->manager, u->service_job))
627                 return true;
628
629         return false;
630 }
631
632 void user_add_to_gc_queue(User *u) {
633         assert(u);
634
635         if (u->in_gc_queue)
636                 return;
637
638         LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
639         u->in_gc_queue = true;
640 }
641
642 UserState user_get_state(User *u) {
643         Session *i;
644
645         assert(u);
646
647         if (u->stopping)
648                 return USER_CLOSING;
649
650         if (u->slice_job || u->service_job)
651                 return USER_OPENING;
652
653         if (u->sessions) {
654                 bool all_closing = true;
655
656                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
657                         SessionState state;
658
659                         state = session_get_state(i);
660                         if (state == SESSION_ACTIVE)
661                                 return USER_ACTIVE;
662                         if (state != SESSION_CLOSING)
663                                 all_closing = false;
664                 }
665
666                 return all_closing ? USER_CLOSING : USER_ONLINE;
667         }
668
669         if (user_check_linger_file(u) > 0)
670                 return USER_LINGERING;
671
672         return USER_CLOSING;
673 }
674
675 int user_kill(User *u, int signo) {
676         assert(u);
677
678         if (!u->slice)
679                 return -ESRCH;
680
681         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
682 }
683
684 static const char* const user_state_table[_USER_STATE_MAX] = {
685         [USER_OFFLINE] = "offline",
686         [USER_OPENING] = "opening",
687         [USER_LINGERING] = "lingering",
688         [USER_ONLINE] = "online",
689         [USER_ACTIVE] = "active",
690         [USER_CLOSING] = "closing"
691 };
692
693 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);