]> git.ipfire.org Git - thirdparty/systemd.git/blob - 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
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 <unistd.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <sys/inotify.h>
26 #include <sys/poll.h>
27
28 #include "util.h"
29 #include "cgroup-util.h"
30 #include "macro.h"
31 #include "sd-login.h"
32 #include "strv.h"
33 #include "fileio.h"
34
35 _public_ int sd_pid_get_session(pid_t pid, char **session) {
36 if (pid < 0)
37 return -EINVAL;
38
39 if (!session)
40 return -EINVAL;
41
42 return cg_pid_get_session(pid, session);
43 }
44
45 _public_ int sd_pid_get_unit(pid_t pid, char **unit) {
46
47 if (pid < 0)
48 return -EINVAL;
49 if (!unit)
50 return -EINVAL;
51
52 return cg_pid_get_unit(pid, unit);
53 }
54
55 _public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
56
57 if (pid < 0)
58 return -EINVAL;
59 if (!unit)
60 return -EINVAL;
61
62 return cg_pid_get_user_unit(pid, unit);
63 }
64
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
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
80 if (pid < 0)
81 return -EINVAL;
82
83 if (!uid)
84 return -EINVAL;
85
86 r = cg_pid_get_path_shifted(pid, &root, &cgroup);
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
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
157 _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
158 char *p, *w, *t, *state, *s = NULL;
159 size_t l;
160 int r;
161 const char *variable;
162
163 if (!seat)
164 return -EINVAL;
165
166 variable = require_active ? "ACTIVE_UID" : "UIDS";
167
168 p = strappend("/run/systemd/seats/", seat);
169 if (!p)
170 return -ENOMEM;
171
172 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
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) {
189 if (strneq(t, w, l)) {
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
203 static int uid_get_array(uid_t uid, const char *variable, char ***array) {
204 char *p, *s = NULL;
205 char **a;
206 int r;
207
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) {
220 if (array)
221 *array = NULL;
222 return 0;
223 }
224
225 return r;
226 }
227
228 if (!s) {
229 if (array)
230 *array = NULL;
231 return 0;
232 }
233
234 a = strv_split(s, " ");
235 free(s);
236
237 if (!a)
238 return -ENOMEM;
239
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;
249 }
250
251 _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
252 return uid_get_array(
253 uid,
254 require_active == 0 ? "ONLINE_SESSIONS" :
255 require_active > 0 ? "ACTIVE_SESSIONS" :
256 "SESSIONS",
257 sessions);
258 }
259
260 _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
261 return uid_get_array(
262 uid,
263 require_active == 0 ? "ONLINE_SEATS" :
264 require_active > 0 ? "ACTIVE_SEATS" :
265 "SEATS",
266 seats);
267 }
268
269 static int file_of_session(const char *session, char **_p) {
270 char *p;
271 int r;
272
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 }
287
288 if (!p)
289 return -ENOMEM;
290
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
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
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
344 _public_ int sd_session_get_uid(const char *session, uid_t *uid) {
345 int r;
346 char *p, *s = NULL;
347
348 if (!uid)
349 return -EINVAL;
350
351 r = file_of_session(session, &p);
352 if (r < 0)
353 return r;
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
366 r = parse_uid(s, uid);
367 free(s);
368
369 return r;
370 }
371
372 static int session_get_string(const char *session, const char *field, char **value) {
373 char *p, *s = NULL;
374 int r;
375
376 if (!value)
377 return -EINVAL;
378
379 r = file_of_session(session, &p);
380 if (r < 0)
381 return r;
382
383 r = parse_env_file(p, NEWLINE, field, &s, NULL);
384 free(p);
385
386 if (r < 0) {
387 free(s);
388 return r;
389 }
390
391 if (isempty(s))
392 return -ENOENT;
393
394 *value = s;
395 return 0;
396 }
397
398 _public_ int sd_session_get_seat(const char *session, char **seat) {
399 return session_get_string(session, "SEAT", seat);
400 }
401
402 _public_ int sd_session_get_tty(const char *session, char **tty) {
403 return session_get_string(session, "TTY", tty);
404 }
405
406 _public_ int sd_session_get_service(const char *session, char **service) {
407 return session_get_string(session, "SERVICE", service);
408 }
409
410 _public_ int sd_session_get_type(const char *session, char **type) {
411 return session_get_string(session, "TYPE", type);
412 }
413
414 _public_ int sd_session_get_class(const char *session, char **class) {
415 return session_get_string(session, "CLASS", class);
416 }
417
418 _public_ int sd_session_get_display(const char *session, char **display) {
419 return session_get_string(session, "DISPLAY", display);
420 }
421
422 static 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
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
452 if (!session && !uid)
453 return -EINVAL;
454
455 r = file_of_seat(seat, &p);
456 if (r < 0)
457 return r;
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);
473 return -ENOENT;
474 }
475
476 if (uid && !t) {
477 free(s);
478 return -ENOENT;
479 }
480
481 if (uid && t) {
482 r = parse_uid(t, uid);
483 if (r < 0) {
484 free(t);
485 free(s);
486 return r;
487 }
488 }
489
490 free(t);
491
492 if (session && s)
493 *session = s;
494 else
495 free(s);
496
497 return 0;
498 }
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
506 r = file_of_seat(seat, &p);
507 if (r < 0)
508 return r;
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
522 if (s) {
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;
536
537 FOREACH_WORD(w, l, t, state)
538 n++;
539
540 if (n == 0)
541 b = NULL;
542 else {
543 unsigned i = 0;
544
545 b = new(uid_t, n);
546 if (!b) {
547 strv_free(a);
548 return -ENOMEM;
549 }
550
551 FOREACH_WORD(w, l, t, state) {
552 char *k;
553
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 }
569 }
570 }
571
572 free(t);
573
574 r = strv_length(a);
575
576 if (sessions)
577 *sessions = a;
578 else
579 strv_free(a);
580
581 if (uids)
582 *uids = b;
583
584 if (n_uids)
585 *n_uids = n;
586
587 return r;
588 }
589
590 static int seat_get_can(const char *seat, const char *variable) {
591 char *p, *s = NULL;
592 int r;
593
594 r = file_of_seat(seat, &p);
595 if (r < 0)
596 return r;
597
598 r = parse_env_file(p, NEWLINE,
599 variable, &s,
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
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
629 _public_ int sd_get_seats(char ***seats) {
630 return get_files_in_directory("/run/systemd/seats/", seats);
631 }
632
633 _public_ int sd_get_sessions(char ***sessions) {
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
643 d = opendir("/run/systemd/users/");
644 if (!d)
645 return -errno;
646
647 for (;;) {
648 struct dirent *de;
649 union dirent_storage buf;
650 int k;
651 uid_t uid;
652
653 k = readdir_r(d, &buf.de, &de);
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
671 if (users) {
672 if ((unsigned) r >= n) {
673 uid_t *t;
674
675 n = MAX(16, 2*r);
676 t = realloc(l, sizeof(uid_t) * n);
677 if (!t) {
678 r = -ENOMEM;
679 goto finish;
680 }
681
682 l = t;
683 }
684
685 assert((unsigned) r < n);
686 l[r++] = uid;
687 } else
688 r++;
689 }
690
691 finish:
692 if (d)
693 closedir(d);
694
695 if (r >= 0) {
696 if (users)
697 *users = l;
698 } else
699 free(l);
700
701 return r;
702 }
703
704 static inline int MONITOR_TO_FD(sd_login_monitor *m) {
705 return (int) (unsigned long) m - 1;
706 }
707
708 static 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) {
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)
721 return -errno;
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 }
789
790 _public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
791
792 if (!m)
793 return -EINVAL;
794
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. */
799 return POLLIN;
800 }
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 }