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