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