]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-login/sd-login.c
build-sys: add missing makefile symlink
[thirdparty/systemd.git] / src / libsystemd / sd-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
74b91131 22#include <errno.h>
0a6f50c0 23#include <poll.h>
4f5dd394
LP
24#include <string.h>
25#include <sys/inotify.h>
26#include <unistd.h>
74b91131 27
07630cea
LP
28#include "sd-login.h"
29
74b91131 30#include "cgroup-util.h"
4f5dd394 31#include "escape.h"
3ffd4af2 32#include "fd-util.h"
a5c32cff 33#include "fileio.h"
6482f626 34#include "formats-util.h"
25300b5a 35#include "hostname-util.h"
c004493c 36#include "io-util.h"
4f5dd394
LP
37#include "login-util.h"
38#include "macro.h"
07630cea 39#include "string-util.h"
4f5dd394 40#include "strv.h"
b1d4f8e1 41#include "user-util.h"
4f5dd394 42#include "util.h"
74b91131 43
707b66c6
LP
44/* Error codes:
45 *
46 * invalid input parameters → -EINVAL
47 * invalid fd → -EBADF
48 * process does not exist → -ESRCH
49 * cgroup does not exist → -ENOENT
50 * machine, session does not exist → -ENXIO
51 * requested metadata on object is missing → -ENODATA
52 */
53
034a2a52 54_public_ int sd_pid_get_session(pid_t pid, char **session) {
ba1261bc 55
1ae464e0
TA
56 assert_return(pid >= 0, -EINVAL);
57 assert_return(session, -EINVAL);
034a2a52 58
7027ff61 59 return cg_pid_get_session(pid, session);
74b91131
LP
60}
61
94fb446e 62_public_ int sd_pid_get_unit(pid_t pid, char **unit) {
9847946e 63
1ae464e0
TA
64 assert_return(pid >= 0, -EINVAL);
65 assert_return(unit, -EINVAL);
9847946e 66
ba1261bc 67 return cg_pid_get_unit(pid, unit);
9847946e
LP
68}
69
97e13058
LP
70_public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
71
1ae464e0
TA
72 assert_return(pid >= 0, -EINVAL);
73 assert_return(unit, -EINVAL);
97e13058
LP
74
75 return cg_pid_get_user_unit(pid, unit);
76}
77
7027ff61
LP
78_public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
79
1ae464e0
TA
80 assert_return(pid >= 0, -EINVAL);
81 assert_return(name, -EINVAL);
7027ff61
LP
82
83 return cg_pid_get_machine_name(pid, name);
84}
85
1021b21b
LP
86_public_ int sd_pid_get_slice(pid_t pid, char **slice) {
87
1ae464e0
TA
88 assert_return(pid >= 0, -EINVAL);
89 assert_return(slice, -EINVAL);
1021b21b
LP
90
91 return cg_pid_get_slice(pid, slice);
92}
93
329ac4bc
LP
94_public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
95
96 assert_return(pid >= 0, -EINVAL);
97 assert_return(slice, -EINVAL);
98
99 return cg_pid_get_user_slice(pid, slice);
100}
101
034a2a52 102_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
034a2a52 103
1ae464e0
TA
104 assert_return(pid >= 0, -EINVAL);
105 assert_return(uid, -EINVAL);
034a2a52 106
ae018d9b 107 return cg_pid_get_owner_uid(pid, uid);
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
123 * that's easier and less ambigious for people to grok. */
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) {
bf34ab14
LP
260 _cleanup_free_ char *p = NULL;
261 char *s = NULL;
74b91131
LP
262 int r;
263
1ae464e0 264 assert_return(state, -EINVAL);
74b91131 265
a077b666
LP
266 r = file_of_uid(uid, &p);
267 if (r < 0)
268 return r;
74b91131
LP
269
270 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
74b91131
LP
271 if (r == -ENOENT) {
272 free(s);
273 s = strdup("offline");
274 if (!s)
275 return -ENOMEM;
276
707b66c6
LP
277 }
278 if (r < 0) {
74b91131
LP
279 free(s);
280 return r;
707b66c6
LP
281 }
282 if (isempty(s)) {
283 free(s);
74b91131 284 return -EIO;
707b66c6 285 }
74b91131
LP
286
287 *state = s;
288 return 0;
289}
290
a077b666
LP
291_public_ int sd_uid_get_display(uid_t uid, char **session) {
292 _cleanup_free_ char *p = NULL, *s = NULL;
293 int r;
294
295 assert_return(session, -EINVAL);
296
297 r = file_of_uid(uid, &p);
298 if (r < 0)
299 return r;
300
301 r = parse_env_file(p, NEWLINE, "DISPLAY", &s, NULL);
fc60d815 302 if (r == -ENOENT)
707b66c6 303 return -ENODATA;
a077b666
LP
304 if (r < 0)
305 return r;
a077b666 306 if (isempty(s))
707b66c6 307 return -ENODATA;
a077b666
LP
308
309 *session = s;
310 s = NULL;
311
312 return 0;
313}
314
707b66c6
LP
315static int file_of_seat(const char *seat, char **_p) {
316 char *p;
317 int r;
318
319 assert(_p);
320
321 if (seat) {
322 if (!filename_is_valid(seat))
323 return -EINVAL;
324
325 p = strappend("/run/systemd/seats/", seat);
326 } else {
327 _cleanup_free_ char *buf = NULL;
328
329 r = sd_session_get_seat(NULL, &buf);
330 if (r < 0)
331 return r;
332
333 p = strappend("/run/systemd/seats/", buf);
334 }
335
336 if (!p)
337 return -ENOMEM;
338
339 *_p = p;
340 p = NULL;
341 return 0;
342}
343
034a2a52 344_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
d70964d0 345 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
74b91131
LP
346 size_t l;
347 int r;
a2a5291b 348 const char *word, *variable, *state;
74b91131 349
a1f686da 350 assert_return(uid_is_valid(uid), -EINVAL);
74b91131 351
707b66c6
LP
352 r = file_of_seat(seat, &p);
353 if (r < 0)
354 return r;
034a2a52 355
707b66c6 356 variable = require_active ? "ACTIVE_UID" : "UIDS";
74b91131 357
034a2a52 358 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
707b66c6
LP
359 if (r == -ENOENT)
360 return 0;
d70964d0 361 if (r < 0)
74b91131 362 return r;
707b66c6
LP
363 if (isempty(s))
364 return 0;
74b91131 365
de0671ee 366 if (asprintf(&t, UID_FMT, uid) < 0)
74b91131 367 return -ENOMEM;
74b91131 368
707b66c6 369 FOREACH_WORD(word, l, s, state)
a2a5291b 370 if (strneq(t, word, l))
74b91131 371 return 1;
74b91131 372
74b91131
LP
373 return 0;
374}
375
034a2a52 376static int uid_get_array(uid_t uid, const char *variable, char ***array) {
d70964d0 377 _cleanup_free_ char *p = NULL, *s = NULL;
034a2a52
LP
378 char **a;
379 int r;
380
707b66c6 381 assert(variable);
a1f686da 382
a077b666
LP
383 r = file_of_uid(uid, &p);
384 if (r < 0)
385 return r;
034a2a52 386
707b66c6
LP
387 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
388 if (r == -ENOENT || (r >= 0 && isempty(s))) {
d60ef526
LP
389 if (array)
390 *array = NULL;
034a2a52
LP
391 return 0;
392 }
707b66c6
LP
393 if (r < 0)
394 return r;
034a2a52
LP
395
396 a = strv_split(s, " ");
034a2a52
LP
397 if (!a)
398 return -ENOMEM;
399
d60ef526
LP
400 strv_uniq(a);
401 r = strv_length(a);
402
403 if (array)
404 *array = a;
405 else
406 strv_free(a);
407
408 return r;
034a2a52
LP
409}
410
411_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
d18dff43
LP
412 return uid_get_array(
413 uid,
414 require_active == 0 ? "ONLINE_SESSIONS" :
415 require_active > 0 ? "ACTIVE_SESSIONS" :
416 "SESSIONS",
417 sessions);
74b91131
LP
418}
419
034a2a52 420_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
d18dff43
LP
421 return uid_get_array(
422 uid,
423 require_active == 0 ? "ONLINE_SEATS" :
424 require_active > 0 ? "ACTIVE_SEATS" :
425 "SEATS",
426 seats);
74b91131
LP
427}
428
50b1678a
LP
429static int file_of_session(const char *session, char **_p) {
430 char *p;
74b91131 431 int r;
74b91131 432
50b1678a
LP
433 assert(_p);
434
4b549144
ZJS
435 if (session) {
436 if (!session_id_valid(session))
437 return -EINVAL;
438
50b1678a 439 p = strappend("/run/systemd/sessions/", session);
4b549144
ZJS
440 } else {
441 _cleanup_free_ char *buf = NULL;
50b1678a
LP
442
443 r = sd_pid_get_session(0, &buf);
444 if (r < 0)
445 return r;
446
447 p = strappend("/run/systemd/sessions/", buf);
50b1678a 448 }
74b91131 449
74b91131
LP
450 if (!p)
451 return -ENOMEM;
452
50b1678a
LP
453 *_p = p;
454 return 0;
455}
456
457_public_ int sd_session_is_active(const char *session) {
d70964d0 458 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 459 int r;
50b1678a
LP
460
461 r = file_of_session(session, &p);
462 if (r < 0)
463 return r;
464
74b91131 465 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
707b66c6
LP
466 if (r == -ENOENT)
467 return -ENXIO;
d70964d0 468 if (r < 0)
74b91131 469 return r;
707b66c6 470 if (isempty(s))
74b91131
LP
471 return -EIO;
472
0325941f 473 return parse_boolean(s);
74b91131
LP
474}
475
5b04fe60 476_public_ int sd_session_is_remote(const char *session) {
5b04fe60 477 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 478 int r;
5b04fe60
MM
479
480 r = file_of_session(session, &p);
481 if (r < 0)
482 return r;
483
484 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
707b66c6
LP
485 if (r == -ENOENT)
486 return -ENXIO;
5b04fe60
MM
487 if (r < 0)
488 return r;
707b66c6
LP
489 if (isempty(s))
490 return -ENODATA;
5b04fe60 491
0325941f 492 return parse_boolean(s);
5b04fe60
MM
493}
494
0604381b 495_public_ int sd_session_get_state(const char *session, char **state) {
d70964d0 496 _cleanup_free_ char *p = NULL, *s = NULL;
0604381b
LP
497 int r;
498
1ae464e0 499 assert_return(state, -EINVAL);
0604381b
LP
500
501 r = file_of_session(session, &p);
502 if (r < 0)
503 return r;
504
505 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
707b66c6
LP
506 if (r == -ENOENT)
507 return -ENXIO;
d70964d0 508 if (r < 0)
0604381b 509 return r;
707b66c6 510 if (isempty(s))
0604381b
LP
511 return -EIO;
512
513 *state = s;
d70964d0
HH
514 s = NULL;
515
0604381b
LP
516 return 0;
517}
518
74b91131
LP
519_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
520 int r;
d70964d0 521 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131 522
1ae464e0 523 assert_return(uid, -EINVAL);
74b91131 524
50b1678a
LP
525 r = file_of_session(session, &p);
526 if (r < 0)
527 return r;
74b91131
LP
528
529 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
707b66c6
LP
530 if (r == -ENOENT)
531 return -ENXIO;
d70964d0 532 if (r < 0)
74b91131 533 return r;
707b66c6 534 if (isempty(s))
74b91131
LP
535 return -EIO;
536
0325941f 537 return parse_uid(s, uid);
74b91131
LP
538}
539
51f58f08 540static int session_get_string(const char *session, const char *field, char **value) {
d70964d0 541 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131
LP
542 int r;
543
1ae464e0 544 assert_return(value, -EINVAL);
707b66c6 545 assert(field);
74b91131 546
50b1678a
LP
547 r = file_of_session(session, &p);
548 if (r < 0)
549 return r;
74b91131 550
51f58f08 551 r = parse_env_file(p, NEWLINE, field, &s, NULL);
707b66c6
LP
552 if (r == -ENOENT)
553 return -ENXIO;
d70964d0 554 if (r < 0)
74b91131 555 return r;
74b91131 556 if (isempty(s))
707b66c6 557 return -ENODATA;
74b91131 558
51f58f08 559 *value = s;
d70964d0 560 s = NULL;
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
LP
643
644 r = parse_env_file(p, NEWLINE,
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
d70964d0 665 if (session && s) {
74b91131 666 *session = s;
d70964d0
HH
667 s = NULL;
668 }
74b91131
LP
669
670 return 0;
671}
034a2a52
LP
672
673_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
d70964d0
HH
674 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
675 _cleanup_strv_free_ char **a = NULL;
676 _cleanup_free_ uid_t *b = NULL;
034a2a52
LP
677 unsigned n = 0;
678 int r;
679
50b1678a
LP
680 r = file_of_seat(seat, &p);
681 if (r < 0)
682 return r;
034a2a52
LP
683
684 r = parse_env_file(p, NEWLINE,
685 "SESSIONS", &s,
686 "ACTIVE_SESSIONS", &t,
687 NULL);
707b66c6
LP
688 if (r == -ENOENT)
689 return -ENXIO;
d70964d0 690 if (r < 0)
034a2a52 691 return r;
034a2a52 692
d60ef526 693 if (s) {
034a2a52 694 a = strv_split(s, " ");
d70964d0 695 if (!a)
034a2a52 696 return -ENOMEM;
034a2a52
LP
697 }
698
034a2a52 699 if (uids && t) {
a2a5291b 700 const char *word, *state;
034a2a52 701 size_t l;
034a2a52 702
a2a5291b 703 FOREACH_WORD(word, l, t, state)
034a2a52
LP
704 n++;
705
d70964d0 706 if (n > 0) {
de3756ab 707 unsigned i = 0;
034a2a52 708
de3756ab 709 b = new(uid_t, n);
d70964d0 710 if (!b)
034a2a52 711 return -ENOMEM;
034a2a52 712
a2a5291b 713 FOREACH_WORD(word, l, t, state) {
d70964d0 714 _cleanup_free_ char *k = NULL;
034a2a52 715
a2a5291b 716 k = strndup(word, l);
d70964d0 717 if (!k)
de3756ab 718 return -ENOMEM;
de3756ab
LP
719
720 r = parse_uid(k, b + i);
de3756ab
LP
721 if (r < 0)
722 continue;
723
724 i++;
725 }
034a2a52
LP
726 }
727 }
728
d60ef526
LP
729 r = strv_length(a);
730
d70964d0 731 if (sessions) {
034a2a52 732 *sessions = a;
d70964d0
HH
733 a = NULL;
734 }
034a2a52 735
d70964d0 736 if (uids) {
034a2a52 737 *uids = b;
d70964d0
HH
738 b = NULL;
739 }
034a2a52
LP
740
741 if (n_uids)
742 *n_uids = n;
743
d60ef526 744 return r;
034a2a52
LP
745}
746
20747498 747static int seat_get_can(const char *seat, const char *variable) {
d70964d0 748 _cleanup_free_ char *p = NULL, *s = NULL;
add30678
LP
749 int r;
750
707b66c6 751 assert(variable);
0325941f 752
50b1678a
LP
753 r = file_of_seat(seat, &p);
754 if (r < 0)
755 return r;
add30678
LP
756
757 r = parse_env_file(p, NEWLINE,
20747498 758 variable, &s,
add30678 759 NULL);
707b66c6
LP
760 if (r == -ENOENT)
761 return -ENXIO;
d70964d0 762 if (r < 0)
add30678 763 return r;
707b66c6
LP
764 if (isempty(s))
765 return -ENODATA;
add30678 766
0325941f 767 return parse_boolean(s);
add30678
LP
768}
769
20747498
LP
770_public_ int sd_seat_can_multi_session(const char *seat) {
771 return seat_get_can(seat, "CAN_MULTI_SESSION");
772}
773
774_public_ int sd_seat_can_tty(const char *seat) {
775 return seat_get_can(seat, "CAN_TTY");
776}
777
778_public_ int sd_seat_can_graphical(const char *seat) {
779 return seat_get_can(seat, "CAN_GRAPHICAL");
780}
781
034a2a52 782_public_ int sd_get_seats(char ***seats) {
034a2a52
LP
783 return get_files_in_directory("/run/systemd/seats/", seats);
784}
785
786_public_ int sd_get_sessions(char ***sessions) {
034a2a52
LP
787 return get_files_in_directory("/run/systemd/sessions/", sessions);
788}
789
790_public_ int sd_get_uids(uid_t **users) {
d70964d0 791 _cleanup_closedir_ DIR *d;
034a2a52
LP
792 int r = 0;
793 unsigned n = 0;
d70964d0 794 _cleanup_free_ uid_t *l = NULL;
034a2a52 795
034a2a52 796 d = opendir("/run/systemd/users/");
8ea913b2
LP
797 if (!d)
798 return -errno;
799
034a2a52 800 for (;;) {
7d5e9c0f 801 struct dirent *de;
034a2a52
LP
802 int k;
803 uid_t uid;
804
66c7a533
FW
805 errno = 0;
806 de = readdir(d);
807 if (!de && errno != 0)
808 return -errno;
034a2a52
LP
809
810 if (!de)
811 break;
812
813 dirent_ensure_type(d, de);
814
815 if (!dirent_is_file(de))
816 continue;
817
818 k = parse_uid(de->d_name, &uid);
819 if (k < 0)
820 continue;
821
d60ef526
LP
822 if (users) {
823 if ((unsigned) r >= n) {
824 uid_t *t;
034a2a52 825
d60ef526
LP
826 n = MAX(16, 2*r);
827 t = realloc(l, sizeof(uid_t) * n);
d70964d0
HH
828 if (!t)
829 return -ENOMEM;
034a2a52 830
d60ef526
LP
831 l = t;
832 }
034a2a52 833
d60ef526
LP
834 assert((unsigned) r < n);
835 l[r++] = uid;
836 } else
837 r++;
034a2a52
LP
838 }
839
d70964d0
HH
840 if (users) {
841 *users = l;
842 l = NULL;
843 }
034a2a52
LP
844
845 return r;
846}
847
4d5fb962 848_public_ int sd_get_machine_names(char ***machines) {
89f7c846
LP
849 char **l = NULL, **a, **b;
850 int r;
851
0325941f
LP
852 assert_return(machines, -EINVAL);
853
89f7c846
LP
854 r = get_files_in_directory("/run/systemd/machines/", &l);
855 if (r < 0)
856 return r;
857
858 if (l) {
859 r = 0;
860
861 /* Filter out the unit: symlinks */
862 for (a = l, b = l; *a; a++) {
b9a8d250 863 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
89f7c846
LP
864 free(*a);
865 else {
866 *b = *a;
867 b++;
868 r++;
869 }
870 }
871
872 *b = NULL;
873 }
874
875 *machines = l;
876 return r;
a20affe2
LP
877}
878
0325941f
LP
879_public_ int sd_machine_get_class(const char *machine, char **class) {
880 _cleanup_free_ char *c = NULL;
881 const char *p;
882 int r;
883
620a687c 884 assert_return(machine_name_is_valid(machine), -EINVAL);
0325941f
LP
885 assert_return(class, -EINVAL);
886
63c372cb 887 p = strjoina("/run/systemd/machines/", machine);
0325941f 888 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
707b66c6
LP
889 if (r == -ENOENT)
890 return -ENXIO;
0325941f
LP
891 if (r < 0)
892 return r;
893 if (!c)
894 return -EIO;
895
896 *class = c;
897 c = NULL;
898
899 return 0;
900}
901
634af566 902_public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
cabb0bc6
LP
903 _cleanup_free_ char *netif = NULL;
904 size_t l, allocated = 0, nr = 0;
cabb0bc6 905 int *ni = NULL;
a2a5291b 906 const char *p, *word, *state;
cabb0bc6
LP
907 int r;
908
909 assert_return(machine_name_is_valid(machine), -EINVAL);
634af566 910 assert_return(ifindices, -EINVAL);
cabb0bc6 911
63c372cb 912 p = strjoina("/run/systemd/machines/", machine);
cabb0bc6 913 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
707b66c6
LP
914 if (r == -ENOENT)
915 return -ENXIO;
cabb0bc6
LP
916 if (r < 0)
917 return r;
918 if (!netif) {
634af566 919 *ifindices = NULL;
cabb0bc6
LP
920 return 0;
921 }
922
a2a5291b 923 FOREACH_WORD(word, l, netif, state) {
cabb0bc6
LP
924 char buf[l+1];
925 int ifi;
926
a2a5291b 927 *(char*) (mempcpy(buf, word, l)) = 0;
cabb0bc6
LP
928
929 if (safe_atoi(buf, &ifi) < 0)
930 continue;
931 if (ifi <= 0)
932 continue;
933
934 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
935 free(ni);
936 return -ENOMEM;
937 }
938
939 ni[nr++] = ifi;
940 }
941
634af566 942 *ifindices = ni;
cabb0bc6
LP
943 return nr;
944}
945
034a2a52
LP
946static inline int MONITOR_TO_FD(sd_login_monitor *m) {
947 return (int) (unsigned long) m - 1;
948}
949
950static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
951 return (sd_login_monitor*) (unsigned long) (fd + 1);
952}
953
954_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
034a2a52
LP
955 int fd, k;
956 bool good = false;
957
1ae464e0 958 assert_return(m, -EINVAL);
034a2a52
LP
959
960 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
961 if (fd < 0)
bcb161b0 962 return -errno;
034a2a52
LP
963
964 if (!category || streq(category, "seat")) {
965 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
966 if (k < 0) {
03e334a1 967 safe_close(fd);
034a2a52
LP
968 return -errno;
969 }
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);
976 if (k < 0) {
03e334a1 977 safe_close(fd);
034a2a52
LP
978 return -errno;
979 }
980
981 good = true;
982 }
983
984 if (!category || streq(category, "uid")) {
985 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
986 if (k < 0) {
03e334a1 987 safe_close(fd);
034a2a52
LP
988 return -errno;
989 }
990
991 good = true;
992 }
993
e10375f2 994 if (!category || streq(category, "machine")) {
ba73ed85 995 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
e10375f2 996 if (k < 0) {
03e334a1 997 safe_close(fd);
e10375f2
LP
998 return -errno;
999 }
1000
1001 good = true;
1002 }
1003
034a2a52
LP
1004 if (!good) {
1005 close_nointr(fd);
1006 return -EINVAL;
1007 }
1008
1009 *m = FD_TO_MONITOR(fd);
1010 return 0;
1011}
1012
1013_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1014 int fd;
1015
1ae464e0 1016 assert_return(m, NULL);
034a2a52
LP
1017
1018 fd = MONITOR_TO_FD(m);
1019 close_nointr(fd);
1020
1021 return NULL;
1022}
1023
1024_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1025
1ae464e0 1026 assert_return(m, -EINVAL);
034a2a52
LP
1027
1028 return flush_fd(MONITOR_TO_FD(m));
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}