]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-login/sd-login.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / libsystemd / sd-login / sd-login.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
74b91131 2/***
74b91131 3 Copyright 2011 Lennart Poettering
74b91131
LP
4***/
5
74b91131 6#include <errno.h>
0a6f50c0 7#include <poll.h>
4f5dd394
LP
8#include <string.h>
9#include <sys/inotify.h>
10#include <unistd.h>
74b91131 11
07630cea
LP
12#include "sd-login.h"
13
b5efdb8a 14#include "alloc-util.h"
74b91131 15#include "cgroup-util.h"
f4f15635 16#include "dirent-util.h"
4f5dd394 17#include "escape.h"
3ffd4af2 18#include "fd-util.h"
a5c32cff 19#include "fileio.h"
f97b34a6 20#include "format-util.h"
f4f15635 21#include "fs-util.h"
25300b5a 22#include "hostname-util.h"
c004493c 23#include "io-util.h"
4f5dd394
LP
24#include "login-util.h"
25#include "macro.h"
6bedfcbb 26#include "parse-util.h"
bb15fafe 27#include "path-util.h"
2583fbea 28#include "socket-util.h"
07630cea 29#include "string-util.h"
4f5dd394 30#include "strv.h"
b1d4f8e1 31#include "user-util.h"
4f5dd394 32#include "util.h"
74b91131 33
707b66c6
LP
34/* Error codes:
35 *
36 * invalid input parameters → -EINVAL
37 * invalid fd → -EBADF
38 * process does not exist → -ESRCH
39 * cgroup does not exist → -ENOENT
40 * machine, session does not exist → -ENXIO
41 * requested metadata on object is missing → -ENODATA
42 */
43
034a2a52 44_public_ int sd_pid_get_session(pid_t pid, char **session) {
19d64d10 45 int r;
ba1261bc 46
1ae464e0
TA
47 assert_return(pid >= 0, -EINVAL);
48 assert_return(session, -EINVAL);
034a2a52 49
19d64d10 50 r = cg_pid_get_session(pid, session);
bc9e9af1 51 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
74b91131
LP
52}
53
94fb446e 54_public_ int sd_pid_get_unit(pid_t pid, char **unit) {
171f8f59 55 int r;
9847946e 56
1ae464e0
TA
57 assert_return(pid >= 0, -EINVAL);
58 assert_return(unit, -EINVAL);
9847946e 59
171f8f59 60 r = cg_pid_get_unit(pid, unit);
bc9e9af1 61 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
9847946e
LP
62}
63
97e13058 64_public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
d440fb97 65 int r;
97e13058 66
1ae464e0
TA
67 assert_return(pid >= 0, -EINVAL);
68 assert_return(unit, -EINVAL);
97e13058 69
d440fb97 70 r = cg_pid_get_user_unit(pid, unit);
bc9e9af1 71 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
97e13058
LP
72}
73
7027ff61 74_public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
bc9e9af1 75 int r;
7027ff61 76
1ae464e0
TA
77 assert_return(pid >= 0, -EINVAL);
78 assert_return(name, -EINVAL);
7027ff61 79
bc9e9af1
ZJS
80 r = cg_pid_get_machine_name(pid, name);
81 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
7027ff61
LP
82}
83
1021b21b 84_public_ int sd_pid_get_slice(pid_t pid, char **slice) {
bc9e9af1 85 int r;
1021b21b 86
1ae464e0
TA
87 assert_return(pid >= 0, -EINVAL);
88 assert_return(slice, -EINVAL);
1021b21b 89
bc9e9af1
ZJS
90 r = cg_pid_get_slice(pid, slice);
91 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
1021b21b
LP
92}
93
329ac4bc 94_public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
bc9e9af1 95 int r;
329ac4bc
LP
96
97 assert_return(pid >= 0, -EINVAL);
98 assert_return(slice, -EINVAL);
99
bc9e9af1
ZJS
100 r = cg_pid_get_user_slice(pid, slice);
101 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
329ac4bc
LP
102}
103
034a2a52 104_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
bc9e9af1 105 int r;
034a2a52 106
1ae464e0
TA
107 assert_return(pid >= 0, -EINVAL);
108 assert_return(uid, -EINVAL);
034a2a52 109
bc9e9af1
ZJS
110 r = cg_pid_get_owner_uid(pid, uid);
111 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
034a2a52
LP
112}
113
f5aaf575
LP
114_public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
115 char *c;
116 int r;
117
118 assert_return(pid >= 0, -EINVAL);
119 assert_return(cgroup, -EINVAL);
120
121 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
122 if (r < 0)
123 return r;
124
125 /* The internal APIs return the empty string for the root
126 * cgroup, let's return the "/" in the public APIs instead, as
595bfe7d 127 * that's easier and less ambiguous for people to grok. */
f5aaf575
LP
128 if (isempty(c)) {
129 free(c);
130 c = strdup("/");
131 if (!c)
132 return -ENOMEM;
133
134 }
135
136 *cgroup = c;
137 return 0;
138}
139
bf34ab14 140_public_ int sd_peer_get_session(int fd, char **session) {
a7f7d1bd 141 struct ucred ucred = {};
bf34ab14
LP
142 int r;
143
8ac43fee 144 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
145 assert_return(session, -EINVAL);
146
147 r = getpeercred(fd, &ucred);
148 if (r < 0)
149 return r;
150
151 return cg_pid_get_session(ucred.pid, session);
152}
153
154_public_ int sd_peer_get_owner_uid(int fd, uid_t *uid) {
155 struct ucred ucred;
156 int r;
157
8ac43fee 158 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
159 assert_return(uid, -EINVAL);
160
161 r = getpeercred(fd, &ucred);
162 if (r < 0)
163 return r;
164
165 return cg_pid_get_owner_uid(ucred.pid, uid);
166}
167
168_public_ int sd_peer_get_unit(int fd, char **unit) {
169 struct ucred ucred;
170 int r;
171
8ac43fee 172 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
173 assert_return(unit, -EINVAL);
174
175 r = getpeercred(fd, &ucred);
176 if (r < 0)
177 return r;
178
179 return cg_pid_get_unit(ucred.pid, unit);
180}
181
182_public_ int sd_peer_get_user_unit(int fd, char **unit) {
183 struct ucred ucred;
184 int r;
185
8ac43fee 186 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
187 assert_return(unit, -EINVAL);
188
189 r = getpeercred(fd, &ucred);
190 if (r < 0)
191 return r;
192
193 return cg_pid_get_user_unit(ucred.pid, unit);
194}
195
196_public_ int sd_peer_get_machine_name(int fd, char **machine) {
197 struct ucred ucred;
198 int r;
199
8ac43fee 200 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
201 assert_return(machine, -EINVAL);
202
203 r = getpeercred(fd, &ucred);
204 if (r < 0)
205 return r;
206
207 return cg_pid_get_machine_name(ucred.pid, machine);
208}
209
210_public_ int sd_peer_get_slice(int fd, char **slice) {
211 struct ucred ucred;
212 int r;
213
8ac43fee 214 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
215 assert_return(slice, -EINVAL);
216
217 r = getpeercred(fd, &ucred);
218 if (r < 0)
219 return r;
220
221 return cg_pid_get_slice(ucred.pid, slice);
222}
223
329ac4bc
LP
224_public_ int sd_peer_get_user_slice(int fd, char **slice) {
225 struct ucred ucred;
226 int r;
227
8ac43fee 228 assert_return(fd >= 0, -EBADF);
329ac4bc
LP
229 assert_return(slice, -EINVAL);
230
231 r = getpeercred(fd, &ucred);
232 if (r < 0)
233 return r;
234
235 return cg_pid_get_user_slice(ucred.pid, slice);
236}
237
f5aaf575
LP
238_public_ int sd_peer_get_cgroup(int fd, char **cgroup) {
239 struct ucred ucred;
240 int r;
241
242 assert_return(fd >= 0, -EBADF);
243 assert_return(cgroup, -EINVAL);
244
245 r = getpeercred(fd, &ucred);
246 if (r < 0)
247 return r;
248
249 return sd_pid_get_cgroup(ucred.pid, cgroup);
250}
251
a077b666 252static int file_of_uid(uid_t uid, char **p) {
707b66c6
LP
253
254 assert_return(uid_is_valid(uid), -EINVAL);
a077b666
LP
255 assert(p);
256
257 if (asprintf(p, "/run/systemd/users/" UID_FMT, uid) < 0)
258 return -ENOMEM;
259
260 return 0;
261}
262
74b91131 263_public_ int sd_uid_get_state(uid_t uid, char**state) {
bf34ab14
LP
264 _cleanup_free_ char *p = NULL;
265 char *s = NULL;
74b91131
LP
266 int r;
267
1ae464e0 268 assert_return(state, -EINVAL);
74b91131 269
a077b666
LP
270 r = file_of_uid(uid, &p);
271 if (r < 0)
272 return r;
74b91131 273
1a5a177e 274 r = parse_env_file(NULL, p, NEWLINE, "STATE", &s, NULL);
74b91131
LP
275 if (r == -ENOENT) {
276 free(s);
277 s = strdup("offline");
278 if (!s)
279 return -ENOMEM;
280
707b66c6 281 }
4c4bc546 282 else if (r < 0) {
74b91131
LP
283 free(s);
284 return r;
707b66c6
LP
285 }
286 if (isempty(s)) {
287 free(s);
74b91131 288 return -EIO;
707b66c6 289 }
74b91131
LP
290
291 *state = s;
292 return 0;
293}
294
a077b666
LP
295_public_ int sd_uid_get_display(uid_t uid, char **session) {
296 _cleanup_free_ char *p = NULL, *s = NULL;
297 int r;
298
299 assert_return(session, -EINVAL);
300
301 r = file_of_uid(uid, &p);
302 if (r < 0)
303 return r;
304
1a5a177e 305 r = parse_env_file(NULL, p, NEWLINE, "DISPLAY", &s, NULL);
fc60d815 306 if (r == -ENOENT)
707b66c6 307 return -ENODATA;
a077b666
LP
308 if (r < 0)
309 return r;
a077b666 310 if (isempty(s))
707b66c6 311 return -ENODATA;
a077b666 312
ae2a15bc 313 *session = TAKE_PTR(s);
a077b666
LP
314
315 return 0;
316}
317
707b66c6
LP
318static int file_of_seat(const char *seat, char **_p) {
319 char *p;
320 int r;
321
322 assert(_p);
323
324 if (seat) {
325 if (!filename_is_valid(seat))
326 return -EINVAL;
327
328 p = strappend("/run/systemd/seats/", seat);
329 } else {
330 _cleanup_free_ char *buf = NULL;
331
332 r = sd_session_get_seat(NULL, &buf);
333 if (r < 0)
334 return r;
335
336 p = strappend("/run/systemd/seats/", buf);
337 }
338
339 if (!p)
340 return -ENOMEM;
341
ae2a15bc 342 *_p = TAKE_PTR(p);
707b66c6
LP
343 return 0;
344}
345
034a2a52 346_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
d70964d0 347 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
74b91131
LP
348 size_t l;
349 int r;
a2a5291b 350 const char *word, *variable, *state;
74b91131 351
a1f686da 352 assert_return(uid_is_valid(uid), -EINVAL);
74b91131 353
707b66c6
LP
354 r = file_of_seat(seat, &p);
355 if (r < 0)
356 return r;
034a2a52 357
707b66c6 358 variable = require_active ? "ACTIVE_UID" : "UIDS";
74b91131 359
1a5a177e 360 r = parse_env_file(NULL, p, NEWLINE, variable, &s, NULL);
707b66c6
LP
361 if (r == -ENOENT)
362 return 0;
d70964d0 363 if (r < 0)
74b91131 364 return r;
707b66c6
LP
365 if (isempty(s))
366 return 0;
74b91131 367
de0671ee 368 if (asprintf(&t, UID_FMT, uid) < 0)
74b91131 369 return -ENOMEM;
74b91131 370
707b66c6 371 FOREACH_WORD(word, l, s, state)
a2a5291b 372 if (strneq(t, word, l))
74b91131 373 return 1;
74b91131 374
74b91131
LP
375 return 0;
376}
377
034a2a52 378static int uid_get_array(uid_t uid, const char *variable, char ***array) {
d70964d0 379 _cleanup_free_ char *p = NULL, *s = NULL;
034a2a52
LP
380 char **a;
381 int r;
382
707b66c6 383 assert(variable);
a1f686da 384
a077b666
LP
385 r = file_of_uid(uid, &p);
386 if (r < 0)
387 return r;
034a2a52 388
1a5a177e 389 r = parse_env_file(NULL, p, NEWLINE, variable, &s, NULL);
707b66c6 390 if (r == -ENOENT || (r >= 0 && isempty(s))) {
d60ef526
LP
391 if (array)
392 *array = NULL;
034a2a52
LP
393 return 0;
394 }
707b66c6
LP
395 if (r < 0)
396 return r;
034a2a52
LP
397
398 a = strv_split(s, " ");
034a2a52
LP
399 if (!a)
400 return -ENOMEM;
401
d60ef526 402 strv_uniq(a);
da6053d0 403 r = (int) strv_length(a);
d60ef526
LP
404
405 if (array)
406 *array = a;
407 else
408 strv_free(a);
409
410 return r;
034a2a52
LP
411}
412
413_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
d18dff43
LP
414 return uid_get_array(
415 uid,
416 require_active == 0 ? "ONLINE_SESSIONS" :
417 require_active > 0 ? "ACTIVE_SESSIONS" :
418 "SESSIONS",
419 sessions);
74b91131
LP
420}
421
034a2a52 422_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
d18dff43
LP
423 return uid_get_array(
424 uid,
425 require_active == 0 ? "ONLINE_SEATS" :
426 require_active > 0 ? "ACTIVE_SEATS" :
427 "SEATS",
428 seats);
74b91131
LP
429}
430
50b1678a
LP
431static int file_of_session(const char *session, char **_p) {
432 char *p;
74b91131 433 int r;
74b91131 434
50b1678a
LP
435 assert(_p);
436
4b549144
ZJS
437 if (session) {
438 if (!session_id_valid(session))
439 return -EINVAL;
440
50b1678a 441 p = strappend("/run/systemd/sessions/", session);
4b549144
ZJS
442 } else {
443 _cleanup_free_ char *buf = NULL;
50b1678a
LP
444
445 r = sd_pid_get_session(0, &buf);
446 if (r < 0)
447 return r;
448
449 p = strappend("/run/systemd/sessions/", buf);
50b1678a 450 }
74b91131 451
74b91131
LP
452 if (!p)
453 return -ENOMEM;
454
50b1678a
LP
455 *_p = p;
456 return 0;
457}
458
459_public_ int sd_session_is_active(const char *session) {
d70964d0 460 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 461 int r;
50b1678a
LP
462
463 r = file_of_session(session, &p);
464 if (r < 0)
465 return r;
466
1a5a177e 467 r = parse_env_file(NULL, p, NEWLINE, "ACTIVE", &s, NULL);
707b66c6
LP
468 if (r == -ENOENT)
469 return -ENXIO;
d70964d0 470 if (r < 0)
74b91131 471 return r;
707b66c6 472 if (isempty(s))
74b91131
LP
473 return -EIO;
474
0325941f 475 return parse_boolean(s);
74b91131
LP
476}
477
5b04fe60 478_public_ int sd_session_is_remote(const char *session) {
5b04fe60 479 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 480 int r;
5b04fe60
MM
481
482 r = file_of_session(session, &p);
483 if (r < 0)
484 return r;
485
1a5a177e 486 r = parse_env_file(NULL, p, NEWLINE, "REMOTE", &s, NULL);
707b66c6
LP
487 if (r == -ENOENT)
488 return -ENXIO;
5b04fe60
MM
489 if (r < 0)
490 return r;
707b66c6
LP
491 if (isempty(s))
492 return -ENODATA;
5b04fe60 493
0325941f 494 return parse_boolean(s);
5b04fe60
MM
495}
496
0604381b 497_public_ int sd_session_get_state(const char *session, char **state) {
d70964d0 498 _cleanup_free_ char *p = NULL, *s = NULL;
0604381b
LP
499 int r;
500
1ae464e0 501 assert_return(state, -EINVAL);
0604381b
LP
502
503 r = file_of_session(session, &p);
504 if (r < 0)
505 return r;
506
1a5a177e 507 r = parse_env_file(NULL, p, NEWLINE, "STATE", &s, NULL);
707b66c6
LP
508 if (r == -ENOENT)
509 return -ENXIO;
d70964d0 510 if (r < 0)
0604381b 511 return r;
707b66c6 512 if (isempty(s))
0604381b
LP
513 return -EIO;
514
ae2a15bc 515 *state = TAKE_PTR(s);
d70964d0 516
0604381b
LP
517 return 0;
518}
519
74b91131
LP
520_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
521 int r;
d70964d0 522 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131 523
1ae464e0 524 assert_return(uid, -EINVAL);
74b91131 525
50b1678a
LP
526 r = file_of_session(session, &p);
527 if (r < 0)
528 return r;
74b91131 529
1a5a177e 530 r = parse_env_file(NULL, p, NEWLINE, "UID", &s, NULL);
707b66c6
LP
531 if (r == -ENOENT)
532 return -ENXIO;
d70964d0 533 if (r < 0)
74b91131 534 return r;
707b66c6 535 if (isempty(s))
74b91131
LP
536 return -EIO;
537
0325941f 538 return parse_uid(s, uid);
74b91131
LP
539}
540
51f58f08 541static int session_get_string(const char *session, const char *field, char **value) {
d70964d0 542 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131
LP
543 int r;
544
1ae464e0 545 assert_return(value, -EINVAL);
707b66c6 546 assert(field);
74b91131 547
50b1678a
LP
548 r = file_of_session(session, &p);
549 if (r < 0)
550 return r;
74b91131 551
1a5a177e 552 r = parse_env_file(NULL, p, NEWLINE, field, &s, NULL);
707b66c6
LP
553 if (r == -ENOENT)
554 return -ENXIO;
d70964d0 555 if (r < 0)
74b91131 556 return r;
74b91131 557 if (isempty(s))
707b66c6 558 return -ENODATA;
74b91131 559
ae2a15bc 560 *value = TAKE_PTR(s);
74b91131
LP
561 return 0;
562}
563
51f58f08
LP
564_public_ int sd_session_get_seat(const char *session, char **seat) {
565 return session_get_string(session, "SEAT", seat);
566}
eff40633 567
c84f5e4a
LP
568_public_ int sd_session_get_tty(const char *session, char **tty) {
569 return session_get_string(session, "TTY", tty);
570}
571
44ded3ab 572_public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
3f4fee03 573 _cleanup_free_ char *vtnr_string = NULL;
44ded3ab
GC
574 unsigned u;
575 int r;
576
707b66c6
LP
577 assert_return(vtnr, -EINVAL);
578
0581dac2 579 r = session_get_string(session, "VTNR", &vtnr_string);
44ded3ab
GC
580 if (r < 0)
581 return r;
582
583 r = safe_atou(vtnr_string, &u);
584 if (r < 0)
585 return r;
586
587 *vtnr = u;
588 return 0;
589}
590
51f58f08
LP
591_public_ int sd_session_get_service(const char *session, char **service) {
592 return session_get_string(session, "SERVICE", service);
593}
eff40633 594
51f58f08
LP
595_public_ int sd_session_get_type(const char *session, char **type) {
596 return session_get_string(session, "TYPE", type);
597}
eff40633 598
51f58f08
LP
599_public_ int sd_session_get_class(const char *session, char **class) {
600 return session_get_string(session, "CLASS", class);
eff40633
LP
601}
602
c72d5456
DH
603_public_ int sd_session_get_desktop(const char *session, char **desktop) {
604 _cleanup_free_ char *escaped = NULL;
605 char *t;
606 int r;
607
608 assert_return(desktop, -EINVAL);
609
610 r = session_get_string(session, "DESKTOP", &escaped);
611 if (r < 0)
612 return r;
613
527b7a42
LP
614 r = cunescape(escaped, 0, &t);
615 if (r < 0)
616 return r;
c72d5456
DH
617
618 *desktop = t;
619 return 0;
620}
621
fc8af9ff
LP
622_public_ int sd_session_get_display(const char *session, char **display) {
623 return session_get_string(session, "DISPLAY", display);
624}
625
5b04fe60
MM
626_public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
627 return session_get_string(session, "REMOTE_USER", remote_user);
628}
629
630_public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
631 return session_get_string(session, "REMOTE_HOST", remote_host);
632}
633
74b91131 634_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
d70964d0 635 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
74b91131
LP
636 int r;
637
1ae464e0 638 assert_return(session || uid, -EINVAL);
74b91131 639
50b1678a
LP
640 r = file_of_seat(seat, &p);
641 if (r < 0)
642 return r;
74b91131 643
1a5a177e 644 r = parse_env_file(NULL, p, NEWLINE,
74b91131
LP
645 "ACTIVE", &s,
646 "ACTIVE_UID", &t,
647 NULL);
707b66c6
LP
648 if (r == -ENOENT)
649 return -ENXIO;
d70964d0 650 if (r < 0)
74b91131 651 return r;
74b91131 652
d70964d0 653 if (session && !s)
4211d5bd 654 return -ENODATA;
74b91131 655
d70964d0 656 if (uid && !t)
4211d5bd 657 return -ENODATA;
74b91131
LP
658
659 if (uid && t) {
034a2a52 660 r = parse_uid(t, uid);
d70964d0 661 if (r < 0)
74b91131 662 return r;
74b91131
LP
663 }
664
ae2a15bc
LP
665 if (session && s)
666 *session = TAKE_PTR(s);
74b91131
LP
667
668 return 0;
669}
034a2a52
LP
670
671_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
d70964d0
HH
672 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
673 _cleanup_strv_free_ char **a = NULL;
674 _cleanup_free_ uid_t *b = NULL;
034a2a52
LP
675 unsigned n = 0;
676 int r;
677
50b1678a
LP
678 r = file_of_seat(seat, &p);
679 if (r < 0)
680 return r;
034a2a52 681
1a5a177e 682 r = parse_env_file(NULL, p, NEWLINE,
034a2a52 683 "SESSIONS", &s,
d3cfab31 684 "UIDS", &t,
034a2a52 685 NULL);
707b66c6
LP
686 if (r == -ENOENT)
687 return -ENXIO;
d70964d0 688 if (r < 0)
034a2a52 689 return r;
034a2a52 690
d60ef526 691 if (s) {
034a2a52 692 a = strv_split(s, " ");
d70964d0 693 if (!a)
034a2a52 694 return -ENOMEM;
034a2a52
LP
695 }
696
034a2a52 697 if (uids && t) {
a2a5291b 698 const char *word, *state;
034a2a52 699 size_t l;
034a2a52 700
a2a5291b 701 FOREACH_WORD(word, l, t, state)
034a2a52
LP
702 n++;
703
d70964d0 704 if (n > 0) {
de3756ab 705 unsigned i = 0;
034a2a52 706
de3756ab 707 b = new(uid_t, n);
d70964d0 708 if (!b)
034a2a52 709 return -ENOMEM;
034a2a52 710
a2a5291b 711 FOREACH_WORD(word, l, t, state) {
d70964d0 712 _cleanup_free_ char *k = NULL;
034a2a52 713
a2a5291b 714 k = strndup(word, l);
d70964d0 715 if (!k)
de3756ab 716 return -ENOMEM;
de3756ab
LP
717
718 r = parse_uid(k, b + i);
de3756ab 719 if (r < 0)
cc6182e8 720 return r;
de3756ab
LP
721
722 i++;
723 }
034a2a52
LP
724 }
725 }
726
da6053d0 727 r = (int) strv_length(a);
d60ef526 728
1cc6c93a
YW
729 if (sessions)
730 *sessions = TAKE_PTR(a);
034a2a52 731
1cc6c93a
YW
732 if (uids)
733 *uids = TAKE_PTR(b);
034a2a52
LP
734
735 if (n_uids)
736 *n_uids = n;
737
d60ef526 738 return r;
034a2a52
LP
739}
740
20747498 741static int seat_get_can(const char *seat, const char *variable) {
d70964d0 742 _cleanup_free_ char *p = NULL, *s = NULL;
add30678
LP
743 int r;
744
707b66c6 745 assert(variable);
0325941f 746
50b1678a
LP
747 r = file_of_seat(seat, &p);
748 if (r < 0)
749 return r;
add30678 750
1a5a177e 751 r = parse_env_file(NULL, p, NEWLINE,
20747498 752 variable, &s,
add30678 753 NULL);
707b66c6
LP
754 if (r == -ENOENT)
755 return -ENXIO;
d70964d0 756 if (r < 0)
add30678 757 return r;
707b66c6
LP
758 if (isempty(s))
759 return -ENODATA;
add30678 760
0325941f 761 return parse_boolean(s);
add30678
LP
762}
763
20747498
LP
764_public_ int sd_seat_can_multi_session(const char *seat) {
765 return seat_get_can(seat, "CAN_MULTI_SESSION");
766}
767
768_public_ int sd_seat_can_tty(const char *seat) {
769 return seat_get_can(seat, "CAN_TTY");
770}
771
772_public_ int sd_seat_can_graphical(const char *seat) {
773 return seat_get_can(seat, "CAN_GRAPHICAL");
774}
775
034a2a52 776_public_ int sd_get_seats(char ***seats) {
2b5e9267
YW
777 int r;
778
779 r = get_files_in_directory("/run/systemd/seats/", seats);
780 if (r == -ENOENT) {
781 if (seats)
782 *seats = NULL;
783 return 0;
784 }
785 return r;
034a2a52
LP
786}
787
788_public_ int sd_get_sessions(char ***sessions) {
2b5e9267
YW
789 int r;
790
791 r = get_files_in_directory("/run/systemd/sessions/", sessions);
792 if (r == -ENOENT) {
793 if (sessions)
794 *sessions = NULL;
795 return 0;
796 }
797 return r;
034a2a52
LP
798}
799
800_public_ int sd_get_uids(uid_t **users) {
d70964d0 801 _cleanup_closedir_ DIR *d;
8fb3f009 802 struct dirent *de;
034a2a52
LP
803 int r = 0;
804 unsigned n = 0;
d70964d0 805 _cleanup_free_ uid_t *l = NULL;
034a2a52 806
034a2a52 807 d = opendir("/run/systemd/users/");
2b5e9267
YW
808 if (!d) {
809 if (errno == ENOENT) {
810 if (users)
811 *users = NULL;
812 return 0;
813 }
8ea913b2 814 return -errno;
2b5e9267 815 }
8ea913b2 816
8fb3f009 817 FOREACH_DIRENT_ALL(de, d, return -errno) {
034a2a52
LP
818 int k;
819 uid_t uid;
820
034a2a52
LP
821 dirent_ensure_type(d, de);
822
823 if (!dirent_is_file(de))
824 continue;
825
826 k = parse_uid(de->d_name, &uid);
827 if (k < 0)
828 continue;
829
d60ef526
LP
830 if (users) {
831 if ((unsigned) r >= n) {
832 uid_t *t;
034a2a52 833
d60ef526
LP
834 n = MAX(16, 2*r);
835 t = realloc(l, sizeof(uid_t) * n);
d70964d0
HH
836 if (!t)
837 return -ENOMEM;
034a2a52 838
d60ef526
LP
839 l = t;
840 }
034a2a52 841
d60ef526
LP
842 assert((unsigned) r < n);
843 l[r++] = uid;
844 } else
845 r++;
034a2a52
LP
846 }
847
1cc6c93a
YW
848 if (users)
849 *users = TAKE_PTR(l);
034a2a52
LP
850
851 return r;
852}
853
4d5fb962 854_public_ int sd_get_machine_names(char ***machines) {
96480634
ZJS
855 _cleanup_strv_free_ char **l = NULL;
856 char **a, **b;
89f7c846
LP
857 int r;
858
859 r = get_files_in_directory("/run/systemd/machines/", &l);
0543105b 860 if (r == -ENOENT) {
76ed21e1
YW
861 if (machines)
862 *machines = NULL;
0543105b
ZJS
863 return 0;
864 }
89f7c846
LP
865 if (r < 0)
866 return r;
867
868 if (l) {
869 r = 0;
870
871 /* Filter out the unit: symlinks */
76ed21e1 872 for (a = b = l; *a; a++) {
b9a8d250 873 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
89f7c846
LP
874 free(*a);
875 else {
876 *b = *a;
877 b++;
878 r++;
879 }
880 }
881
882 *b = NULL;
883 }
884
ae2a15bc
LP
885 if (machines)
886 *machines = TAKE_PTR(l);
887
89f7c846 888 return r;
a20affe2
LP
889}
890
0325941f
LP
891_public_ int sd_machine_get_class(const char *machine, char **class) {
892 _cleanup_free_ char *c = NULL;
893 const char *p;
894 int r;
895
620a687c 896 assert_return(machine_name_is_valid(machine), -EINVAL);
0325941f
LP
897 assert_return(class, -EINVAL);
898
63c372cb 899 p = strjoina("/run/systemd/machines/", machine);
1a5a177e 900 r = parse_env_file(NULL, p, NEWLINE, "CLASS", &c, NULL);
707b66c6
LP
901 if (r == -ENOENT)
902 return -ENXIO;
0325941f
LP
903 if (r < 0)
904 return r;
905 if (!c)
906 return -EIO;
907
ae2a15bc 908 *class = TAKE_PTR(c);
0325941f
LP
909
910 return 0;
911}
912
634af566 913_public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
cabb0bc6
LP
914 _cleanup_free_ char *netif = NULL;
915 size_t l, allocated = 0, nr = 0;
cabb0bc6 916 int *ni = NULL;
a2a5291b 917 const char *p, *word, *state;
cabb0bc6
LP
918 int r;
919
920 assert_return(machine_name_is_valid(machine), -EINVAL);
634af566 921 assert_return(ifindices, -EINVAL);
cabb0bc6 922
63c372cb 923 p = strjoina("/run/systemd/machines/", machine);
1a5a177e 924 r = parse_env_file(NULL, p, NEWLINE, "NETIF", &netif, NULL);
707b66c6
LP
925 if (r == -ENOENT)
926 return -ENXIO;
cabb0bc6
LP
927 if (r < 0)
928 return r;
929 if (!netif) {
634af566 930 *ifindices = NULL;
cabb0bc6
LP
931 return 0;
932 }
933
a2a5291b 934 FOREACH_WORD(word, l, netif, state) {
cabb0bc6
LP
935 char buf[l+1];
936 int ifi;
937
a2a5291b 938 *(char*) (mempcpy(buf, word, l)) = 0;
cabb0bc6 939
6ad623a3 940 if (parse_ifindex(buf, &ifi) < 0)
cabb0bc6
LP
941 continue;
942
943 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
944 free(ni);
945 return -ENOMEM;
946 }
947
948 ni[nr++] = ifi;
949 }
950
634af566 951 *ifindices = ni;
cabb0bc6
LP
952 return nr;
953}
954
034a2a52
LP
955static inline int MONITOR_TO_FD(sd_login_monitor *m) {
956 return (int) (unsigned long) m - 1;
957}
958
959static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
960 return (sd_login_monitor*) (unsigned long) (fd + 1);
961}
962
963_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
4cbbc2a2 964 _cleanup_close_ int fd = -1;
034a2a52 965 bool good = false;
4cbbc2a2 966 int k;
034a2a52 967
1ae464e0 968 assert_return(m, -EINVAL);
034a2a52
LP
969
970 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
971 if (fd < 0)
bcb161b0 972 return -errno;
034a2a52
LP
973
974 if (!category || streq(category, "seat")) {
975 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
4cbbc2a2 976 if (k < 0)
034a2a52 977 return -errno;
034a2a52
LP
978
979 good = true;
980 }
981
982 if (!category || streq(category, "session")) {
983 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
4cbbc2a2 984 if (k < 0)
034a2a52 985 return -errno;
034a2a52
LP
986
987 good = true;
988 }
989
990 if (!category || streq(category, "uid")) {
991 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
4cbbc2a2 992 if (k < 0)
034a2a52 993 return -errno;
034a2a52
LP
994
995 good = true;
996 }
997
e10375f2 998 if (!category || streq(category, "machine")) {
ba73ed85 999 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
4cbbc2a2 1000 if (k < 0)
e10375f2 1001 return -errno;
e10375f2
LP
1002
1003 good = true;
1004 }
1005
4cbbc2a2 1006 if (!good)
034a2a52 1007 return -EINVAL;
034a2a52
LP
1008
1009 *m = FD_TO_MONITOR(fd);
4cbbc2a2
LP
1010 fd = -1;
1011
034a2a52
LP
1012 return 0;
1013}
1014
1015_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1016 int fd;
1017
4afd3348
LP
1018 if (!m)
1019 return NULL;
034a2a52
LP
1020
1021 fd = MONITOR_TO_FD(m);
1022 close_nointr(fd);
1023
1024 return NULL;
1025}
1026
1027_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
665dfe93 1028 int r;
034a2a52 1029
1ae464e0 1030 assert_return(m, -EINVAL);
034a2a52 1031
665dfe93
LP
1032 r = flush_fd(MONITOR_TO_FD(m));
1033 if (r < 0)
1034 return r;
1035
1036 return 0;
034a2a52
LP
1037}
1038
1039_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1040
1ae464e0 1041 assert_return(m, -EINVAL);
034a2a52
LP
1042
1043 return MONITOR_TO_FD(m);
1044}
dace83cb
LP
1045
1046_public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1047
1ae464e0 1048 assert_return(m, -EINVAL);
dace83cb 1049
667c24a6
LP
1050 /* For now we will only return POLLIN here, since we don't
1051 * need anything else ever for inotify. However, let's have
1052 * this API to keep our options open should we later on need
1053 * it. */
dace83cb
LP
1054 return POLLIN;
1055}
667c24a6
LP
1056
1057_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1058
1ae464e0
TA
1059 assert_return(m, -EINVAL);
1060 assert_return(timeout_usec, -EINVAL);
667c24a6
LP
1061
1062 /* For now we will only return (uint64_t) -1, since we don't
1063 * need any timeout. However, let's have this API to keep our
1064 * options open should we later on need it. */
1065 *timeout_usec = (uint64_t) -1;
1066 return 0;
1067}