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