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