]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/sd-login.c
nspawn: introduce the new /machine/ tree in the cgroup tree and move containers there
[thirdparty/systemd.git] / src / login / sd-login.c
CommitLineData
74b91131
LP
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
5430f7f2
LP
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
74b91131
LP
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
5430f7f2 16 Lesser General Public License for more details.
74b91131 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
74b91131
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
23#include <string.h>
24#include <errno.h>
034a2a52 25#include <sys/inotify.h>
dace83cb 26#include <sys/poll.h>
74b91131
LP
27
28#include "util.h"
29#include "cgroup-util.h"
30#include "macro.h"
31#include "sd-login.h"
034a2a52 32#include "strv.h"
a5c32cff 33#include "fileio.h"
74b91131 34
034a2a52 35_public_ int sd_pid_get_session(pid_t pid, char **session) {
ba1261bc
LP
36 if (pid < 0)
37 return -EINVAL;
38
034a2a52
LP
39 if (!session)
40 return -EINVAL;
41
7027ff61 42 return cg_pid_get_session(pid, session);
74b91131
LP
43}
44
94fb446e 45_public_ int sd_pid_get_unit(pid_t pid, char **unit) {
9847946e 46
ba1261bc 47 if (pid < 0)
9847946e 48 return -EINVAL;
ba1261bc
LP
49 if (!unit)
50 return -EINVAL;
9847946e 51
ba1261bc 52 return cg_pid_get_unit(pid, unit);
9847946e
LP
53}
54
97e13058
LP
55_public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
56
57 if (pid < 0)
58 return -EINVAL;
97e13058
LP
59 if (!unit)
60 return -EINVAL;
61
62 return cg_pid_get_user_unit(pid, unit);
63}
64
7027ff61
LP
65_public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
66
67 if (pid < 0)
68 return -EINVAL;
69 if (!name)
70 return -EINVAL;
71
72 return cg_pid_get_machine_name(pid, name);
73}
74
034a2a52
LP
75_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
76 int r;
77 char *root, *cgroup, *p, *cc;
78 struct stat st;
79
ba1261bc
LP
80 if (pid < 0)
81 return -EINVAL;
82
034a2a52
LP
83 if (!uid)
84 return -EINVAL;
85
7027ff61 86 r = cg_pid_get_path_shifted(pid, &root, &cgroup);
034a2a52
LP
87 if (r < 0)
88 return r;
89
90 if (!startswith(cgroup, "/user/")) {
91 free(cgroup);
92 free(root);
93 return -ENOENT;
94 }
95
96 p = strchr(cgroup + 6, '/');
97 if (!p) {
98 free(cgroup);
99 return -ENOENT;
100 }
101
102 p++;
103 p += strcspn(p, "/");
104 *p = 0;
105
106 r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc);
107 free(root);
108 free(cgroup);
109
110 if (r < 0)
111 return -ENOMEM;
112
113 r = lstat(cc, &st);
114 free(cc);
115
116 if (r < 0)
117 return -errno;
118
119 if (!S_ISDIR(st.st_mode))
120 return -ENOTDIR;
121
122 *uid = st.st_uid;
123 return 0;
124}
125
74b91131
LP
126_public_ int sd_uid_get_state(uid_t uid, char**state) {
127 char *p, *s = NULL;
128 int r;
129
130 if (!state)
131 return -EINVAL;
132
133 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
134 return -ENOMEM;
135
136 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
137 free(p);
138
139 if (r == -ENOENT) {
140 free(s);
141 s = strdup("offline");
142 if (!s)
143 return -ENOMEM;
144
145 *state = s;
146 return 0;
147 } else if (r < 0) {
148 free(s);
149 return r;
150 } else if (!s)
151 return -EIO;
152
153 *state = s;
154 return 0;
155}
156
034a2a52 157_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
74b91131
LP
158 char *p, *w, *t, *state, *s = NULL;
159 size_t l;
160 int r;
034a2a52 161 const char *variable;
74b91131
LP
162
163 if (!seat)
164 return -EINVAL;
165
034a2a52
LP
166 variable = require_active ? "ACTIVE_UID" : "UIDS";
167
74b91131
LP
168 p = strappend("/run/systemd/seats/", seat);
169 if (!p)
170 return -ENOMEM;
171
034a2a52 172 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
74b91131
LP
173 free(p);
174
175 if (r < 0) {
176 free(s);
177 return r;
178 }
179
180 if (!s)
181 return -EIO;
182
183 if (asprintf(&t, "%lu", (unsigned long) uid) < 0) {
184 free(s);
185 return -ENOMEM;
186 }
187
188 FOREACH_WORD(w, l, s, state) {
641906e9 189 if (strneq(t, w, l)) {
74b91131
LP
190 free(s);
191 free(t);
192
193 return 1;
194 }
195 }
196
197 free(s);
198 free(t);
199
200 return 0;
201}
202
034a2a52
LP
203static int uid_get_array(uid_t uid, const char *variable, char ***array) {
204 char *p, *s = NULL;
205 char **a;
206 int r;
207
034a2a52
LP
208 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
209 return -ENOMEM;
210
211 r = parse_env_file(p, NEWLINE,
212 variable, &s,
213 NULL);
214 free(p);
215
216 if (r < 0) {
217 free(s);
218
219 if (r == -ENOENT) {
d60ef526
LP
220 if (array)
221 *array = NULL;
034a2a52
LP
222 return 0;
223 }
224
225 return r;
226 }
227
228 if (!s) {
d60ef526
LP
229 if (array)
230 *array = NULL;
034a2a52
LP
231 return 0;
232 }
233
234 a = strv_split(s, " ");
235 free(s);
236
237 if (!a)
238 return -ENOMEM;
239
d60ef526
LP
240 strv_uniq(a);
241 r = strv_length(a);
242
243 if (array)
244 *array = a;
245 else
246 strv_free(a);
247
248 return r;
034a2a52
LP
249}
250
251_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
d18dff43
LP
252 return uid_get_array(
253 uid,
254 require_active == 0 ? "ONLINE_SESSIONS" :
255 require_active > 0 ? "ACTIVE_SESSIONS" :
256 "SESSIONS",
257 sessions);
74b91131
LP
258}
259
034a2a52 260_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
d18dff43
LP
261 return uid_get_array(
262 uid,
263 require_active == 0 ? "ONLINE_SEATS" :
264 require_active > 0 ? "ACTIVE_SEATS" :
265 "SEATS",
266 seats);
74b91131
LP
267}
268
50b1678a
LP
269static int file_of_session(const char *session, char **_p) {
270 char *p;
74b91131 271 int r;
74b91131 272
50b1678a
LP
273 assert(_p);
274
275 if (session)
276 p = strappend("/run/systemd/sessions/", session);
277 else {
278 char *buf;
279
280 r = sd_pid_get_session(0, &buf);
281 if (r < 0)
282 return r;
283
284 p = strappend("/run/systemd/sessions/", buf);
285 free(buf);
286 }
74b91131 287
74b91131
LP
288 if (!p)
289 return -ENOMEM;
290
50b1678a
LP
291 *_p = p;
292 return 0;
293}
294
295_public_ int sd_session_is_active(const char *session) {
296 int r;
297 char *p, *s = NULL;
298
299 r = file_of_session(session, &p);
300 if (r < 0)
301 return r;
302
74b91131
LP
303 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
304 free(p);
305
306 if (r < 0) {
307 free(s);
308 return r;
309 }
310
311 if (!s)
312 return -EIO;
313
314 r = parse_boolean(s);
315 free(s);
316
317 return r;
318}
319
0604381b
LP
320_public_ int sd_session_get_state(const char *session, char **state) {
321 char *p, *s = NULL;
322 int r;
323
324 if (!state)
325 return -EINVAL;
326
327 r = file_of_session(session, &p);
328 if (r < 0)
329 return r;
330
331 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
332 free(p);
333
334 if (r < 0) {
335 free(s);
336 return r;
337 } else if (!s)
338 return -EIO;
339
340 *state = s;
341 return 0;
342}
343
74b91131
LP
344_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
345 int r;
346 char *p, *s = NULL;
74b91131 347
74b91131
LP
348 if (!uid)
349 return -EINVAL;
350
50b1678a
LP
351 r = file_of_session(session, &p);
352 if (r < 0)
353 return r;
74b91131
LP
354
355 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
356 free(p);
357
358 if (r < 0) {
359 free(s);
360 return r;
361 }
362
363 if (!s)
364 return -EIO;
365
ddd88763 366 r = parse_uid(s, uid);
74b91131
LP
367 free(s);
368
ddd88763 369 return r;
74b91131
LP
370}
371
51f58f08 372static int session_get_string(const char *session, const char *field, char **value) {
74b91131
LP
373 char *p, *s = NULL;
374 int r;
375
51f58f08 376 if (!value)
74b91131
LP
377 return -EINVAL;
378
50b1678a
LP
379 r = file_of_session(session, &p);
380 if (r < 0)
381 return r;
74b91131 382
51f58f08 383 r = parse_env_file(p, NEWLINE, field, &s, NULL);
74b91131
LP
384 free(p);
385
386 if (r < 0) {
387 free(s);
388 return r;
389 }
390
391 if (isempty(s))
392 return -ENOENT;
393
51f58f08 394 *value = s;
74b91131
LP
395 return 0;
396}
397
51f58f08
LP
398_public_ int sd_session_get_seat(const char *session, char **seat) {
399 return session_get_string(session, "SEAT", seat);
400}
eff40633 401
c84f5e4a
LP
402_public_ int sd_session_get_tty(const char *session, char **tty) {
403 return session_get_string(session, "TTY", tty);
404}
405
51f58f08
LP
406_public_ int sd_session_get_service(const char *session, char **service) {
407 return session_get_string(session, "SERVICE", service);
408}
eff40633 409
51f58f08
LP
410_public_ int sd_session_get_type(const char *session, char **type) {
411 return session_get_string(session, "TYPE", type);
412}
eff40633 413
51f58f08
LP
414_public_ int sd_session_get_class(const char *session, char **class) {
415 return session_get_string(session, "CLASS", class);
eff40633
LP
416}
417
fc8af9ff
LP
418_public_ int sd_session_get_display(const char *session, char **display) {
419 return session_get_string(session, "DISPLAY", display);
420}
421
50b1678a
LP
422static int file_of_seat(const char *seat, char **_p) {
423 char *p;
424 int r;
425
426 assert(_p);
427
428 if (seat)
429 p = strappend("/run/systemd/seats/", seat);
430 else {
431 char *buf;
432
433 r = sd_session_get_seat(NULL, &buf);
434 if (r < 0)
435 return r;
436
437 p = strappend("/run/systemd/seats/", buf);
438 free(buf);
439 }
440
441 if (!p)
442 return -ENOMEM;
443
444 *_p = p;
445 return 0;
446}
447
74b91131
LP
448_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
449 char *p, *s = NULL, *t = NULL;
450 int r;
451
74b91131
LP
452 if (!session && !uid)
453 return -EINVAL;
454
50b1678a
LP
455 r = file_of_seat(seat, &p);
456 if (r < 0)
457 return r;
74b91131
LP
458
459 r = parse_env_file(p, NEWLINE,
460 "ACTIVE", &s,
461 "ACTIVE_UID", &t,
462 NULL);
463 free(p);
464
465 if (r < 0) {
466 free(s);
467 free(t);
468 return r;
469 }
470
471 if (session && !s) {
472 free(t);
034a2a52 473 return -ENOENT;
74b91131
LP
474 }
475
476 if (uid && !t) {
477 free(s);
034a2a52 478 return -ENOENT;
74b91131
LP
479 }
480
481 if (uid && t) {
034a2a52 482 r = parse_uid(t, uid);
74b91131
LP
483 if (r < 0) {
484 free(t);
485 free(s);
486 return r;
487 }
74b91131
LP
488 }
489
490 free(t);
491
492 if (session && s)
493 *session = s;
494 else
495 free(s);
496
497 return 0;
498}
034a2a52
LP
499
500_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
501 char *p, *s = NULL, *t = NULL, **a = NULL;
502 uid_t *b = NULL;
503 unsigned n = 0;
504 int r;
505
50b1678a
LP
506 r = file_of_seat(seat, &p);
507 if (r < 0)
508 return r;
034a2a52
LP
509
510 r = parse_env_file(p, NEWLINE,
511 "SESSIONS", &s,
512 "ACTIVE_SESSIONS", &t,
513 NULL);
514 free(p);
515
516 if (r < 0) {
517 free(s);
518 free(t);
519 return r;
520 }
521
d60ef526 522 if (s) {
034a2a52
LP
523 a = strv_split(s, " ");
524 if (!a) {
525 free(s);
526 free(t);
527 return -ENOMEM;
528 }
529 }
530
531 free(s);
532
533 if (uids && t) {
534 char *w, *state;
535 size_t l;
034a2a52
LP
536
537 FOREACH_WORD(w, l, t, state)
538 n++;
539
de3756ab
LP
540 if (n == 0)
541 b = NULL;
542 else {
543 unsigned i = 0;
034a2a52 544
de3756ab
LP
545 b = new(uid_t, n);
546 if (!b) {
8ea913b2 547 strv_free(a);
034a2a52
LP
548 return -ENOMEM;
549 }
550
de3756ab
LP
551 FOREACH_WORD(w, l, t, state) {
552 char *k;
034a2a52 553
de3756ab
LP
554 k = strndup(w, l);
555 if (!k) {
556 free(t);
557 free(b);
558 strv_free(a);
559 return -ENOMEM;
560 }
561
562 r = parse_uid(k, b + i);
563 free(k);
564 if (r < 0)
565 continue;
566
567 i++;
568 }
034a2a52
LP
569 }
570 }
571
572 free(t);
573
d60ef526
LP
574 r = strv_length(a);
575
034a2a52
LP
576 if (sessions)
577 *sessions = a;
d60ef526
LP
578 else
579 strv_free(a);
034a2a52
LP
580
581 if (uids)
582 *uids = b;
583
584 if (n_uids)
585 *n_uids = n;
586
d60ef526 587 return r;
034a2a52
LP
588}
589
20747498 590static int seat_get_can(const char *seat, const char *variable) {
add30678
LP
591 char *p, *s = NULL;
592 int r;
593
50b1678a
LP
594 r = file_of_seat(seat, &p);
595 if (r < 0)
596 return r;
add30678
LP
597
598 r = parse_env_file(p, NEWLINE,
20747498 599 variable, &s,
add30678
LP
600 NULL);
601 free(p);
602
603 if (r < 0) {
604 free(s);
605 return r;
606 }
607
608 if (s) {
609 r = parse_boolean(s);
610 free(s);
611 } else
612 r = 0;
613
614 return r;
615}
616
20747498
LP
617_public_ int sd_seat_can_multi_session(const char *seat) {
618 return seat_get_can(seat, "CAN_MULTI_SESSION");
619}
620
621_public_ int sd_seat_can_tty(const char *seat) {
622 return seat_get_can(seat, "CAN_TTY");
623}
624
625_public_ int sd_seat_can_graphical(const char *seat) {
626 return seat_get_can(seat, "CAN_GRAPHICAL");
627}
628
034a2a52 629_public_ int sd_get_seats(char ***seats) {
034a2a52
LP
630 return get_files_in_directory("/run/systemd/seats/", seats);
631}
632
633_public_ int sd_get_sessions(char ***sessions) {
034a2a52
LP
634 return get_files_in_directory("/run/systemd/sessions/", sessions);
635}
636
637_public_ int sd_get_uids(uid_t **users) {
638 DIR *d;
639 int r = 0;
640 unsigned n = 0;
641 uid_t *l = NULL;
642
034a2a52 643 d = opendir("/run/systemd/users/");
8ea913b2
LP
644 if (!d)
645 return -errno;
646
034a2a52 647 for (;;) {
7d5e9c0f
LP
648 struct dirent *de;
649 union dirent_storage buf;
034a2a52
LP
650 int k;
651 uid_t uid;
652
7d5e9c0f 653 k = readdir_r(d, &buf.de, &de);
034a2a52
LP
654 if (k != 0) {
655 r = -k;
656 goto finish;
657 }
658
659 if (!de)
660 break;
661
662 dirent_ensure_type(d, de);
663
664 if (!dirent_is_file(de))
665 continue;
666
667 k = parse_uid(de->d_name, &uid);
668 if (k < 0)
669 continue;
670
d60ef526
LP
671 if (users) {
672 if ((unsigned) r >= n) {
673 uid_t *t;
034a2a52 674
d60ef526
LP
675 n = MAX(16, 2*r);
676 t = realloc(l, sizeof(uid_t) * n);
677 if (!t) {
678 r = -ENOMEM;
679 goto finish;
680 }
034a2a52 681
d60ef526
LP
682 l = t;
683 }
034a2a52 684
d60ef526
LP
685 assert((unsigned) r < n);
686 l[r++] = uid;
687 } else
688 r++;
034a2a52
LP
689 }
690
691finish:
692 if (d)
693 closedir(d);
694
d60ef526
LP
695 if (r >= 0) {
696 if (users)
697 *users = l;
698 } else
034a2a52
LP
699 free(l);
700
701 return r;
702}
703
704static inline int MONITOR_TO_FD(sd_login_monitor *m) {
705 return (int) (unsigned long) m - 1;
706}
707
708static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
709 return (sd_login_monitor*) (unsigned long) (fd + 1);
710}
711
712_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
034a2a52
LP
713 int fd, k;
714 bool good = false;
715
716 if (!m)
717 return -EINVAL;
718
719 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
720 if (fd < 0)
bcb161b0 721 return -errno;
034a2a52
LP
722
723 if (!category || streq(category, "seat")) {
724 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
725 if (k < 0) {
726 close_nointr_nofail(fd);
727 return -errno;
728 }
729
730 good = true;
731 }
732
733 if (!category || streq(category, "session")) {
734 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
735 if (k < 0) {
736 close_nointr_nofail(fd);
737 return -errno;
738 }
739
740 good = true;
741 }
742
743 if (!category || streq(category, "uid")) {
744 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
745 if (k < 0) {
746 close_nointr_nofail(fd);
747 return -errno;
748 }
749
750 good = true;
751 }
752
753 if (!good) {
754 close_nointr(fd);
755 return -EINVAL;
756 }
757
758 *m = FD_TO_MONITOR(fd);
759 return 0;
760}
761
762_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
763 int fd;
764
765 if (!m)
766 return NULL;
767
768 fd = MONITOR_TO_FD(m);
769 close_nointr(fd);
770
771 return NULL;
772}
773
774_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
775
776 if (!m)
777 return -EINVAL;
778
779 return flush_fd(MONITOR_TO_FD(m));
780}
781
782_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
783
784 if (!m)
785 return -EINVAL;
786
787 return MONITOR_TO_FD(m);
788}
dace83cb
LP
789
790_public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
791
792 if (!m)
793 return -EINVAL;
794
667c24a6
LP
795 /* For now we will only return POLLIN here, since we don't
796 * need anything else ever for inotify. However, let's have
797 * this API to keep our options open should we later on need
798 * it. */
dace83cb
LP
799 return POLLIN;
800}
667c24a6
LP
801
802_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
803
804 if (!m)
805 return -EINVAL;
806 if (!timeout_usec)
807 return -EINVAL;
808
809 /* For now we will only return (uint64_t) -1, since we don't
810 * need any timeout. However, let's have this API to keep our
811 * options open should we later on need it. */
812 *timeout_usec = (uint64_t) -1;
813 return 0;
814}