]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/sd-login.c
core: failed scope units may not be restarted
[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
1021b21b
LP
75_public_ int sd_pid_get_slice(pid_t pid, char **slice) {
76
77 if (pid < 0)
78 return -EINVAL;
79 if (!slice)
80 return -EINVAL;
81
82 return cg_pid_get_slice(pid, slice);
83}
84
034a2a52 85_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
034a2a52 86
ba1261bc
LP
87 if (pid < 0)
88 return -EINVAL;
89
034a2a52
LP
90 if (!uid)
91 return -EINVAL;
92
ae018d9b 93 return cg_pid_get_owner_uid(pid, uid);
034a2a52
LP
94}
95
74b91131
LP
96_public_ int sd_uid_get_state(uid_t uid, char**state) {
97 char *p, *s = NULL;
98 int r;
99
100 if (!state)
101 return -EINVAL;
102
103 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
104 return -ENOMEM;
105
106 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
107 free(p);
108
109 if (r == -ENOENT) {
110 free(s);
111 s = strdup("offline");
112 if (!s)
113 return -ENOMEM;
114
115 *state = s;
116 return 0;
117 } else if (r < 0) {
118 free(s);
119 return r;
120 } else if (!s)
121 return -EIO;
122
123 *state = s;
124 return 0;
125}
126
034a2a52 127_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
d70964d0
HH
128 char *w, *state;
129 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
74b91131
LP
130 size_t l;
131 int r;
034a2a52 132 const char *variable;
74b91131
LP
133
134 if (!seat)
135 return -EINVAL;
136
034a2a52
LP
137 variable = require_active ? "ACTIVE_UID" : "UIDS";
138
74b91131
LP
139 p = strappend("/run/systemd/seats/", seat);
140 if (!p)
141 return -ENOMEM;
142
034a2a52 143 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
74b91131 144
d70964d0 145 if (r < 0)
74b91131 146 return r;
74b91131
LP
147
148 if (!s)
149 return -EIO;
150
d70964d0 151 if (asprintf(&t, "%lu", (unsigned long) uid) < 0)
74b91131 152 return -ENOMEM;
74b91131
LP
153
154 FOREACH_WORD(w, l, s, state) {
d70964d0 155 if (strneq(t, w, l))
74b91131 156 return 1;
74b91131
LP
157 }
158
74b91131
LP
159 return 0;
160}
161
034a2a52 162static int uid_get_array(uid_t uid, const char *variable, char ***array) {
d70964d0 163 _cleanup_free_ char *p = NULL, *s = NULL;
034a2a52
LP
164 char **a;
165 int r;
166
034a2a52
LP
167 if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0)
168 return -ENOMEM;
169
170 r = parse_env_file(p, NEWLINE,
171 variable, &s,
172 NULL);
034a2a52 173 if (r < 0) {
034a2a52 174 if (r == -ENOENT) {
d60ef526
LP
175 if (array)
176 *array = NULL;
034a2a52
LP
177 return 0;
178 }
179
180 return r;
181 }
182
183 if (!s) {
d60ef526
LP
184 if (array)
185 *array = NULL;
034a2a52
LP
186 return 0;
187 }
188
189 a = strv_split(s, " ");
034a2a52
LP
190
191 if (!a)
192 return -ENOMEM;
193
d60ef526
LP
194 strv_uniq(a);
195 r = strv_length(a);
196
197 if (array)
198 *array = a;
199 else
200 strv_free(a);
201
202 return r;
034a2a52
LP
203}
204
205_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
d18dff43
LP
206 return uid_get_array(
207 uid,
208 require_active == 0 ? "ONLINE_SESSIONS" :
209 require_active > 0 ? "ACTIVE_SESSIONS" :
210 "SESSIONS",
211 sessions);
74b91131
LP
212}
213
034a2a52 214_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
d18dff43
LP
215 return uid_get_array(
216 uid,
217 require_active == 0 ? "ONLINE_SEATS" :
218 require_active > 0 ? "ACTIVE_SEATS" :
219 "SEATS",
220 seats);
74b91131
LP
221}
222
50b1678a
LP
223static int file_of_session(const char *session, char **_p) {
224 char *p;
74b91131 225 int r;
74b91131 226
50b1678a
LP
227 assert(_p);
228
229 if (session)
230 p = strappend("/run/systemd/sessions/", session);
231 else {
232 char *buf;
233
234 r = sd_pid_get_session(0, &buf);
235 if (r < 0)
236 return r;
237
238 p = strappend("/run/systemd/sessions/", buf);
239 free(buf);
240 }
74b91131 241
74b91131
LP
242 if (!p)
243 return -ENOMEM;
244
50b1678a
LP
245 *_p = p;
246 return 0;
247}
248
249_public_ int sd_session_is_active(const char *session) {
250 int r;
d70964d0 251 _cleanup_free_ char *p = NULL, *s = NULL;
50b1678a
LP
252
253 r = file_of_session(session, &p);
254 if (r < 0)
255 return r;
256
74b91131 257 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
74b91131 258
d70964d0 259 if (r < 0)
74b91131 260 return r;
74b91131
LP
261
262 if (!s)
263 return -EIO;
264
265 r = parse_boolean(s);
74b91131
LP
266
267 return r;
268}
269
0604381b 270_public_ int sd_session_get_state(const char *session, char **state) {
d70964d0 271 _cleanup_free_ char *p = NULL, *s = NULL;
0604381b
LP
272 int r;
273
274 if (!state)
275 return -EINVAL;
276
277 r = file_of_session(session, &p);
278 if (r < 0)
279 return r;
280
281 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
0604381b 282
d70964d0 283 if (r < 0)
0604381b 284 return r;
d70964d0 285 else if (!s)
0604381b
LP
286 return -EIO;
287
288 *state = s;
d70964d0
HH
289 s = NULL;
290
0604381b
LP
291 return 0;
292}
293
74b91131
LP
294_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
295 int r;
d70964d0 296 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131 297
74b91131
LP
298 if (!uid)
299 return -EINVAL;
300
50b1678a
LP
301 r = file_of_session(session, &p);
302 if (r < 0)
303 return r;
74b91131
LP
304
305 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
74b91131 306
d70964d0 307 if (r < 0)
74b91131 308 return r;
74b91131
LP
309
310 if (!s)
311 return -EIO;
312
ddd88763 313 r = parse_uid(s, uid);
74b91131 314
ddd88763 315 return r;
74b91131
LP
316}
317
51f58f08 318static int session_get_string(const char *session, const char *field, char **value) {
d70964d0 319 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131
LP
320 int r;
321
51f58f08 322 if (!value)
74b91131
LP
323 return -EINVAL;
324
50b1678a
LP
325 r = file_of_session(session, &p);
326 if (r < 0)
327 return r;
74b91131 328
51f58f08 329 r = parse_env_file(p, NEWLINE, field, &s, NULL);
74b91131 330
d70964d0 331 if (r < 0)
74b91131 332 return r;
74b91131
LP
333
334 if (isempty(s))
335 return -ENOENT;
336
51f58f08 337 *value = s;
d70964d0 338 s = NULL;
74b91131
LP
339 return 0;
340}
341
51f58f08
LP
342_public_ int sd_session_get_seat(const char *session, char **seat) {
343 return session_get_string(session, "SEAT", seat);
344}
eff40633 345
c84f5e4a
LP
346_public_ int sd_session_get_tty(const char *session, char **tty) {
347 return session_get_string(session, "TTY", tty);
348}
349
44ded3ab
GC
350_public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
351 _cleanup_free_ char *vtnr_string;
352 unsigned u;
353 int r;
354
355 r = session_get_string(session, "VTNr", &vtnr_string);
356 if (r < 0)
357 return r;
358
359 r = safe_atou(vtnr_string, &u);
360 if (r < 0)
361 return r;
362
363 *vtnr = u;
364 return 0;
365}
366
51f58f08
LP
367_public_ int sd_session_get_service(const char *session, char **service) {
368 return session_get_string(session, "SERVICE", service);
369}
eff40633 370
51f58f08
LP
371_public_ int sd_session_get_type(const char *session, char **type) {
372 return session_get_string(session, "TYPE", type);
373}
eff40633 374
51f58f08
LP
375_public_ int sd_session_get_class(const char *session, char **class) {
376 return session_get_string(session, "CLASS", class);
eff40633
LP
377}
378
fc8af9ff
LP
379_public_ int sd_session_get_display(const char *session, char **display) {
380 return session_get_string(session, "DISPLAY", display);
381}
382
50b1678a
LP
383static int file_of_seat(const char *seat, char **_p) {
384 char *p;
385 int r;
386
387 assert(_p);
388
389 if (seat)
390 p = strappend("/run/systemd/seats/", seat);
391 else {
d70964d0 392 _cleanup_free_ char *buf = NULL;
50b1678a
LP
393
394 r = sd_session_get_seat(NULL, &buf);
395 if (r < 0)
396 return r;
397
398 p = strappend("/run/systemd/seats/", buf);
50b1678a
LP
399 }
400
401 if (!p)
402 return -ENOMEM;
403
404 *_p = p;
d70964d0 405 p = NULL;
50b1678a
LP
406 return 0;
407}
408
74b91131 409_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
d70964d0 410 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
74b91131
LP
411 int r;
412
74b91131
LP
413 if (!session && !uid)
414 return -EINVAL;
415
50b1678a
LP
416 r = file_of_seat(seat, &p);
417 if (r < 0)
418 return r;
74b91131
LP
419
420 r = parse_env_file(p, NEWLINE,
421 "ACTIVE", &s,
422 "ACTIVE_UID", &t,
423 NULL);
d70964d0 424 if (r < 0)
74b91131 425 return r;
74b91131 426
d70964d0 427 if (session && !s)
034a2a52 428 return -ENOENT;
74b91131 429
d70964d0 430 if (uid && !t)
034a2a52 431 return -ENOENT;
74b91131
LP
432
433 if (uid && t) {
034a2a52 434 r = parse_uid(t, uid);
d70964d0 435 if (r < 0)
74b91131 436 return r;
74b91131
LP
437 }
438
d70964d0 439 if (session && s) {
74b91131 440 *session = s;
d70964d0
HH
441 s = NULL;
442 }
74b91131
LP
443
444 return 0;
445}
034a2a52
LP
446
447_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
d70964d0
HH
448 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
449 _cleanup_strv_free_ char **a = NULL;
450 _cleanup_free_ uid_t *b = NULL;
034a2a52
LP
451 unsigned n = 0;
452 int r;
453
50b1678a
LP
454 r = file_of_seat(seat, &p);
455 if (r < 0)
456 return r;
034a2a52
LP
457
458 r = parse_env_file(p, NEWLINE,
459 "SESSIONS", &s,
460 "ACTIVE_SESSIONS", &t,
461 NULL);
034a2a52 462
d70964d0 463 if (r < 0)
034a2a52 464 return r;
034a2a52 465
d60ef526 466 if (s) {
034a2a52 467 a = strv_split(s, " ");
d70964d0 468 if (!a)
034a2a52 469 return -ENOMEM;
034a2a52
LP
470 }
471
034a2a52
LP
472 if (uids && t) {
473 char *w, *state;
474 size_t l;
034a2a52
LP
475
476 FOREACH_WORD(w, l, t, state)
477 n++;
478
d70964d0 479 if (n > 0) {
de3756ab 480 unsigned i = 0;
034a2a52 481
de3756ab 482 b = new(uid_t, n);
d70964d0 483 if (!b)
034a2a52 484 return -ENOMEM;
034a2a52 485
de3756ab 486 FOREACH_WORD(w, l, t, state) {
d70964d0 487 _cleanup_free_ char *k = NULL;
034a2a52 488
de3756ab 489 k = strndup(w, l);
d70964d0 490 if (!k)
de3756ab 491 return -ENOMEM;
de3756ab
LP
492
493 r = parse_uid(k, b + i);
d70964d0 494
de3756ab
LP
495 if (r < 0)
496 continue;
497
498 i++;
499 }
034a2a52
LP
500 }
501 }
502
d60ef526
LP
503 r = strv_length(a);
504
d70964d0 505 if (sessions) {
034a2a52 506 *sessions = a;
d70964d0
HH
507 a = NULL;
508 }
034a2a52 509
d70964d0 510 if (uids) {
034a2a52 511 *uids = b;
d70964d0
HH
512 b = NULL;
513 }
034a2a52
LP
514
515 if (n_uids)
516 *n_uids = n;
517
d60ef526 518 return r;
034a2a52
LP
519}
520
20747498 521static int seat_get_can(const char *seat, const char *variable) {
d70964d0 522 _cleanup_free_ char *p = NULL, *s = NULL;
add30678
LP
523 int r;
524
50b1678a
LP
525 r = file_of_seat(seat, &p);
526 if (r < 0)
527 return r;
add30678
LP
528
529 r = parse_env_file(p, NEWLINE,
20747498 530 variable, &s,
add30678 531 NULL);
d70964d0 532 if (r < 0)
add30678 533 return r;
add30678 534
d70964d0 535 if (s)
add30678 536 r = parse_boolean(s);
d70964d0 537 else
add30678
LP
538 r = 0;
539
540 return r;
541}
542
20747498
LP
543_public_ int sd_seat_can_multi_session(const char *seat) {
544 return seat_get_can(seat, "CAN_MULTI_SESSION");
545}
546
547_public_ int sd_seat_can_tty(const char *seat) {
548 return seat_get_can(seat, "CAN_TTY");
549}
550
551_public_ int sd_seat_can_graphical(const char *seat) {
552 return seat_get_can(seat, "CAN_GRAPHICAL");
553}
554
034a2a52 555_public_ int sd_get_seats(char ***seats) {
034a2a52
LP
556 return get_files_in_directory("/run/systemd/seats/", seats);
557}
558
559_public_ int sd_get_sessions(char ***sessions) {
034a2a52
LP
560 return get_files_in_directory("/run/systemd/sessions/", sessions);
561}
562
563_public_ int sd_get_uids(uid_t **users) {
d70964d0 564 _cleanup_closedir_ DIR *d;
034a2a52
LP
565 int r = 0;
566 unsigned n = 0;
d70964d0 567 _cleanup_free_ uid_t *l = NULL;
034a2a52 568
034a2a52 569 d = opendir("/run/systemd/users/");
8ea913b2
LP
570 if (!d)
571 return -errno;
572
034a2a52 573 for (;;) {
7d5e9c0f
LP
574 struct dirent *de;
575 union dirent_storage buf;
034a2a52
LP
576 int k;
577 uid_t uid;
578
7d5e9c0f 579 k = readdir_r(d, &buf.de, &de);
d70964d0
HH
580 if (k != 0)
581 return -k;
034a2a52
LP
582
583 if (!de)
584 break;
585
586 dirent_ensure_type(d, de);
587
588 if (!dirent_is_file(de))
589 continue;
590
591 k = parse_uid(de->d_name, &uid);
592 if (k < 0)
593 continue;
594
d60ef526
LP
595 if (users) {
596 if ((unsigned) r >= n) {
597 uid_t *t;
034a2a52 598
d60ef526
LP
599 n = MAX(16, 2*r);
600 t = realloc(l, sizeof(uid_t) * n);
d70964d0
HH
601 if (!t)
602 return -ENOMEM;
034a2a52 603
d60ef526
LP
604 l = t;
605 }
034a2a52 606
d60ef526
LP
607 assert((unsigned) r < n);
608 l[r++] = uid;
609 } else
610 r++;
034a2a52
LP
611 }
612
d70964d0
HH
613 if (users) {
614 *users = l;
615 l = NULL;
616 }
034a2a52
LP
617
618 return r;
619}
620
4d5fb962 621_public_ int sd_get_machine_names(char ***machines) {
ba73ed85 622 return get_files_in_directory("/run/systemd/machines/", machines);
a20affe2
LP
623}
624
034a2a52
LP
625static inline int MONITOR_TO_FD(sd_login_monitor *m) {
626 return (int) (unsigned long) m - 1;
627}
628
629static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
630 return (sd_login_monitor*) (unsigned long) (fd + 1);
631}
632
633_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
034a2a52
LP
634 int fd, k;
635 bool good = false;
636
637 if (!m)
638 return -EINVAL;
639
640 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
641 if (fd < 0)
bcb161b0 642 return -errno;
034a2a52
LP
643
644 if (!category || streq(category, "seat")) {
645 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
646 if (k < 0) {
647 close_nointr_nofail(fd);
648 return -errno;
649 }
650
651 good = true;
652 }
653
654 if (!category || streq(category, "session")) {
655 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
656 if (k < 0) {
657 close_nointr_nofail(fd);
658 return -errno;
659 }
660
661 good = true;
662 }
663
664 if (!category || streq(category, "uid")) {
665 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
666 if (k < 0) {
667 close_nointr_nofail(fd);
668 return -errno;
669 }
670
671 good = true;
672 }
673
e10375f2 674 if (!category || streq(category, "machine")) {
ba73ed85 675 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
e10375f2
LP
676 if (k < 0) {
677 close_nointr_nofail(fd);
678 return -errno;
679 }
680
681 good = true;
682 }
683
034a2a52
LP
684 if (!good) {
685 close_nointr(fd);
686 return -EINVAL;
687 }
688
689 *m = FD_TO_MONITOR(fd);
690 return 0;
691}
692
693_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
694 int fd;
695
696 if (!m)
697 return NULL;
698
699 fd = MONITOR_TO_FD(m);
700 close_nointr(fd);
701
702 return NULL;
703}
704
705_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
706
707 if (!m)
708 return -EINVAL;
709
710 return flush_fd(MONITOR_TO_FD(m));
711}
712
713_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
714
715 if (!m)
716 return -EINVAL;
717
718 return MONITOR_TO_FD(m);
719}
dace83cb
LP
720
721_public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
722
723 if (!m)
724 return -EINVAL;
725
667c24a6
LP
726 /* For now we will only return POLLIN here, since we don't
727 * need anything else ever for inotify. However, let's have
728 * this API to keep our options open should we later on need
729 * it. */
dace83cb
LP
730 return POLLIN;
731}
667c24a6
LP
732
733_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
734
735 if (!m)
736 return -EINVAL;
737 if (!timeout_usec)
738 return -EINVAL;
739
740 /* For now we will only return (uint64_t) -1, since we don't
741 * need any timeout. However, let's have this API to keep our
742 * options open should we later on need it. */
743 *timeout_usec = (uint64_t) -1;
744 return 0;
745}