]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
74b91131 | 2 | |
0a6f50c0 | 3 | #include <poll.h> |
4f5dd394 LP |
4 | #include <sys/inotify.h> |
5 | #include <unistd.h> | |
74b91131 | 6 | |
07630cea LP |
7 | #include "sd-login.h" |
8 | ||
b5efdb8a | 9 | #include "alloc-util.h" |
74b91131 | 10 | #include "cgroup-util.h" |
f4f15635 | 11 | #include "dirent-util.h" |
686d13b9 | 12 | #include "env-file.h" |
81823e6c | 13 | #include "extract-word.h" |
3ffd4af2 | 14 | #include "fd-util.h" |
f97b34a6 | 15 | #include "format-util.h" |
f4f15635 | 16 | #include "fs-util.h" |
25300b5a | 17 | #include "hostname-util.h" |
c004493c | 18 | #include "io-util.h" |
4f5dd394 | 19 | #include "login-util.h" |
6bedfcbb | 20 | #include "parse-util.h" |
bb15fafe | 21 | #include "path-util.h" |
b234026d | 22 | #include "pidfd-util.h" |
5cdf13c7 | 23 | #include "pidref.h" |
2583fbea | 24 | #include "socket-util.h" |
07630cea | 25 | #include "string-util.h" |
4f5dd394 | 26 | #include "strv.h" |
b1d4f8e1 | 27 | #include "user-util.h" |
74b91131 | 28 | |
707b66c6 LP |
29 | /* Error codes: |
30 | * | |
31 | * invalid input parameters → -EINVAL | |
32 | * invalid fd → -EBADF | |
33 | * process does not exist → -ESRCH | |
34 | * cgroup does not exist → -ENOENT | |
35 | * machine, session does not exist → -ENXIO | |
36 | * requested metadata on object is missing → -ENODATA | |
37 | */ | |
38 | ||
eac4a028 | 39 | _public_ int sd_pid_get_session(pid_t pid, char **ret_session) { |
19d64d10 | 40 | int r; |
ba1261bc | 41 | |
1ae464e0 | 42 | assert_return(pid >= 0, -EINVAL); |
034a2a52 | 43 | |
eac4a028 | 44 | r = cg_pid_get_session(pid, ret_session); |
bc9e9af1 | 45 | return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; |
74b91131 LP |
46 | } |
47 | ||
eac4a028 | 48 | _public_ int sd_pid_get_unit(pid_t pid, char **ret_unit) { |
171f8f59 | 49 | int r; |
9847946e | 50 | |
1ae464e0 | 51 | assert_return(pid >= 0, -EINVAL); |
9847946e | 52 | |
eac4a028 | 53 | r = cg_pid_get_unit(pid, ret_unit); |
bc9e9af1 | 54 | return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; |
9847946e LP |
55 | } |
56 | ||
eac4a028 | 57 | _public_ int sd_pid_get_user_unit(pid_t pid, char **ret_unit) { |
d440fb97 | 58 | int r; |
97e13058 | 59 | |
1ae464e0 | 60 | assert_return(pid >= 0, -EINVAL); |
97e13058 | 61 | |
eac4a028 | 62 | r = cg_pid_get_user_unit(pid, ret_unit); |
bc9e9af1 | 63 | return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; |
97e13058 LP |
64 | } |
65 | ||
eac4a028 | 66 | _public_ int sd_pid_get_machine_name(pid_t pid, char **ret_name) { |
bc9e9af1 | 67 | int r; |
7027ff61 | 68 | |
1ae464e0 | 69 | assert_return(pid >= 0, -EINVAL); |
7027ff61 | 70 | |
eac4a028 | 71 | r = cg_pid_get_machine_name(pid, ret_name); |
bc9e9af1 | 72 | return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; |
7027ff61 LP |
73 | } |
74 | ||
eac4a028 | 75 | _public_ int sd_pid_get_slice(pid_t pid, char **ret_slice) { |
bc9e9af1 | 76 | int r; |
1021b21b | 77 | |
1ae464e0 | 78 | assert_return(pid >= 0, -EINVAL); |
1021b21b | 79 | |
eac4a028 | 80 | r = cg_pid_get_slice(pid, ret_slice); |
bc9e9af1 | 81 | return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; |
1021b21b LP |
82 | } |
83 | ||
eac4a028 | 84 | _public_ int sd_pid_get_user_slice(pid_t pid, char **ret_slice) { |
bc9e9af1 | 85 | int r; |
329ac4bc LP |
86 | |
87 | assert_return(pid >= 0, -EINVAL); | |
329ac4bc | 88 | |
eac4a028 | 89 | r = cg_pid_get_user_slice(pid, ret_slice); |
bc9e9af1 | 90 | return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; |
329ac4bc LP |
91 | } |
92 | ||
eac4a028 | 93 | _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *ret_uid) { |
bc9e9af1 | 94 | int r; |
034a2a52 | 95 | |
1ae464e0 | 96 | assert_return(pid >= 0, -EINVAL); |
034a2a52 | 97 | |
eac4a028 | 98 | r = cg_pid_get_owner_uid(pid, ret_uid); |
bc9e9af1 | 99 | return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; |
034a2a52 LP |
100 | } |
101 | ||
eac4a028 | 102 | _public_ int sd_pid_get_cgroup(pid_t pid, char **ret_cgroup) { |
f5aaf575 LP |
103 | int r; |
104 | ||
105 | assert_return(pid >= 0, -EINVAL); | |
f5aaf575 | 106 | |
eac4a028 | 107 | _cleanup_free_ char *c = NULL; |
f5aaf575 LP |
108 | r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &c); |
109 | if (r < 0) | |
110 | return r; | |
111 | ||
eac4a028 LP |
112 | if (ret_cgroup) { |
113 | /* The internal APIs return the empty string for the root cgroup, let's return the "/" in the | |
114 | * public APIs instead, as that's easier and less ambiguous for people to grok. */ | |
115 | if (isempty(c)) { | |
116 | r = free_and_strdup(&c, "/"); | |
117 | if (r < 0) | |
118 | return r; | |
119 | } | |
f5aaf575 | 120 | |
eac4a028 | 121 | *ret_cgroup = TAKE_PTR(c); |
f5aaf575 LP |
122 | } |
123 | ||
f5aaf575 LP |
124 | return 0; |
125 | } | |
126 | ||
da20baae LB |
127 | _public_ int sd_pidfd_get_session(int pidfd, char **ret_session) { |
128 | _cleanup_free_ char *session = NULL; | |
129 | pid_t pid; | |
130 | int r; | |
131 | ||
132 | assert_return(pidfd >= 0, -EBADF); | |
da20baae LB |
133 | |
134 | r = pidfd_get_pid(pidfd, &pid); | |
135 | if (r < 0) | |
136 | return r; | |
137 | ||
138 | r = sd_pid_get_session(pid, &session); | |
139 | if (r < 0) | |
140 | return r; | |
141 | ||
142 | r = pidfd_verify_pid(pidfd, pid); | |
143 | if (r < 0) | |
144 | return r; | |
145 | ||
eac4a028 LP |
146 | if (ret_session) |
147 | *ret_session = TAKE_PTR(session); | |
da20baae LB |
148 | return 0; |
149 | } | |
150 | ||
151 | _public_ int sd_pidfd_get_unit(int pidfd, char **ret_unit) { | |
152 | _cleanup_free_ char *unit = NULL; | |
153 | pid_t pid; | |
154 | int r; | |
155 | ||
156 | assert_return(pidfd >= 0, -EBADF); | |
da20baae LB |
157 | |
158 | r = pidfd_get_pid(pidfd, &pid); | |
159 | if (r < 0) | |
160 | return r; | |
161 | ||
162 | r = sd_pid_get_unit(pid, &unit); | |
163 | if (r < 0) | |
164 | return r; | |
165 | ||
166 | r = pidfd_verify_pid(pidfd, pid); | |
167 | if (r < 0) | |
168 | return r; | |
169 | ||
eac4a028 LP |
170 | if (ret_unit) |
171 | *ret_unit = TAKE_PTR(unit); | |
da20baae LB |
172 | return 0; |
173 | } | |
174 | ||
175 | _public_ int sd_pidfd_get_user_unit(int pidfd, char **ret_unit) { | |
176 | _cleanup_free_ char *unit = NULL; | |
177 | pid_t pid; | |
178 | int r; | |
179 | ||
180 | assert_return(pidfd >= 0, -EBADF); | |
da20baae LB |
181 | |
182 | r = pidfd_get_pid(pidfd, &pid); | |
183 | if (r < 0) | |
184 | return r; | |
185 | ||
186 | r = sd_pid_get_user_unit(pid, &unit); | |
187 | if (r < 0) | |
188 | return r; | |
189 | ||
190 | r = pidfd_verify_pid(pidfd, pid); | |
191 | if (r < 0) | |
192 | return r; | |
193 | ||
eac4a028 LP |
194 | if (ret_unit) |
195 | *ret_unit = TAKE_PTR(unit); | |
da20baae LB |
196 | return 0; |
197 | } | |
198 | ||
199 | _public_ int sd_pidfd_get_machine_name(int pidfd, char **ret_name) { | |
200 | _cleanup_free_ char *name = NULL; | |
201 | pid_t pid; | |
202 | int r; | |
203 | ||
204 | assert_return(pidfd >= 0, -EBADF); | |
da20baae LB |
205 | |
206 | r = pidfd_get_pid(pidfd, &pid); | |
207 | if (r < 0) | |
208 | return r; | |
209 | ||
210 | r = sd_pid_get_machine_name(pid, &name); | |
211 | if (r < 0) | |
212 | return r; | |
213 | ||
214 | r = pidfd_verify_pid(pidfd, pid); | |
215 | if (r < 0) | |
216 | return r; | |
217 | ||
eac4a028 LP |
218 | if (ret_name) |
219 | *ret_name = TAKE_PTR(name); | |
da20baae LB |
220 | return 0; |
221 | } | |
222 | ||
223 | _public_ int sd_pidfd_get_slice(int pidfd, char **ret_slice) { | |
224 | _cleanup_free_ char *slice = NULL; | |
225 | pid_t pid; | |
226 | int r; | |
227 | ||
228 | assert_return(pidfd >= 0, -EBADF); | |
da20baae LB |
229 | |
230 | r = pidfd_get_pid(pidfd, &pid); | |
231 | if (r < 0) | |
232 | return r; | |
233 | ||
234 | r = sd_pid_get_slice(pid, &slice); | |
235 | if (r < 0) | |
236 | return r; | |
237 | ||
238 | r = pidfd_verify_pid(pidfd, pid); | |
239 | if (r < 0) | |
240 | return r; | |
241 | ||
eac4a028 LP |
242 | if (ret_slice) |
243 | *ret_slice = TAKE_PTR(slice); | |
da20baae LB |
244 | return 0; |
245 | } | |
246 | ||
247 | _public_ int sd_pidfd_get_user_slice(int pidfd, char **ret_slice) { | |
248 | _cleanup_free_ char *slice = NULL; | |
249 | pid_t pid; | |
250 | int r; | |
251 | ||
252 | assert_return(pidfd >= 0, -EBADF); | |
da20baae LB |
253 | |
254 | r = pidfd_get_pid(pidfd, &pid); | |
255 | if (r < 0) | |
256 | return r; | |
257 | ||
258 | r = sd_pid_get_user_slice(pid, &slice); | |
259 | if (r < 0) | |
260 | return r; | |
261 | ||
262 | r = pidfd_verify_pid(pidfd, pid); | |
263 | if (r < 0) | |
264 | return r; | |
265 | ||
eac4a028 LP |
266 | if (ret_slice) |
267 | *ret_slice = TAKE_PTR(slice); | |
da20baae LB |
268 | return 0; |
269 | } | |
270 | ||
271 | _public_ int sd_pidfd_get_owner_uid(int pidfd, uid_t *ret_uid) { | |
272 | uid_t uid; | |
273 | pid_t pid; | |
274 | int r; | |
275 | ||
68db777a | 276 | assert_return(pidfd >= 0, -EBADF); |
da20baae LB |
277 | |
278 | r = pidfd_get_pid(pidfd, &pid); | |
279 | if (r < 0) | |
280 | return r; | |
281 | ||
282 | r = sd_pid_get_owner_uid(pid, &uid); | |
283 | if (r < 0) | |
284 | return r; | |
285 | ||
286 | r = pidfd_verify_pid(pidfd, pid); | |
287 | if (r < 0) | |
288 | return r; | |
289 | ||
eac4a028 LP |
290 | if (ret_uid) |
291 | *ret_uid = uid; | |
da20baae LB |
292 | return 0; |
293 | } | |
294 | ||
295 | _public_ int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup) { | |
296 | _cleanup_free_ char *cgroup = NULL; | |
297 | pid_t pid; | |
298 | int r; | |
299 | ||
300 | assert_return(pidfd >= 0, -EBADF); | |
da20baae LB |
301 | |
302 | r = pidfd_get_pid(pidfd, &pid); | |
303 | if (r < 0) | |
304 | return r; | |
305 | ||
306 | r = sd_pid_get_cgroup(pid, &cgroup); | |
307 | if (r < 0) | |
308 | return r; | |
309 | ||
310 | r = pidfd_verify_pid(pidfd, pid); | |
311 | if (r < 0) | |
312 | return r; | |
313 | ||
eac4a028 LP |
314 | if (ret_cgroup) |
315 | *ret_cgroup = TAKE_PTR(cgroup); | |
da20baae LB |
316 | return 0; |
317 | } | |
318 | ||
eac4a028 | 319 | _public_ int sd_peer_get_session(int fd, char **ret_session) { |
bf34ab14 LP |
320 | int r; |
321 | ||
8ac43fee | 322 | assert_return(fd >= 0, -EBADF); |
bf34ab14 | 323 | |
1740d3e0 LP |
324 | _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; |
325 | r = getpeerpidref(fd, &pidref); | |
bf34ab14 LP |
326 | if (r < 0) |
327 | return r; | |
328 | ||
eac4a028 | 329 | return cg_pidref_get_session(&pidref, ret_session); |
bf34ab14 LP |
330 | } |
331 | ||
eac4a028 | 332 | _public_ int sd_peer_get_owner_uid(int fd, uid_t *ret_uid) { |
bf34ab14 LP |
333 | int r; |
334 | ||
8ac43fee | 335 | assert_return(fd >= 0, -EBADF); |
bf34ab14 | 336 | |
1740d3e0 LP |
337 | _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; |
338 | r = getpeerpidref(fd, &pidref); | |
bf34ab14 LP |
339 | if (r < 0) |
340 | return r; | |
341 | ||
eac4a028 | 342 | return cg_pidref_get_owner_uid(&pidref, ret_uid); |
bf34ab14 LP |
343 | } |
344 | ||
eac4a028 | 345 | _public_ int sd_peer_get_unit(int fd, char **ret_unit) { |
bf34ab14 LP |
346 | int r; |
347 | ||
8ac43fee | 348 | assert_return(fd >= 0, -EBADF); |
bf34ab14 | 349 | |
1740d3e0 LP |
350 | _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; |
351 | r = getpeerpidref(fd, &pidref); | |
bf34ab14 LP |
352 | if (r < 0) |
353 | return r; | |
354 | ||
eac4a028 | 355 | return cg_pidref_get_unit(&pidref, ret_unit); |
bf34ab14 LP |
356 | } |
357 | ||
eac4a028 | 358 | _public_ int sd_peer_get_user_unit(int fd, char **ret_unit) { |
bf34ab14 LP |
359 | struct ucred ucred; |
360 | int r; | |
361 | ||
8ac43fee | 362 | assert_return(fd >= 0, -EBADF); |
bf34ab14 LP |
363 | |
364 | r = getpeercred(fd, &ucred); | |
365 | if (r < 0) | |
366 | return r; | |
367 | ||
eac4a028 | 368 | return cg_pid_get_user_unit(ucred.pid, ret_unit); |
bf34ab14 LP |
369 | } |
370 | ||
eac4a028 | 371 | _public_ int sd_peer_get_machine_name(int fd, char **ret_machine) { |
bf34ab14 LP |
372 | struct ucred ucred; |
373 | int r; | |
374 | ||
8ac43fee | 375 | assert_return(fd >= 0, -EBADF); |
bf34ab14 LP |
376 | |
377 | r = getpeercred(fd, &ucred); | |
378 | if (r < 0) | |
379 | return r; | |
380 | ||
eac4a028 | 381 | return cg_pid_get_machine_name(ucred.pid, ret_machine); |
bf34ab14 LP |
382 | } |
383 | ||
eac4a028 | 384 | _public_ int sd_peer_get_slice(int fd, char **ret_slice) { |
bf34ab14 LP |
385 | struct ucred ucred; |
386 | int r; | |
387 | ||
8ac43fee | 388 | assert_return(fd >= 0, -EBADF); |
bf34ab14 LP |
389 | |
390 | r = getpeercred(fd, &ucred); | |
391 | if (r < 0) | |
392 | return r; | |
393 | ||
eac4a028 | 394 | return cg_pid_get_slice(ucred.pid, ret_slice); |
bf34ab14 LP |
395 | } |
396 | ||
eac4a028 | 397 | _public_ int sd_peer_get_user_slice(int fd, char **ret_slice) { |
329ac4bc LP |
398 | struct ucred ucred; |
399 | int r; | |
400 | ||
8ac43fee | 401 | assert_return(fd >= 0, -EBADF); |
329ac4bc LP |
402 | |
403 | r = getpeercred(fd, &ucred); | |
404 | if (r < 0) | |
405 | return r; | |
406 | ||
eac4a028 | 407 | return cg_pid_get_user_slice(ucred.pid, ret_slice); |
329ac4bc LP |
408 | } |
409 | ||
eac4a028 | 410 | _public_ int sd_peer_get_cgroup(int fd, char **ret_cgroup) { |
f5aaf575 LP |
411 | int r; |
412 | ||
413 | assert_return(fd >= 0, -EBADF); | |
f5aaf575 | 414 | |
eb780108 LP |
415 | _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; |
416 | r = getpeerpidref(fd, &pidref); | |
f5aaf575 LP |
417 | if (r < 0) |
418 | return r; | |
419 | ||
eb780108 LP |
420 | _cleanup_free_ char *c = NULL; |
421 | r = cg_pidref_get_path(SYSTEMD_CGROUP_CONTROLLER, &pidref, &c); | |
422 | if (r < 0) | |
423 | return r; | |
424 | ||
425 | if (ret_cgroup) { | |
426 | /* The internal APIs return the empty string for the root cgroup, let's return the "/" in the | |
427 | * public APIs instead, as that's easier and less ambiguous for people to grok. */ | |
428 | if (isempty(c)) { | |
429 | r = free_and_strdup(&c, "/"); | |
430 | if (r < 0) | |
431 | return r; | |
432 | } | |
433 | ||
434 | *ret_cgroup = TAKE_PTR(c); | |
435 | } | |
436 | ||
437 | return 0; | |
f5aaf575 LP |
438 | } |
439 | ||
eac4a028 | 440 | static int file_of_uid(uid_t uid, char **ret) { |
707b66c6 LP |
441 | |
442 | assert_return(uid_is_valid(uid), -EINVAL); | |
eac4a028 | 443 | assert(ret); |
a077b666 | 444 | |
eac4a028 | 445 | if (asprintf(ret, "/run/systemd/users/" UID_FMT, uid) < 0) |
a077b666 LP |
446 | return -ENOMEM; |
447 | ||
448 | return 0; | |
449 | } | |
450 | ||
eac4a028 | 451 | _public_ int sd_uid_get_state(uid_t uid, char **ret_state) { |
13df9c39 | 452 | _cleanup_free_ char *p = NULL, *s = NULL; |
74b91131 LP |
453 | int r; |
454 | ||
a077b666 LP |
455 | r = file_of_uid(uid, &p); |
456 | if (r < 0) | |
457 | return r; | |
74b91131 | 458 | |
eac4a028 | 459 | r = parse_env_file(/* f= */ NULL, p, "STATE", &s); |
40f35786 | 460 | if (r == -ENOENT) |
13df9c39 | 461 | r = free_and_strdup(&s, "offline"); |
40f35786 | 462 | if (r < 0) |
74b91131 | 463 | return r; |
40f35786 | 464 | if (isempty(s)) |
74b91131 LP |
465 | return -EIO; |
466 | ||
eac4a028 LP |
467 | if (ret_state) |
468 | *ret_state = TAKE_PTR(s); | |
74b91131 LP |
469 | return 0; |
470 | } | |
471 | ||
eac4a028 | 472 | _public_ int sd_uid_get_display(uid_t uid, char **ret_session) { |
a077b666 LP |
473 | _cleanup_free_ char *p = NULL, *s = NULL; |
474 | int r; | |
475 | ||
a077b666 LP |
476 | r = file_of_uid(uid, &p); |
477 | if (r < 0) | |
478 | return r; | |
479 | ||
eac4a028 | 480 | r = parse_env_file(/* f= */ NULL, p, "DISPLAY", &s); |
fc60d815 | 481 | if (r == -ENOENT) |
707b66c6 | 482 | return -ENODATA; |
a077b666 LP |
483 | if (r < 0) |
484 | return r; | |
a077b666 | 485 | if (isempty(s)) |
707b66c6 | 486 | return -ENODATA; |
a077b666 | 487 | |
eac4a028 LP |
488 | if (ret_session) |
489 | *ret_session = TAKE_PTR(s); | |
a077b666 LP |
490 | return 0; |
491 | } | |
492 | ||
eac4a028 | 493 | _public_ int sd_uid_get_login_time(uid_t uid, uint64_t *ret_usec) { |
d622fefc | 494 | _cleanup_free_ char *p = NULL, *s = NULL, *rt = NULL; |
d622fefc TK |
495 | int r; |
496 | ||
d622fefc TK |
497 | r = file_of_uid(uid, &p); |
498 | if (r < 0) | |
499 | return r; | |
500 | ||
eac4a028 | 501 | r = parse_env_file(/* f= */ NULL, p, "STATE", &s, "REALTIME", &rt); |
d622fefc TK |
502 | if (r == -ENOENT) |
503 | return -ENXIO; | |
504 | if (r < 0) | |
505 | return r; | |
506 | if (isempty(s) || isempty(rt)) | |
507 | return -EIO; | |
508 | ||
509 | if (!STR_IN_SET(s, "active", "online")) | |
510 | return -ENXIO; | |
511 | ||
eac4a028 | 512 | return safe_atou64(rt, ret_usec); |
d622fefc TK |
513 | } |
514 | ||
eac4a028 | 515 | static int file_of_seat(const char *seat, char **ret) { |
707b66c6 LP |
516 | char *p; |
517 | int r; | |
518 | ||
eac4a028 | 519 | assert(ret); |
707b66c6 LP |
520 | |
521 | if (seat) { | |
522 | if (!filename_is_valid(seat)) | |
523 | return -EINVAL; | |
524 | ||
b910cc72 | 525 | p = path_join("/run/systemd/seats", seat); |
707b66c6 LP |
526 | } else { |
527 | _cleanup_free_ char *buf = NULL; | |
528 | ||
529 | r = sd_session_get_seat(NULL, &buf); | |
530 | if (r < 0) | |
531 | return r; | |
532 | ||
b910cc72 | 533 | p = path_join("/run/systemd/seats", buf); |
707b66c6 | 534 | } |
707b66c6 LP |
535 | if (!p) |
536 | return -ENOMEM; | |
537 | ||
eac4a028 | 538 | *ret = TAKE_PTR(p); |
707b66c6 LP |
539 | return 0; |
540 | } | |
541 | ||
034a2a52 | 542 | _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { |
81823e6c | 543 | _cleanup_free_ char *filename = NULL, *content = NULL; |
74b91131 LP |
544 | int r; |
545 | ||
a1f686da | 546 | assert_return(uid_is_valid(uid), -EINVAL); |
74b91131 | 547 | |
81823e6c | 548 | r = file_of_seat(seat, &filename); |
707b66c6 LP |
549 | if (r < 0) |
550 | return r; | |
034a2a52 | 551 | |
eac4a028 | 552 | r = parse_env_file(/* f= */ NULL, filename, |
81823e6c ZJS |
553 | require_active ? "ACTIVE_UID" : "UIDS", |
554 | &content); | |
707b66c6 LP |
555 | if (r == -ENOENT) |
556 | return 0; | |
d70964d0 | 557 | if (r < 0) |
74b91131 | 558 | return r; |
81823e6c | 559 | if (isempty(content)) |
707b66c6 | 560 | return 0; |
74b91131 | 561 | |
80d07162 | 562 | return string_contains_word(content, NULL, FORMAT_UID(uid)); |
74b91131 LP |
563 | } |
564 | ||
eac4a028 | 565 | static int uid_get_array(uid_t uid, const char *variable, char ***ret_array) { |
d70964d0 | 566 | _cleanup_free_ char *p = NULL, *s = NULL; |
034a2a52 LP |
567 | int r; |
568 | ||
707b66c6 | 569 | assert(variable); |
a1f686da | 570 | |
a077b666 LP |
571 | r = file_of_uid(uid, &p); |
572 | if (r < 0) | |
573 | return r; | |
034a2a52 | 574 | |
eac4a028 | 575 | r = parse_env_file(/* f= */ NULL, p, variable, &s); |
707b66c6 | 576 | if (r == -ENOENT || (r >= 0 && isempty(s))) { |
eac4a028 LP |
577 | if (ret_array) |
578 | *ret_array = NULL; | |
034a2a52 LP |
579 | return 0; |
580 | } | |
707b66c6 LP |
581 | if (r < 0) |
582 | return r; | |
034a2a52 | 583 | |
eac4a028 | 584 | _cleanup_strv_free_ char **a = strv_split(s, NULL); |
034a2a52 LP |
585 | if (!a) |
586 | return -ENOMEM; | |
587 | ||
d60ef526 | 588 | strv_uniq(a); |
da6053d0 | 589 | r = (int) strv_length(a); |
d60ef526 | 590 | |
eac4a028 LP |
591 | if (ret_array) |
592 | *ret_array = TAKE_PTR(a); | |
d60ef526 LP |
593 | |
594 | return r; | |
034a2a52 LP |
595 | } |
596 | ||
eac4a028 | 597 | _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***ret_sessions) { |
d18dff43 LP |
598 | return uid_get_array( |
599 | uid, | |
600 | require_active == 0 ? "ONLINE_SESSIONS" : | |
601 | require_active > 0 ? "ACTIVE_SESSIONS" : | |
602 | "SESSIONS", | |
eac4a028 | 603 | ret_sessions); |
74b91131 LP |
604 | } |
605 | ||
eac4a028 | 606 | _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***ret_seats) { |
d18dff43 LP |
607 | return uid_get_array( |
608 | uid, | |
609 | require_active == 0 ? "ONLINE_SEATS" : | |
610 | require_active > 0 ? "ACTIVE_SEATS" : | |
611 | "SEATS", | |
eac4a028 | 612 | ret_seats); |
74b91131 LP |
613 | } |
614 | ||
eac4a028 | 615 | static int file_of_session(const char *session, char **ret) { |
50b1678a | 616 | char *p; |
74b91131 | 617 | int r; |
74b91131 | 618 | |
eac4a028 | 619 | assert(ret); |
50b1678a | 620 | |
4b549144 ZJS |
621 | if (session) { |
622 | if (!session_id_valid(session)) | |
623 | return -EINVAL; | |
624 | ||
b910cc72 | 625 | p = path_join("/run/systemd/sessions", session); |
4b549144 ZJS |
626 | } else { |
627 | _cleanup_free_ char *buf = NULL; | |
50b1678a LP |
628 | |
629 | r = sd_pid_get_session(0, &buf); | |
630 | if (r < 0) | |
631 | return r; | |
632 | ||
b910cc72 | 633 | p = path_join("/run/systemd/sessions", buf); |
50b1678a | 634 | } |
74b91131 LP |
635 | if (!p) |
636 | return -ENOMEM; | |
637 | ||
eac4a028 | 638 | *ret = p; |
50b1678a LP |
639 | return 0; |
640 | } | |
641 | ||
642 | _public_ int sd_session_is_active(const char *session) { | |
d70964d0 | 643 | _cleanup_free_ char *p = NULL, *s = NULL; |
707b66c6 | 644 | int r; |
50b1678a LP |
645 | |
646 | r = file_of_session(session, &p); | |
647 | if (r < 0) | |
648 | return r; | |
649 | ||
eac4a028 | 650 | r = parse_env_file(/* f= */ NULL, p, "ACTIVE", &s); |
707b66c6 LP |
651 | if (r == -ENOENT) |
652 | return -ENXIO; | |
d70964d0 | 653 | if (r < 0) |
74b91131 | 654 | return r; |
707b66c6 | 655 | if (isempty(s)) |
74b91131 LP |
656 | return -EIO; |
657 | ||
0325941f | 658 | return parse_boolean(s); |
74b91131 LP |
659 | } |
660 | ||
5b04fe60 | 661 | _public_ int sd_session_is_remote(const char *session) { |
5b04fe60 | 662 | _cleanup_free_ char *p = NULL, *s = NULL; |
707b66c6 | 663 | int r; |
5b04fe60 MM |
664 | |
665 | r = file_of_session(session, &p); | |
666 | if (r < 0) | |
667 | return r; | |
668 | ||
eac4a028 | 669 | r = parse_env_file(/* f= */ NULL, p, "REMOTE", &s); |
707b66c6 LP |
670 | if (r == -ENOENT) |
671 | return -ENXIO; | |
5b04fe60 MM |
672 | if (r < 0) |
673 | return r; | |
707b66c6 LP |
674 | if (isempty(s)) |
675 | return -ENODATA; | |
5b04fe60 | 676 | |
0325941f | 677 | return parse_boolean(s); |
5b04fe60 MM |
678 | } |
679 | ||
eac4a028 | 680 | _public_ int sd_session_get_state(const char *session, char **ret_state) { |
d70964d0 | 681 | _cleanup_free_ char *p = NULL, *s = NULL; |
0604381b LP |
682 | int r; |
683 | ||
0604381b LP |
684 | r = file_of_session(session, &p); |
685 | if (r < 0) | |
686 | return r; | |
687 | ||
eac4a028 | 688 | r = parse_env_file(/* f= */ NULL, p, "STATE", &s); |
707b66c6 LP |
689 | if (r == -ENOENT) |
690 | return -ENXIO; | |
d70964d0 | 691 | if (r < 0) |
0604381b | 692 | return r; |
707b66c6 | 693 | if (isempty(s)) |
0604381b LP |
694 | return -EIO; |
695 | ||
eac4a028 LP |
696 | if (ret_state) |
697 | *ret_state = TAKE_PTR(s); | |
0604381b LP |
698 | return 0; |
699 | } | |
700 | ||
eac4a028 | 701 | _public_ int sd_session_get_uid(const char *session, uid_t *ret_uid) { |
74b91131 | 702 | int r; |
d70964d0 | 703 | _cleanup_free_ char *p = NULL, *s = NULL; |
74b91131 | 704 | |
50b1678a LP |
705 | r = file_of_session(session, &p); |
706 | if (r < 0) | |
707 | return r; | |
74b91131 | 708 | |
eac4a028 | 709 | r = parse_env_file(/* f= */ NULL, p, "UID", &s); |
707b66c6 LP |
710 | if (r == -ENOENT) |
711 | return -ENXIO; | |
d70964d0 | 712 | if (r < 0) |
74b91131 | 713 | return r; |
707b66c6 | 714 | if (isempty(s)) |
74b91131 LP |
715 | return -EIO; |
716 | ||
eac4a028 | 717 | return parse_uid(s, ret_uid); |
74b91131 LP |
718 | } |
719 | ||
eac4a028 | 720 | static int session_get_string(const char *session, const char *field, char **ret_value) { |
d70964d0 | 721 | _cleanup_free_ char *p = NULL, *s = NULL; |
74b91131 LP |
722 | int r; |
723 | ||
707b66c6 | 724 | assert(field); |
74b91131 | 725 | |
50b1678a LP |
726 | r = file_of_session(session, &p); |
727 | if (r < 0) | |
728 | return r; | |
74b91131 | 729 | |
eac4a028 | 730 | r = parse_env_file(/* f= */ NULL, p, field, &s); |
707b66c6 LP |
731 | if (r == -ENOENT) |
732 | return -ENXIO; | |
d70964d0 | 733 | if (r < 0) |
74b91131 | 734 | return r; |
74b91131 | 735 | if (isempty(s)) |
707b66c6 | 736 | return -ENODATA; |
74b91131 | 737 | |
eac4a028 LP |
738 | if (ret_value) |
739 | *ret_value = TAKE_PTR(s); | |
74b91131 LP |
740 | return 0; |
741 | } | |
742 | ||
eac4a028 LP |
743 | _public_ int sd_session_get_username(const char *session, char **ret_username) { |
744 | return session_get_string(session, "USER", ret_username); | |
d71f5b12 MY |
745 | } |
746 | ||
eac4a028 LP |
747 | _public_ int sd_session_get_seat(const char *session, char **ret_seat) { |
748 | return session_get_string(session, "SEAT", ret_seat); | |
51f58f08 | 749 | } |
eff40633 | 750 | |
eac4a028 | 751 | _public_ int sd_session_get_start_time(const char *session, uint64_t *ret_usec) { |
c4ef14dc | 752 | _cleanup_free_ char *p = NULL, *s = NULL; |
c4ef14dc MY |
753 | int r; |
754 | ||
c4ef14dc MY |
755 | r = file_of_session(session, &p); |
756 | if (r < 0) | |
757 | return r; | |
758 | ||
eac4a028 | 759 | r = parse_env_file(/* f= */ NULL, p, "REALTIME", &s); |
c4ef14dc MY |
760 | if (r == -ENOENT) |
761 | return -ENXIO; | |
762 | if (r < 0) | |
763 | return r; | |
764 | if (isempty(s)) | |
765 | return -EIO; | |
766 | ||
eac4a028 | 767 | return safe_atou64(s, ret_usec); |
c4ef14dc MY |
768 | } |
769 | ||
eac4a028 LP |
770 | _public_ int sd_session_get_tty(const char *session, char **ret_tty) { |
771 | return session_get_string(session, "TTY", ret_tty); | |
c84f5e4a LP |
772 | } |
773 | ||
eac4a028 | 774 | _public_ int sd_session_get_vt(const char *session, unsigned *ret_vtnr) { |
3f4fee03 | 775 | _cleanup_free_ char *vtnr_string = NULL; |
44ded3ab GC |
776 | int r; |
777 | ||
0581dac2 | 778 | r = session_get_string(session, "VTNR", &vtnr_string); |
44ded3ab GC |
779 | if (r < 0) |
780 | return r; | |
781 | ||
eac4a028 | 782 | return safe_atou(vtnr_string, ret_vtnr); |
44ded3ab GC |
783 | } |
784 | ||
eac4a028 LP |
785 | _public_ int sd_session_get_service(const char *session, char **ret_service) { |
786 | return session_get_string(session, "SERVICE", ret_service); | |
51f58f08 | 787 | } |
eff40633 | 788 | |
eac4a028 LP |
789 | _public_ int sd_session_get_type(const char *session, char **ret_type) { |
790 | return session_get_string(session, "TYPE", ret_type); | |
51f58f08 | 791 | } |
eff40633 | 792 | |
eac4a028 LP |
793 | _public_ int sd_session_get_class(const char *session, char **ret_class) { |
794 | return session_get_string(session, "CLASS", ret_class); | |
eff40633 LP |
795 | } |
796 | ||
eac4a028 LP |
797 | _public_ int sd_session_get_desktop(const char *session, char **ret_desktop) { |
798 | return session_get_string(session, "DESKTOP", ret_desktop); | |
c72d5456 DH |
799 | } |
800 | ||
eac4a028 LP |
801 | _public_ int sd_session_get_display(const char *session, char **ret_display) { |
802 | return session_get_string(session, "DISPLAY", ret_display); | |
fc8af9ff LP |
803 | } |
804 | ||
eac4a028 LP |
805 | _public_ int sd_session_get_remote_user(const char *session, char **ret_remote_user) { |
806 | return session_get_string(session, "REMOTE_USER", ret_remote_user); | |
5b04fe60 MM |
807 | } |
808 | ||
eac4a028 LP |
809 | _public_ int sd_session_get_remote_host(const char *session, char **ret_remote_host) { |
810 | return session_get_string(session, "REMOTE_HOST", ret_remote_host); | |
5b04fe60 MM |
811 | } |
812 | ||
eac4a028 | 813 | _public_ int sd_session_get_leader(const char *session, pid_t *ret_leader) { |
40308260 | 814 | _cleanup_free_ char *leader_string = NULL; |
40308260 TK |
815 | int r; |
816 | ||
40308260 TK |
817 | r = session_get_string(session, "LEADER", &leader_string); |
818 | if (r < 0) | |
819 | return r; | |
820 | ||
eac4a028 | 821 | return parse_pid(leader_string, ret_leader); |
40308260 TK |
822 | } |
823 | ||
26b5eea4 | 824 | _public_ int sd_seat_get_active(const char *seat, char **ret_session, uid_t *ret_uid) { |
d70964d0 | 825 | _cleanup_free_ char *p = NULL, *s = NULL, *t = NULL; |
74b91131 LP |
826 | int r; |
827 | ||
50b1678a LP |
828 | r = file_of_seat(seat, &p); |
829 | if (r < 0) | |
830 | return r; | |
74b91131 | 831 | |
eac4a028 | 832 | r = parse_env_file(/* f= */ NULL, p, |
74b91131 | 833 | "ACTIVE", &s, |
13df9c39 | 834 | "ACTIVE_UID", &t); |
707b66c6 LP |
835 | if (r == -ENOENT) |
836 | return -ENXIO; | |
d70964d0 | 837 | if (r < 0) |
74b91131 | 838 | return r; |
74b91131 | 839 | |
26b5eea4 | 840 | if (ret_session && !s) |
4211d5bd | 841 | return -ENODATA; |
74b91131 | 842 | |
26b5eea4 | 843 | if (ret_uid && !t) |
4211d5bd | 844 | return -ENODATA; |
74b91131 | 845 | |
26b5eea4 JW |
846 | if (ret_uid && t) { |
847 | r = parse_uid(t, ret_uid); | |
d70964d0 | 848 | if (r < 0) |
74b91131 | 849 | return r; |
74b91131 LP |
850 | } |
851 | ||
26b5eea4 JW |
852 | if (ret_session && s) |
853 | *ret_session = TAKE_PTR(s); | |
74b91131 LP |
854 | |
855 | return 0; | |
856 | } | |
034a2a52 | 857 | |
aa3b40c3 ZJS |
858 | _public_ int sd_seat_get_sessions( |
859 | const char *seat, | |
860 | char ***ret_sessions, | |
861 | uid_t **ret_uids, | |
862 | unsigned *ret_n_uids) { | |
863 | ||
864 | _cleanup_free_ char *fname = NULL, *session_line = NULL, *uid_line = NULL; | |
865 | _cleanup_strv_free_ char **sessions = NULL; | |
866 | _cleanup_free_ uid_t *uids = NULL; | |
867 | unsigned n_sessions = 0; | |
034a2a52 LP |
868 | int r; |
869 | ||
aa3b40c3 | 870 | r = file_of_seat(seat, &fname); |
50b1678a LP |
871 | if (r < 0) |
872 | return r; | |
034a2a52 | 873 | |
eac4a028 | 874 | r = parse_env_file(/* f= */ NULL, fname, |
aa3b40c3 ZJS |
875 | "SESSIONS", &session_line, |
876 | "UIDS", &uid_line); | |
707b66c6 LP |
877 | if (r == -ENOENT) |
878 | return -ENXIO; | |
d70964d0 | 879 | if (r < 0) |
034a2a52 | 880 | return r; |
034a2a52 | 881 | |
aa3b40c3 ZJS |
882 | if (session_line) { |
883 | sessions = strv_split(session_line, NULL); | |
884 | if (!sessions) | |
034a2a52 | 885 | return -ENOMEM; |
034a2a52 | 886 | |
aa3b40c3 ZJS |
887 | n_sessions = strv_length(sessions); |
888 | }; | |
034a2a52 | 889 | |
aa3b40c3 ZJS |
890 | if (ret_uids && uid_line) { |
891 | uids = new(uid_t, n_sessions); | |
892 | if (!uids) | |
893 | return -ENOMEM; | |
034a2a52 | 894 | |
aa3b40c3 ZJS |
895 | size_t n = 0; |
896 | for (const char *p = uid_line;;) { | |
897 | _cleanup_free_ char *word = NULL; | |
de3756ab | 898 | |
aa3b40c3 ZJS |
899 | r = extract_first_word(&p, &word, NULL, 0); |
900 | if (r < 0) | |
901 | return r; | |
902 | if (r == 0) | |
903 | break; | |
de3756ab | 904 | |
aa3b40c3 ZJS |
905 | r = parse_uid(word, &uids[n++]); |
906 | if (r < 0) | |
907 | return r; | |
034a2a52 | 908 | } |
d60ef526 | 909 | |
aa3b40c3 ZJS |
910 | if (n != n_sessions) |
911 | return -EUCLEAN; | |
912 | } | |
034a2a52 | 913 | |
aa3b40c3 ZJS |
914 | if (ret_sessions) |
915 | *ret_sessions = TAKE_PTR(sessions); | |
916 | if (ret_uids) | |
917 | *ret_uids = TAKE_PTR(uids); | |
918 | if (ret_n_uids) | |
919 | *ret_n_uids = n_sessions; | |
034a2a52 | 920 | |
aa3b40c3 | 921 | return n_sessions; |
034a2a52 LP |
922 | } |
923 | ||
20747498 | 924 | static int seat_get_can(const char *seat, const char *variable) { |
d70964d0 | 925 | _cleanup_free_ char *p = NULL, *s = NULL; |
add30678 LP |
926 | int r; |
927 | ||
707b66c6 | 928 | assert(variable); |
0325941f | 929 | |
50b1678a LP |
930 | r = file_of_seat(seat, &p); |
931 | if (r < 0) | |
932 | return r; | |
add30678 | 933 | |
eac4a028 | 934 | r = parse_env_file(/* f= */ NULL, p, |
13df9c39 | 935 | variable, &s); |
707b66c6 LP |
936 | if (r == -ENOENT) |
937 | return -ENXIO; | |
d70964d0 | 938 | if (r < 0) |
add30678 | 939 | return r; |
707b66c6 LP |
940 | if (isempty(s)) |
941 | return -ENODATA; | |
add30678 | 942 | |
0325941f | 943 | return parse_boolean(s); |
add30678 LP |
944 | } |
945 | ||
20747498 | 946 | _public_ int sd_seat_can_multi_session(const char *seat) { |
8f8cc84b | 947 | return true; |
20747498 LP |
948 | } |
949 | ||
950 | _public_ int sd_seat_can_tty(const char *seat) { | |
951 | return seat_get_can(seat, "CAN_TTY"); | |
952 | } | |
953 | ||
954 | _public_ int sd_seat_can_graphical(const char *seat) { | |
955 | return seat_get_can(seat, "CAN_GRAPHICAL"); | |
956 | } | |
957 | ||
eac4a028 | 958 | _public_ int sd_get_seats(char ***ret_seats) { |
2b5e9267 YW |
959 | int r; |
960 | ||
eac4a028 | 961 | r = get_files_in_directory("/run/systemd/seats/", ret_seats); |
2b5e9267 | 962 | if (r == -ENOENT) { |
eac4a028 LP |
963 | if (ret_seats) |
964 | *ret_seats = NULL; | |
2b5e9267 YW |
965 | return 0; |
966 | } | |
967 | return r; | |
034a2a52 LP |
968 | } |
969 | ||
eac4a028 | 970 | _public_ int sd_get_sessions(char ***ret_sessions) { |
2b5e9267 YW |
971 | int r; |
972 | ||
eac4a028 | 973 | r = get_files_in_directory("/run/systemd/sessions/", ret_sessions); |
2b5e9267 | 974 | if (r == -ENOENT) { |
eac4a028 LP |
975 | if (ret_sessions) |
976 | *ret_sessions = NULL; | |
2b5e9267 YW |
977 | return 0; |
978 | } | |
979 | return r; | |
034a2a52 LP |
980 | } |
981 | ||
eac4a028 | 982 | _public_ int sd_get_uids(uid_t **ret_users) { |
c2b2df60 | 983 | _cleanup_closedir_ DIR *d = NULL; |
d70964d0 | 984 | _cleanup_free_ uid_t *l = NULL; |
223a67e5 | 985 | size_t n = 0; |
034a2a52 | 986 | |
034a2a52 | 987 | d = opendir("/run/systemd/users/"); |
2b5e9267 YW |
988 | if (!d) { |
989 | if (errno == ENOENT) { | |
eac4a028 LP |
990 | if (ret_users) |
991 | *ret_users = NULL; | |
2b5e9267 YW |
992 | return 0; |
993 | } | |
8ea913b2 | 994 | return -errno; |
2b5e9267 | 995 | } |
8ea913b2 | 996 | |
8fb3f009 | 997 | FOREACH_DIRENT_ALL(de, d, return -errno) { |
034a2a52 LP |
998 | uid_t uid; |
999 | ||
034a2a52 LP |
1000 | if (!dirent_is_file(de)) |
1001 | continue; | |
1002 | ||
223a67e5 | 1003 | if (parse_uid(de->d_name, &uid) < 0) |
034a2a52 LP |
1004 | continue; |
1005 | ||
eac4a028 | 1006 | if (ret_users) { |
223a67e5 YW |
1007 | if (!GREEDY_REALLOC(l, n + 1)) |
1008 | return -ENOMEM; | |
034a2a52 | 1009 | |
223a67e5 YW |
1010 | l[n] = uid; |
1011 | } | |
034a2a52 | 1012 | |
223a67e5 | 1013 | n++; |
034a2a52 LP |
1014 | } |
1015 | ||
223a67e5 YW |
1016 | if (n > INT_MAX) |
1017 | return -EOVERFLOW; | |
1018 | ||
eac4a028 LP |
1019 | if (ret_users) |
1020 | *ret_users = TAKE_PTR(l); | |
034a2a52 | 1021 | |
223a67e5 | 1022 | return (int) n; |
034a2a52 LP |
1023 | } |
1024 | ||
eac4a028 | 1025 | _public_ int sd_get_machine_names(char ***ret_machines) { |
96480634 ZJS |
1026 | _cleanup_strv_free_ char **l = NULL; |
1027 | char **a, **b; | |
89f7c846 LP |
1028 | int r; |
1029 | ||
1030 | r = get_files_in_directory("/run/systemd/machines/", &l); | |
0543105b | 1031 | if (r == -ENOENT) { |
eac4a028 LP |
1032 | if (ret_machines) |
1033 | *ret_machines = NULL; | |
0543105b ZJS |
1034 | return 0; |
1035 | } | |
89f7c846 LP |
1036 | if (r < 0) |
1037 | return r; | |
1038 | ||
1039 | if (l) { | |
1040 | r = 0; | |
1041 | ||
1042 | /* Filter out the unit: symlinks */ | |
76ed21e1 | 1043 | for (a = b = l; *a; a++) { |
52ef5dd7 | 1044 | if (startswith(*a, "unit:") || !hostname_is_valid(*a, 0)) |
89f7c846 LP |
1045 | free(*a); |
1046 | else { | |
1047 | *b = *a; | |
1048 | b++; | |
1049 | r++; | |
1050 | } | |
1051 | } | |
1052 | ||
1053 | *b = NULL; | |
1054 | } | |
1055 | ||
eac4a028 LP |
1056 | if (ret_machines) |
1057 | *ret_machines = TAKE_PTR(l); | |
ae2a15bc | 1058 | |
89f7c846 | 1059 | return r; |
a20affe2 LP |
1060 | } |
1061 | ||
eac4a028 | 1062 | _public_ int sd_machine_get_class(const char *machine, char **ret_class) { |
0325941f | 1063 | _cleanup_free_ char *c = NULL; |
0325941f LP |
1064 | int r; |
1065 | ||
eac4a028 | 1066 | if (streq_ptr(machine, ".host")) { |
a8c9b7a0 LP |
1067 | c = strdup("host"); |
1068 | if (!c) | |
1069 | return -ENOMEM; | |
1070 | } else { | |
52ef5dd7 | 1071 | if (!hostname_is_valid(machine, 0)) |
a8c9b7a0 | 1072 | return -EINVAL; |
0325941f | 1073 | |
eac4a028 LP |
1074 | _cleanup_free_ char *p = path_join("/run/systemd/machines/", machine); |
1075 | if (!p) | |
1076 | return -ENOMEM; | |
1077 | ||
1078 | r = parse_env_file(/* f= */ NULL, p, "CLASS", &c); | |
a8c9b7a0 LP |
1079 | if (r == -ENOENT) |
1080 | return -ENXIO; | |
1081 | if (r < 0) | |
1082 | return r; | |
1083 | if (!c) | |
1084 | return -EIO; | |
1085 | } | |
0325941f | 1086 | |
eac4a028 LP |
1087 | if (ret_class) |
1088 | *ret_class = TAKE_PTR(c); | |
1089 | ||
0325941f LP |
1090 | return 0; |
1091 | } | |
1092 | ||
0ef14adc | 1093 | _public_ int sd_machine_get_ifindices(const char *machine, int **ret_ifindices) { |
eac4a028 | 1094 | _cleanup_free_ char *netif_line = NULL, *p = NULL; |
cabb0bc6 LP |
1095 | int r; |
1096 | ||
52ef5dd7 | 1097 | assert_return(hostname_is_valid(machine, 0), -EINVAL); |
cabb0bc6 | 1098 | |
eac4a028 LP |
1099 | p = path_join("/run/systemd/machines/", machine); |
1100 | if (!p) | |
1101 | return -ENOMEM; | |
1102 | ||
1103 | r = parse_env_file(/* f= */ NULL, p, "NETIF", &netif_line); | |
707b66c6 LP |
1104 | if (r == -ENOENT) |
1105 | return -ENXIO; | |
cabb0bc6 LP |
1106 | if (r < 0) |
1107 | return r; | |
0ef14adc | 1108 | if (!netif_line) { |
eac4a028 LP |
1109 | if (ret_ifindices) |
1110 | *ret_ifindices = NULL; | |
cabb0bc6 LP |
1111 | return 0; |
1112 | } | |
1113 | ||
0ef14adc ZJS |
1114 | _cleanup_strv_free_ char **tt = strv_split(netif_line, NULL); |
1115 | if (!tt) | |
1116 | return -ENOMEM; | |
cabb0bc6 | 1117 | |
7a7e97ad | 1118 | _cleanup_free_ int *ifindices = NULL; |
dd630d3c ZJS |
1119 | if (ret_ifindices) { |
1120 | ifindices = new(int, strv_length(tt)); | |
1121 | if (!ifindices) | |
1122 | return -ENOMEM; | |
1123 | } | |
cabb0bc6 | 1124 | |
7a7e97ad | 1125 | size_t n = 0; |
0ef14adc ZJS |
1126 | for (size_t i = 0; tt[i]; i++) { |
1127 | int ind; | |
cabb0bc6 | 1128 | |
0ef14adc ZJS |
1129 | ind = parse_ifindex(tt[i]); |
1130 | if (ind < 0) | |
1131 | /* Return -EUCLEAN to distinguish from -EINVAL for invalid args */ | |
1132 | return ind == -EINVAL ? -EUCLEAN : ind; | |
cabb0bc6 | 1133 | |
dd630d3c ZJS |
1134 | if (ret_ifindices) |
1135 | ifindices[n] = ind; | |
1136 | n++; | |
cabb0bc6 LP |
1137 | } |
1138 | ||
dd630d3c | 1139 | if (ret_ifindices) |
7a7e97ad LP |
1140 | *ret_ifindices = TAKE_PTR(ifindices); |
1141 | ||
0ef14adc | 1142 | return n; |
cabb0bc6 LP |
1143 | } |
1144 | ||
a1e92eee | 1145 | static int MONITOR_TO_FD(sd_login_monitor *m) { |
034a2a52 LP |
1146 | return (int) (unsigned long) m - 1; |
1147 | } | |
1148 | ||
a1e92eee | 1149 | static sd_login_monitor* FD_TO_MONITOR(int fd) { |
034a2a52 LP |
1150 | return (sd_login_monitor*) (unsigned long) (fd + 1); |
1151 | } | |
1152 | ||
eac4a028 | 1153 | _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **ret) { |
254d1313 | 1154 | _cleanup_close_ int fd = -EBADF; |
034a2a52 | 1155 | |
eac4a028 | 1156 | assert_return(ret, -EINVAL); |
034a2a52 LP |
1157 | |
1158 | fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); | |
1159 | if (fd < 0) | |
bcb161b0 | 1160 | return -errno; |
034a2a52 | 1161 | |
e2af482f LP |
1162 | static const struct { |
1163 | const char *name; | |
1164 | const char *path; | |
1165 | } categories[] = { | |
1166 | { "seat", "/run/systemd/seats/" }, | |
1167 | { "session", "/run/systemd/sessions/" }, | |
1168 | { "uid", "/run/systemd/users/" }, | |
1169 | { "machine", "/run/systemd/machines/" }, | |
1170 | }; | |
034a2a52 | 1171 | |
e2af482f LP |
1172 | bool good = false; |
1173 | FOREACH_ELEMENT(c, categories) { | |
1174 | if (category && !streq(category, c->name)) | |
1175 | continue; | |
034a2a52 | 1176 | |
e2af482f | 1177 | if (inotify_add_watch(fd, c->path, IN_MOVED_TO|IN_DELETE) < 0) |
e10375f2 | 1178 | return -errno; |
e10375f2 LP |
1179 | |
1180 | good = true; | |
1181 | } | |
1182 | ||
4cbbc2a2 | 1183 | if (!good) |
034a2a52 | 1184 | return -EINVAL; |
034a2a52 | 1185 | |
eac4a028 | 1186 | *ret = FD_TO_MONITOR(TAKE_FD(fd)); |
034a2a52 LP |
1187 | return 0; |
1188 | } | |
1189 | ||
1190 | _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { | |
d52e1c42 | 1191 | if (m) |
da6c52c5 | 1192 | (void) close(MONITOR_TO_FD(m)); |
034a2a52 LP |
1193 | |
1194 | return NULL; | |
1195 | } | |
1196 | ||
1197 | _public_ int sd_login_monitor_flush(sd_login_monitor *m) { | |
665dfe93 | 1198 | int r; |
034a2a52 | 1199 | |
1ae464e0 | 1200 | assert_return(m, -EINVAL); |
034a2a52 | 1201 | |
665dfe93 LP |
1202 | r = flush_fd(MONITOR_TO_FD(m)); |
1203 | if (r < 0) | |
1204 | return r; | |
1205 | ||
1206 | return 0; | |
034a2a52 LP |
1207 | } |
1208 | ||
1209 | _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) { | |
1210 | ||
1ae464e0 | 1211 | assert_return(m, -EINVAL); |
034a2a52 LP |
1212 | |
1213 | return MONITOR_TO_FD(m); | |
1214 | } | |
dace83cb LP |
1215 | |
1216 | _public_ int sd_login_monitor_get_events(sd_login_monitor *m) { | |
1217 | ||
1ae464e0 | 1218 | assert_return(m, -EINVAL); |
dace83cb | 1219 | |
667c24a6 LP |
1220 | /* For now we will only return POLLIN here, since we don't |
1221 | * need anything else ever for inotify. However, let's have | |
1222 | * this API to keep our options open should we later on need | |
1223 | * it. */ | |
dace83cb LP |
1224 | return POLLIN; |
1225 | } | |
667c24a6 | 1226 | |
eac4a028 | 1227 | _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *ret_timeout_usec) { |
667c24a6 | 1228 | |
1ae464e0 | 1229 | assert_return(m, -EINVAL); |
eac4a028 | 1230 | assert_return(ret_timeout_usec, -EINVAL); |
667c24a6 | 1231 | |
f5fbe71d | 1232 | /* For now we will only return UINT64_MAX, since we don't |
667c24a6 LP |
1233 | * need any timeout. However, let's have this API to keep our |
1234 | * options open should we later on need it. */ | |
eac4a028 | 1235 | *ret_timeout_usec = UINT64_MAX; |
667c24a6 LP |
1236 | return 0; |
1237 | } |