chiark / gitweb /
bus-policy: append items rather than prepending them
[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 <sys/mount.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <errno.h>
26
27 #include "util.h"
28 #include "mkdir.h"
29 #include "hashmap.h"
30 #include "strv.h"
31 #include "fileio.h"
32 #include "path-util.h"
33 #include "special.h"
34 #include "unit-name.h"
35 #include "bus-util.h"
36 #include "bus-error.h"
37 #include "conf-parser.h"
38 #include "clean-ipc.h"
39 #include "logind-user.h"
40
41 User* user_new(Manager *m, uid_t uid, gid_t gid, const char *name) {
42         User *u;
43
44         assert(m);
45         assert(name);
46
47         u = new0(User, 1);
48         if (!u)
49                 return NULL;
50
51         u->name = strdup(name);
52         if (!u->name)
53                 goto fail;
54
55         if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
56                 goto fail;
57
58         if (hashmap_put(m->users, ULONG_TO_PTR((unsigned long) uid), u) < 0)
59                 goto fail;
60
61         u->manager = m;
62         u->uid = uid;
63         u->gid = gid;
64
65         return u;
66
67 fail:
68         free(u->state_file);
69         free(u->name);
70         free(u);
71
72         return NULL;
73 }
74
75 void user_free(User *u) {
76         assert(u);
77
78         if (u->in_gc_queue)
79                 LIST_REMOVE(gc_queue, u->manager->user_gc_queue, u);
80
81         while (u->sessions)
82                 session_free(u->sessions);
83
84         if (u->slice) {
85                 hashmap_remove(u->manager->user_units, u->slice);
86                 free(u->slice);
87         }
88
89         if (u->service) {
90                 hashmap_remove(u->manager->user_units, u->service);
91                 free(u->service);
92         }
93
94         free(u->slice_job);
95         free(u->service_job);
96
97         free(u->runtime_path);
98
99         hashmap_remove(u->manager->users, ULONG_TO_PTR((unsigned long) u->uid));
100
101         free(u->name);
102         free(u->state_file);
103         free(u);
104 }
105
106 int user_save(User *u) {
107         _cleanup_free_ char *temp_path = NULL;
108         _cleanup_fclose_ FILE *f = NULL;
109         int r;
110
111         assert(u);
112         assert(u->state_file);
113
114         if (!u->started)
115                 return 0;
116
117         r = mkdir_safe_label("/run/systemd/users", 0755, 0, 0);
118         if (r < 0)
119                 goto finish;
120
121         r = fopen_temporary(u->state_file, &f, &temp_path);
122         if (r < 0)
123                 goto finish;
124
125         fchmod(fileno(f), 0644);
126
127         fprintf(f,
128                 "# This is private data. Do not parse.\n"
129                 "NAME=%s\n"
130                 "STATE=%s\n",
131                 u->name,
132                 user_state_to_string(user_get_state(u)));
133
134         if (u->runtime_path)
135                 fprintf(f, "RUNTIME=%s\n", u->runtime_path);
136
137         if (u->service)
138                 fprintf(f, "SERVICE=%s\n", u->service);
139         if (u->service_job)
140                 fprintf(f, "SERVICE_JOB=%s\n", u->service_job);
141
142         if (u->slice)
143                 fprintf(f, "SLICE=%s\n", u->slice);
144         if (u->slice_job)
145                 fprintf(f, "SLICE_JOB=%s\n", u->slice_job);
146
147         if (u->display)
148                 fprintf(f, "DISPLAY=%s\n", u->display->id);
149
150         if (dual_timestamp_is_set(&u->timestamp))
151                 fprintf(f,
152                         "REALTIME="USEC_FMT"\n"
153                         "MONOTONIC="USEC_FMT"\n",
154                         u->timestamp.realtime,
155                         u->timestamp.monotonic);
156
157         if (u->sessions) {
158                 Session *i;
159                 bool first;
160
161                 fputs("SESSIONS=", f);
162                 first = true;
163                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
164                         if (first)
165                                 first = false;
166                         else
167                                 fputc(' ', f);
168
169                         fputs(i->id, f);
170                 }
171
172                 fputs("\nSEATS=", f);
173                 first = true;
174                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
175                         if (!i->seat)
176                                 continue;
177
178                         if (first)
179                                 first = false;
180                         else
181                                 fputc(' ', f);
182
183                         fputs(i->seat->id, f);
184                 }
185
186                 fputs("\nACTIVE_SESSIONS=", f);
187                 first = true;
188                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
189                         if (!session_is_active(i))
190                                 continue;
191
192                         if (first)
193                                 first = false;
194                         else
195                                 fputc(' ', f);
196
197                         fputs(i->id, f);
198                 }
199
200                 fputs("\nONLINE_SESSIONS=", f);
201                 first = true;
202                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
203                         if (session_get_state(i) == SESSION_CLOSING)
204                                 continue;
205
206                         if (first)
207                                 first = false;
208                         else
209                                 fputc(' ', f);
210
211                         fputs(i->id, f);
212                 }
213
214                 fputs("\nACTIVE_SEATS=", f);
215                 first = true;
216                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
217                         if (!session_is_active(i) || !i->seat)
218                                 continue;
219
220                         if (first)
221                                 first = false;
222                         else
223                                 fputc(' ', f);
224
225                         fputs(i->seat->id, f);
226                 }
227
228                 fputs("\nONLINE_SEATS=", f);
229                 first = true;
230                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
231                         if (session_get_state(i) == SESSION_CLOSING || !i->seat)
232                                 continue;
233
234                         if (first)
235                                 first = false;
236                         else
237                                 fputc(' ', f);
238
239                         fputs(i->seat->id, f);
240                 }
241                 fputc('\n', f);
242         }
243
244         fflush(f);
245
246         if (ferror(f) || rename(temp_path, u->state_file) < 0) {
247                 r = -errno;
248                 unlink(u->state_file);
249                 unlink(temp_path);
250         }
251
252 finish:
253         if (r < 0)
254                 log_error("Failed to save user data %s: %s", u->state_file, strerror(-r));
255
256         return r;
257 }
258
259 int user_load(User *u) {
260         _cleanup_free_ char *display = NULL, *realtime = NULL, *monotonic = NULL;
261         Session *s = NULL;
262         int r;
263
264         assert(u);
265
266         r = parse_env_file(u->state_file, NEWLINE,
267                            "RUNTIME",     &u->runtime_path,
268                            "SERVICE",     &u->service,
269                            "SERVICE_JOB", &u->service_job,
270                            "SLICE",       &u->slice,
271                            "SLICE_JOB",   &u->slice_job,
272                            "DISPLAY",     &display,
273                            "REALTIME",    &realtime,
274                            "MONOTONIC",   &monotonic,
275                            NULL);
276         if (r < 0) {
277                 if (r == -ENOENT)
278                         return 0;
279
280                 log_error("Failed to read %s: %s", u->state_file, strerror(-r));
281                 return r;
282         }
283
284         if (display)
285                 s = hashmap_get(u->manager->sessions, display);
286
287         if (s && s->display && display_is_local(s->display))
288                 u->display = s;
289
290         if (realtime) {
291                 unsigned long long l;
292                 if (sscanf(realtime, "%llu", &l) > 0)
293                         u->timestamp.realtime = l;
294         }
295
296         if (monotonic) {
297                 unsigned long long l;
298                 if (sscanf(monotonic, "%llu", &l) > 0)
299                         u->timestamp.monotonic = l;
300         }
301
302         return r;
303 }
304
305 static int user_mkdir_runtime_path(User *u) {
306         char *p;
307         int r;
308
309         assert(u);
310
311         r = mkdir_safe_label("/run/user", 0755, 0, 0);
312         if (r < 0) {
313                 log_error("Failed to create /run/user: %s", strerror(-r));
314                 return r;
315         }
316
317         if (!u->runtime_path) {
318                 if (asprintf(&p, "/run/user/" UID_FMT, u->uid) < 0)
319                         return log_oom();
320         } else
321                 p = u->runtime_path;
322
323         if (path_is_mount_point(p, false) <= 0) {
324                 _cleanup_free_ char *t = NULL;
325
326                 mkdir(p, 0700);
327
328                 if (asprintf(&t, "mode=0700,uid=" UID_FMT ",gid=" GID_FMT ",size=%zu", u->uid, u->gid, u->manager->runtime_dir_size) < 0) {
329                         r = log_oom();
330                         goto fail;
331                 }
332
333                 r = mount("tmpfs", p, "tmpfs", MS_NODEV|MS_NOSUID, t);
334                 if (r < 0) {
335                         log_error("Failed to mount per-user tmpfs directory %s: %s", p, strerror(-r));
336                         goto fail;
337                 }
338         }
339
340         u->runtime_path = p;
341         return 0;
342
343 fail:
344         free(p);
345         u->runtime_path = NULL;
346         return r;
347 }
348
349 static int user_start_slice(User *u) {
350         char *job;
351         int r;
352
353         assert(u);
354
355         if (!u->slice) {
356                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
357                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *slice;
358                 sprintf(lu, UID_FMT, u->uid);
359
360                 r = build_subslice(SPECIAL_USER_SLICE, lu, &slice);
361                 if (r < 0)
362                         return r;
363
364                 r = manager_start_unit(u->manager, slice, &error, &job);
365                 if (r < 0) {
366                         log_error("Failed to start user slice: %s", bus_error_message(&error, r));
367                         free(slice);
368                 } else {
369                         u->slice = slice;
370
371                         free(u->slice_job);
372                         u->slice_job = job;
373                 }
374         }
375
376         if (u->slice)
377                 hashmap_put(u->manager->user_units, u->slice, u);
378
379         return 0;
380 }
381
382 static int user_start_service(User *u) {
383         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
384         char *job;
385         int r;
386
387         assert(u);
388
389         if (!u->service) {
390                 char lu[DECIMAL_STR_MAX(uid_t) + 1], *service;
391                 sprintf(lu, UID_FMT, u->uid);
392
393                 service = unit_name_build("user", lu, ".service");
394                 if (!service)
395                         return log_oom();
396
397                 r = manager_start_unit(u->manager, service, &error, &job);
398                 if (r < 0) {
399                         log_error("Failed to start user service: %s", bus_error_message(&error, r));
400                         free(service);
401                 } else {
402                         u->service = service;
403
404                         free(u->service_job);
405                         u->service_job = job;
406                 }
407         }
408
409         if (u->service)
410                 hashmap_put(u->manager->user_units, u->service, u);
411
412         return 0;
413 }
414
415 int user_start(User *u) {
416         int r;
417
418         assert(u);
419
420         if (u->started)
421                 return 0;
422
423         log_debug("New user %s logged in.", u->name);
424
425         /* Make XDG_RUNTIME_DIR */
426         r = user_mkdir_runtime_path(u);
427         if (r < 0)
428                 return r;
429
430         /* Create cgroup */
431         r = user_start_slice(u);
432         if (r < 0)
433                 return r;
434
435         /* Spawn user systemd */
436         r = user_start_service(u);
437         if (r < 0)
438                 return r;
439
440         if (!dual_timestamp_is_set(&u->timestamp))
441                 dual_timestamp_get(&u->timestamp);
442
443         u->started = true;
444
445         /* Save new user data */
446         user_save(u);
447
448         user_send_signal(u, true);
449
450         return 0;
451 }
452
453 static int user_stop_slice(User *u) {
454         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
455         char *job;
456         int r;
457
458         assert(u);
459
460         if (!u->slice)
461                 return 0;
462
463         r = manager_stop_unit(u->manager, u->slice, &error, &job);
464         if (r < 0) {
465                 log_error("Failed to stop user slice: %s", bus_error_message(&error, r));
466                 return r;
467         }
468
469         free(u->slice_job);
470         u->slice_job = job;
471
472         return r;
473 }
474
475 static int user_stop_service(User *u) {
476         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
477         char *job;
478         int r;
479
480         assert(u);
481
482         if (!u->service)
483                 return 0;
484
485         r = manager_stop_unit(u->manager, u->service, &error, &job);
486         if (r < 0) {
487                 log_error("Failed to stop user service: %s", bus_error_message(&error, r));
488                 return r;
489         }
490
491         free(u->service_job);
492         u->service_job = job;
493
494         return r;
495 }
496
497 static int user_remove_runtime_path(User *u) {
498         int r;
499
500         assert(u);
501
502         if (!u->runtime_path)
503                 return 0;
504
505         r = rm_rf(u->runtime_path, false, false, false);
506         if (r < 0)
507                 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
508
509         if (umount2(u->runtime_path, MNT_DETACH) < 0)
510                 log_error("Failed to unmount user runtime directory %s: %m", u->runtime_path);
511
512         r = rm_rf(u->runtime_path, false, true, false);
513         if (r < 0)
514                 log_error("Failed to remove runtime directory %s: %s", u->runtime_path, strerror(-r));
515
516         free(u->runtime_path);
517         u->runtime_path = NULL;
518
519         return r;
520 }
521
522 int user_stop(User *u, bool force) {
523         Session *s;
524         int r = 0, k;
525         assert(u);
526
527         /* Stop jobs have already been queued */
528         if (u->stopping) {
529                 user_save(u);
530                 return r;
531         }
532
533         LIST_FOREACH(sessions_by_user, s, u->sessions) {
534                 k = session_stop(s, force);
535                 if (k < 0)
536                         r = k;
537         }
538
539         /* Kill systemd */
540         k = user_stop_service(u);
541         if (k < 0)
542                 r = k;
543
544         /* Kill cgroup */
545         k = user_stop_slice(u);
546         if (k < 0)
547                 r = k;
548
549         u->stopping = true;
550
551         user_save(u);
552
553         return r;
554 }
555
556 int user_finalize(User *u) {
557         Session *s;
558         int r = 0, k;
559
560         assert(u);
561
562         if (u->started)
563                 log_debug("User %s logged out.", u->name);
564
565         LIST_FOREACH(sessions_by_user, s, u->sessions) {
566                 k = session_finalize(s);
567                 if (k < 0)
568                         r = k;
569         }
570
571         /* Kill XDG_RUNTIME_DIR */
572         k = user_remove_runtime_path(u);
573         if (k < 0)
574                 r = k;
575
576         /* Clean SysV + POSIX IPC objects */
577         if (u->manager->remove_ipc) {
578                 k = clean_ipc(u->uid);
579                 if (k < 0)
580                         r = k;
581         }
582
583         unlink(u->state_file);
584         user_add_to_gc_queue(u);
585
586         if (u->started) {
587                 user_send_signal(u, false);
588                 u->started = false;
589         }
590
591         return r;
592 }
593
594 int user_get_idle_hint(User *u, dual_timestamp *t) {
595         Session *s;
596         bool idle_hint = true;
597         dual_timestamp ts = { 0, 0 };
598
599         assert(u);
600
601         LIST_FOREACH(sessions_by_user, s, u->sessions) {
602                 dual_timestamp k;
603                 int ih;
604
605                 ih = session_get_idle_hint(s, &k);
606                 if (ih < 0)
607                         return ih;
608
609                 if (!ih) {
610                         if (!idle_hint) {
611                                 if (k.monotonic < ts.monotonic)
612                                         ts = k;
613                         } else {
614                                 idle_hint = false;
615                                 ts = k;
616                         }
617                 } else if (idle_hint) {
618
619                         if (k.monotonic > ts.monotonic)
620                                 ts = k;
621                 }
622         }
623
624         if (t)
625                 *t = ts;
626
627         return idle_hint;
628 }
629
630 int user_check_linger_file(User *u) {
631         _cleanup_free_ char *cc = NULL;
632         char *p = NULL;
633
634         cc = cescape(u->name);
635         if (!cc)
636                 return -ENOMEM;
637
638         p = strappenda("/var/lib/systemd/linger/", cc);
639
640         return access(p, F_OK) >= 0;
641 }
642
643 bool user_check_gc(User *u, bool drop_not_started) {
644         assert(u);
645
646         if (drop_not_started && !u->started)
647                 return false;
648
649         if (u->sessions)
650                 return true;
651
652         if (user_check_linger_file(u) > 0)
653                 return true;
654
655         if (u->slice_job && manager_job_is_active(u->manager, u->slice_job))
656                 return true;
657
658         if (u->service_job && manager_job_is_active(u->manager, u->service_job))
659                 return true;
660
661         return false;
662 }
663
664 void user_add_to_gc_queue(User *u) {
665         assert(u);
666
667         if (u->in_gc_queue)
668                 return;
669
670         LIST_PREPEND(gc_queue, u->manager->user_gc_queue, u);
671         u->in_gc_queue = true;
672 }
673
674 UserState user_get_state(User *u) {
675         Session *i;
676
677         assert(u);
678
679         if (u->stopping)
680                 return USER_CLOSING;
681
682         if (u->slice_job || u->service_job)
683                 return USER_OPENING;
684
685         if (u->sessions) {
686                 bool all_closing = true;
687
688                 LIST_FOREACH(sessions_by_user, i, u->sessions) {
689                         SessionState state;
690
691                         state = session_get_state(i);
692                         if (state == SESSION_ACTIVE)
693                                 return USER_ACTIVE;
694                         if (state != SESSION_CLOSING)
695                                 all_closing = false;
696                 }
697
698                 return all_closing ? USER_CLOSING : USER_ONLINE;
699         }
700
701         if (user_check_linger_file(u) > 0)
702                 return USER_LINGERING;
703
704         return USER_CLOSING;
705 }
706
707 int user_kill(User *u, int signo) {
708         assert(u);
709
710         if (!u->slice)
711                 return -ESRCH;
712
713         return manager_kill_unit(u->manager, u->slice, KILL_ALL, signo, NULL);
714 }
715
716 void user_elect_display(User *u) {
717         Session *graphical = NULL, *text = NULL, *other = NULL, *s;
718
719         assert(u);
720
721         /* This elects a primary session for each user, which we call
722          * the "display". We try to keep the assignment stable, but we
723          * "upgrade" to better choices. */
724
725         LIST_FOREACH(sessions_by_user, s, u->sessions) {
726
727                 if (s->class != SESSION_USER)
728                         continue;
729
730                 if (s->stopping)
731                         continue;
732
733                 if (SESSION_TYPE_IS_GRAPHICAL(s->type))
734                         graphical = s;
735                 else if (s->type == SESSION_TTY)
736                         text = s;
737                 else
738                         other = s;
739         }
740
741         if (graphical &&
742             (!u->display ||
743              u->display->class != SESSION_USER ||
744              u->display->stopping ||
745              !SESSION_TYPE_IS_GRAPHICAL(u->display->type))) {
746                 u->display = graphical;
747                 return;
748         }
749
750         if (text &&
751             (!u->display ||
752              u->display->class != SESSION_USER ||
753              u->display->stopping ||
754              u->display->type != SESSION_TTY)) {
755                 u->display = text;
756                 return;
757         }
758
759         if (other &&
760             (!u->display ||
761              u->display->class != SESSION_USER ||
762              u->display->stopping))
763                 u->display = other;
764 }
765
766 static const char* const user_state_table[_USER_STATE_MAX] = {
767         [USER_OFFLINE] = "offline",
768         [USER_OPENING] = "opening",
769         [USER_LINGERING] = "lingering",
770         [USER_ONLINE] = "online",
771         [USER_ACTIVE] = "active",
772         [USER_CLOSING] = "closing"
773 };
774
775 DEFINE_STRING_TABLE_LOOKUP(user_state, UserState);
776
777 int config_parse_tmpfs_size(
778                 const char* unit,
779                 const char *filename,
780                 unsigned line,
781                 const char *section,
782                 unsigned section_line,
783                 const char *lvalue,
784                 int ltype,
785                 const char *rvalue,
786                 void *data,
787                 void *userdata) {
788
789         size_t *sz = data;
790         const char *e;
791         int r;
792
793         assert(filename);
794         assert(lvalue);
795         assert(rvalue);
796         assert(data);
797
798         e = endswith(rvalue, "%");
799         if (e) {
800                 unsigned long ul;
801                 char *f;
802
803                 errno = 0;
804                 ul = strtoul(rvalue, &f, 10);
805                 if (errno != 0 || f != e) {
806                         log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Failed to parse percentage value, ignoring: %s", rvalue);
807                         return 0;
808                 }
809
810                 if (ul <= 0 || ul >= 100) {
811                         log_syntax(unit, LOG_ERR, filename, line, errno ? errno : EINVAL, "Percentage value out of range, ignoring: %s", rvalue);
812                         return 0;
813                 }
814
815                 *sz = PAGE_ALIGN((size_t) ((physical_memory() * (uint64_t) ul) / (uint64_t) 100));
816         } else {
817                 off_t o;
818
819                 r = parse_size(rvalue, 1024, &o);
820                 if (r < 0 || (off_t) (size_t) o != o) {
821                         log_syntax(unit, LOG_ERR, filename, line, r < 0 ? -r : ERANGE, "Failed to parse size value, ignoring: %s", rvalue);
822                         return 0;
823                 }
824
825                 *sz = PAGE_ALIGN((size_t) o);
826         }
827
828         return 0;
829 }