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