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