]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd/sd-login/sd-login.c
Merge pull request #2495 from heftig/master
[thirdparty/systemd.git] / src / libsystemd / sd-login / sd-login.c
CommitLineData
74b91131
LP
1/***
2 This file is part of systemd.
3
4 Copyright 2011 Lennart Poettering
5
6 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
74b91131
LP
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 14 Lesser General Public License for more details.
74b91131 15
5430f7f2 16 You should have received a copy of the GNU Lesser General Public License
74b91131
LP
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
74b91131 20#include <errno.h>
0a6f50c0 21#include <poll.h>
4f5dd394
LP
22#include <string.h>
23#include <sys/inotify.h>
24#include <unistd.h>
74b91131 25
07630cea
LP
26#include "sd-login.h"
27
b5efdb8a 28#include "alloc-util.h"
74b91131 29#include "cgroup-util.h"
f4f15635 30#include "dirent-util.h"
4f5dd394 31#include "escape.h"
3ffd4af2 32#include "fd-util.h"
a5c32cff 33#include "fileio.h"
6482f626 34#include "formats-util.h"
f4f15635 35#include "fs-util.h"
25300b5a 36#include "hostname-util.h"
c004493c 37#include "io-util.h"
4f5dd394
LP
38#include "login-util.h"
39#include "macro.h"
6bedfcbb 40#include "parse-util.h"
bb15fafe 41#include "path-util.h"
2583fbea 42#include "socket-util.h"
07630cea 43#include "string-util.h"
4f5dd394 44#include "strv.h"
b1d4f8e1 45#include "user-util.h"
4f5dd394 46#include "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);
b3267152 811 if (!de && errno > 0)
66c7a533 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 932
6ad623a3 933 if (parse_ifindex(buf, &ifi) < 0)
cabb0bc6
LP
934 continue;
935
936 if (!GREEDY_REALLOC(ni, allocated, nr+1)) {
937 free(ni);
938 return -ENOMEM;
939 }
940
941 ni[nr++] = ifi;
942 }
943
634af566 944 *ifindices = ni;
cabb0bc6
LP
945 return nr;
946}
947
034a2a52
LP
948static inline int MONITOR_TO_FD(sd_login_monitor *m) {
949 return (int) (unsigned long) m - 1;
950}
951
952static inline sd_login_monitor* FD_TO_MONITOR(int fd) {
953 return (sd_login_monitor*) (unsigned long) (fd + 1);
954}
955
956_public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
034a2a52
LP
957 int fd, k;
958 bool good = false;
959
1ae464e0 960 assert_return(m, -EINVAL);
034a2a52
LP
961
962 fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
963 if (fd < 0)
bcb161b0 964 return -errno;
034a2a52
LP
965
966 if (!category || streq(category, "seat")) {
967 k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE);
968 if (k < 0) {
03e334a1 969 safe_close(fd);
034a2a52
LP
970 return -errno;
971 }
972
973 good = true;
974 }
975
976 if (!category || streq(category, "session")) {
977 k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE);
978 if (k < 0) {
03e334a1 979 safe_close(fd);
034a2a52
LP
980 return -errno;
981 }
982
983 good = true;
984 }
985
986 if (!category || streq(category, "uid")) {
987 k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE);
988 if (k < 0) {
03e334a1 989 safe_close(fd);
034a2a52
LP
990 return -errno;
991 }
992
993 good = true;
994 }
995
e10375f2 996 if (!category || streq(category, "machine")) {
ba73ed85 997 k = inotify_add_watch(fd, "/run/systemd/machines/", IN_MOVED_TO|IN_DELETE);
e10375f2 998 if (k < 0) {
03e334a1 999 safe_close(fd);
e10375f2
LP
1000 return -errno;
1001 }
1002
1003 good = true;
1004 }
1005
034a2a52
LP
1006 if (!good) {
1007 close_nointr(fd);
1008 return -EINVAL;
1009 }
1010
1011 *m = FD_TO_MONITOR(fd);
1012 return 0;
1013}
1014
1015_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
1016 int fd;
1017
4afd3348
LP
1018 if (!m)
1019 return NULL;
034a2a52
LP
1020
1021 fd = MONITOR_TO_FD(m);
1022 close_nointr(fd);
1023
1024 return NULL;
1025}
1026
1027_public_ int sd_login_monitor_flush(sd_login_monitor *m) {
1028
1ae464e0 1029 assert_return(m, -EINVAL);
034a2a52
LP
1030
1031 return flush_fd(MONITOR_TO_FD(m));
1032}
1033
1034_public_ int sd_login_monitor_get_fd(sd_login_monitor *m) {
1035
1ae464e0 1036 assert_return(m, -EINVAL);
034a2a52
LP
1037
1038 return MONITOR_TO_FD(m);
1039}
dace83cb
LP
1040
1041_public_ int sd_login_monitor_get_events(sd_login_monitor *m) {
1042
1ae464e0 1043 assert_return(m, -EINVAL);
dace83cb 1044
667c24a6
LP
1045 /* For now we will only return POLLIN here, since we don't
1046 * need anything else ever for inotify. However, let's have
1047 * this API to keep our options open should we later on need
1048 * it. */
dace83cb
LP
1049 return POLLIN;
1050}
667c24a6
LP
1051
1052_public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec) {
1053
1ae464e0
TA
1054 assert_return(m, -EINVAL);
1055 assert_return(timeout_usec, -EINVAL);
667c24a6
LP
1056
1057 /* For now we will only return (uint64_t) -1, since we don't
1058 * need any timeout. However, let's have this API to keep our
1059 * options open should we later on need it. */
1060 *timeout_usec = (uint64_t) -1;
1061 return 0;
1062}