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