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