]>
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 | ||
22 | #include <unistd.h> | |
23 | #include <string.h> | |
24 | #include <errno.h> | |
034a2a52 | 25 | #include <sys/inotify.h> |
74b91131 LP |
26 | |
27 | #include "util.h" | |
28 | #include "cgroup-util.h" | |
29 | #include "macro.h" | |
30 | #include "sd-login.h" | |
034a2a52 | 31 | #include "strv.h" |
74b91131 | 32 | |
034a2a52 | 33 | static int pid_get_cgroup(pid_t pid, char **root, char **cgroup) { |
74b91131 | 34 | char *cg_process, *cg_init, *p; |
034a2a52 | 35 | int r; |
74b91131 LP |
36 | |
37 | if (pid == 0) | |
38 | pid = getpid(); | |
39 | ||
40 | if (pid <= 0) | |
41 | return -EINVAL; | |
42 | ||
74b91131 LP |
43 | r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &cg_process); |
44 | if (r < 0) | |
45 | return r; | |
46 | ||
47 | r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &cg_init); | |
48 | if (r < 0) { | |
49 | free(cg_process); | |
50 | return r; | |
51 | } | |
52 | ||
53 | if (endswith(cg_init, "/system")) | |
54 | cg_init[strlen(cg_init)-7] = 0; | |
55 | else if (streq(cg_init, "/")) | |
56 | cg_init[0] = 0; | |
57 | ||
58 | if (startswith(cg_process, cg_init)) | |
59 | p = cg_process + strlen(cg_init); | |
60 | else | |
61 | p = cg_process; | |
62 | ||
63 | free(cg_init); | |
64 | ||
034a2a52 LP |
65 | if (cgroup) { |
66 | char* c; | |
67 | ||
68 | c = strdup(p); | |
69 | if (!c) { | |
70 | free(cg_process); | |
71 | return -ENOMEM; | |
72 | } | |
73 | ||
74 | *cgroup = c; | |
74b91131 LP |
75 | } |
76 | ||
034a2a52 LP |
77 | if (root) { |
78 | cg_process[p-cg_process] = 0; | |
79 | *root = cg_process; | |
80 | } else | |
74b91131 | 81 | free(cg_process); |
034a2a52 LP |
82 | |
83 | return 0; | |
84 | } | |
85 | ||
86 | _public_ int sd_pid_get_session(pid_t pid, char **session) { | |
87 | int r; | |
88 | char *cgroup, *p; | |
89 | ||
90 | if (!session) | |
91 | return -EINVAL; | |
92 | ||
93 | r = pid_get_cgroup(pid, NULL, &cgroup); | |
94 | if (r < 0) | |
95 | return r; | |
96 | ||
97 | if (!startswith(cgroup, "/user/")) { | |
98 | free(cgroup); | |
74b91131 LP |
99 | return -ENOENT; |
100 | } | |
101 | ||
034a2a52 | 102 | p = strchr(cgroup + 6, '/'); |
74b91131 | 103 | if (!p) { |
034a2a52 | 104 | free(cgroup); |
74b91131 LP |
105 | return -ENOENT; |
106 | } | |
107 | ||
108 | p++; | |
034a2a52 LP |
109 | if (startswith(p, "shared/") || streq(p, "shared")) { |
110 | free(cgroup); | |
111 | return -ENOENT; | |
112 | } | |
113 | ||
74b91131 | 114 | p = strndup(p, strcspn(p, "/")); |
034a2a52 | 115 | free(cgroup); |
74b91131 LP |
116 | |
117 | if (!p) | |
118 | return -ENOMEM; | |
119 | ||
120 | *session = p; | |
121 | return 0; | |
122 | } | |
123 | ||
94fb446e | 124 | _public_ int sd_pid_get_unit(pid_t pid, char **unit) { |
9847946e | 125 | int r; |
ebda471d LP |
126 | char *cgroup, *p, *at, *b; |
127 | size_t k; | |
9847946e | 128 | |
94fb446e | 129 | if (!unit) |
9847946e LP |
130 | return -EINVAL; |
131 | ||
132 | r = pid_get_cgroup(pid, NULL, &cgroup); | |
133 | if (r < 0) | |
134 | return r; | |
135 | ||
136 | if (!startswith(cgroup, "/system/")) { | |
137 | free(cgroup); | |
138 | return -ENOENT; | |
139 | } | |
140 | ||
141 | p = cgroup + 8; | |
ebda471d LP |
142 | k = strcspn(p, "/"); |
143 | ||
144 | at = memchr(p, '@', k); | |
145 | if (at && at[1] == '.') { | |
146 | size_t j; | |
147 | ||
148 | /* This is a templated service */ | |
149 | if (p[k] != '/') { | |
150 | free(cgroup); | |
151 | return -EIO; | |
152 | } | |
153 | ||
154 | j = strcspn(p+k+1, "/"); | |
155 | ||
156 | b = malloc(k + j + 1); | |
157 | ||
158 | if (b) { | |
159 | memcpy(b, p, at - p + 1); | |
160 | memcpy(b + (at - p) + 1, p + k + 1, j); | |
161 | memcpy(b + (at - p) + 1 + j, at + 1, k - (at - p) - 1); | |
162 | b[k+j] = 0; | |
163 | } | |
164 | } else | |
165 | b = strndup(p, k); | |
166 | ||
9847946e LP |
167 | free(cgroup); |
168 | ||
ebda471d | 169 | if (!b) |
9847946e LP |
170 | return -ENOMEM; |
171 | ||
ebda471d | 172 | *unit = b; |
9847946e LP |
173 | return 0; |
174 | } | |
175 | ||
034a2a52 LP |
176 | _public_ int sd_pid_get_owner_uid(pid_t pid, uid_t *uid) { |
177 | int r; | |
178 | char *root, *cgroup, *p, *cc; | |
179 | struct stat st; | |
180 | ||
181 | if (!uid) | |
182 | return -EINVAL; | |
183 | ||
184 | r = pid_get_cgroup(pid, &root, &cgroup); | |
185 | if (r < 0) | |
186 | return r; | |
187 | ||
188 | if (!startswith(cgroup, "/user/")) { | |
189 | free(cgroup); | |
190 | free(root); | |
191 | return -ENOENT; | |
192 | } | |
193 | ||
194 | p = strchr(cgroup + 6, '/'); | |
195 | if (!p) { | |
196 | free(cgroup); | |
197 | return -ENOENT; | |
198 | } | |
199 | ||
200 | p++; | |
201 | p += strcspn(p, "/"); | |
202 | *p = 0; | |
203 | ||
204 | r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, cgroup, &cc); | |
205 | free(root); | |
206 | free(cgroup); | |
207 | ||
208 | if (r < 0) | |
209 | return -ENOMEM; | |
210 | ||
211 | r = lstat(cc, &st); | |
212 | free(cc); | |
213 | ||
214 | if (r < 0) | |
215 | return -errno; | |
216 | ||
217 | if (!S_ISDIR(st.st_mode)) | |
218 | return -ENOTDIR; | |
219 | ||
220 | *uid = st.st_uid; | |
221 | return 0; | |
222 | } | |
223 | ||
74b91131 LP |
224 | _public_ int sd_uid_get_state(uid_t uid, char**state) { |
225 | char *p, *s = NULL; | |
226 | int r; | |
227 | ||
228 | if (!state) | |
229 | return -EINVAL; | |
230 | ||
231 | if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) | |
232 | return -ENOMEM; | |
233 | ||
234 | r = parse_env_file(p, NEWLINE, "STATE", &s, NULL); | |
235 | free(p); | |
236 | ||
237 | if (r == -ENOENT) { | |
238 | free(s); | |
239 | s = strdup("offline"); | |
240 | if (!s) | |
241 | return -ENOMEM; | |
242 | ||
243 | *state = s; | |
244 | return 0; | |
245 | } else if (r < 0) { | |
246 | free(s); | |
247 | return r; | |
248 | } else if (!s) | |
249 | return -EIO; | |
250 | ||
251 | *state = s; | |
252 | return 0; | |
253 | } | |
254 | ||
034a2a52 | 255 | _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat) { |
74b91131 LP |
256 | char *p, *w, *t, *state, *s = NULL; |
257 | size_t l; | |
258 | int r; | |
034a2a52 | 259 | const char *variable; |
74b91131 LP |
260 | |
261 | if (!seat) | |
262 | return -EINVAL; | |
263 | ||
034a2a52 LP |
264 | variable = require_active ? "ACTIVE_UID" : "UIDS"; |
265 | ||
74b91131 LP |
266 | p = strappend("/run/systemd/seats/", seat); |
267 | if (!p) | |
268 | return -ENOMEM; | |
269 | ||
034a2a52 | 270 | r = parse_env_file(p, NEWLINE, variable, &s, NULL); |
74b91131 LP |
271 | free(p); |
272 | ||
273 | if (r < 0) { | |
274 | free(s); | |
275 | return r; | |
276 | } | |
277 | ||
278 | if (!s) | |
279 | return -EIO; | |
280 | ||
281 | if (asprintf(&t, "%lu", (unsigned long) uid) < 0) { | |
282 | free(s); | |
283 | return -ENOMEM; | |
284 | } | |
285 | ||
286 | FOREACH_WORD(w, l, s, state) { | |
287 | if (strncmp(t, w, l) == 0) { | |
288 | free(s); | |
289 | free(t); | |
290 | ||
291 | return 1; | |
292 | } | |
293 | } | |
294 | ||
295 | free(s); | |
296 | free(t); | |
297 | ||
298 | return 0; | |
299 | } | |
300 | ||
034a2a52 LP |
301 | static int uid_get_array(uid_t uid, const char *variable, char ***array) { |
302 | char *p, *s = NULL; | |
303 | char **a; | |
304 | int r; | |
305 | ||
034a2a52 LP |
306 | if (asprintf(&p, "/run/systemd/users/%lu", (unsigned long) uid) < 0) |
307 | return -ENOMEM; | |
308 | ||
309 | r = parse_env_file(p, NEWLINE, | |
310 | variable, &s, | |
311 | NULL); | |
312 | free(p); | |
313 | ||
314 | if (r < 0) { | |
315 | free(s); | |
316 | ||
317 | if (r == -ENOENT) { | |
d60ef526 LP |
318 | if (array) |
319 | *array = NULL; | |
034a2a52 LP |
320 | return 0; |
321 | } | |
322 | ||
323 | return r; | |
324 | } | |
325 | ||
326 | if (!s) { | |
d60ef526 LP |
327 | if (array) |
328 | *array = NULL; | |
034a2a52 LP |
329 | return 0; |
330 | } | |
331 | ||
332 | a = strv_split(s, " "); | |
333 | free(s); | |
334 | ||
335 | if (!a) | |
336 | return -ENOMEM; | |
337 | ||
d60ef526 LP |
338 | strv_uniq(a); |
339 | r = strv_length(a); | |
340 | ||
341 | if (array) | |
342 | *array = a; | |
343 | else | |
344 | strv_free(a); | |
345 | ||
346 | return r; | |
034a2a52 LP |
347 | } |
348 | ||
349 | _public_ int sd_uid_get_sessions(uid_t uid, int require_active, char ***sessions) { | |
350 | return uid_get_array(uid, require_active ? "ACTIVE_SESSIONS" : "SESSIONS", sessions); | |
74b91131 LP |
351 | } |
352 | ||
034a2a52 LP |
353 | _public_ int sd_uid_get_seats(uid_t uid, int require_active, char ***seats) { |
354 | return uid_get_array(uid, require_active ? "ACTIVE_SEATS" : "SEATS", seats); | |
74b91131 LP |
355 | } |
356 | ||
50b1678a LP |
357 | static int file_of_session(const char *session, char **_p) { |
358 | char *p; | |
74b91131 | 359 | int r; |
74b91131 | 360 | |
50b1678a LP |
361 | assert(_p); |
362 | ||
363 | if (session) | |
364 | p = strappend("/run/systemd/sessions/", session); | |
365 | else { | |
366 | char *buf; | |
367 | ||
368 | r = sd_pid_get_session(0, &buf); | |
369 | if (r < 0) | |
370 | return r; | |
371 | ||
372 | p = strappend("/run/systemd/sessions/", buf); | |
373 | free(buf); | |
374 | } | |
74b91131 | 375 | |
74b91131 LP |
376 | if (!p) |
377 | return -ENOMEM; | |
378 | ||
50b1678a LP |
379 | *_p = p; |
380 | return 0; | |
381 | } | |
382 | ||
383 | _public_ int sd_session_is_active(const char *session) { | |
384 | int r; | |
385 | char *p, *s = NULL; | |
386 | ||
387 | r = file_of_session(session, &p); | |
388 | if (r < 0) | |
389 | return r; | |
390 | ||
74b91131 LP |
391 | r = parse_env_file(p, NEWLINE, "ACTIVE", &s, NULL); |
392 | free(p); | |
393 | ||
394 | if (r < 0) { | |
395 | free(s); | |
396 | return r; | |
397 | } | |
398 | ||
399 | if (!s) | |
400 | return -EIO; | |
401 | ||
402 | r = parse_boolean(s); | |
403 | free(s); | |
404 | ||
405 | return r; | |
406 | } | |
407 | ||
408 | _public_ int sd_session_get_uid(const char *session, uid_t *uid) { | |
409 | int r; | |
410 | char *p, *s = NULL; | |
74b91131 | 411 | |
74b91131 LP |
412 | if (!uid) |
413 | return -EINVAL; | |
414 | ||
50b1678a LP |
415 | r = file_of_session(session, &p); |
416 | if (r < 0) | |
417 | return r; | |
74b91131 LP |
418 | |
419 | r = parse_env_file(p, NEWLINE, "UID", &s, NULL); | |
420 | free(p); | |
421 | ||
422 | if (r < 0) { | |
423 | free(s); | |
424 | return r; | |
425 | } | |
426 | ||
427 | if (!s) | |
428 | return -EIO; | |
429 | ||
ddd88763 | 430 | r = parse_uid(s, uid); |
74b91131 LP |
431 | free(s); |
432 | ||
ddd88763 | 433 | return r; |
74b91131 LP |
434 | } |
435 | ||
51f58f08 | 436 | static int session_get_string(const char *session, const char *field, char **value) { |
74b91131 LP |
437 | char *p, *s = NULL; |
438 | int r; | |
439 | ||
51f58f08 | 440 | if (!value) |
74b91131 LP |
441 | return -EINVAL; |
442 | ||
50b1678a LP |
443 | r = file_of_session(session, &p); |
444 | if (r < 0) | |
445 | return r; | |
74b91131 | 446 | |
51f58f08 | 447 | r = parse_env_file(p, NEWLINE, field, &s, NULL); |
74b91131 LP |
448 | free(p); |
449 | ||
450 | if (r < 0) { | |
451 | free(s); | |
452 | return r; | |
453 | } | |
454 | ||
455 | if (isempty(s)) | |
456 | return -ENOENT; | |
457 | ||
51f58f08 | 458 | *value = s; |
74b91131 LP |
459 | return 0; |
460 | } | |
461 | ||
51f58f08 LP |
462 | _public_ int sd_session_get_seat(const char *session, char **seat) { |
463 | return session_get_string(session, "SEAT", seat); | |
464 | } | |
eff40633 | 465 | |
51f58f08 LP |
466 | _public_ int sd_session_get_service(const char *session, char **service) { |
467 | return session_get_string(session, "SERVICE", service); | |
468 | } | |
eff40633 | 469 | |
51f58f08 LP |
470 | _public_ int sd_session_get_type(const char *session, char **type) { |
471 | return session_get_string(session, "TYPE", type); | |
472 | } | |
eff40633 | 473 | |
51f58f08 LP |
474 | _public_ int sd_session_get_class(const char *session, char **class) { |
475 | return session_get_string(session, "CLASS", class); | |
eff40633 LP |
476 | } |
477 | ||
fc8af9ff LP |
478 | _public_ int sd_session_get_display(const char *session, char **display) { |
479 | return session_get_string(session, "DISPLAY", display); | |
480 | } | |
481 | ||
50b1678a LP |
482 | static int file_of_seat(const char *seat, char **_p) { |
483 | char *p; | |
484 | int r; | |
485 | ||
486 | assert(_p); | |
487 | ||
488 | if (seat) | |
489 | p = strappend("/run/systemd/seats/", seat); | |
490 | else { | |
491 | char *buf; | |
492 | ||
493 | r = sd_session_get_seat(NULL, &buf); | |
494 | if (r < 0) | |
495 | return r; | |
496 | ||
497 | p = strappend("/run/systemd/seats/", buf); | |
498 | free(buf); | |
499 | } | |
500 | ||
501 | if (!p) | |
502 | return -ENOMEM; | |
503 | ||
504 | *_p = p; | |
505 | return 0; | |
506 | } | |
507 | ||
74b91131 LP |
508 | _public_ int sd_seat_get_active(const char *seat, char **session, uid_t *uid) { |
509 | char *p, *s = NULL, *t = NULL; | |
510 | int r; | |
511 | ||
74b91131 LP |
512 | if (!session && !uid) |
513 | return -EINVAL; | |
514 | ||
50b1678a LP |
515 | r = file_of_seat(seat, &p); |
516 | if (r < 0) | |
517 | return r; | |
74b91131 LP |
518 | |
519 | r = parse_env_file(p, NEWLINE, | |
520 | "ACTIVE", &s, | |
521 | "ACTIVE_UID", &t, | |
522 | NULL); | |
523 | free(p); | |
524 | ||
525 | if (r < 0) { | |
526 | free(s); | |
527 | free(t); | |
528 | return r; | |
529 | } | |
530 | ||
531 | if (session && !s) { | |
532 | free(t); | |
034a2a52 | 533 | return -ENOENT; |
74b91131 LP |
534 | } |
535 | ||
536 | if (uid && !t) { | |
537 | free(s); | |
034a2a52 | 538 | return -ENOENT; |
74b91131 LP |
539 | } |
540 | ||
541 | if (uid && t) { | |
034a2a52 | 542 | r = parse_uid(t, uid); |
74b91131 LP |
543 | if (r < 0) { |
544 | free(t); | |
545 | free(s); | |
546 | return r; | |
547 | } | |
74b91131 LP |
548 | } |
549 | ||
550 | free(t); | |
551 | ||
552 | if (session && s) | |
553 | *session = s; | |
554 | else | |
555 | free(s); | |
556 | ||
557 | return 0; | |
558 | } | |
034a2a52 LP |
559 | |
560 | _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uids, unsigned *n_uids) { | |
561 | char *p, *s = NULL, *t = NULL, **a = NULL; | |
562 | uid_t *b = NULL; | |
563 | unsigned n = 0; | |
564 | int r; | |
565 | ||
50b1678a LP |
566 | r = file_of_seat(seat, &p); |
567 | if (r < 0) | |
568 | return r; | |
034a2a52 LP |
569 | |
570 | r = parse_env_file(p, NEWLINE, | |
571 | "SESSIONS", &s, | |
572 | "ACTIVE_SESSIONS", &t, | |
573 | NULL); | |
574 | free(p); | |
575 | ||
576 | if (r < 0) { | |
577 | free(s); | |
578 | free(t); | |
579 | return r; | |
580 | } | |
581 | ||
d60ef526 | 582 | if (s) { |
034a2a52 LP |
583 | a = strv_split(s, " "); |
584 | if (!a) { | |
585 | free(s); | |
586 | free(t); | |
587 | return -ENOMEM; | |
588 | } | |
589 | } | |
590 | ||
591 | free(s); | |
592 | ||
593 | if (uids && t) { | |
594 | char *w, *state; | |
595 | size_t l; | |
034a2a52 LP |
596 | |
597 | FOREACH_WORD(w, l, t, state) | |
598 | n++; | |
599 | ||
de3756ab LP |
600 | if (n == 0) |
601 | b = NULL; | |
602 | else { | |
603 | unsigned i = 0; | |
034a2a52 | 604 | |
de3756ab LP |
605 | b = new(uid_t, n); |
606 | if (!b) { | |
8ea913b2 | 607 | strv_free(a); |
034a2a52 LP |
608 | return -ENOMEM; |
609 | } | |
610 | ||
de3756ab LP |
611 | FOREACH_WORD(w, l, t, state) { |
612 | char *k; | |
034a2a52 | 613 | |
de3756ab LP |
614 | k = strndup(w, l); |
615 | if (!k) { | |
616 | free(t); | |
617 | free(b); | |
618 | strv_free(a); | |
619 | return -ENOMEM; | |
620 | } | |
621 | ||
622 | r = parse_uid(k, b + i); | |
623 | free(k); | |
624 | if (r < 0) | |
625 | continue; | |
626 | ||
627 | i++; | |
628 | } | |
034a2a52 LP |
629 | } |
630 | } | |
631 | ||
632 | free(t); | |
633 | ||
d60ef526 LP |
634 | r = strv_length(a); |
635 | ||
034a2a52 LP |
636 | if (sessions) |
637 | *sessions = a; | |
d60ef526 LP |
638 | else |
639 | strv_free(a); | |
034a2a52 LP |
640 | |
641 | if (uids) | |
642 | *uids = b; | |
643 | ||
644 | if (n_uids) | |
645 | *n_uids = n; | |
646 | ||
d60ef526 | 647 | return r; |
034a2a52 LP |
648 | } |
649 | ||
add30678 LP |
650 | _public_ int sd_seat_can_multi_session(const char *seat) { |
651 | char *p, *s = NULL; | |
652 | int r; | |
653 | ||
50b1678a LP |
654 | r = file_of_seat(seat, &p); |
655 | if (r < 0) | |
656 | return r; | |
add30678 LP |
657 | |
658 | r = parse_env_file(p, NEWLINE, | |
addedec4 | 659 | "CAN_MULTI_SESSION", &s, |
add30678 LP |
660 | NULL); |
661 | free(p); | |
662 | ||
663 | if (r < 0) { | |
664 | free(s); | |
665 | return r; | |
666 | } | |
667 | ||
668 | if (s) { | |
669 | r = parse_boolean(s); | |
670 | free(s); | |
671 | } else | |
672 | r = 0; | |
673 | ||
674 | return r; | |
675 | } | |
676 | ||
034a2a52 | 677 | _public_ int sd_get_seats(char ***seats) { |
034a2a52 LP |
678 | return get_files_in_directory("/run/systemd/seats/", seats); |
679 | } | |
680 | ||
681 | _public_ int sd_get_sessions(char ***sessions) { | |
034a2a52 LP |
682 | return get_files_in_directory("/run/systemd/sessions/", sessions); |
683 | } | |
684 | ||
685 | _public_ int sd_get_uids(uid_t **users) { | |
686 | DIR *d; | |
687 | int r = 0; | |
688 | unsigned n = 0; | |
689 | uid_t *l = NULL; | |
690 | ||
034a2a52 | 691 | d = opendir("/run/systemd/users/"); |
8ea913b2 LP |
692 | if (!d) |
693 | return -errno; | |
694 | ||
034a2a52 LP |
695 | for (;;) { |
696 | struct dirent buffer, *de; | |
697 | int k; | |
698 | uid_t uid; | |
699 | ||
700 | k = readdir_r(d, &buffer, &de); | |
701 | if (k != 0) { | |
702 | r = -k; | |
703 | goto finish; | |
704 | } | |
705 | ||
706 | if (!de) | |
707 | break; | |
708 | ||
709 | dirent_ensure_type(d, de); | |
710 | ||
711 | if (!dirent_is_file(de)) | |
712 | continue; | |
713 | ||
714 | k = parse_uid(de->d_name, &uid); | |
715 | if (k < 0) | |
716 | continue; | |
717 | ||
d60ef526 LP |
718 | if (users) { |
719 | if ((unsigned) r >= n) { | |
720 | uid_t *t; | |
034a2a52 | 721 | |
d60ef526 LP |
722 | n = MAX(16, 2*r); |
723 | t = realloc(l, sizeof(uid_t) * n); | |
724 | if (!t) { | |
725 | r = -ENOMEM; | |
726 | goto finish; | |
727 | } | |
034a2a52 | 728 | |
d60ef526 LP |
729 | l = t; |
730 | } | |
034a2a52 | 731 | |
d60ef526 LP |
732 | assert((unsigned) r < n); |
733 | l[r++] = uid; | |
734 | } else | |
735 | r++; | |
034a2a52 LP |
736 | } |
737 | ||
738 | finish: | |
739 | if (d) | |
740 | closedir(d); | |
741 | ||
d60ef526 LP |
742 | if (r >= 0) { |
743 | if (users) | |
744 | *users = l; | |
745 | } else | |
034a2a52 LP |
746 | free(l); |
747 | ||
748 | return r; | |
749 | } | |
750 | ||
751 | static inline int MONITOR_TO_FD(sd_login_monitor *m) { | |
752 | return (int) (unsigned long) m - 1; | |
753 | } | |
754 | ||
755 | static inline sd_login_monitor* FD_TO_MONITOR(int fd) { | |
756 | return (sd_login_monitor*) (unsigned long) (fd + 1); | |
757 | } | |
758 | ||
759 | _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { | |
034a2a52 LP |
760 | int fd, k; |
761 | bool good = false; | |
762 | ||
763 | if (!m) | |
764 | return -EINVAL; | |
765 | ||
766 | fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC); | |
767 | if (fd < 0) | |
768 | return errno; | |
769 | ||
770 | if (!category || streq(category, "seat")) { | |
771 | k = inotify_add_watch(fd, "/run/systemd/seats/", IN_MOVED_TO|IN_DELETE); | |
772 | if (k < 0) { | |
773 | close_nointr_nofail(fd); | |
774 | return -errno; | |
775 | } | |
776 | ||
777 | good = true; | |
778 | } | |
779 | ||
780 | if (!category || streq(category, "session")) { | |
781 | k = inotify_add_watch(fd, "/run/systemd/sessions/", IN_MOVED_TO|IN_DELETE); | |
782 | if (k < 0) { | |
783 | close_nointr_nofail(fd); | |
784 | return -errno; | |
785 | } | |
786 | ||
787 | good = true; | |
788 | } | |
789 | ||
790 | if (!category || streq(category, "uid")) { | |
791 | k = inotify_add_watch(fd, "/run/systemd/users/", IN_MOVED_TO|IN_DELETE); | |
792 | if (k < 0) { | |
793 | close_nointr_nofail(fd); | |
794 | return -errno; | |
795 | } | |
796 | ||
797 | good = true; | |
798 | } | |
799 | ||
800 | if (!good) { | |
801 | close_nointr(fd); | |
802 | return -EINVAL; | |
803 | } | |
804 | ||
805 | *m = FD_TO_MONITOR(fd); | |
806 | return 0; | |
807 | } | |
808 | ||
809 | _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { | |
810 | int fd; | |
811 | ||
812 | if (!m) | |
813 | return NULL; | |
814 | ||
815 | fd = MONITOR_TO_FD(m); | |
816 | close_nointr(fd); | |
817 | ||
818 | return NULL; | |
819 | } | |
820 | ||
821 | _public_ int sd_login_monitor_flush(sd_login_monitor *m) { | |
822 | ||
823 | if (!m) | |
824 | return -EINVAL; | |
825 | ||
826 | return flush_fd(MONITOR_TO_FD(m)); | |
827 | } | |
828 | ||
829 | _public_ int sd_login_monitor_get_fd(sd_login_monitor *m) { | |
830 | ||
831 | if (!m) | |
832 | return -EINVAL; | |
833 | ||
834 | return MONITOR_TO_FD(m); | |
835 | } |