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