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