]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-login/sd-login.c
Fixes for vscode/intellisense parsing (#38040)
[thirdparty/systemd.git] / src / libsystemd / sd-login / sd-login.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
74b91131 2
0a6f50c0 3#include <poll.h>
4f5dd394
LP
4#include <sys/inotify.h>
5#include <unistd.h>
74b91131 6
07630cea
LP
7#include "sd-login.h"
8
b5efdb8a 9#include "alloc-util.h"
74b91131 10#include "cgroup-util.h"
f4f15635 11#include "dirent-util.h"
686d13b9 12#include "env-file.h"
81823e6c 13#include "extract-word.h"
3ffd4af2 14#include "fd-util.h"
f97b34a6 15#include "format-util.h"
f4f15635 16#include "fs-util.h"
25300b5a 17#include "hostname-util.h"
c004493c 18#include "io-util.h"
4f5dd394 19#include "login-util.h"
6bedfcbb 20#include "parse-util.h"
bb15fafe 21#include "path-util.h"
b234026d 22#include "pidfd-util.h"
5cdf13c7 23#include "pidref.h"
2583fbea 24#include "socket-util.h"
07630cea 25#include "string-util.h"
4f5dd394 26#include "strv.h"
b1d4f8e1 27#include "user-util.h"
74b91131 28
707b66c6
LP
29/* Error codes:
30 *
31 * invalid input parameters → -EINVAL
32 * invalid fd → -EBADF
33 * process does not exist → -ESRCH
34 * cgroup does not exist → -ENOENT
35 * machine, session does not exist → -ENXIO
36 * requested metadata on object is missing → -ENODATA
37 */
38
eac4a028 39_public_ int sd_pid_get_session(pid_t pid, char **ret_session) {
19d64d10 40 int r;
ba1261bc 41
1ae464e0 42 assert_return(pid >= 0, -EINVAL);
034a2a52 43
eac4a028 44 r = cg_pid_get_session(pid, ret_session);
bc9e9af1 45 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
74b91131
LP
46}
47
eac4a028 48_public_ int sd_pid_get_unit(pid_t pid, char **ret_unit) {
171f8f59 49 int r;
9847946e 50
1ae464e0 51 assert_return(pid >= 0, -EINVAL);
9847946e 52
eac4a028 53 r = cg_pid_get_unit(pid, ret_unit);
bc9e9af1 54 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
9847946e
LP
55}
56
eac4a028 57_public_ int sd_pid_get_user_unit(pid_t pid, char **ret_unit) {
d440fb97 58 int r;
97e13058 59
1ae464e0 60 assert_return(pid >= 0, -EINVAL);
97e13058 61
eac4a028 62 r = cg_pid_get_user_unit(pid, ret_unit);
bc9e9af1 63 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
97e13058
LP
64}
65
eac4a028 66_public_ int sd_pid_get_machine_name(pid_t pid, char **ret_name) {
bc9e9af1 67 int r;
7027ff61 68
1ae464e0 69 assert_return(pid >= 0, -EINVAL);
7027ff61 70
eac4a028 71 r = cg_pid_get_machine_name(pid, ret_name);
bc9e9af1 72 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
7027ff61
LP
73}
74
eac4a028 75_public_ int sd_pid_get_slice(pid_t pid, char **ret_slice) {
bc9e9af1 76 int r;
1021b21b 77
1ae464e0 78 assert_return(pid >= 0, -EINVAL);
1021b21b 79
eac4a028 80 r = cg_pid_get_slice(pid, ret_slice);
bc9e9af1 81 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
1021b21b
LP
82}
83
eac4a028 84_public_ int sd_pid_get_user_slice(pid_t pid, char **ret_slice) {
bc9e9af1 85 int r;
329ac4bc
LP
86
87 assert_return(pid >= 0, -EINVAL);
329ac4bc 88
eac4a028 89 r = cg_pid_get_user_slice(pid, ret_slice);
bc9e9af1 90 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
329ac4bc
LP
91}
92
eac4a028 93_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *ret_uid) {
bc9e9af1 94 int r;
034a2a52 95
1ae464e0 96 assert_return(pid >= 0, -EINVAL);
034a2a52 97
eac4a028 98 r = cg_pid_get_owner_uid(pid, ret_uid);
bc9e9af1 99 return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r;
034a2a52
LP
100}
101
eac4a028 102_public_ int sd_pid_get_cgroup(pid_t pid, char **ret_cgroup) {
f5aaf575
LP
103 int r;
104
105 assert_return(pid >= 0, -EINVAL);
f5aaf575 106
eac4a028 107 _cleanup_free_ char *c = NULL;
f5aaf575
LP
108 r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c);
109 if (r < 0)
110 return r;
111
eac4a028
LP
112 if (ret_cgroup) {
113 /* The internal APIs return the empty string for the root cgroup, let's return the "/" in the
114 * public APIs instead, as that's easier and less ambiguous for people to grok. */
115 if (isempty(c)) {
116 r = free_and_strdup(&c, "/");
117 if (r < 0)
118 return r;
119 }
f5aaf575 120
eac4a028 121 *ret_cgroup = TAKE_PTR(c);
f5aaf575
LP
122 }
123
f5aaf575
LP
124 return 0;
125}
126
da20baae
LB
127_public_ int sd_pidfd_get_session(int pidfd, char **ret_session) {
128 _cleanup_free_ char *session = NULL;
129 pid_t pid;
130 int r;
131
132 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
133
134 r = pidfd_get_pid(pidfd, &pid);
135 if (r < 0)
136 return r;
137
138 r = sd_pid_get_session(pid, &session);
139 if (r < 0)
140 return r;
141
142 r = pidfd_verify_pid(pidfd, pid);
143 if (r < 0)
144 return r;
145
eac4a028
LP
146 if (ret_session)
147 *ret_session = TAKE_PTR(session);
da20baae
LB
148 return 0;
149}
150
151_public_ int sd_pidfd_get_unit(int pidfd, char **ret_unit) {
152 _cleanup_free_ char *unit = NULL;
153 pid_t pid;
154 int r;
155
156 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
157
158 r = pidfd_get_pid(pidfd, &pid);
159 if (r < 0)
160 return r;
161
162 r = sd_pid_get_unit(pid, &unit);
163 if (r < 0)
164 return r;
165
166 r = pidfd_verify_pid(pidfd, pid);
167 if (r < 0)
168 return r;
169
eac4a028
LP
170 if (ret_unit)
171 *ret_unit = TAKE_PTR(unit);
da20baae
LB
172 return 0;
173}
174
175_public_ int sd_pidfd_get_user_unit(int pidfd, char **ret_unit) {
176 _cleanup_free_ char *unit = NULL;
177 pid_t pid;
178 int r;
179
180 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
181
182 r = pidfd_get_pid(pidfd, &pid);
183 if (r < 0)
184 return r;
185
186 r = sd_pid_get_user_unit(pid, &unit);
187 if (r < 0)
188 return r;
189
190 r = pidfd_verify_pid(pidfd, pid);
191 if (r < 0)
192 return r;
193
eac4a028
LP
194 if (ret_unit)
195 *ret_unit = TAKE_PTR(unit);
da20baae
LB
196 return 0;
197}
198
199_public_ int sd_pidfd_get_machine_name(int pidfd, char **ret_name) {
200 _cleanup_free_ char *name = NULL;
201 pid_t pid;
202 int r;
203
204 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
205
206 r = pidfd_get_pid(pidfd, &pid);
207 if (r < 0)
208 return r;
209
210 r = sd_pid_get_machine_name(pid, &name);
211 if (r < 0)
212 return r;
213
214 r = pidfd_verify_pid(pidfd, pid);
215 if (r < 0)
216 return r;
217
eac4a028
LP
218 if (ret_name)
219 *ret_name = TAKE_PTR(name);
da20baae
LB
220 return 0;
221}
222
223_public_ int sd_pidfd_get_slice(int pidfd, char **ret_slice) {
224 _cleanup_free_ char *slice = NULL;
225 pid_t pid;
226 int r;
227
228 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
229
230 r = pidfd_get_pid(pidfd, &pid);
231 if (r < 0)
232 return r;
233
234 r = sd_pid_get_slice(pid, &slice);
235 if (r < 0)
236 return r;
237
238 r = pidfd_verify_pid(pidfd, pid);
239 if (r < 0)
240 return r;
241
eac4a028
LP
242 if (ret_slice)
243 *ret_slice = TAKE_PTR(slice);
da20baae
LB
244 return 0;
245}
246
247_public_ int sd_pidfd_get_user_slice(int pidfd, char **ret_slice) {
248 _cleanup_free_ char *slice = NULL;
249 pid_t pid;
250 int r;
251
252 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
253
254 r = pidfd_get_pid(pidfd, &pid);
255 if (r < 0)
256 return r;
257
258 r = sd_pid_get_user_slice(pid, &slice);
259 if (r < 0)
260 return r;
261
262 r = pidfd_verify_pid(pidfd, pid);
263 if (r < 0)
264 return r;
265
eac4a028
LP
266 if (ret_slice)
267 *ret_slice = TAKE_PTR(slice);
da20baae
LB
268 return 0;
269}
270
271_public_ int sd_pidfd_get_owner_uid(int pidfd, uid_t *ret_uid) {
272 uid_t uid;
273 pid_t pid;
274 int r;
275
68db777a 276 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
277
278 r = pidfd_get_pid(pidfd, &pid);
279 if (r < 0)
280 return r;
281
282 r = sd_pid_get_owner_uid(pid, &uid);
283 if (r < 0)
284 return r;
285
286 r = pidfd_verify_pid(pidfd, pid);
287 if (r < 0)
288 return r;
289
eac4a028
LP
290 if (ret_uid)
291 *ret_uid = uid;
da20baae
LB
292 return 0;
293}
294
295_public_ int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup) {
296 _cleanup_free_ char *cgroup = NULL;
297 pid_t pid;
298 int r;
299
300 assert_return(pidfd >= 0, -EBADF);
da20baae
LB
301
302 r = pidfd_get_pid(pidfd, &pid);
303 if (r < 0)
304 return r;
305
306 r = sd_pid_get_cgroup(pid, &cgroup);
307 if (r < 0)
308 return r;
309
310 r = pidfd_verify_pid(pidfd, pid);
311 if (r < 0)
312 return r;
313
eac4a028
LP
314 if (ret_cgroup)
315 *ret_cgroup = TAKE_PTR(cgroup);
da20baae
LB
316 return 0;
317}
318
eac4a028 319_public_ int sd_peer_get_session(int fd, char **ret_session) {
bf34ab14
LP
320 int r;
321
8ac43fee 322 assert_return(fd >= 0, -EBADF);
bf34ab14 323
1740d3e0
LP
324 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
325 r = getpeerpidref(fd, &pidref);
bf34ab14
LP
326 if (r < 0)
327 return r;
328
eac4a028 329 return cg_pidref_get_session(&pidref, ret_session);
bf34ab14
LP
330}
331
eac4a028 332_public_ int sd_peer_get_owner_uid(int fd, uid_t *ret_uid) {
bf34ab14
LP
333 int r;
334
8ac43fee 335 assert_return(fd >= 0, -EBADF);
bf34ab14 336
1740d3e0
LP
337 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
338 r = getpeerpidref(fd, &pidref);
bf34ab14
LP
339 if (r < 0)
340 return r;
341
eac4a028 342 return cg_pidref_get_owner_uid(&pidref, ret_uid);
bf34ab14
LP
343}
344
eac4a028 345_public_ int sd_peer_get_unit(int fd, char **ret_unit) {
bf34ab14
LP
346 int r;
347
8ac43fee 348 assert_return(fd >= 0, -EBADF);
bf34ab14 349
1740d3e0
LP
350 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
351 r = getpeerpidref(fd, &pidref);
bf34ab14
LP
352 if (r < 0)
353 return r;
354
eac4a028 355 return cg_pidref_get_unit(&pidref, ret_unit);
bf34ab14
LP
356}
357
eac4a028 358_public_ int sd_peer_get_user_unit(int fd, char **ret_unit) {
bf34ab14
LP
359 struct ucred ucred;
360 int r;
361
8ac43fee 362 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
363
364 r = getpeercred(fd, &ucred);
365 if (r < 0)
366 return r;
367
eac4a028 368 return cg_pid_get_user_unit(ucred.pid, ret_unit);
bf34ab14
LP
369}
370
eac4a028 371_public_ int sd_peer_get_machine_name(int fd, char **ret_machine) {
bf34ab14
LP
372 struct ucred ucred;
373 int r;
374
8ac43fee 375 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
376
377 r = getpeercred(fd, &ucred);
378 if (r < 0)
379 return r;
380
eac4a028 381 return cg_pid_get_machine_name(ucred.pid, ret_machine);
bf34ab14
LP
382}
383
eac4a028 384_public_ int sd_peer_get_slice(int fd, char **ret_slice) {
bf34ab14
LP
385 struct ucred ucred;
386 int r;
387
8ac43fee 388 assert_return(fd >= 0, -EBADF);
bf34ab14
LP
389
390 r = getpeercred(fd, &ucred);
391 if (r < 0)
392 return r;
393
eac4a028 394 return cg_pid_get_slice(ucred.pid, ret_slice);
bf34ab14
LP
395}
396
eac4a028 397_public_ int sd_peer_get_user_slice(int fd, char **ret_slice) {
329ac4bc
LP
398 struct ucred ucred;
399 int r;
400
8ac43fee 401 assert_return(fd >= 0, -EBADF);
329ac4bc
LP
402
403 r = getpeercred(fd, &ucred);
404 if (r < 0)
405 return r;
406
eac4a028 407 return cg_pid_get_user_slice(ucred.pid, ret_slice);
329ac4bc
LP
408}
409
eac4a028 410_public_ int sd_peer_get_cgroup(int fd, char **ret_cgroup) {
f5aaf575
LP
411 int r;
412
413 assert_return(fd >= 0, -EBADF);
f5aaf575 414
eb780108
LP
415 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
416 r = getpeerpidref(fd, &pidref);
f5aaf575
LP
417 if (r < 0)
418 return r;
419
eb780108
LP
420 _cleanup_free_ char *c = NULL;
421 r = cg_pidref_get_path(SYSTEMD_CGROUP_CONTROLLER, &pidref, &c);
422 if (r < 0)
423 return r;
424
425 if (ret_cgroup) {
426 /* The internal APIs return the empty string for the root cgroup, let's return the "/" in the
427 * public APIs instead, as that's easier and less ambiguous for people to grok. */
428 if (isempty(c)) {
429 r = free_and_strdup(&c, "/");
430 if (r < 0)
431 return r;
432 }
433
434 *ret_cgroup = TAKE_PTR(c);
435 }
436
437 return 0;
f5aaf575
LP
438}
439
eac4a028 440static int file_of_uid(uid_t uid, char **ret) {
707b66c6
LP
441
442 assert_return(uid_is_valid(uid), -EINVAL);
eac4a028 443 assert(ret);
a077b666 444
eac4a028 445 if (asprintf(ret, "/run/systemd/users/" UID_FMT, uid) < 0)
a077b666
LP
446 return -ENOMEM;
447
448 return 0;
449}
450
eac4a028 451_public_ int sd_uid_get_state(uid_t uid, char **ret_state) {
13df9c39 452 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131
LP
453 int r;
454
a077b666
LP
455 r = file_of_uid(uid, &p);
456 if (r < 0)
457 return r;
74b91131 458
eac4a028 459 r = parse_env_file(/* f= */ NULL, p, "STATE", &s);
40f35786 460 if (r == -ENOENT)
13df9c39 461 r = free_and_strdup(&s, "offline");
40f35786 462 if (r < 0)
74b91131 463 return r;
40f35786 464 if (isempty(s))
74b91131
LP
465 return -EIO;
466
eac4a028
LP
467 if (ret_state)
468 *ret_state = TAKE_PTR(s);
74b91131
LP
469 return 0;
470}
471
eac4a028 472_public_ int sd_uid_get_display(uid_t uid, char **ret_session) {
a077b666
LP
473 _cleanup_free_ char *p = NULL, *s = NULL;
474 int r;
475
a077b666
LP
476 r = file_of_uid(uid, &p);
477 if (r < 0)
478 return r;
479
eac4a028 480 r = parse_env_file(/* f= */ NULL, p, "DISPLAY", &s);
fc60d815 481 if (r == -ENOENT)
707b66c6 482 return -ENODATA;
a077b666
LP
483 if (r < 0)
484 return r;
a077b666 485 if (isempty(s))
707b66c6 486 return -ENODATA;
a077b666 487
eac4a028
LP
488 if (ret_session)
489 *ret_session = TAKE_PTR(s);
a077b666
LP
490 return 0;
491}
492
eac4a028 493_public_ int sd_uid_get_login_time(uid_t uid, uint64_t *ret_usec) {
d622fefc 494 _cleanup_free_ char *p = NULL, *s = NULL, *rt = NULL;
d622fefc
TK
495 int r;
496
d622fefc
TK
497 r = file_of_uid(uid, &p);
498 if (r < 0)
499 return r;
500
eac4a028 501 r = parse_env_file(/* f= */ NULL, p, "STATE", &s, "REALTIME", &rt);
d622fefc
TK
502 if (r == -ENOENT)
503 return -ENXIO;
504 if (r < 0)
505 return r;
506 if (isempty(s) || isempty(rt))
507 return -EIO;
508
509 if (!STR_IN_SET(s, "active", "online"))
510 return -ENXIO;
511
eac4a028 512 return safe_atou64(rt, ret_usec);
d622fefc
TK
513}
514
eac4a028 515static int file_of_seat(const char *seat, char **ret) {
707b66c6
LP
516 char *p;
517 int r;
518
eac4a028 519 assert(ret);
707b66c6
LP
520
521 if (seat) {
522 if (!filename_is_valid(seat))
523 return -EINVAL;
524
b910cc72 525 p = path_join("/run/systemd/seats", seat);
707b66c6
LP
526 } else {
527 _cleanup_free_ char *buf = NULL;
528
529 r = sd_session_get_seat(NULL, &buf);
530 if (r < 0)
531 return r;
532
b910cc72 533 p = path_join("/run/systemd/seats", buf);
707b66c6 534 }
707b66c6
LP
535 if (!p)
536 return -ENOMEM;
537
eac4a028 538 *ret = TAKE_PTR(p);
707b66c6
LP
539 return 0;
540}
541
034a2a52 542_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
81823e6c 543 _cleanup_free_ char *filename = NULL, *content = NULL;
74b91131
LP
544 int r;
545
a1f686da 546 assert_return(uid_is_valid(uid), -EINVAL);
74b91131 547
81823e6c 548 r = file_of_seat(seat, &filename);
707b66c6
LP
549 if (r < 0)
550 return r;
034a2a52 551
eac4a028 552 r = parse_env_file(/* f= */ NULL, filename,
81823e6c
ZJS
553 require_active ? "ACTIVE_UID" : "UIDS",
554 &content);
707b66c6
LP
555 if (r == -ENOENT)
556 return 0;
d70964d0 557 if (r < 0)
74b91131 558 return r;
81823e6c 559 if (isempty(content))
707b66c6 560 return 0;
74b91131 561
80d07162 562 return string_contains_word(content, NULL, FORMAT_UID(uid));
74b91131
LP
563}
564
eac4a028 565static int uid_get_array(uid_t uid, const char *variable, char ***ret_array) {
d70964d0 566 _cleanup_free_ char *p = NULL, *s = NULL;
034a2a52
LP
567 int r;
568
707b66c6 569 assert(variable);
a1f686da 570
a077b666
LP
571 r = file_of_uid(uid, &p);
572 if (r < 0)
573 return r;
034a2a52 574
eac4a028 575 r = parse_env_file(/* f= */ NULL, p, variable, &s);
707b66c6 576 if (r == -ENOENT || (r >= 0 && isempty(s))) {
eac4a028
LP
577 if (ret_array)
578 *ret_array = NULL;
034a2a52
LP
579 return 0;
580 }
707b66c6
LP
581 if (r < 0)
582 return r;
034a2a52 583
eac4a028 584 _cleanup_strv_free_ char **a = strv_split(s, NULL);
034a2a52
LP
585 if (!a)
586 return -ENOMEM;
587
d60ef526 588 strv_uniq(a);
da6053d0 589 r = (int) strv_length(a);
d60ef526 590
eac4a028
LP
591 if (ret_array)
592 *ret_array = TAKE_PTR(a);
d60ef526
LP
593
594 return r;
034a2a52
LP
595}
596
eac4a028 597_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***ret_sessions) {
d18dff43
LP
598 return uid_get_array(
599 uid,
600 require_active == 0 ? "ONLINE_SESSIONS" :
601 require_active > 0 ? "ACTIVE_SESSIONS" :
602 "SESSIONS",
eac4a028 603 ret_sessions);
74b91131
LP
604}
605
eac4a028 606_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***ret_seats) {
d18dff43
LP
607 return uid_get_array(
608 uid,
609 require_active == 0 ? "ONLINE_SEATS" :
610 require_active > 0 ? "ACTIVE_SEATS" :
611 "SEATS",
eac4a028 612 ret_seats);
74b91131
LP
613}
614
eac4a028 615static int file_of_session(const char *session, char **ret) {
50b1678a 616 char *p;
74b91131 617 int r;
74b91131 618
eac4a028 619 assert(ret);
50b1678a 620
4b549144
ZJS
621 if (session) {
622 if (!session_id_valid(session))
623 return -EINVAL;
624
b910cc72 625 p = path_join("/run/systemd/sessions", session);
4b549144
ZJS
626 } else {
627 _cleanup_free_ char *buf = NULL;
50b1678a
LP
628
629 r = sd_pid_get_session(0, &buf);
630 if (r < 0)
631 return r;
632
b910cc72 633 p = path_join("/run/systemd/sessions", buf);
50b1678a 634 }
74b91131
LP
635 if (!p)
636 return -ENOMEM;
637
eac4a028 638 *ret = p;
50b1678a
LP
639 return 0;
640}
641
642_public_ int sd_session_is_active(const char *session) {
d70964d0 643 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 644 int r;
50b1678a
LP
645
646 r = file_of_session(session, &p);
647 if (r < 0)
648 return r;
649
eac4a028 650 r = parse_env_file(/* f= */ NULL, p, "ACTIVE", &s);
707b66c6
LP
651 if (r == -ENOENT)
652 return -ENXIO;
d70964d0 653 if (r < 0)
74b91131 654 return r;
707b66c6 655 if (isempty(s))
74b91131
LP
656 return -EIO;
657
0325941f 658 return parse_boolean(s);
74b91131
LP
659}
660
5b04fe60 661_public_ int sd_session_is_remote(const char *session) {
5b04fe60 662 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 663 int r;
5b04fe60
MM
664
665 r = file_of_session(session, &p);
666 if (r < 0)
667 return r;
668
eac4a028 669 r = parse_env_file(/* f= */ NULL, p, "REMOTE", &s);
707b66c6
LP
670 if (r == -ENOENT)
671 return -ENXIO;
5b04fe60
MM
672 if (r < 0)
673 return r;
707b66c6
LP
674 if (isempty(s))
675 return -ENODATA;
5b04fe60 676
0325941f 677 return parse_boolean(s);
5b04fe60
MM
678}
679
eac4a028 680_public_ int sd_session_get_state(const char *session, char **ret_state) {
d70964d0 681 _cleanup_free_ char *p = NULL, *s = NULL;
0604381b
LP
682 int r;
683
0604381b
LP
684 r = file_of_session(session, &p);
685 if (r < 0)
686 return r;
687
eac4a028 688 r = parse_env_file(/* f= */ NULL, p, "STATE", &s);
707b66c6
LP
689 if (r == -ENOENT)
690 return -ENXIO;
d70964d0 691 if (r < 0)
0604381b 692 return r;
707b66c6 693 if (isempty(s))
0604381b
LP
694 return -EIO;
695
eac4a028
LP
696 if (ret_state)
697 *ret_state = TAKE_PTR(s);
0604381b
LP
698 return 0;
699}
700
eac4a028 701_public_ int sd_session_get_uid(const char *session, uid_t *ret_uid) {
74b91131 702 int r;
d70964d0 703 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131 704
50b1678a
LP
705 r = file_of_session(session, &p);
706 if (r < 0)
707 return r;
74b91131 708
eac4a028 709 r = parse_env_file(/* f= */ NULL, p, "UID", &s);
707b66c6
LP
710 if (r == -ENOENT)
711 return -ENXIO;
d70964d0 712 if (r < 0)
74b91131 713 return r;
707b66c6 714 if (isempty(s))
74b91131
LP
715 return -EIO;
716
eac4a028 717 return parse_uid(s, ret_uid);
74b91131
LP
718}
719
eac4a028 720static int session_get_string(const char *session, const char *field, char **ret_value) {
d70964d0 721 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131
LP
722 int r;
723
707b66c6 724 assert(field);
74b91131 725
50b1678a
LP
726 r = file_of_session(session, &p);
727 if (r < 0)
728 return r;
74b91131 729
eac4a028 730 r = parse_env_file(/* f= */ NULL, p, field, &s);
707b66c6
LP
731 if (r == -ENOENT)
732 return -ENXIO;
d70964d0 733 if (r < 0)
74b91131 734 return r;
74b91131 735 if (isempty(s))
707b66c6 736 return -ENODATA;
74b91131 737
eac4a028
LP
738 if (ret_value)
739 *ret_value = TAKE_PTR(s);
74b91131
LP
740 return 0;
741}
742
eac4a028
LP
743_public_ int sd_session_get_username(const char *session, char **ret_username) {
744 return session_get_string(session, "USER", ret_username);
d71f5b12
MY
745}
746
eac4a028
LP
747_public_ int sd_session_get_seat(const char *session, char **ret_seat) {
748 return session_get_string(session, "SEAT", ret_seat);
51f58f08 749}
eff40633 750
eac4a028 751_public_ int sd_session_get_start_time(const char *session, uint64_t *ret_usec) {
c4ef14dc 752 _cleanup_free_ char *p = NULL, *s = NULL;
c4ef14dc
MY
753 int r;
754
c4ef14dc
MY
755 r = file_of_session(session, &p);
756 if (r < 0)
757 return r;
758
eac4a028 759 r = parse_env_file(/* f= */ NULL, p, "REALTIME", &s);
c4ef14dc
MY
760 if (r == -ENOENT)
761 return -ENXIO;
762 if (r < 0)
763 return r;
764 if (isempty(s))
765 return -EIO;
766
eac4a028 767 return safe_atou64(s, ret_usec);
c4ef14dc
MY
768}
769
eac4a028
LP
770_public_ int sd_session_get_tty(const char *session, char **ret_tty) {
771 return session_get_string(session, "TTY", ret_tty);
c84f5e4a
LP
772}
773
eac4a028 774_public_ int sd_session_get_vt(const char *session, unsigned *ret_vtnr) {
3f4fee03 775 _cleanup_free_ char *vtnr_string = NULL;
44ded3ab
GC
776 int r;
777
0581dac2 778 r = session_get_string(session, "VTNR", &vtnr_string);
44ded3ab
GC
779 if (r < 0)
780 return r;
781
eac4a028 782 return safe_atou(vtnr_string, ret_vtnr);
44ded3ab
GC
783}
784
eac4a028
LP
785_public_ int sd_session_get_service(const char *session, char **ret_service) {
786 return session_get_string(session, "SERVICE", ret_service);
51f58f08 787}
eff40633 788
eac4a028
LP
789_public_ int sd_session_get_type(const char *session, char **ret_type) {
790 return session_get_string(session, "TYPE", ret_type);
51f58f08 791}
eff40633 792
eac4a028
LP
793_public_ int sd_session_get_class(const char *session, char **ret_class) {
794 return session_get_string(session, "CLASS", ret_class);
eff40633
LP
795}
796
eac4a028
LP
797_public_ int sd_session_get_desktop(const char *session, char **ret_desktop) {
798 return session_get_string(session, "DESKTOP", ret_desktop);
c72d5456
DH
799}
800
eac4a028
LP
801_public_ int sd_session_get_display(const char *session, char **ret_display) {
802 return session_get_string(session, "DISPLAY", ret_display);
fc8af9ff
LP
803}
804
eac4a028
LP
805_public_ int sd_session_get_remote_user(const char *session, char **ret_remote_user) {
806 return session_get_string(session, "REMOTE_USER", ret_remote_user);
5b04fe60
MM
807}
808
eac4a028
LP
809_public_ int sd_session_get_remote_host(const char *session, char **ret_remote_host) {
810 return session_get_string(session, "REMOTE_HOST", ret_remote_host);
5b04fe60
MM
811}
812
eac4a028 813_public_ int sd_session_get_leader(const char *session, pid_t *ret_leader) {
40308260 814 _cleanup_free_ char *leader_string = NULL;
40308260
TK
815 int r;
816
40308260
TK
817 r = session_get_string(session, "LEADER", &leader_string);
818 if (r < 0)
819 return r;
820
eac4a028 821 return parse_pid(leader_string, ret_leader);
40308260
TK
822}
823
26b5eea4 824_public_ int sd_seat_get_active(const char *seat, char **ret_session, uid_t *ret_uid) {
d70964d0 825 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
74b91131
LP
826 int r;
827
50b1678a
LP
828 r = file_of_seat(seat, &p);
829 if (r < 0)
830 return r;
74b91131 831
eac4a028 832 r = parse_env_file(/* f= */ NULL, p,
74b91131 833 "ACTIVE", &s,
13df9c39 834 "ACTIVE_UID", &t);
707b66c6
LP
835 if (r == -ENOENT)
836 return -ENXIO;
d70964d0 837 if (r < 0)
74b91131 838 return r;
74b91131 839
26b5eea4 840 if (ret_session && !s)
4211d5bd 841 return -ENODATA;
74b91131 842
26b5eea4 843 if (ret_uid && !t)
4211d5bd 844 return -ENODATA;
74b91131 845
26b5eea4
JW
846 if (ret_uid && t) {
847 r = parse_uid(t, ret_uid);
d70964d0 848 if (r < 0)
74b91131 849 return r;
74b91131
LP
850 }
851
26b5eea4
JW
852 if (ret_session && s)
853 *ret_session = TAKE_PTR(s);
74b91131
LP
854
855 return 0;
856}
034a2a52 857
aa3b40c3
ZJS
858_public_ int sd_seat_get_sessions(
859 const char *seat,
860 char ***ret_sessions,
861 uid_t **ret_uids,
862 unsigned *ret_n_uids) {
863
864 _cleanup_free_ char *fname = NULL, *session_line = NULL, *uid_line = NULL;
865 _cleanup_strv_free_ char **sessions = NULL;
866 _cleanup_free_ uid_t *uids = NULL;
867 unsigned n_sessions = 0;
034a2a52
LP
868 int r;
869
aa3b40c3 870 r = file_of_seat(seat, &fname);
50b1678a
LP
871 if (r < 0)
872 return r;
034a2a52 873
eac4a028 874 r = parse_env_file(/* f= */ NULL, fname,
aa3b40c3
ZJS
875 "SESSIONS", &session_line,
876 "UIDS", &uid_line);
707b66c6
LP
877 if (r == -ENOENT)
878 return -ENXIO;
d70964d0 879 if (r < 0)
034a2a52 880 return r;
034a2a52 881
aa3b40c3
ZJS
882 if (session_line) {
883 sessions = strv_split(session_line, NULL);
884 if (!sessions)
034a2a52 885 return -ENOMEM;
034a2a52 886
aa3b40c3
ZJS
887 n_sessions = strv_length(sessions);
888 };
034a2a52 889
aa3b40c3
ZJS
890 if (ret_uids && uid_line) {
891 uids = new(uid_t, n_sessions);
892 if (!uids)
893 return -ENOMEM;
034a2a52 894
aa3b40c3
ZJS
895 size_t n = 0;
896 for (const char *p = uid_line;;) {
897 _cleanup_free_ char *word = NULL;
de3756ab 898
aa3b40c3
ZJS
899 r = extract_first_word(&p, &word, NULL, 0);
900 if (r < 0)
901 return r;
902 if (r == 0)
903 break;
de3756ab 904
aa3b40c3
ZJS
905 r = parse_uid(word, &uids[n++]);
906 if (r < 0)
907 return r;
034a2a52 908 }
d60ef526 909
aa3b40c3
ZJS
910 if (n != n_sessions)
911 return -EUCLEAN;
912 }
034a2a52 913
aa3b40c3
ZJS
914 if (ret_sessions)
915 *ret_sessions = TAKE_PTR(sessions);
916 if (ret_uids)
917 *ret_uids = TAKE_PTR(uids);
918 if (ret_n_uids)
919 *ret_n_uids = n_sessions;
034a2a52 920
aa3b40c3 921 return n_sessions;
034a2a52
LP
922}
923
20747498 924static int seat_get_can(const char *seat, const char *variable) {
d70964d0 925 _cleanup_free_ char *p = NULL, *s = NULL;
add30678
LP
926 int r;
927
707b66c6 928 assert(variable);
0325941f 929
50b1678a
LP
930 r = file_of_seat(seat, &p);
931 if (r < 0)
932 return r;
add30678 933
eac4a028 934 r = parse_env_file(/* f= */ NULL, p,
13df9c39 935 variable, &s);
707b66c6
LP
936 if (r == -ENOENT)
937 return -ENXIO;
d70964d0 938 if (r < 0)
add30678 939 return r;
707b66c6
LP
940 if (isempty(s))
941 return -ENODATA;
add30678 942
0325941f 943 return parse_boolean(s);
add30678
LP
944}
945
20747498 946_public_ int sd_seat_can_multi_session(const char *seat) {
8f8cc84b 947 return true;
20747498
LP
948}
949
950_public_ int sd_seat_can_tty(const char *seat) {
951 return seat_get_can(seat, "CAN_TTY");
952}
953
954_public_ int sd_seat_can_graphical(const char *seat) {
955 return seat_get_can(seat, "CAN_GRAPHICAL");
956}
957
eac4a028 958_public_ int sd_get_seats(char ***ret_seats) {
2b5e9267
YW
959 int r;
960
eac4a028 961 r = get_files_in_directory("/run/systemd/seats/", ret_seats);
2b5e9267 962 if (r == -ENOENT) {
eac4a028
LP
963 if (ret_seats)
964 *ret_seats = NULL;
2b5e9267
YW
965 return 0;
966 }
967 return r;
034a2a52
LP
968}
969
eac4a028 970_public_ int sd_get_sessions(char ***ret_sessions) {
2b5e9267
YW
971 int r;
972
eac4a028 973 r = get_files_in_directory("/run/systemd/sessions/", ret_sessions);
2b5e9267 974 if (r == -ENOENT) {
eac4a028
LP
975 if (ret_sessions)
976 *ret_sessions = NULL;
2b5e9267
YW
977 return 0;
978 }
979 return r;
034a2a52
LP
980}
981
eac4a028 982_public_ int sd_get_uids(uid_t **ret_users) {
c2b2df60 983 _cleanup_closedir_ DIR *d = NULL;
d70964d0 984 _cleanup_free_ uid_t *l = NULL;
223a67e5 985 size_t n = 0;
034a2a52 986
034a2a52 987 d = opendir("/run/systemd/users/");
2b5e9267
YW
988 if (!d) {
989 if (errno == ENOENT) {
eac4a028
LP
990 if (ret_users)
991 *ret_users = NULL;
2b5e9267
YW
992 return 0;
993 }
8ea913b2 994 return -errno;
2b5e9267 995 }
8ea913b2 996
8fb3f009 997 FOREACH_DIRENT_ALL(de, d, return -errno) {
034a2a52
LP
998 uid_t uid;
999
034a2a52
LP
1000 if (!dirent_is_file(de))
1001 continue;
1002
223a67e5 1003 if (parse_uid(de->d_name, &uid) < 0)
034a2a52
LP
1004 continue;
1005
eac4a028 1006 if (ret_users) {
223a67e5
YW
1007 if (!GREEDY_REALLOC(l, n + 1))
1008 return -ENOMEM;
034a2a52 1009
223a67e5
YW
1010 l[n] = uid;
1011 }
034a2a52 1012
223a67e5 1013 n++;
034a2a52
LP
1014 }
1015
223a67e5
YW
1016 if (n > INT_MAX)
1017 return -EOVERFLOW;
1018
eac4a028
LP
1019 if (ret_users)
1020 *ret_users = TAKE_PTR(l);
034a2a52 1021
223a67e5 1022 return (int) n;
034a2a52
LP
1023}
1024
eac4a028 1025_public_ int sd_get_machine_names(char ***ret_machines) {
96480634
ZJS
1026 _cleanup_strv_free_ char **l = NULL;
1027 char **a, **b;
89f7c846
LP
1028 int r;
1029
1030 r = get_files_in_directory("/run/systemd/machines/", &l);
0543105b 1031 if (r == -ENOENT) {
eac4a028
LP
1032 if (ret_machines)
1033 *ret_machines = NULL;
0543105b
ZJS
1034 return 0;
1035 }
89f7c846
LP
1036 if (r < 0)
1037 return r;
1038
1039 if (l) {
1040 r = 0;
1041
1042 /* Filter out the unit: symlinks */
76ed21e1 1043 for (a = b = l; *a; a++) {
52ef5dd7 1044 if (startswith(*a, "unit:") || !hostname_is_valid(*a, 0))
89f7c846
LP
1045 free(*a);
1046 else {
1047 *b = *a;
1048 b++;
1049 r++;
1050 }
1051 }
1052
1053 *b = NULL;
1054 }
1055
eac4a028
LP
1056 if (ret_machines)
1057 *ret_machines = TAKE_PTR(l);
ae2a15bc 1058
89f7c846 1059 return r;
a20affe2
LP
1060}
1061
eac4a028 1062_public_ int sd_machine_get_class(const char *machine, char **ret_class) {
0325941f 1063 _cleanup_free_ char *c = NULL;
0325941f
LP
1064 int r;
1065
eac4a028 1066 if (streq_ptr(machine, ".host")) {
a8c9b7a0
LP
1067 c = strdup("host");
1068 if (!c)
1069 return -ENOMEM;
1070 } else {
52ef5dd7 1071 if (!hostname_is_valid(machine, 0))
a8c9b7a0 1072 return -EINVAL;
0325941f 1073
eac4a028
LP
1074 _cleanup_free_ char *p = path_join("/run/systemd/machines/", machine);
1075 if (!p)
1076 return -ENOMEM;
1077
1078 r = parse_env_file(/* f= */ NULL, p, "CLASS", &c);
a8c9b7a0
LP
1079 if (r == -ENOENT)
1080 return -ENXIO;
1081 if (r < 0)
1082 return r;
1083 if (!c)
1084 return -EIO;
1085 }
0325941f 1086
eac4a028
LP
1087 if (ret_class)
1088 *ret_class = TAKE_PTR(c);
1089
0325941f
LP
1090 return 0;
1091}
1092
0ef14adc 1093_public_ int sd_machine_get_ifindices(const char *machine, int **ret_ifindices) {
eac4a028 1094 _cleanup_free_ char *netif_line = NULL, *p = NULL;
cabb0bc6
LP
1095 int r;
1096
52ef5dd7 1097 assert_return(hostname_is_valid(machine, 0), -EINVAL);
cabb0bc6 1098
eac4a028
LP
1099 p = path_join("/run/systemd/machines/", machine);
1100 if (!p)
1101 return -ENOMEM;
1102
1103 r = parse_env_file(/* f= */ NULL, p, "NETIF", &netif_line);
707b66c6
LP
1104 if (r == -ENOENT)
1105 return -ENXIO;
cabb0bc6
LP
1106 if (r < 0)
1107 return r;
0ef14adc 1108 if (!netif_line) {
eac4a028
LP
1109 if (ret_ifindices)
1110 *ret_ifindices = NULL;
cabb0bc6
LP
1111 return 0;
1112 }
1113
0ef14adc
ZJS
1114 _cleanup_strv_free_ char **tt = strv_split(netif_line, NULL);
1115 if (!tt)
1116 return -ENOMEM;
cabb0bc6 1117
7a7e97ad 1118 _cleanup_free_ int *ifindices = NULL;
dd630d3c
ZJS
1119 if (ret_ifindices) {
1120 ifindices = new(int, strv_length(tt));
1121 if (!ifindices)
1122 return -ENOMEM;
1123 }
cabb0bc6 1124
7a7e97ad 1125 size_t n = 0;
0ef14adc
ZJS
1126 for (size_t i = 0; tt[i]; i++) {
1127 int ind;
cabb0bc6 1128
0ef14adc
ZJS
1129 ind = parse_ifindex(tt[i]);
1130 if (ind < 0)
1131 /* Return -EUCLEAN to distinguish from -EINVAL for invalid args */
1132 return ind == -EINVAL ? -EUCLEAN : ind;
cabb0bc6 1133
dd630d3c
ZJS
1134 if (ret_ifindices)
1135 ifindices[n] = ind;
1136 n++;
cabb0bc6
LP
1137 }
1138
dd630d3c 1139 if (ret_ifindices)
7a7e97ad
LP
1140 *ret_ifindices = TAKE_PTR(ifindices);
1141
0ef14adc 1142 return n;
cabb0bc6
LP
1143}
1144
a1e92eee 1145static int MONITOR_TO_FD(sd_login_monitor *m) {
034a2a52
LP
1146 return (int) (unsigned long) m - 1;
1147}
1148
a1e92eee 1149static sd_login_monitor* FD_TO_MONITOR(int fd) {
034a2a52
LP
1150 return (sd_login_monitor*) (unsigned long) (fd + 1);
1151}
1152
eac4a028 1153_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **ret) {
254d1313 1154 _cleanup_close_ int fd = -EBADF;
034a2a52 1155
eac4a028 1156 assert_return(ret, -EINVAL);
034a2a52
LP
1157
1158 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1159 if (fd < 0)
bcb161b0 1160 return -errno;
034a2a52 1161
e2af482f
LP
1162 static const struct {
1163 const char *name;
1164 const char *path;
1165 } categories[] = {
1166 { "seat", "/run/systemd/seats/" },
1167 { "session", "/run/systemd/sessions/" },
1168 { "uid", "/run/systemd/users/" },
1169 { "machine", "/run/systemd/machines/" },
1170 };
034a2a52 1171
e2af482f
LP
1172 bool good = false;
1173 FOREACH_ELEMENT(c, categories) {
1174 if (category && !streq(category, c->name))
1175 continue;
034a2a52 1176
e2af482f 1177 if (inotify_add_watch(fd, c->path, IN_MOVED_TO|IN_DELETE) < 0)
e10375f2 1178 return -errno;
e10375f2
LP
1179
1180 good = true;
1181 }
1182
4cbbc2a2 1183 if (!good)
034a2a52 1184 return -EINVAL;
034a2a52 1185
eac4a028 1186 *ret = FD_TO_MONITOR(TAKE_FD(fd));
034a2a52
LP
1187 return 0;
1188}
1189
1190_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
d52e1c42 1191 if (m)
da6c52c5 1192 (void) close(MONITOR_TO_FD(m));
034a2a52
LP
1193
1194 return NULL;
1195}
1196
1197_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
665dfe93 1198 int r;
034a2a52 1199
1ae464e0 1200 assert_return(m, -EINVAL);
034a2a52 1201
665dfe93
LP
1202 r = flush_fd(MONITOR_TO_FD(m));
1203 if (r < 0)
1204 return r;
1205
1206 return 0;
034a2a52
LP
1207}
1208
1209_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1210
1ae464e0 1211 assert_return(m, -EINVAL);
034a2a52
LP
1212
1213 return MONITOR_TO_FD(m);
1214}
dace83cb
LP
1215
1216_public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1217
1ae464e0 1218 assert_return(m, -EINVAL);
dace83cb 1219
667c24a6
LP
1220 /* For now we will only return POLLIN here, since we don't
1221 * need anything else ever for inotify. However, let's have
1222 * this API to keep our options open should we later on need
1223 * it. */
dace83cb
LP
1224 return POLLIN;
1225}
667c24a6 1226
eac4a028 1227_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *ret_timeout_usec) {
667c24a6 1228
1ae464e0 1229 assert_return(m, -EINVAL);
eac4a028 1230 assert_return(ret_timeout_usec, -EINVAL);
667c24a6 1231
f5fbe71d 1232 /* For now we will only return UINT64_MAX, since we don't
667c24a6
LP
1233 * need any timeout. However, let's have this API to keep our
1234 * options open should we later on need it. */
eac4a028 1235 *ret_timeout_usec = UINT64_MAX;
667c24a6
LP
1236 return 0;
1237}