]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-login/sd-login.c
util-lib: introduce dirent-util.[ch] for directory entry calls
[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"
6bedfcbb 39#include "parse-util.h"
bb15fafe 40#include "path-util.h"
2583fbea 41#include "socket-util.h"
07630cea 42#include "string-util.h"
4f5dd394 43#include "strv.h"
b1d4f8e1 44#include "user-util.h"
4f5dd394 45#include "util.h"
a0956174 46#include "dirent-util.h"
74b91131 47
707b66c6
LP
48/* Error codes:
49 *
50 * invalid input parameters → -EINVAL
51 * invalid fd → -EBADF
52 * process does not exist → -ESRCH
53 * cgroup does not exist → -ENOENT
54 * machine, session does not exist → -ENXIO
55 * requested metadata on object is missing → -ENODATA
56 */
57
034a2a52 58_public_ int sd_pid_get_session(pid_t pid, char **session) {
ba1261bc 59
1ae464e0
TA
60 assert_return(pid >= 0, -EINVAL);
61 assert_return(session, -EINVAL);
034a2a52 62
7027ff61 63 return cg_pid_get_session(pid, session);
74b91131
LP
64}
65
94fb446e 66_public_ int sd_pid_get_unit(pid_t pid, char **unit) {
9847946e 67
1ae464e0
TA
68 assert_return(pid >= 0, -EINVAL);
69 assert_return(unit, -EINVAL);
9847946e 70
ba1261bc 71 return cg_pid_get_unit(pid, unit);
9847946e
LP
72}
73
97e13058
LP
74_public_ int sd_pid_get_user_unit(pid_t pid, char **unit) {
75
1ae464e0
TA
76 assert_return(pid >= 0, -EINVAL);
77 assert_return(unit, -EINVAL);
97e13058
LP
78
79 return cg_pid_get_user_unit(pid, unit);
80}
81
7027ff61
LP
82_public_ int sd_pid_get_machine_name(pid_t pid, char **name) {
83
1ae464e0
TA
84 assert_return(pid >= 0, -EINVAL);
85 assert_return(name, -EINVAL);
7027ff61
LP
86
87 return cg_pid_get_machine_name(pid, name);
88}
89
1021b21b
LP
90_public_ int sd_pid_get_slice(pid_t pid, char **slice) {
91
1ae464e0
TA
92 assert_return(pid >= 0, -EINVAL);
93 assert_return(slice, -EINVAL);
1021b21b
LP
94
95 return cg_pid_get_slice(pid, slice);
96}
97
329ac4bc
LP
98_public_ int sd_pid_get_user_slice(pid_t pid, char **slice) {
99
100 assert_return(pid >= 0, -EINVAL);
101 assert_return(slice, -EINVAL);
102
103 return cg_pid_get_user_slice(pid, slice);
104}
105
034a2a52 106_public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) {
034a2a52 107
1ae464e0
TA
108 assert_return(pid >= 0, -EINVAL);
109 assert_return(uid, -EINVAL);
034a2a52 110
ae018d9b 111 return cg_pid_get_owner_uid(pid, uid);
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
127 * that's easier and less ambigious for people to grok. */
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
LP
273
274 r = parse_env_file(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
LP
281 }
282 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
305 r = parse_env_file(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
LP
312
313 *session = s;
314 s = NULL;
315
316 return 0;
317}
318
707b66c6
LP
319static int file_of_seat(const char *seat, char **_p) {
320 char *p;
321 int r;
322
323 assert(_p);
324
325 if (seat) {
326 if (!filename_is_valid(seat))
327 return -EINVAL;
328
329 p = strappend("/run/systemd/seats/", seat);
330 } else {
331 _cleanup_free_ char *buf = NULL;
332
333 r = sd_session_get_seat(NULL, &buf);
334 if (r < 0)
335 return r;
336
337 p = strappend("/run/systemd/seats/", buf);
338 }
339
340 if (!p)
341 return -ENOMEM;
342
343 *_p = p;
344 p = NULL;
345 return 0;
346}
347
034a2a52 348_public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) {
d70964d0 349 _cleanup_free_ char *t = NULL, *s = NULL, *p = NULL;
74b91131
LP
350 size_t l;
351 int r;
a2a5291b 352 const char *word, *variable, *state;
74b91131 353
a1f686da 354 assert_return(uid_is_valid(uid), -EINVAL);
74b91131 355
707b66c6
LP
356 r = file_of_seat(seat, &p);
357 if (r < 0)
358 return r;
034a2a52 359
707b66c6 360 variable = require_active ? "ACTIVE_UID" : "UIDS";
74b91131 361
034a2a52 362 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
707b66c6
LP
363 if (r == -ENOENT)
364 return 0;
d70964d0 365 if (r < 0)
74b91131 366 return r;
707b66c6
LP
367 if (isempty(s))
368 return 0;
74b91131 369
de0671ee 370 if (asprintf(&t, UID_FMT, uid) < 0)
74b91131 371 return -ENOMEM;
74b91131 372
707b66c6 373 FOREACH_WORD(word, l, s, state)
a2a5291b 374 if (strneq(t, word, l))
74b91131 375 return 1;
74b91131 376
74b91131
LP
377 return 0;
378}
379
034a2a52 380static int uid_get_array(uid_t uid, const char *variable, char ***array) {
d70964d0 381 _cleanup_free_ char *p = NULL, *s = NULL;
034a2a52
LP
382 char **a;
383 int r;
384
707b66c6 385 assert(variable);
a1f686da 386
a077b666
LP
387 r = file_of_uid(uid, &p);
388 if (r < 0)
389 return r;
034a2a52 390
707b66c6
LP
391 r = parse_env_file(p, NEWLINE, variable, &s, NULL);
392 if (r == -ENOENT || (r >= 0 && isempty(s))) {
d60ef526
LP
393 if (array)
394 *array = NULL;
034a2a52
LP
395 return 0;
396 }
707b66c6
LP
397 if (r < 0)
398 return r;
034a2a52
LP
399
400 a = strv_split(s, " ");
034a2a52
LP
401 if (!a)
402 return -ENOMEM;
403
d60ef526
LP
404 strv_uniq(a);
405 r = strv_length(a);
406
407 if (array)
408 *array = a;
409 else
410 strv_free(a);
411
412 return r;
034a2a52
LP
413}
414
415_public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) {
d18dff43
LP
416 return uid_get_array(
417 uid,
418 require_active == 0 ? "ONLINE_SESSIONS" :
419 require_active > 0 ? "ACTIVE_SESSIONS" :
420 "SESSIONS",
421 sessions);
74b91131
LP
422}
423
034a2a52 424_public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) {
d18dff43
LP
425 return uid_get_array(
426 uid,
427 require_active == 0 ? "ONLINE_SEATS" :
428 require_active > 0 ? "ACTIVE_SEATS" :
429 "SEATS",
430 seats);
74b91131
LP
431}
432
50b1678a
LP
433static int file_of_session(const char *session, char **_p) {
434 char *p;
74b91131 435 int r;
74b91131 436
50b1678a
LP
437 assert(_p);
438
4b549144
ZJS
439 if (session) {
440 if (!session_id_valid(session))
441 return -EINVAL;
442
50b1678a 443 p = strappend("/run/systemd/sessions/", session);
4b549144
ZJS
444 } else {
445 _cleanup_free_ char *buf = NULL;
50b1678a
LP
446
447 r = sd_pid_get_session(0, &buf);
448 if (r < 0)
449 return r;
450
451 p = strappend("/run/systemd/sessions/", buf);
50b1678a 452 }
74b91131 453
74b91131
LP
454 if (!p)
455 return -ENOMEM;
456
50b1678a
LP
457 *_p = p;
458 return 0;
459}
460
461_public_ int sd_session_is_active(const char *session) {
d70964d0 462 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 463 int r;
50b1678a
LP
464
465 r = file_of_session(session, &p);
466 if (r < 0)
467 return r;
468
74b91131 469 r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL);
707b66c6
LP
470 if (r == -ENOENT)
471 return -ENXIO;
d70964d0 472 if (r < 0)
74b91131 473 return r;
707b66c6 474 if (isempty(s))
74b91131
LP
475 return -EIO;
476
0325941f 477 return parse_boolean(s);
74b91131
LP
478}
479
5b04fe60 480_public_ int sd_session_is_remote(const char *session) {
5b04fe60 481 _cleanup_free_ char *p = NULL, *s = NULL;
707b66c6 482 int r;
5b04fe60
MM
483
484 r = file_of_session(session, &p);
485 if (r < 0)
486 return r;
487
488 r = parse_env_file(p, NEWLINE, "REMOTE", &s, NULL);
707b66c6
LP
489 if (r == -ENOENT)
490 return -ENXIO;
5b04fe60
MM
491 if (r < 0)
492 return r;
707b66c6
LP
493 if (isempty(s))
494 return -ENODATA;
5b04fe60 495
0325941f 496 return parse_boolean(s);
5b04fe60
MM
497}
498
0604381b 499_public_ int sd_session_get_state(const char *session, char **state) {
d70964d0 500 _cleanup_free_ char *p = NULL, *s = NULL;
0604381b
LP
501 int r;
502
1ae464e0 503 assert_return(state, -EINVAL);
0604381b
LP
504
505 r = file_of_session(session, &p);
506 if (r < 0)
507 return r;
508
509 r = parse_env_file(p, NEWLINE, "STATE", &s, NULL);
707b66c6
LP
510 if (r == -ENOENT)
511 return -ENXIO;
d70964d0 512 if (r < 0)
0604381b 513 return r;
707b66c6 514 if (isempty(s))
0604381b
LP
515 return -EIO;
516
517 *state = s;
d70964d0
HH
518 s = NULL;
519
0604381b
LP
520 return 0;
521}
522
74b91131
LP
523_public_ int sd_session_get_uid(const char *session, uid_t *uid) {
524 int r;
d70964d0 525 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131 526
1ae464e0 527 assert_return(uid, -EINVAL);
74b91131 528
50b1678a
LP
529 r = file_of_session(session, &p);
530 if (r < 0)
531 return r;
74b91131
LP
532
533 r = parse_env_file(p, NEWLINE, "UID", &s, NULL);
707b66c6
LP
534 if (r == -ENOENT)
535 return -ENXIO;
d70964d0 536 if (r < 0)
74b91131 537 return r;
707b66c6 538 if (isempty(s))
74b91131
LP
539 return -EIO;
540
0325941f 541 return parse_uid(s, uid);
74b91131
LP
542}
543
51f58f08 544static int session_get_string(const char *session, const char *field, char **value) {
d70964d0 545 _cleanup_free_ char *p = NULL, *s = NULL;
74b91131
LP
546 int r;
547
1ae464e0 548 assert_return(value, -EINVAL);
707b66c6 549 assert(field);
74b91131 550
50b1678a
LP
551 r = file_of_session(session, &p);
552 if (r < 0)
553 return r;
74b91131 554
51f58f08 555 r = parse_env_file(p, NEWLINE, field, &s, NULL);
707b66c6
LP
556 if (r == -ENOENT)
557 return -ENXIO;
d70964d0 558 if (r < 0)
74b91131 559 return r;
74b91131 560 if (isempty(s))
707b66c6 561 return -ENODATA;
74b91131 562
51f58f08 563 *value = s;
d70964d0 564 s = NULL;
74b91131
LP
565 return 0;
566}
567
51f58f08
LP
568_public_ int sd_session_get_seat(const char *session, char **seat) {
569 return session_get_string(session, "SEAT", seat);
570}
eff40633 571
c84f5e4a
LP
572_public_ int sd_session_get_tty(const char *session, char **tty) {
573 return session_get_string(session, "TTY", tty);
574}
575
44ded3ab 576_public_ int sd_session_get_vt(const char *session, unsigned *vtnr) {
3f4fee03 577 _cleanup_free_ char *vtnr_string = NULL;
44ded3ab
GC
578 unsigned u;
579 int r;
580
707b66c6
LP
581 assert_return(vtnr, -EINVAL);
582
0581dac2 583 r = session_get_string(session, "VTNR", &vtnr_string);
44ded3ab
GC
584 if (r < 0)
585 return r;
586
587 r = safe_atou(vtnr_string, &u);
588 if (r < 0)
589 return r;
590
591 *vtnr = u;
592 return 0;
593}
594
51f58f08
LP
595_public_ int sd_session_get_service(const char *session, char **service) {
596 return session_get_string(session, "SERVICE", service);
597}
eff40633 598
51f58f08
LP
599_public_ int sd_session_get_type(const char *session, char **type) {
600 return session_get_string(session, "TYPE", type);
601}
eff40633 602
51f58f08
LP
603_public_ int sd_session_get_class(const char *session, char **class) {
604 return session_get_string(session, "CLASS", class);
eff40633
LP
605}
606
c72d5456
DH
607_public_ int sd_session_get_desktop(const char *session, char **desktop) {
608 _cleanup_free_ char *escaped = NULL;
609 char *t;
610 int r;
611
612 assert_return(desktop, -EINVAL);
613
614 r = session_get_string(session, "DESKTOP", &escaped);
615 if (r < 0)
616 return r;
617
527b7a42
LP
618 r = cunescape(escaped, 0, &t);
619 if (r < 0)
620 return r;
c72d5456
DH
621
622 *desktop = t;
623 return 0;
624}
625
fc8af9ff
LP
626_public_ int sd_session_get_display(const char *session, char **display) {
627 return session_get_string(session, "DISPLAY", display);
628}
629
5b04fe60
MM
630_public_ int sd_session_get_remote_user(const char *session, char **remote_user) {
631 return session_get_string(session, "REMOTE_USER", remote_user);
632}
633
634_public_ int sd_session_get_remote_host(const char *session, char **remote_host) {
635 return session_get_string(session, "REMOTE_HOST", remote_host);
636}
637
74b91131 638_public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) {
d70964d0 639 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
74b91131
LP
640 int r;
641
1ae464e0 642 assert_return(session || uid, -EINVAL);
74b91131 643
50b1678a
LP
644 r = file_of_seat(seat, &p);
645 if (r < 0)
646 return r;
74b91131
LP
647
648 r = parse_env_file(p, NEWLINE,
649 "ACTIVE", &s,
650 "ACTIVE_UID", &t,
651 NULL);
707b66c6
LP
652 if (r == -ENOENT)
653 return -ENXIO;
d70964d0 654 if (r < 0)
74b91131 655 return r;
74b91131 656
d70964d0 657 if (session && !s)
4211d5bd 658 return -ENODATA;
74b91131 659
d70964d0 660 if (uid && !t)
4211d5bd 661 return -ENODATA;
74b91131
LP
662
663 if (uid && t) {
034a2a52 664 r = parse_uid(t, uid);
d70964d0 665 if (r < 0)
74b91131 666 return r;
74b91131
LP
667 }
668
d70964d0 669 if (session && s) {
74b91131 670 *session = s;
d70964d0
HH
671 s = NULL;
672 }
74b91131
LP
673
674 return 0;
675}
034a2a52
LP
676
677_public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) {
d70964d0
HH
678 _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
679 _cleanup_strv_free_ char **a = NULL;
680 _cleanup_free_ uid_t *b = NULL;
034a2a52
LP
681 unsigned n = 0;
682 int r;
683
50b1678a
LP
684 r = file_of_seat(seat, &p);
685 if (r < 0)
686 return r;
034a2a52
LP
687
688 r = parse_env_file(p, NEWLINE,
689 "SESSIONS", &s,
690 "ACTIVE_SESSIONS", &t,
691 NULL);
707b66c6
LP
692 if (r == -ENOENT)
693 return -ENXIO;
d70964d0 694 if (r < 0)
034a2a52 695 return r;
034a2a52 696
d60ef526 697 if (s) {
034a2a52 698 a = strv_split(s, " ");
d70964d0 699 if (!a)
034a2a52 700 return -ENOMEM;
034a2a52
LP
701 }
702
034a2a52 703 if (uids && t) {
a2a5291b 704 const char *word, *state;
034a2a52 705 size_t l;
034a2a52 706
a2a5291b 707 FOREACH_WORD(word, l, t, state)
034a2a52
LP
708 n++;
709
d70964d0 710 if (n > 0) {
de3756ab 711 unsigned i = 0;
034a2a52 712
de3756ab 713 b = new(uid_t, n);
d70964d0 714 if (!b)
034a2a52 715 return -ENOMEM;
034a2a52 716
a2a5291b 717 FOREACH_WORD(word, l, t, state) {
d70964d0 718 _cleanup_free_ char *k = NULL;
034a2a52 719
a2a5291b 720 k = strndup(word, l);
d70964d0 721 if (!k)
de3756ab 722 return -ENOMEM;
de3756ab
LP
723
724 r = parse_uid(k, b + i);
de3756ab
LP
725 if (r < 0)
726 continue;
727
728 i++;
729 }
034a2a52
LP
730 }
731 }
732
d60ef526
LP
733 r = strv_length(a);
734
d70964d0 735 if (sessions) {
034a2a52 736 *sessions = a;
d70964d0
HH
737 a = NULL;
738 }
034a2a52 739
d70964d0 740 if (uids) {
034a2a52 741 *uids = b;
d70964d0
HH
742 b = NULL;
743 }
034a2a52
LP
744
745 if (n_uids)
746 *n_uids = n;
747
d60ef526 748 return r;
034a2a52
LP
749}
750
20747498 751static int seat_get_can(const char *seat, const char *variable) {
d70964d0 752 _cleanup_free_ char *p = NULL, *s = NULL;
add30678
LP
753 int r;
754
707b66c6 755 assert(variable);
0325941f 756
50b1678a
LP
757 r = file_of_seat(seat, &p);
758 if (r < 0)
759 return r;
add30678
LP
760
761 r = parse_env_file(p, NEWLINE,
20747498 762 variable, &s,
add30678 763 NULL);
707b66c6
LP
764 if (r == -ENOENT)
765 return -ENXIO;
d70964d0 766 if (r < 0)
add30678 767 return r;
707b66c6
LP
768 if (isempty(s))
769 return -ENODATA;
add30678 770
0325941f 771 return parse_boolean(s);
add30678
LP
772}
773
20747498
LP
774_public_ int sd_seat_can_multi_session(const char *seat) {
775 return seat_get_can(seat, "CAN_MULTI_SESSION");
776}
777
778_public_ int sd_seat_can_tty(const char *seat) {
779 return seat_get_can(seat, "CAN_TTY");
780}
781
782_public_ int sd_seat_can_graphical(const char *seat) {
783 return seat_get_can(seat, "CAN_GRAPHICAL");
784}
785
034a2a52 786_public_ int sd_get_seats(char ***seats) {
034a2a52
LP
787 return get_files_in_directory("/run/systemd/seats/", seats);
788}
789
790_public_ int sd_get_sessions(char ***sessions) {
034a2a52
LP
791 return get_files_in_directory("/run/systemd/sessions/", sessions);
792}
793
794_public_ int sd_get_uids(uid_t **users) {
d70964d0 795 _cleanup_closedir_ DIR *d;
034a2a52
LP
796 int r = 0;
797 unsigned n = 0;
d70964d0 798 _cleanup_free_ uid_t *l = NULL;
034a2a52 799
034a2a52 800 d = opendir("/run/systemd/users/");
8ea913b2
LP
801 if (!d)
802 return -errno;
803
034a2a52 804 for (;;) {
7d5e9c0f 805 struct dirent *de;
034a2a52
LP
806 int k;
807 uid_t uid;
808
66c7a533
FW
809 errno = 0;
810 de = readdir(d);
811 if (!de && errno != 0)
812 return -errno;
034a2a52
LP
813
814 if (!de)
815 break;
816
817 dirent_ensure_type(d, de);
818
819 if (!dirent_is_file(de))
820 continue;
821
822 k = parse_uid(de->d_name, &uid);
823 if (k < 0)
824 continue;
825
d60ef526
LP
826 if (users) {
827 if ((unsigned) r >= n) {
828 uid_t *t;
034a2a52 829
d60ef526
LP
830 n = MAX(16, 2*r);
831 t = realloc(l, sizeof(uid_t) * n);
d70964d0
HH
832 if (!t)
833 return -ENOMEM;
034a2a52 834
d60ef526
LP
835 l = t;
836 }
034a2a52 837
d60ef526
LP
838 assert((unsigned) r < n);
839 l[r++] = uid;
840 } else
841 r++;
034a2a52
LP
842 }
843
d70964d0
HH
844 if (users) {
845 *users = l;
846 l = NULL;
847 }
034a2a52
LP
848
849 return r;
850}
851
4d5fb962 852_public_ int sd_get_machine_names(char ***machines) {
89f7c846
LP
853 char **l = NULL, **a, **b;
854 int r;
855
0325941f
LP
856 assert_return(machines, -EINVAL);
857
89f7c846
LP
858 r = get_files_in_directory("/run/systemd/machines/", &l);
859 if (r < 0)
860 return r;
861
862 if (l) {
863 r = 0;
864
865 /* Filter out the unit: symlinks */
866 for (a = l, b = l; *a; a++) {
b9a8d250 867 if (startswith(*a, "unit:") || !machine_name_is_valid(*a))
89f7c846
LP
868 free(*a);
869 else {
870 *b = *a;
871 b++;
872 r++;
873 }
874 }
875
876 *b = NULL;
877 }
878
879 *machines = l;
880 return r;
a20affe2
LP
881}
882
0325941f
LP
883_public_ int sd_machine_get_class(const char *machine, char **class) {
884 _cleanup_free_ char *c = NULL;
885 const char *p;
886 int r;
887
620a687c 888 assert_return(machine_name_is_valid(machine), -EINVAL);
0325941f
LP
889 assert_return(class, -EINVAL);
890
63c372cb 891 p = strjoina("/run/systemd/machines/", machine);
0325941f 892 r = parse_env_file(p, NEWLINE, "CLASS", &c, NULL);
707b66c6
LP
893 if (r == -ENOENT)
894 return -ENXIO;
0325941f
LP
895 if (r < 0)
896 return r;
897 if (!c)
898 return -EIO;
899
900 *class = c;
901 c = NULL;
902
903 return 0;
904}
905
634af566 906_public_ int sd_machine_get_ifindices(const char *machine, int **ifindices) {
cabb0bc6
LP
907 _cleanup_free_ char *netif = NULL;
908 size_t l, allocated = 0, nr = 0;
cabb0bc6 909 int *ni = NULL;
a2a5291b 910 const char *p, *word, *state;
cabb0bc6
LP
911 int r;
912
913 assert_return(machine_name_is_valid(machine), -EINVAL);
634af566 914 assert_return(ifindices, -EINVAL);
cabb0bc6 915
63c372cb 916 p = strjoina("/run/systemd/machines/", machine);
cabb0bc6 917 r = parse_env_file(p, NEWLINE, "NETIF", &netif, NULL);
707b66c6
LP
918 if (r == -ENOENT)
919 return -ENXIO;
cabb0bc6
LP
920 if (r < 0)
921 return r;
922 if (!netif) {
634af566 923 *ifindices = NULL;
cabb0bc6
LP
924 return 0;
925 }
926
a2a5291b 927 FOREACH_WORD(word, l, netif, state) {
cabb0bc6
LP
928 char buf[l+1];
929 int ifi;
930
a2a5291b 931 *(char*) (mempcpy(buf, word, l)) = 0;
cabb0bc6
LP
932
933 if (safe_atoi(buf, &ifi) < 0)
934 continue;
935 if (ifi <= 0)
936 continue;
937
938 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
939 free(ni);
940 return -ENOMEM;
941 }
942
943 ni[nr++] = ifi;
944 }
945
634af566 946 *ifindices = ni;
cabb0bc6
LP
947 return nr;
948}
949
034a2a52
LP
950static inline int MONITOR_TO_FD(sd_login_monitor *m) {
951 return (int) (unsigned long) m - 1;
952}
953
954static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
955 return (sd_login_monitor*) (unsigned long) (fd + 1);
956}
957
958_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
034a2a52
LP
959 int fd, k;
960 bool good = false;
961
1ae464e0 962 assert_return(m, -EINVAL);
034a2a52
LP
963
964 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
965 if (fd < 0)
bcb161b0 966 return -errno;
034a2a52
LP
967
968 if (!category || streq(category, "seat")) {
969 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
970 if (k < 0) {
03e334a1 971 safe_close(fd);
034a2a52
LP
972 return -errno;
973 }
974
975 good = true;
976 }
977
978 if (!category || streq(category, "session")) {
979 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
980 if (k < 0) {
03e334a1 981 safe_close(fd);
034a2a52
LP
982 return -errno;
983 }
984
985 good = true;
986 }
987
988 if (!category || streq(category, "uid")) {
989 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
990 if (k < 0) {
03e334a1 991 safe_close(fd);
034a2a52
LP
992 return -errno;
993 }
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);
e10375f2 1000 if (k < 0) {
03e334a1 1001 safe_close(fd);
e10375f2
LP
1002 return -errno;
1003 }
1004
1005 good = true;
1006 }
1007
034a2a52
LP
1008 if (!good) {
1009 close_nointr(fd);
1010 return -EINVAL;
1011 }
1012
1013 *m = FD_TO_MONITOR(fd);
1014 return 0;
1015}
1016
1017_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1018 int fd;
1019
1ae464e0 1020 assert_return(m, NULL);
034a2a52
LP
1021
1022 fd = MONITOR_TO_FD(m);
1023 close_nointr(fd);
1024
1025 return NULL;
1026}
1027
1028_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1029
1ae464e0 1030 assert_return(m, -EINVAL);
034a2a52
LP
1031
1032 return flush_fd(MONITOR_TO_FD(m));
1033}
1034
1035_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1036
1ae464e0 1037 assert_return(m, -EINVAL);
034a2a52
LP
1038
1039 return MONITOR_TO_FD(m);
1040}
dace83cb
LP
1041
1042_public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1043
1ae464e0 1044 assert_return(m, -EINVAL);
dace83cb 1045
667c24a6
LP
1046 /* For now we will only return POLLIN here, since we don't
1047 * need anything else ever for inotify. However, let's have
1048 * this API to keep our options open should we later on need
1049 * it. */
dace83cb
LP
1050 return POLLIN;
1051}
667c24a6
LP
1052
1053_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1054
1ae464e0
TA
1055 assert_return(m, -EINVAL);
1056 assert_return(timeout_usec, -EINVAL);
667c24a6
LP
1057
1058 /* For now we will only return (uint64_t) -1, since we don't
1059 * need any timeout. However, let's have this API to keep our
1060 * options open should we later on need it. */
1061 *timeout_usec = (uint64_t) -1;
1062 return 0;
1063}